├── .gitignore ├── AUTHORS ├── CHANGLOG.md ├── LICENSE ├── README.md ├── TODO ├── doc ├── HOWTO.md └── img │ ├── 00-configure-libnfc.jpg │ ├── 01-configure-libfreefare.jpg │ └── 02-configure-libfreefare.jpg ├── img ├── 00-GNFC-0.1.1.jpg ├── 00-GNFC-0.2.0-default.jpg └── 00-GNFC-0.2.0-ndef.jpg └── src ├── ewin_beep.cpp ├── ewin_beep.h ├── gnfc.pro ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── mf1ics50writeblock.cpp ├── mf1ics50writeblock.h ├── mf1ics50writeblock.ui ├── pn532_extend_cmd.cpp ├── pn532_extend_cmd.h ├── snepClient.cpp ├── snepClient.h ├── snepServer.cpp └── snepServer.h /.gitignore: -------------------------------------------------------------------------------- 1 | bak 2 | build* 3 | release 4 | *.patch 5 | *.pro.user -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Jiapeng Li -------------------------------------------------------------------------------- /CHANGLOG.md: -------------------------------------------------------------------------------- 1 | ## V0.2.0 2 | *2013-12-28* 3 | 4 | + NDEF is supported on both Win32 and Linux 5 | + Net PN532 device is supported 6 | + Fix some bugs 7 | 8 | ## V0.1.1 9 | *2013-12-17* 10 | 11 | + Serial Port Auto Detect 12 | + Read Felica/ISO14443-A/ISO14443-B types card ID, support verbose mode. 13 | + Read/Write Mifare S50 card blocks. 14 | + On Linux, support push/pull NDEF with Android 4.0+ 15 | 16 | ## V0.1.0 17 | 18 | *Non-Release version, used for internal testing.* 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GNFC 2 | 3 | GNFC is an OpenSource GUI NFC tool, it is based on QT and several nfc libraries(libnfc/libfreefare/libllcp/libndef). GNFC aims at showing how to NFC devices/modules to read card, write card, even exchange data with Android 4.0+ device. 4 | 5 | ## Feature 6 | 7 | + Support uart and net pn532 device 8 | + Serial Port Auto Detect 9 | + Read Felica/ISO14443-A/ISO14443-B types card ID, support verbose mode. 10 | + Read/Write Mifare S50 card blocks. 11 | + Support push/pull NDEF with Android 4.0+(Win32/Linux) 12 | + Beep function for Uart device 13 | 14 | ## Supported Devices 15 | 16 | + [Elechouse USB NFC Device]() 17 | + [Elechouse WIFI NFC Device]() 18 | 19 | ## Latest Release 20 | 21 | #### Windows 22 | Pre-build binary file. [Download](https://github.com/JiapengLi/GNFC/releases/download/v0.2.0/gnfc-0.2.0-win.zip) 23 | 24 | #### Linux 25 | Source code. [Download](https://github.com/JiapengLi/GNFC/archive/v0.2.0.zip) 26 | 27 | ## Bugs 28 | 29 | ## DOC 30 | [HOWTO](./doc/HOWTO.md) 31 | 32 | 33 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/JiapengLi/gnfc/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 34 | 35 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | # TO DO 2 | 3 | + icon 4 | + Add support to MiFare s70 5 | + MiFare NDEF Support 6 | + NDEF Card Emulator 7 | + vCard 8 | + Be kind to user, limit operation(lock tabs, lock ndef push&pull) 9 | + push/pull cycle 10 | -------------------------------------------------------------------------------- /doc/HOWTO.md: -------------------------------------------------------------------------------- 1 | #GNFC 2 | GNFC is an OpenSource GUI NFC tool, it is based on QT and several nfc libraries(libnfc/libfreefare/libllcp/libndef). GNFC aims at showing how to NFC devices/modules to read card, write card, even exchange data with Android 4.0+ device. 3 | 4 | 5 | ## Supported Devices 6 | 7 | ### [Elechouse USB NFC Device](http://elechouse.com) 8 | 9 | [ELECHOUSE USB NFC Device]() is based on PN532, with an MCU and a beeper inside, the beeper can be controlled by sending command(in PN532 frame format) to it, the command value to control beeper is **0xA0**, after receive the `BEEP` command [ELECHOUSE USB NFC Device](http://elechouse.com) won't send ack package. 10 | 11 | ### [Elechouse WIFI NFC Device](http://elechouse.com) 12 | It is an OpenWrt based device, with a pn532 module in it. It is supported by pn532_net driver, pn532_net driver is at [JiapengLi/libnfc](https://github.com/JiapengLi/libnfc) 13 | 14 | [Elechouse WIFI NFC Device]() 15 | 16 | ## Dependence 17 | 18 | + [libnfc](https://code.google.com/p/libnfc/) 19 | + [libfreefare](https://code.google.com/p/libfreefare/) 20 | + [libllcp](https://code.google.com/p/libllcp/) 21 | + [libndef](https://github.com/nfc-tools/libndef) 22 | + [QT5](http://qt-project.org/) 23 | 24 | ## Compile Environment 25 | 26 | ### Windows 27 | 28 | There is a pre-build binary file. [Download](https://github.com/JiapengLi/GNFC/releases/download/v0.2.0/gnfc-0.2.0-win.zip) 29 | 30 | #### Tools 31 | Some tools is needed to compile libnfc and libfreefare. 32 | 33 | + [Win32OpenSSL](http://slproweb.com/download/Win32OpenSSL-1_0_1e.exe) 34 | + [PCRE](http://hivelocity.dl.sourceforge.net/project/gnuwin32/pcre/7.0/pcre-7.0.exe) 35 | + [cmake](http://www.cmake.org/files/v2.8/cmake-2.8.12.1-win32-x86.exe) 36 | 37 | Install all of these tools. 38 | 39 | #### QT5 40 | Install [QT5.1.1](http://download.qt-project.org/official_releases/qt/) or high. 41 | 42 | To build libnfc and libfreefare, we use the MinGW tool chain of QT, so add 43 | `Qt/Qt5.1.1/Tools/mingw48_32/bin` to environment variable `PATH` 44 | 45 | #### libnfc 46 | [A detailed instruction to compile libnfc under Windows](http://www.mobilefish.com/developer/libnfc/libnfc.html) 47 | ![0](./img/00-configure-libnfc.jpg) 48 | 49 | #### libfreefare 50 | Use cmake to configure libfreefare, then generate Makefile for it. 51 | ![1](./img/01-configure-libfreefare.jpg) 52 | 53 | ![2](./img/02-configure-libfreefare.jpg) 54 | 55 | #### libllcp 56 | Download the libllcp source code. switch to **origin/socket** branch. Then use cmake to generate MinGW Makefiles just like *libfreefare*, by addition, specify the libws2_32.lib.a for it. 57 | 58 | mingw32-make 59 | 60 | #### libndef 61 | 62 | 63 | *Install programs by default and set parameter like pictures above may save some time.* 64 | 65 | ### Linux 66 | 67 | #### QT5 68 | 69 | 1. Download [`qt-linux-opensource-5.x.x-x86-offline.run`](http://download.qt-project.org/official_releases/qt/) 70 | 2. `sudo chmod +x qt-linux-opensource-5.1.1-x86-offline.run` 71 | 3. `./qt-linux-opensource-5.1.1-x86-offline.run` 72 | 4. next...next...next... 73 | 5. (Optional) Fix startup error. [See Reference](http://askubuntu.com/questions/253785/cannot-overwrite-file-home-baadshah-config-qtproject-qtcreator-toolchains-xml) 74 | 75 | sudo -s chmod o+w /home/yourname/.config/QtProject/qtcreator/*.x 76 | sudo chown -R $USER:$USER /home/lich/.config/QtProject/ 77 | 78 | #### libnfc 79 | 80 | *so far, pn532_net driver is not included by libnfc, checkout [JiapengLi/libnfc](https://github.com/JiapengLi/libnfc) instead, by which net driver is included. To use net driver specify a device name like "pn532_net:192.168.1.1:8000".* 81 | 82 | autoreconf -vis 83 | ./configure --with-drivers=pn532_uart,pn532_net --sysconfdir=/etc --prefix=/usr 84 | make 85 | sudo make install all 86 | 87 | #### libfreefare 88 | 89 | autoreconf -vis 90 | ./configure --prefix=/usr 91 | make 92 | sudo make install 93 | 94 | #### libllcp 95 | 96 | autoreconf -vis 97 | ./configure --prefix=/usr 98 | make 99 | sudo make install 100 | 101 | #### libndef 102 | 103 | qmake 104 | mingw32-make 105 | 106 | lib files locate at *libndef/libndef/release/*, named **libndef1.a** and **ndef1.dll**, libndef/include/*.h is also needed. 107 | 108 | 109 | ## GNFC 110 | After all are prepared done. Download the GNFC source code, open the `gnfc.pro` with QT Creator, compile and run it. 111 | 112 | ### Windows 113 | For windows, the dll files below may be needed. Different QT may be different here. 114 | 115 | ./icudt51.dll 116 | ./icuin51.dll 117 | ./icuuc51.dll 118 | ./libeay32.dll 119 | ./libfreefare.dll 120 | ./libgcc_s_dw2-1.dll 121 | ./libnfc.dll 122 | ./libstdc++-6.dll 123 | ./libwinpthread-1.dll 124 | ./pcre3.dll 125 | ./Qt5Core.dll 126 | ./Qt5Gui.dll 127 | ./Qt5SerialPort.dll 128 | ./Qt5Widgets.dll 129 | 130 | ./platforms/qwindows.dll 131 | 132 | ### Linux -------------------------------------------------------------------------------- /doc/img/00-configure-libnfc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/doc/img/00-configure-libnfc.jpg -------------------------------------------------------------------------------- /doc/img/01-configure-libfreefare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/doc/img/01-configure-libfreefare.jpg -------------------------------------------------------------------------------- /doc/img/02-configure-libfreefare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/doc/img/02-configure-libfreefare.jpg -------------------------------------------------------------------------------- /img/00-GNFC-0.1.1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/img/00-GNFC-0.1.1.jpg -------------------------------------------------------------------------------- /img/00-GNFC-0.2.0-default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/img/00-GNFC-0.2.0-default.jpg -------------------------------------------------------------------------------- /img/00-GNFC-0.2.0-ndef.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JiapengLi/GNFC/5698a1118f310686ca6662df777faa728bf1e428/img/00-GNFC-0.2.0-ndef.jpg -------------------------------------------------------------------------------- /src/ewin_beep.cpp: -------------------------------------------------------------------------------- 1 | #include "ewin_beep.h" 2 | #include 3 | #include 4 | 5 | ewin_beep::ewin_beep() 6 | { 7 | 8 | } 9 | 10 | int ewin_beep :: sendCommand(uint8_t *buf, int len) 11 | { 12 | if(state() != QAbstractSocket::ConnectedState){ 13 | return -1; 14 | } 15 | 16 | if(!len){ 17 | return -1; 18 | } 19 | 20 | uint8_t *frame = new uint8_t[len+8]; 21 | frame[0] = 0x00; 22 | frame[1] = 0x00; 23 | frame[2] = 0xFF; 24 | frame[3] = len + 1; 25 | frame[4] = ~(len+1) + 1; 26 | frame[5] = 0xD4; 27 | uint8_t sum = 0xD4; 28 | for(int i=0; i 5 | #include 6 | #include 7 | 8 | class ewin_beep : public QTcpSocket 9 | { 10 | public: 11 | ewin_beep(); 12 | int beep(void); 13 | int sendCommand(uint8_t *buf, int len); 14 | public slots: 15 | 16 | }; 17 | 18 | #endif // EWIN_BEEP_H 19 | -------------------------------------------------------------------------------- /src/gnfc.pro: -------------------------------------------------------------------------------- 1 | QT += core gui 2 | 3 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 4 | 5 | QT += serialport network 6 | 7 | TARGET = gnfc 8 | TEMPLATE = app 9 | 10 | SOURCES += main.cpp\ 11 | mainwindow.cpp \ 12 | pn532_extend_cmd.cpp \ 13 | mf1ics50writeblock.cpp \ 14 | ewin_beep.cpp 15 | SOURCES += snepClient.cpp \ 16 | snepServer.cpp 17 | 18 | 19 | HEADERS += mainwindow.h \ 20 | pn532_extend_cmd.h \ 21 | mf1ics50writeblock.h \ 22 | ewin_beep.h 23 | HEADERS += snepClient.h \ 24 | snepServer.h 25 | 26 | 27 | FORMS += mainwindow.ui \ 28 | mf1ics50writeblock.ui 29 | 30 | !win32{ 31 | LIBS += -lnfc -lfreefare -lllcp -lndef 32 | } 33 | 34 | win32 { 35 | INCLUDEPATH += "C:\libnfc\include" "C:\libfreefare\include\freefare" "C:\libndef\include" 36 | LIBS += -L"C:\libnfc\lib" -L"C:\libfreefare\lib" -L"C:\libndef\lib" 37 | LIBS += -lnfc -lfreefare -lllcp -lndef1 -lws2_32 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | MainWindow w; 8 | w.show(); 9 | 10 | return a.exec(); 11 | } 12 | -------------------------------------------------------------------------------- /src/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "nfc/nfc.h" 14 | #include "nfc/nfc-emulation.h" 15 | 16 | #include "freefare.h" 17 | 18 | #include "nfc/mac.h" 19 | #include "nfc/llcp.h" 20 | #include "nfc/llc_link.h" 21 | #include "nfc/llc_service.h" 22 | #include "nfc/llc_connection.h" 23 | 24 | #include "ndef/libndef_global.h" 25 | #include "ndef/ndefmessage.h" 26 | #include "ndef/ndefrecord.h" 27 | #include "ndef/ndefrecordtype.h" 28 | #include "ndef/tlv.h" 29 | 30 | #include "mainwindow.h" 31 | #include "ui_mainwindow.h" 32 | #include "pn532_extend_cmd.h" 33 | #include "mf1ics50writeblock.h" 34 | 35 | void sleep(unsigned int msec) 36 | { 37 | QTime dieTime = QTime::currentTime().addMSecs(msec); 38 | while( QTime::currentTime() < dieTime ) 39 | QCoreApplication::processEvents(QEventLoop::AllEvents, 100); 40 | } 41 | 42 | MainWindow::MainWindow(QWidget *parent) : 43 | QMainWindow(parent), 44 | ui(new Ui::MainWindow), snepClient(new snepClientThread), snepServer(new snepServerThread) 45 | { 46 | ui->setupUi(this); 47 | wbDialog = new mf1ics50WriteBlock(this); 48 | this->setWindowTitle("GNFC - " GNFC_VERSION); 49 | ewinBeep = new ewin_beep; 50 | 51 | init(); 52 | } 53 | 54 | MainWindow::~MainWindow() 55 | { 56 | if(pnd != NULL) 57 | nfc_close(pnd); 58 | 59 | if(context != NULL) 60 | nfc_exit(context); 61 | 62 | pnd = NULL; 63 | context = NULL; 64 | 65 | delete wbDialog; 66 | 67 | delete snepClient; 68 | delete snepServer; 69 | 70 | delete ewinBeep; 71 | 72 | delete ui; 73 | } 74 | 75 | void MainWindow :: about(void) 76 | { 77 | QMessageBox::about (this, "About", "GNFC " GNFC_VERSION "\nUsing Qt "\ 78 | QT_VERSION_STR "\nwww.elechouse.com "); 79 | } 80 | 81 | QByteArray MainWindow :: hexStr2ByteArr(QString &hexStr) 82 | { 83 | QByteArray byteArr; 84 | if(hexStr.size()%2 != 0){ 85 | byteArr.append((char)QString(hexStr.at(0)).toInt(0, 16)); 86 | hexStr.remove(0, 1); 87 | } 88 | while(hexStr.size()){ 89 | QString hex; 90 | hex.append(hexStr.at(0)); 91 | hex.append(hexStr.at(1)); 92 | byteArr.append((char)hex.toInt(0, 16)); 93 | hexStr.remove(0, 2); 94 | } 95 | 96 | return byteArr; 97 | } 98 | 99 | void MainWindow::refresh() 100 | { 101 | /** clear serial device list */ 102 | ui->comboBoxSerialDevice->clear(); 103 | 104 | #ifdef Q_OS_WIN32 105 | int cnt = QSerialPortInfo::availablePorts().size(); 106 | if(cnt <= 0){ 107 | sysLog("No serial port is available."); 108 | return; 109 | } 110 | sysLog(QString("Find %1 Serial Port(s):").arg(cnt)); 111 | foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { 112 | qDebug() << "Name : " << info.portName(); 113 | qDebug() << "Description : " << info.description(); 114 | qDebug() << "Manufacturer: " << info.manufacturer(); 115 | qDebug() << "SystemLocation: " << info.systemLocation(); 116 | sysLog(info.portName() + "\t----\t" + info.manufacturer() + ' ' + info.description()); 117 | ui->comboBoxSerialDevice->addItem(info.portName()); 118 | } 119 | 120 | #else 121 | QDir serialDir("/dev/serial/by-id"); 122 | QFileInfoList serialFileList = serialDir.entryInfoList(QDir::Readable | QDir::Writable | \ 123 | QDir::NoDotAndDotDot | QDir::Files); 124 | 125 | for(int i=0; icomboBoxSerialDevice->addItem(serialFileList.at(i).symLinkTarget()); 131 | } 132 | } 133 | #endif 134 | } 135 | 136 | void MainWindow::beep(void) 137 | { 138 | if(ui->checkBoxBeep->isChecked()){ 139 | if(ui->rbUART->isChecked()){ 140 | pn532ExCmd->beep(pnd); 141 | }else if(ui->rbNET->isChecked()){ 142 | /* fix me: net device beep function */ 143 | ewinBeep->beep(); 144 | } 145 | } 146 | sleep(1); 147 | } 148 | 149 | void MainWindow::setOutputTextFont(void) 150 | { 151 | 152 | QFontDatabase fdb; 153 | QStringList fl = fdb.families(); 154 | QString fn; 155 | if(fl.contains("Monospace")){ 156 | fn = "Monospace"; 157 | } 158 | 159 | if(fl.contains("Consolas")){ 160 | fn = "Consolas"; 161 | } 162 | if(!fn.isEmpty()){ 163 | qDebug() << "Set Font: " << fn; 164 | ui->outputText->setFontFamily(fn); 165 | ui->outputText->setFontPointSize(9); 166 | //ui->outputText->setFontPointSize(); 167 | } 168 | } 169 | 170 | void MainWindow::init(void) 171 | { 172 | pnd = NULL; 173 | context = NULL; 174 | 175 | sysLog("Elechouse USB NFC Demo."); 176 | 177 | /** get device list */ 178 | refresh(); 179 | 180 | /** About dialog */ 181 | connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about())); 182 | 183 | /** App Quit */ 184 | connect(ui->actionExit, SIGNAL(triggered()), this, SLOT(close())); 185 | 186 | /** refresh device list */ 187 | connect(ui->refreshButton, SIGNAL(clicked()), this, SLOT(refresh())); 188 | 189 | /** clear software log */ 190 | connect(ui->debugInfoClearButton, SIGNAL(clicked()), ui->debugInfoText, SLOT(clear())); 191 | 192 | /** clear output text */ 193 | connect(ui->outputTextClearButton, SIGNAL(clicked()), ui->outputText, SLOT(clear())); 194 | 195 | /** read id */ 196 | connect(ui->readIDButton, SIGNAL(clicked()), this, SLOT(readIdInit())); 197 | 198 | /** open or close device */ 199 | connect(ui->openCloseButton, SIGNAL(clicked()), this, SLOT(openClose())); 200 | 201 | /** reset old tag record */ 202 | connect(ui->checkBoxVerbos, SIGNAL(toggled(bool)), this, SLOT(clearOldTag())); 203 | connect(ui->hexRB, SIGNAL(toggled(bool)), this, SLOT(clearOldTag())); 204 | //connect(ui->hexRB, SIGNAL(toggled(bool)), this, SLOT(clearOldTag())); 205 | 206 | connect(ui->blockRB, SIGNAL(toggled(bool)), this, SLOT(readBlockPrepare())); 207 | connect(ui->sectorRB, SIGNAL(toggled(bool)), this, SLOT(readBlockPrepare())); 208 | 209 | /** Read Blocks */ 210 | connect(ui->readBlockButton, SIGNAL(clicked()), this, SLOT(readBlock())); 211 | 212 | /** password configure */ 213 | // connect(ui->enableSetPassWordButton, SIGNAL(toggled(bool)), this, SLOT(passwdSetConfig())); 214 | connect(ui->keyARB, SIGNAL(toggled(bool)), this, SLOT(passwdSelect())); 215 | connect(ui->keyBRB, SIGNAL(toggled(bool)), this, SLOT(passwdSelect())); 216 | connect(ui->keyHideCheckBox, SIGNAL(toggled(bool)), this, SLOT(passwdHide())); 217 | // connect(ui->setPassWordButton, SIGNAL(clicked()), this, SLOT(passwdSet())); 218 | 219 | /** Write Block */ 220 | connect(ui->writeBlockStartButton, SIGNAL(clicked()), this, SLOT(writeBlock())); 221 | connect(wbDialog, SIGNAL(sendRead(sectorData_t*)), this, SLOT(wbRead(sectorData_t*))); 222 | connect(wbDialog, SIGNAL(sendWrite(sectorData_t*)), this, SLOT(wbWrite(sectorData_t*))); 223 | 224 | /** Erase all blocks */ 225 | connect(ui->resetBlockButton, SIGNAL(clicked()), this, SLOT(resetBlock())); 226 | 227 | /** test */ 228 | // connect(ui->readBlockButton, SIGNAL(clicked()), this, SLOT(test())); 229 | // ui->checkBoxBeep->setStyleSheet("color: rgb(255, 0, 0);"); 230 | 231 | /** Text Window is read-only */ 232 | ui->outputText->setReadOnly(true); 233 | ui->debugInfoText->setReadOnly(true); 234 | 235 | /** debugInfoText table size */ 236 | // QFontMetrics metrics(ui->debugInfoText->font()); 237 | // ui->debugInfoText->setTabStopWidth(6*metrics.width(' ')); 238 | 239 | /** disable control panel when device is closed */ 240 | ui->tabWidget->setEnabled(false); 241 | 242 | ui->outputText->setLineWrapMode(QTextEdit::NoWrap); 243 | 244 | setOutputTextFont(); 245 | calcOutputSeperatorLength(); 246 | 247 | passwdInit(); 248 | 249 | /** NDEF */ 250 | connect(ui->ndefPush, SIGNAL(clicked()), this, SLOT(ndefPush())); 251 | connect(snepClient, SIGNAL(finished()), this, SLOT(ndefPushed())); 252 | connect(ui->ndefPull, SIGNAL(clicked()), this, SLOT(ndefPull())); 253 | connect(snepServer, SIGNAL(finished()), this, SLOT(ndefPulled())); 254 | connect(snepServer, SIGNAL(sendNdefMessage(QString)), this, SLOT(ndefTextPulled(QString))); 255 | 256 | /** device select */ 257 | ui->lineEditIP->setEnabled(false); 258 | ui->lineEditPort->setEnabled(false); 259 | connect(ui->rbNET, SIGNAL(toggled(bool)), this, SLOT(deviceSelect())); 260 | 261 | ui->tabWidget->removeTab(2); 262 | } 263 | 264 | void MainWindow :: deviceSelect(void) 265 | { 266 | if(ui->rbNET->isChecked()){ 267 | ui->lineEditIP->setEnabled(true); 268 | ui->lineEditPort->setEnabled(true); 269 | ui->comboBoxSerialDevice->setEnabled(false); 270 | ui->refreshButton->setEnabled(false); 271 | }else if (ui->rbUART->isChecked()){ 272 | ui->lineEditIP->setEnabled(false); 273 | ui->lineEditPort->setEnabled(false); 274 | ui->comboBoxSerialDevice->setEnabled(true); 275 | ui->refreshButton->setEnabled(true); 276 | } 277 | } 278 | 279 | void MainWindow::openClose(void) 280 | { 281 | ui->openCloseButton->setEnabled(false); 282 | ui->rbNET->setEnabled(false); 283 | ui->rbUART->setEnabled(false); 284 | 285 | if(ui->openCloseButton->text() == "Close"){ 286 | 287 | if(pnd != NULL) 288 | nfc_close(pnd); 289 | 290 | if(context != NULL) 291 | nfc_exit(context); 292 | pnd = NULL, context = NULL; 293 | 294 | if(ui->rbUART->isChecked()){ 295 | /** print log info, enable uart device */ 296 | sysLog(ui->comboBoxSerialDevice->currentText() + " closed."); 297 | ui->refreshButton->setEnabled(true); 298 | ui->comboBoxSerialDevice->setEnabled(true); 299 | }else if(ui->rbNET->isChecked()){ 300 | ewinBeep->disconnectFromHost(); 301 | ui->lineEditIP->setEnabled(true); 302 | ui->lineEditPort->setEnabled(true); 303 | } 304 | 305 | 306 | ui->rbNET->setEnabled(true); 307 | ui->rbUART->setEnabled(true); 308 | 309 | ui->openCloseButton->setText("Open"); 310 | ui->openCloseButton->setEnabled(true); 311 | ui->tabWidget->setEnabled(false); 312 | return; 313 | } 314 | 315 | QString dn; 316 | if(ui->rbUART->isChecked()){ 317 | if(ui->comboBoxSerialDevice->count()<=0){ 318 | sysLog("ERROR: No device found."); 319 | ui->openCloseButton->setEnabled(true); 320 | return; 321 | } 322 | if(ui->comboBoxSerialDevice->currentText().isEmpty()){ 323 | sysLog("ERROR: Device name error"); 324 | ui->openCloseButton->setEnabled(true); 325 | return; 326 | } 327 | 328 | /** choose uart device */ 329 | dn = "pn532_uart:"; 330 | dn += ui->comboBoxSerialDevice->currentText(); 331 | qDebug() << dn; 332 | }else if(ui->rbNET->isChecked()){ 333 | /* fix me: check text format */ 334 | dn = "pn532_net:"; 335 | dn += ui->lineEditIP->text() + ":" + ui->lineEditPort->text(); 336 | 337 | /** connect to beep port */ 338 | QHostAddress ip_test; 339 | ip_test.setAddress(ui->lineEditIP->text()); 340 | ewinBeep->connectToHost(ip_test,8001); 341 | if (ewinBeep->waitForConnected(1000)){ 342 | qDebug("Beep port is Connected!"); 343 | }else{ 344 | qDebug("Beep port is Unconnected!"); 345 | } 346 | } 347 | 348 | nfc_init(&context); 349 | if (context == NULL) { 350 | sysLog("ERROR: Unable to init libnfc"); 351 | ui->openCloseButton->setEnabled(true); 352 | ui->rbNET->setEnabled(true); 353 | ui->rbUART->setEnabled(true); 354 | return; 355 | } 356 | 357 | pnd = nfc_open(context, dn.toLocal8Bit().data()); 358 | if (pnd == NULL) { 359 | sysLog("ERROR: Unable to open NFC device."); 360 | ui->openCloseButton->setEnabled(true); 361 | ui->rbNET->setEnabled(true); 362 | ui->rbUART->setEnabled(true); 363 | return; 364 | } 365 | 366 | if(ui->rbUART->isChecked()){ 367 | /** print log info, diable uart widgets */ 368 | sysLog(ui->comboBoxSerialDevice->currentText() + " opened."); 369 | ui->refreshButton->setEnabled(false); 370 | ui->comboBoxSerialDevice->setEnabled(false); 371 | }else if(ui->rbNET->isChecked()){ 372 | ui->lineEditIP->setEnabled(true); 373 | ui->lineEditPort->setEnabled(true); 374 | } 375 | 376 | ui->openCloseButton->setText("Close"); 377 | ui->openCloseButton->setEnabled(true); 378 | ui->tabWidget->setEnabled(true); 379 | } 380 | 381 | 382 | void MainWindow :: test() 383 | { 384 | // QString f = ui->idFormat->checkedButton()->objectName(); 385 | // if( f == "decRB"){ 386 | // sysLog("DEC checked."); 387 | // }else if(f == "hexRB"){ 388 | // sysLog("HEX checked."); 389 | // } 390 | // outputSeperator(); 391 | 392 | // qDebug() << "Text size" << ui->keyALineEdit->text().size(); 393 | // QString keyString = ui->keyALineEdit->text(); 394 | // qDebug() << "Key String Size: " << keyString.size(); 395 | // QByteArray key; 396 | // if(keyString.size()%2 != 0){ 397 | // key.append((char)QString(keyString.at(0)).toInt(0, 16)); 398 | // keyString.remove(0, 1); 399 | // } 400 | // while(keyString.size()){ 401 | // QString hex; 402 | // hex.append(keyString.at(0)); 403 | // hex.append(keyString.at(1)); 404 | // qDebug() << hex; 405 | // key.append((char)hex.toInt(0, 16)); 406 | // keyString.remove(0, 2); 407 | // } 408 | 409 | // qDebug() << QString(key.toHex().toUpper()); 410 | // qDebug() << (int)key.at(0); 411 | 412 | QString keyString = ui->keyALineEdit->text(); 413 | QByteArray key = hexStr2ByteArr(keyString); 414 | qDebug() << QString(key.toHex().toUpper()); 415 | qDebug() << (int)key.at(0); 416 | 417 | qDebug() << "Index: " << ui->sectorComboBox->currentIndex(); 418 | } 419 | 420 | void MainWindow :: ndefPush(void) 421 | { 422 | ui->ndefPush->setEnabled(false); 423 | QString str=ui->pushURL->text(); 424 | if(!snepClient->setNdefMessage(str)){ 425 | sysLog("URL is invalid."); 426 | ui->ndefPush->setEnabled(true); 427 | return; 428 | } 429 | snepClient->init(&pnd); 430 | snepClient->start(); 431 | } 432 | 433 | void MainWindow :: ndefPushed(void) 434 | { 435 | qDebug() << "ndefpush set enabled."; 436 | ui->ndefPush->setEnabled(true); 437 | } 438 | 439 | void MainWindow :: ndefPull() 440 | { 441 | ui->ndefPull->setEnabled(false); 442 | if(snepServer->init(&pnd)<0){ 443 | sysLog("NDEF PULL init failed."); 444 | return; 445 | } 446 | snepServer->start(); 447 | } 448 | 449 | void MainWindow :: ndefPulled() 450 | { 451 | qDebug() << "ndefpull set enabled."; 452 | ui->ndefPull->setEnabled(true); 453 | } 454 | 455 | void MainWindow :: ndefTextPulled(QString str) 456 | { 457 | qDebug() << "Text is received."; 458 | if(str.isEmpty()){ 459 | return; 460 | } 461 | ui->pullText->setText(str); 462 | } 463 | 464 | void MainWindow :: sysLog(QString str) 465 | { 466 | int val = ui->debugInfoText->verticalScrollBar()->value(); 467 | 468 | if( ui->debugInfoText->verticalScrollBar()->value() != ui->debugInfoText->verticalScrollBar()->maximum() ){ 469 | ui->debugInfoText->append(str); 470 | ui->debugInfoText->verticalScrollBar()->setValue(val); 471 | return; 472 | } 473 | ui->debugInfoText->append(str); 474 | int maxVal = ui->debugInfoText->verticalScrollBar()->maximum(); 475 | ui->debugInfoText->verticalScrollBar()->setValue(maxVal); 476 | } 477 | 478 | void MainWindow::readBlockPrepare() 479 | { 480 | if(ui->blockRB->isChecked()){ 481 | ui->block0CheckBox->setEnabled(true); 482 | ui->block1CheckBox->setEnabled(true); 483 | ui->block2CheckBox->setEnabled(true); 484 | ui->block3CheckBox->setEnabled(true); 485 | }else if(ui->sectorRB->isChecked()){ 486 | ui->block0CheckBox->setEnabled(false); 487 | ui->block1CheckBox->setEnabled(false); 488 | ui->block2CheckBox->setEnabled(false); 489 | ui->block3CheckBox->setEnabled(false); 490 | } 491 | } 492 | 493 | void MainWindow::readBlock() 494 | { 495 | MifareTag *tags = NULL; 496 | MifareClassicKey key={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 497 | MifareClassicBlock data; 498 | MifareClassicKeyType keyType = MFC_KEY_A; 499 | 500 | int block = 0; 501 | int sector = 0; 502 | 503 | if(ui->keyARB->isChecked()){ 504 | if(ui->keyALineEdit->text().size() != 12){ 505 | sysLog("KEYA is too short, must be 12 characters."); 506 | return; 507 | } 508 | keyA = ui->keyALineEdit->text(); 509 | QByteArray keyByteArr = hexStr2ByteArr(keyA).data(); 510 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 511 | keyType = MFC_KEY_A; 512 | }else if(ui->keyBRB->isChecked()){ 513 | if(ui->keyBLineEdit->text().size() != 12){ 514 | sysLog("KEYB is too short, must be 12 characters."); 515 | return; 516 | } 517 | keyB = ui->keyBLineEdit->text(); 518 | QByteArray keyByteArr = hexStr2ByteArr(keyA).data(); 519 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 520 | keyType = MFC_KEY_B; 521 | } 522 | 523 | sector = ui->sectorComboBox->currentIndex(); 524 | sector--; 525 | if(ui->sectorRB->isChecked()){ 526 | block |= 0x0F; 527 | }else{ 528 | if(ui->block0CheckBox->isChecked()){ 529 | block |= 0x01; 530 | } 531 | if(ui->block1CheckBox->isChecked()){ 532 | block |= 0x02; 533 | } 534 | if(ui->block2CheckBox->isChecked()){ 535 | block |= 0x04; 536 | } 537 | if(ui->block3CheckBox->isChecked()){ 538 | block |= 0x08; 539 | } 540 | if(block == 0){ 541 | sysLog("Select one block first."); 542 | return; 543 | } 544 | } 545 | qDebug() << "block: " << block; 546 | qDebug() << "sector: " << sector; 547 | tags = freefare_get_tags(pnd); 548 | 549 | if(!tags){ 550 | sysLog("No card is in field."); 551 | return; 552 | } 553 | int i; 554 | for(i=0; tags[i]; i++){ 555 | if(freefare_get_tag_type(tags[i]) == CLASSIC_1K){ 556 | qDebug() << "Classic 1K card found."; 557 | 558 | if( 0 == mifare_classic_connect(tags[i]) ){ 559 | if(sector == -1){ 560 | //read all sectors 561 | for(int secNum=0; secNum<16; secNum++){ 562 | if(0 == mifare_classic_authenticate(tags[i], (unsigned char)secNum*4, key, keyType) ){ 563 | for(int blockNum=0; blockNum<4; blockNum++){ 564 | if((block & (1<outputText->append(pre+QString(QByteArray((char *)data, 16).toHex().toUpper())); 570 | } 571 | } 572 | beep(); 573 | }else{ 574 | qDebug() << "Sector: " << secNum << "authenticate failed."; 575 | } 576 | } 577 | }else{ 578 | if(0 == mifare_classic_authenticate(tags[i], sector*4, key, keyType) ){ 579 | for(int blockNum=0; blockNum<4; blockNum++){ 580 | if((block & (1<outputText->append(pre+QString(QByteArray((char *)data, 16).toHex().toUpper())); 586 | } 587 | } 588 | beep(); 589 | } 590 | } 591 | mifare_classic_disconnect(tags[i]); 592 | } 593 | } 594 | } 595 | qDebug() << "Tag number: " << i; 596 | if(i==0){ 597 | sysLog("No card is in field."); 598 | }else{ 599 | sysLog("Read block successfully."); 600 | } 601 | freefare_free_tags(tags); 602 | 603 | } 604 | 605 | /****************************************************************************/ 606 | /** Password */ 607 | void MainWindow :: passwdInit() 608 | { 609 | QRegExp rx("[a-fA-F0-9]{,12}"); 610 | ui->keyALineEdit->setValidator (new QRegExpValidator (rx, this)); 611 | ui->keyBLineEdit->setValidator (new QRegExpValidator (rx, this)); 612 | // ui->confirmLineEdit->setValidator (new QRegExpValidator (rx, this)); 613 | } 614 | 615 | void MainWindow :: passwdSelect() 616 | { 617 | if(ui->keyARB->isChecked()){ 618 | ui->keyALineEdit->setEnabled(true); 619 | ui->keyBLineEdit->setEnabled(false); 620 | }else if (ui->keyBRB->isChecked()){ 621 | ui->keyBLineEdit->setEnabled(true); 622 | ui->keyALineEdit->setEnabled(false); 623 | } 624 | } 625 | 626 | void MainWindow :: passwdHide() 627 | { 628 | if(ui->keyHideCheckBox->isChecked()){ 629 | ui->keyALineEdit->setEchoMode(QLineEdit::Password); 630 | ui->keyBLineEdit->setEchoMode(QLineEdit::Password); 631 | // ui->confirmLineEdit->setEchoMode(QLineEdit::Password); 632 | }else{ 633 | ui->keyALineEdit->setEchoMode(QLineEdit::Normal); 634 | ui->keyBLineEdit->setEchoMode(QLineEdit::Normal); 635 | // ui->confirmLineEdit->setEchoMode(QLineEdit::Normal); 636 | } 637 | 638 | } 639 | 640 | void MainWindow :: passwdSetConfig() 641 | { 642 | // if(ui->enableSetPassWordButton->isChecked()){ 643 | // /** clear keyA and keyB */ 644 | 645 | // /** enable widgets */ 646 | // ui->confirmLineEdit->setEnabled(true); 647 | // ui->setPassWordButton->setEnabled(true); 648 | // }else{ 649 | // /** restore keyA and keyB */ 650 | 651 | // /** disable widgets*/ 652 | // ui->confirmLineEdit->setEnabled(false); 653 | // ui->setPassWordButton->setEnabled(false); 654 | // } 655 | 656 | } 657 | 658 | void MainWindow :: passwdSet() 659 | { 660 | test(); 661 | } 662 | 663 | 664 | /****************************************************************************/ 665 | /** write block */ 666 | void MainWindow :: writeBlock() 667 | { 668 | wbDialog->open(); 669 | // wbDialog->exec(); 670 | qDebug() << "Write Block Finish."; 671 | } 672 | 673 | void MainWindow :: wbWrite(sectorData_t * sector) 674 | { 675 | MifareTag *tags = NULL; 676 | MifareClassicKey key={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 677 | MifareClassicBlock data; 678 | MifareClassicKeyType keyType; 679 | 680 | tags = freefare_get_tags(pnd); 681 | 682 | if(!tags){ 683 | sysLog("No card is in field."); 684 | wbDialog->recieveWrite(false); 685 | return; 686 | } 687 | 688 | if(!tags[0]){ 689 | sysLog("No card is in field."); 690 | wbDialog->recieveWrite(false); 691 | return; 692 | } 693 | 694 | QByteArray keyByteArr = hexStr2ByteArr(*sector->key->keyData).data(); 695 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 696 | keyType = sector->key->type; 697 | 698 | if(freefare_get_tag_type(tags[0]) == CLASSIC_1K){ 699 | sysLog("Classic 1K card found."); 700 | if( 0 == mifare_classic_connect(tags[0]) ){ 701 | if(0 == mifare_classic_authenticate(tags[0], sector->sector*4+1, key, keyType) ){ 702 | if(sector->block->blockMap&0x01){ 703 | QByteArray dataByteArr = hexStr2ByteArr(*sector->block->block0).data(); 704 | memcpy(data, dataByteArr.data(), dataByteArr.size()); 705 | if( 0 == mifare_classic_write(tags[0], (unsigned char)((sector->sector)*4+0), data) ){ 706 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(0); 707 | sysLog("Write "+pre+" successfully."); 708 | }else{ 709 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(0); 710 | sysLog("Write "+pre+" failed."); 711 | } 712 | } 713 | if(sector->block->blockMap&0x02){ 714 | QByteArray dataByteArr = hexStr2ByteArr(*sector->block->block1).data(); 715 | memcpy(data, dataByteArr.data(), dataByteArr.size()); 716 | if( 0 == mifare_classic_write(tags[0], (unsigned char)((sector->sector)*4+1), data) ){ 717 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(1); 718 | sysLog("Write "+pre+" successfully."); 719 | }else{ 720 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(1); 721 | sysLog("Write "+pre+" failed."); 722 | } 723 | } 724 | if(sector->block->blockMap&0x04){ 725 | QByteArray dataByteArr = hexStr2ByteArr(*sector->block->block2).data(); 726 | memcpy(data, dataByteArr.data(), dataByteArr.size()); 727 | if( 0 == mifare_classic_write(tags[0], (unsigned char)((sector->sector)*4+2), data) ){ 728 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(2); 729 | sysLog("Write "+pre+" successfully."); 730 | }else{ 731 | QString pre=QString("Sector:%1 Block:%2").arg(sector->sector).arg(2); 732 | sysLog("Write "+pre+" failed."); 733 | } 734 | } 735 | if(sector->block->blockMap&0x08){ 736 | QString sectorTrailor; 737 | sectorTrailor += *sector->block->blockKeyA; 738 | sectorTrailor += *sector->block->blockControl; 739 | sectorTrailor += *sector->block->blockKeyB; 740 | qDebug() << sectorTrailor; 741 | QByteArray dataByteArr = hexStr2ByteArr(sectorTrailor).data(); 742 | memcpy(data, dataByteArr.data(), dataByteArr.size()); 743 | if( 0 == mifare_classic_write(tags[0], (unsigned char)((sector->sector)*4+3), data) ){ 744 | QString pre=QString("Sector:%1 trailer(block 3)").arg(sector->sector); 745 | sysLog("Write "+pre+" successfully."); 746 | }else{ 747 | QString pre=QString("Sector:%1 trailer(block 3)").arg(sector->sector); 748 | sysLog("Write "+pre+" failed."); 749 | } 750 | } 751 | beep(); 752 | } 753 | mifare_classic_disconnect(tags[0]); 754 | } 755 | }else{ 756 | sysLog("Not a Classic 1K card."); 757 | wbDialog->recieveWrite(false); 758 | return; 759 | } 760 | 761 | wbDialog->recieveWrite(true); 762 | 763 | qDebug() << "wbWrite"; 764 | } 765 | 766 | void MainWindow :: wbRead(sectorData_t *sector) 767 | { 768 | MifareTag *tags = NULL; 769 | MifareClassicKey key={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 770 | MifareClassicBlock data; 771 | MifareClassicKeyType keyType; 772 | 773 | 774 | blockData_t *blockData = new blockData_t; 775 | blockData->block0 = new QString(""); 776 | blockData->block1 = new QString(""); 777 | blockData->block2 = new QString(""); 778 | blockData->blockKeyA = new QString(""); 779 | blockData->blockControl = new QString(""); 780 | blockData->blockKeyB = new QString(""); 781 | 782 | tags = freefare_get_tags(pnd); 783 | 784 | if(!tags){ 785 | sysLog("No card is in field."); 786 | wbDialog->recieveRead(NULL, false); 787 | return; 788 | } 789 | 790 | if(!tags[0]){ 791 | sysLog("No card is in field."); 792 | wbDialog->recieveRead(NULL, false); 793 | return; 794 | } 795 | 796 | blockData->blockMap = 0; 797 | 798 | QByteArray keyByteArr = hexStr2ByteArr(*sector->key->keyData).data(); 799 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 800 | keyType = sector->key->type; 801 | 802 | if(freefare_get_tag_type(tags[0]) == CLASSIC_1K){ 803 | sysLog("Classic 1K card found."); 804 | if( 0 == mifare_classic_connect(tags[0]) ){ 805 | if(0 == mifare_classic_authenticate(tags[0], sector->sector*4+1, key, keyType) ){ 806 | if(sector->block->blockMap&0x01){ 807 | if( 0 == mifare_classic_read(tags[0], (unsigned char)((sector->sector)*4+0), &data) ){ 808 | blockData->blockMap |= 0x01; 809 | *blockData->block0 = QString(QByteArray((char *)data, 16).toHex().toUpper()); 810 | } 811 | } 812 | if(sector->block->blockMap&0x02){ 813 | if( 0 == mifare_classic_read(tags[0], (unsigned char)((sector->sector)*4+1), &data) ){ 814 | blockData->blockMap |= 0x02; 815 | *blockData->block1 = QString(QByteArray((char *)data, 16).toHex().toUpper()); 816 | } 817 | } 818 | if(sector->block->blockMap&0x04){ 819 | if( 0 == mifare_classic_read(tags[0], (unsigned char)((sector->sector)*4+2), &data) ){ 820 | blockData->blockMap |= 0x04; 821 | *blockData->block2 = QString(QByteArray((char *)data, 16).toHex().toUpper()); 822 | } 823 | } 824 | if(sector->block->blockMap&0x08){ 825 | if( 0 == mifare_classic_read(tags[0], (unsigned char)((sector->sector)*4+3), &data) ){ 826 | blockData->blockMap |= 0x08; 827 | QString block3 = QString(QByteArray((char *)data, 16).toHex().toUpper()); 828 | qDebug() << block3; 829 | /** KeyA is not readable, */ 830 | *blockData->blockKeyA = "FFFFFFFFFFFF"; 831 | block3.remove(0, 12); 832 | *blockData->blockControl = block3.left(8); 833 | block3.remove(0, 8); 834 | *blockData->blockKeyB = block3.left(12); 835 | } 836 | } 837 | if( 0 != blockData->blockMap){ 838 | qDebug() << "receiveRead"; 839 | wbDialog->recieveRead(blockData, true); 840 | } 841 | beep(); 842 | } 843 | mifare_classic_disconnect(tags[0]); 844 | } 845 | }else{ 846 | sysLog("Not a Classic 1K card."); 847 | wbDialog->recieveRead(NULL, false); 848 | return; 849 | } 850 | 851 | qDebug() << "wbRead"; 852 | } 853 | 854 | /****************************************************************************/ 855 | /** reset all blocks */ 856 | void MainWindow :: resetBlock() 857 | { 858 | QMessageBox::StandardButton reply; 859 | reply = QMessageBox::question(this, "Mifare Card Erase", "Are you sure to erase all blocks?", 860 | QMessageBox::Yes|QMessageBox::No); 861 | if (reply != QMessageBox::Yes) { 862 | return; 863 | } 864 | qDebug() << "Erase all blocks."; 865 | 866 | MifareTag *tags = NULL; 867 | MifareClassicKey key={0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 868 | MifareClassicBlock data; 869 | MifareClassicBlock block3={ 870 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 871 | 0xFF, 0x07, 0x80, 0x69, 872 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 873 | }; 874 | MifareClassicKeyType keyType = MFC_KEY_A; 875 | 876 | memset(data, 0, sizeof(MifareClassicBlock)); 877 | 878 | int block = 0; 879 | int sector = 0; 880 | 881 | if(ui->keyARB->isChecked()){ 882 | if(ui->keyALineEdit->text().size() != 12){ 883 | sysLog("KEYA is too short, must be 12 characters."); 884 | return; 885 | } 886 | keyA = ui->keyALineEdit->text(); 887 | QByteArray keyByteArr = hexStr2ByteArr(keyA).data(); 888 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 889 | keyType = MFC_KEY_A; 890 | }else if(ui->keyBRB->isChecked()){ 891 | if(ui->keyBLineEdit->text().size() != 12){ 892 | sysLog("KEYB is too short, must be 12 characters."); 893 | return; 894 | } 895 | keyB = ui->keyBLineEdit->text(); 896 | QByteArray keyByteArr = hexStr2ByteArr(keyA).data(); 897 | memcpy(key, keyByteArr.data(), keyByteArr.size()); 898 | keyType = MFC_KEY_B; 899 | } 900 | 901 | ui->openCloseButton->setEnabled(false); 902 | ui->readIDButton->setEnabled(false); 903 | ui->readBlockButton->setEnabled(false); 904 | ui->writeBlockStartButton->setEnabled(false); 905 | 906 | tags = freefare_get_tags(pnd); 907 | 908 | if(!tags){ 909 | sysLog("No card is in field."); 910 | ui->openCloseButton->setEnabled(true); 911 | ui->readIDButton->setEnabled(true); 912 | ui->readBlockButton->setEnabled(true); 913 | ui->writeBlockStartButton->setEnabled(true); 914 | return; 915 | } 916 | 917 | if(!tags[0]){ 918 | sysLog("No card is in field."); 919 | ui->openCloseButton->setEnabled(true); 920 | ui->readIDButton->setEnabled(true); 921 | ui->readBlockButton->setEnabled(true); 922 | ui->writeBlockStartButton->setEnabled(true); 923 | return; 924 | } 925 | 926 | if(freefare_get_tag_type(tags[0]) == CLASSIC_1K){ 927 | if( 0 == mifare_classic_connect(tags[0]) ){ 928 | for(sector=0; sector<16; sector++){ 929 | for(block=0; block<4; block++){ 930 | if(0 == mifare_classic_authenticate(tags[0], sector*4+block, key, keyType) ){ 931 | if(sector==0 && block==0){ 932 | continue; 933 | } 934 | if(block != 3){ 935 | if( 0 == mifare_classic_write(tags[0], (unsigned char)(sector*4+block), data) ){ 936 | QString pre=QString("Sector:%1 Block:%2").arg(sector).arg(block); 937 | sysLog("Reset "+pre+" successfully."); 938 | }else{ 939 | QString pre=QString("Sector:%1 Block:%2").arg(sector).arg(block); 940 | sysLog("Reset "+pre+" failed."); 941 | } 942 | }else{ 943 | if( 0 == mifare_classic_write(tags[0], (unsigned char)(sector*4+block), block3) ){ 944 | QString pre=QString("Sector:%1 Block:%2").arg(sector).arg(block); 945 | sysLog("Reset "+pre+" successfully."); 946 | }else{ 947 | QString pre=QString("Sector:%1 Block:%2").arg(sector).arg(block); 948 | sysLog("Reset "+pre+" failed."); 949 | } 950 | } 951 | } 952 | } 953 | beep(); 954 | } 955 | beep(); 956 | mifare_classic_disconnect(tags[0]); 957 | } 958 | }else{ 959 | sysLog("Not a Classic 1K card."); 960 | } 961 | 962 | ui->openCloseButton->setEnabled(true); 963 | ui->readIDButton->setEnabled(true); 964 | ui->readBlockButton->setEnabled(true); 965 | ui->writeBlockStartButton->setEnabled(true); 966 | 967 | QMessageBox::information(this, "Mifare Card Erase", "Factroy Erase Done." ); 968 | } 969 | 970 | /****************************************************************************/ 971 | void MainWindow :: readIdInit() 972 | { 973 | if(pnd==NULL || context == NULL){ 974 | sysLog("Device is not opened"); 975 | return; 976 | } 977 | 978 | if(ui->readIDButton->text() == "Stop"){ 979 | sysLog("Stop read ID."); 980 | 981 | /** Enable buttons */ 982 | ui->openCloseButton->setEnabled(true); 983 | ui->readBlockButton->setEnabled(true); 984 | ui->writeBlockStartButton->setEnabled(true); 985 | ui->resetBlockButton->setEnabled(true); 986 | 987 | t->stop(); 988 | disconnect(this, SLOT(readId())); 989 | delete t; 990 | ui->readIDButton->setText("ReadID"); 991 | }else{ 992 | sysLog("Start read ID."); 993 | 994 | /** Enable buttons */ 995 | ui->openCloseButton->setEnabled(false); 996 | ui->readBlockButton->setEnabled(false); 997 | ui->writeBlockStartButton->setEnabled(false); 998 | ui->resetBlockButton->setEnabled(false); 999 | 1000 | t = new QTimer(this); 1001 | connect(t, SIGNAL(timeout()), this, SLOT(readId())); 1002 | t->start(1000); 1003 | ui->readIDButton->setText("Stop"); 1004 | } 1005 | } 1006 | 1007 | QString MainWindow::checkBaudRate() 1008 | { 1009 | QString br; 1010 | switch(nt.nm.nbr){ 1011 | case NBR_UNDEFINED: 1012 | default: 1013 | br = "NA"; 1014 | break; 1015 | case NBR_106: 1016 | br = "106k"; 1017 | break; 1018 | case NBR_212: 1019 | br = "212k"; 1020 | break; 1021 | case NBR_424: 1022 | br = "424k"; 1023 | break; 1024 | case NBR_847: 1025 | br = "847k"; 1026 | break; 1027 | } 1028 | return br; 1029 | } 1030 | 1031 | QString MainWindow::checkIdType() 1032 | { 1033 | switch(nt.nm.nmt){ 1034 | case NMT_ISO14443A: 1035 | return "14443A"; 1036 | break; 1037 | case NMT_ISO14443B: 1038 | return "14443-4B"; 1039 | break; 1040 | case NMT_ISO14443BI: 1041 | return "14443-4B'"; 1042 | break; 1043 | case NMT_ISO14443B2CT: 1044 | return "14443-2BCT"; 1045 | break; 1046 | case NMT_ISO14443B2SR: 1047 | return "14443-2BSR"; 1048 | break; 1049 | case NMT_FELICA: 1050 | return "FeliCa"; 1051 | break; 1052 | case NMT_JEWEL: 1053 | return "Innovision Jewel"; 1054 | break; 1055 | case NMT_DEP: 1056 | return "D.E.P."; 1057 | break; 1058 | } 1059 | return ""; 1060 | } 1061 | 1062 | QByteArray MainWindow::checkId() 1063 | { 1064 | QByteArray res; 1065 | switch(nt.nm.nmt){ 1066 | case NMT_ISO14443A: 1067 | res.append((char *)nt.nti.nai.abtUid, nt.nti.nai.szUidLen); 1068 | break; 1069 | case NMT_ISO14443B: 1070 | res.append((char *)nt.nti.nbi.abtPupi, 4); 1071 | break; 1072 | case NMT_ISO14443BI: 1073 | res.append((char *)nt.nti.nii.abtDIV, 4); 1074 | break; 1075 | case NMT_ISO14443B2CT: 1076 | res.append((char *)nt.nti.nci.abtUID, 4); 1077 | break; 1078 | case NMT_ISO14443B2SR: 1079 | res.append((char *)nt.nti.nsi.abtUID, 8); 1080 | break; 1081 | case NMT_FELICA: 1082 | res.append((char *)nt.nti.nfi.abtId, 8); 1083 | break; 1084 | case NMT_JEWEL: 1085 | res.append((char *)nt.nti.nji.btId, 4); 1086 | break; 1087 | case NMT_DEP: 1088 | res.append((char *)nt.nti.ndi.abtNFCID3, 10); 1089 | break; 1090 | } 1091 | return res; 1092 | } 1093 | 1094 | bool MainWindow::isNewTag() 1095 | { 1096 | newTag = checkId(); 1097 | 1098 | if(oldTag != newTag){ 1099 | oldTag = newTag; 1100 | return true; 1101 | } 1102 | 1103 | return false; 1104 | } 1105 | 1106 | void MainWindow::clearOldTag(void) 1107 | { 1108 | QRadioButton *cb = dynamic_cast(sender()); 1109 | if(cb){ 1110 | if(ui->checkBoxVerbos->isChecked()){ 1111 | return; 1112 | } 1113 | } 1114 | oldTag.clear(); 1115 | } 1116 | 1117 | void MainWindow::readId() 1118 | { 1119 | if(pnd==NULL || context == NULL){ 1120 | sysLog("Device is not opened"); 1121 | 1122 | return; 1123 | } 1124 | const nfc_modulation nmMods[8] = { 1125 | {NMT_ISO14443A, NBR_106}, 1126 | {NMT_FELICA, NBR_212}, 1127 | {NMT_FELICA, NBR_424}, 1128 | {NMT_ISO14443B, NBR_106}, 1129 | {NMT_ISO14443BI, NBR_106}, 1130 | {NMT_ISO14443B2SR, NBR_106}, 1131 | {NMT_ISO14443B2CT, NBR_106}, 1132 | {NMT_JEWEL, NBR_106}, 1133 | }; 1134 | int res; 1135 | 1136 | // Set opened NFC device to initiator mode 1137 | if (nfc_initiator_init(pnd) < 0) { 1138 | nfc_perror(pnd, "nfc_initiator_init"); 1139 | sysLog("ERROR: nfc_initiator_init"); 1140 | return; 1141 | } 1142 | for(int nmCnt=0; nmCnt<8; nmCnt++){ 1143 | if ((res = nfc_initiator_list_passive_targets(pnd, nmMods[nmCnt], &nt, 1)) < 0) { 1144 | nfc_perror(pnd, "nfc_initiator_poll_target"); 1145 | qDebug() << "Poll Target Timeout."; 1146 | oldTag.clear(); 1147 | continue; 1148 | } 1149 | 1150 | if(res>0){ 1151 | if(!isNewTag()){ 1152 | beep(); 1153 | return ; 1154 | } 1155 | 1156 | qDebug() <<"Target Found."; 1157 | if(ui->checkBoxVerbos->isChecked()){ 1158 | char *s; 1159 | str_nfc_target(&s, &nt, true); 1160 | ui->outputText->append(s); 1161 | nfc_free(s); 1162 | }else{ 1163 | QString f = ui->idFormat->checkedButton()->objectName(); 1164 | if( f == "decRB"){ 1165 | bool ok; 1166 | ui->outputText->append(QString::number(QString(newTag.toHex().toUpper()).toULongLong(&ok, 16))); 1167 | qDebug() << QString(newTag.toHex().toUpper()); 1168 | qDebug() << QString(newTag.toHex().toUpper()).toULongLong(&ok, 16); 1169 | }else if(f == "hexRB"){ 1170 | ui->outputText->append(QString(newTag.toHex().toUpper())); 1171 | } 1172 | } 1173 | beep(); 1174 | }else{ 1175 | if(!oldTag.isEmpty()){ 1176 | oldTag.clear(); 1177 | } 1178 | //sysLog("No target found."); 1179 | } 1180 | QCoreApplication::processEvents(QEventLoop::AllEvents, 100); 1181 | } 1182 | return; 1183 | 1184 | 1185 | if(pnd==NULL || context == NULL){ 1186 | sysLog("Device is not opened"); 1187 | 1188 | return; 1189 | } 1190 | 1191 | const nfc_modulation nmModulations[5] = { 1192 | { NMT_ISO14443A, NBR_106 }, 1193 | { NMT_ISO14443B, NBR_106 }, 1194 | { NMT_FELICA, NBR_212 }, 1195 | { NMT_FELICA, NBR_424 }, 1196 | { NMT_JEWEL, NBR_106 }, 1197 | }; 1198 | 1199 | const uint8_t uiPollNr = 1; 1200 | const uint8_t uiPeriod = 1; 1201 | const size_t szModulations = 5; 1202 | 1203 | 1204 | // Set opened NFC device to initiator mode 1205 | if (nfc_initiator_init(pnd) < 0) { 1206 | nfc_perror(pnd, "nfc_initiator_init"); 1207 | sysLog("ERROR: nfc_initiator_init"); 1208 | return; 1209 | } 1210 | 1211 | if ((res = nfc_initiator_poll_target(pnd, nmModulations, szModulations, uiPollNr, uiPeriod, &nt)) < 0) { 1212 | nfc_perror(pnd, "nfc_initiator_poll_target"); 1213 | sysLog("Poll Target Timeout."); 1214 | oldTag.clear(); 1215 | return; 1216 | } 1217 | 1218 | if(res>0){ 1219 | beep(); 1220 | if(!isNewTag()){ 1221 | return ; 1222 | } 1223 | 1224 | sysLog("Target Found."); 1225 | if(ui->checkBoxVerbos->isChecked()){ 1226 | char *s; 1227 | str_nfc_target(&s, &nt, true); 1228 | ui->outputText->append(s); 1229 | nfc_free(s); 1230 | }else{ 1231 | QString f = ui->idFormat->checkedButton()->objectName(); 1232 | if( f == "decRB"){ 1233 | bool ok; 1234 | ui->outputText->append(QString::number(QString(newTag.toHex().toUpper()).toULongLong(&ok, 16))); 1235 | qDebug() << QString(newTag.toHex().toUpper()); 1236 | qDebug() << QString(newTag.toHex().toUpper()).toULongLong(&ok, 16); 1237 | }else if(f == "hexRB"){ 1238 | ui->outputText->append(QString(newTag.toHex().toUpper())); 1239 | } 1240 | } 1241 | }else{ 1242 | sysLog("No target found."); 1243 | } 1244 | } 1245 | 1246 | 1247 | /*****************************************************************************/ 1248 | /** Output seperator */ 1249 | void MainWindow::outputSeperator(void) 1250 | { 1251 | QString sep(outputSeperatorLength, '-'); 1252 | ui->outputText->append(sep); 1253 | } 1254 | 1255 | void MainWindow::calcOutputSeperatorLength(void) 1256 | { 1257 | qDebug() << "Calculate Sep length"; 1258 | QString sep; 1259 | QFont ft(ui->outputText->fontFamily(), ui->outputText->fontPointSize()); 1260 | qDebug() << "Font name:" << ft.family() << "size: " << ft.pointSize(); 1261 | QFontMetrics fm(ft); 1262 | int width = ui->outputText->width() - ui->outputText->contentsMargins().right() \ 1263 | -ui->outputText->contentsMargins().left(); 1264 | for(; ;){ 1265 | sep.append('-'); 1266 | if(fm.width(sep)>=width){ 1267 | if(ui->outputText->verticalScrollBar()->isVisible()){ 1268 | sep.remove(0, 3); 1269 | 1270 | }else{ 1271 | sep.remove(0, 6); 1272 | } 1273 | break; 1274 | } 1275 | } 1276 | outputSeperatorLength = sep.length(); 1277 | } 1278 | 1279 | void MainWindow::resizeEvent(QResizeEvent *event) 1280 | { 1281 | calcOutputSeperatorLength(); 1282 | QWidget::resizeEvent(event); 1283 | } 1284 | 1285 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "pn532_extend_cmd.h" 9 | #include "mf1ics50writeblock.h" 10 | 11 | #include "snepClient.h" 12 | #include "snepServer.h" 13 | 14 | #include "ewin_beep.h" 15 | 16 | #define GNFC_VERSION "0.2.0" 17 | 18 | namespace Ui { 19 | class MainWindow; 20 | } 21 | 22 | class MainWindow : public QMainWindow 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit MainWindow(QWidget *parent = 0); 28 | ~MainWindow(); 29 | QByteArray hexStr2ByteArr(QString &hexStr); 30 | 31 | signals: 32 | void deviceFound(); 33 | 34 | private slots: 35 | void refresh(); 36 | void readIdInit(); 37 | void readId(); 38 | void openClose(); 39 | void test(); 40 | bool isNewTag(); 41 | void clearOldTag(); 42 | 43 | void readBlockPrepare(); 44 | void readBlock(); 45 | 46 | void passwdSelect(void); 47 | void passwdSetConfig(void); 48 | void passwdSet(void); 49 | void passwdHide(void); 50 | 51 | void writeBlock(); 52 | void wbRead(sectorData_t * sector); 53 | void wbWrite(sectorData_t * sector); 54 | 55 | /** clear all data */ 56 | void resetBlock(); 57 | 58 | /** About */ 59 | void about(void); 60 | 61 | /** ndef */ 62 | void ndefPush(void); 63 | void ndefPushed(void); 64 | void ndefPull(void); 65 | void ndefPulled(void); 66 | void ndefTextPulled(QString str); 67 | 68 | /** uart or net device choose */ 69 | void deviceSelect(void); 70 | 71 | protected: 72 | void resizeEvent ( QResizeEvent * event ); 73 | 74 | private: 75 | void sysLog(QString str); 76 | void beep(void); 77 | void init(void); 78 | void calcOutputSeperatorLength(void); 79 | void outputSeperator(void); 80 | 81 | void setOutputTextFont(void); 82 | 83 | void passwdInit(void); 84 | 85 | QString checkBaudRate(void); 86 | QString checkIdType(void); 87 | QByteArray checkId(void); 88 | 89 | Ui::MainWindow *ui; 90 | mf1ics50WriteBlock *wbDialog; 91 | 92 | /**NFC*/ 93 | nfc_device *pnd; 94 | nfc_target nt; 95 | nfc_context *context; 96 | 97 | pn532_extend_cmd *pn532ExCmd; 98 | ewin_beep *ewinBeep; 99 | QTimer *t; 100 | 101 | QByteArray oldTag, newTag; 102 | QString keyA, keyB, keyConfirm; 103 | 104 | int outputSeperatorLength; 105 | 106 | snepClientThread *snepClient; 107 | snepServerThread *snepServer; 108 | }; 109 | 110 | #endif // MAINWINDOW_H 111 | -------------------------------------------------------------------------------- /src/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 740 10 | 627 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | UART 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | /dev/ttyACM0 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 0 40 | 41 | 42 | 43 | Refresh 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | true 54 | 55 | 56 | d 57 | 58 | 59 | 60 | 61 | 62 | 63 | Qt::Horizontal 64 | 65 | 66 | QSizePolicy::Fixed 67 | 68 | 69 | 70 | 15 71 | 17 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Open 80 | 81 | 82 | 83 | 84 | 85 | 86 | Qt::Horizontal 87 | 88 | 89 | 90 | 297 91 | 20 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Qt::RightToLeft 100 | 101 | 102 | color: rgb(255, 0, 0); 103 | 104 | 105 | Beep 106 | 107 | 108 | true 109 | 110 | 111 | true 112 | 113 | 114 | false 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 35 123 | 16 124 | 125 | 126 | 127 | NET 128 | 129 | 130 | 131 | 132 | 133 | 134 | 192.168.1.1 135 | 136 | 137 | 138 | 139 | 140 | 141 | Qt::Horizontal 142 | 143 | 144 | QSizePolicy::Fixed 145 | 146 | 147 | 148 | 8 149 | 17 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 0 159 | 0 160 | 161 | 162 | 163 | 164 | 60 165 | 16777215 166 | 167 | 168 | 169 | 8000 170 | 171 | 172 | Qt::AlignCenter 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | false 183 | 184 | 185 | d 186 | 187 | 188 | 189 | 190 | 191 | 192 | true 193 | 194 | 195 | 196 | 0 197 | 0 198 | 199 | 200 | 201 | 202 | 721 203 | 386 204 | 205 | 206 | 207 | Qt::LeftToRight 208 | 209 | 210 | 0 211 | 212 | 213 | 214 | MF1ICS50 215 | 216 | 217 | 218 | 219 | 220 | Qt::Vertical 221 | 222 | 223 | QSizePolicy::Expanding 224 | 225 | 226 | 227 | 20 228 | 43 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 0 238 | 0 239 | 240 | 241 | 242 | 243 | 90 244 | 23 245 | 246 | 247 | 248 | 249 | 90 250 | 23 251 | 252 | 253 | 254 | Clear >> 255 | 256 | 257 | 258 | 259 | 260 | 261 | Qt::Horizontal 262 | 263 | 264 | 265 | 157 266 | 20 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | Qt::Vertical 275 | 276 | 277 | QSizePolicy::Expanding 278 | 279 | 280 | 281 | 20 282 | 70 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | Qt::Vertical 291 | 292 | 293 | QSizePolicy::Expanding 294 | 295 | 296 | 297 | 20 298 | 52 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 0 308 | 0 309 | 310 | 311 | 312 | 313 | 80 314 | 23 315 | 316 | 317 | 318 | 319 | 80 320 | 23 321 | 322 | 323 | 324 | Clear ↓ 325 | 326 | 327 | 328 | 329 | 330 | 331 | Qt::Vertical 332 | 333 | 334 | QSizePolicy::Expanding 335 | 336 | 337 | 338 | 20 339 | 79 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | Mode: 350 | 351 | 352 | 353 | 354 | 355 | 356 | Block 357 | 358 | 359 | true 360 | 361 | 362 | readBlockMode 363 | 364 | 365 | 366 | 367 | 368 | 369 | Sector 370 | 371 | 372 | false 373 | 374 | 375 | readBlockMode 376 | 377 | 378 | 379 | 380 | 381 | 382 | Block: 383 | 384 | 385 | 386 | 387 | 388 | 389 | 0 390 | 391 | 392 | true 393 | 394 | 395 | 396 | 397 | 398 | 399 | 1 400 | 401 | 402 | true 403 | 404 | 405 | 406 | 407 | 408 | 409 | 2 410 | 411 | 412 | true 413 | 414 | 415 | 416 | 417 | 418 | 419 | 3 420 | 421 | 422 | true 423 | 424 | 425 | 426 | 427 | 428 | 429 | Sector: 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | All Sectors 438 | 439 | 440 | 441 | 442 | Sector 0 443 | 444 | 445 | 446 | 447 | Sector 1 448 | 449 | 450 | 451 | 452 | Sector 2 453 | 454 | 455 | 456 | 457 | Sector 3 458 | 459 | 460 | 461 | 462 | Sector 4 463 | 464 | 465 | 466 | 467 | Sector 5 468 | 469 | 470 | 471 | 472 | Sector 6 473 | 474 | 475 | 476 | 477 | Sector 7 478 | 479 | 480 | 481 | 482 | Sector 8 483 | 484 | 485 | 486 | 487 | Sector 9 488 | 489 | 490 | 491 | 492 | Sector 10 493 | 494 | 495 | 496 | 497 | Sector 11 498 | 499 | 500 | 501 | 502 | Sector 12 503 | 504 | 505 | 506 | 507 | Sector 13 508 | 509 | 510 | 511 | 512 | Sector 14 513 | 514 | 515 | 516 | 517 | Sector 15 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | Qt::Horizontal 526 | 527 | 528 | 529 | 28 530 | 20 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | Qt::Horizontal 539 | 540 | 541 | 542 | 88 543 | 20 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 80 553 | 23 554 | 555 | 556 | 557 | 558 | 80 559 | 23 560 | 561 | 562 | 563 | ReadBlock 564 | 565 | 566 | 567 | 568 | 569 | 570 | Qt::Horizontal 571 | 572 | 573 | 574 | 28 575 | 20 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 0 587 | 0 588 | 589 | 590 | 591 | 592 | 90 593 | 23 594 | 595 | 596 | 597 | 598 | 90 599 | 23 600 | 601 | 602 | 603 | ResetBlock 604 | 605 | 606 | 607 | 608 | 609 | 610 | true 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | Qt::LeftToRight 620 | 621 | 622 | Hide 623 | 624 | 625 | true 626 | 627 | 628 | false 629 | 630 | 631 | false 632 | 633 | 634 | 635 | 636 | 637 | 638 | KEYA 639 | 640 | 641 | 642 | 643 | 644 | 645 | FFFFFFFFFFFF 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | true 656 | 657 | 658 | keySelector 659 | 660 | 661 | 662 | 663 | 664 | 665 | KEYB 666 | 667 | 668 | 669 | 670 | 671 | 672 | false 673 | 674 | 675 | FFFFFFFFFFFF 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | keySelector 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 0 698 | 0 699 | 700 | 701 | 702 | Qt::RightToLeft 703 | 704 | 705 | VERBOSE 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 0 716 | 0 717 | 718 | 719 | 720 | DEC 721 | 722 | 723 | true 724 | 725 | 726 | idFormat 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 0 735 | 0 736 | 737 | 738 | 739 | HEX 740 | 741 | 742 | false 743 | 744 | 745 | idFormat 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | Qt::Horizontal 755 | 756 | 757 | QSizePolicy::Fixed 758 | 759 | 760 | 761 | 13 762 | 20 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 0 772 | 0 773 | 774 | 775 | 776 | 777 | 90 778 | 23 779 | 780 | 781 | 782 | 783 | 90 784 | 23 785 | 786 | 787 | 788 | Qt::LeftToRight 789 | 790 | 791 | ReadID 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | Qt::Horizontal 801 | 802 | 803 | QSizePolicy::Fixed 804 | 805 | 806 | 807 | 13 808 | 20 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | Qt::Horizontal 817 | 818 | 819 | QSizePolicy::Fixed 820 | 821 | 822 | 823 | 13 824 | 20 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 0 834 | 0 835 | 836 | 837 | 838 | 839 | 90 840 | 23 841 | 842 | 843 | 844 | 845 | 90 846 | 23 847 | 848 | 849 | 850 | WriteBlock 851 | 852 | 853 | 854 | 855 | 856 | 857 | Qt::Vertical 858 | 859 | 860 | QSizePolicy::Expanding 861 | 862 | 863 | 864 | 20 865 | 23 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | NDEF 875 | 876 | 877 | 878 | 879 | 20 880 | 80 881 | 80 882 | 23 883 | 884 | 885 | 886 | Pull 887 | 888 | 889 | 890 | 891 | 892 | 20 893 | 20 894 | 80 895 | 23 896 | 897 | 898 | 899 | Push 900 | 901 | 902 | 903 | 904 | 905 | 130 906 | 20 907 | 581 908 | 23 909 | 910 | 911 | 912 | http://elechouse.com 913 | 914 | 915 | 916 | 917 | 918 | 130 919 | 80 920 | 581 921 | 23 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | CardEmulate 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 0 941 | 0 942 | 943 | 944 | 945 | 946 | 16777215 947 | 111 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 0 958 | 0 959 | 740 960 | 21 961 | 962 | 963 | 964 | 965 | File 966 | 967 | 968 | 969 | 970 | 971 | Help 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | About 982 | 983 | 984 | 985 | 986 | Exit 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | true 1000 | 1001 | 1002 | 1003 | 1004 | -------------------------------------------------------------------------------- /src/mf1ics50writeblock.cpp: -------------------------------------------------------------------------------- 1 | #include "mf1ics50writeblock.h" 2 | #include "ui_mf1ics50writeblock.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | mf1ics50WriteBlock::mf1ics50WriteBlock(QWidget *parent) : 11 | QDialog(parent), 12 | ui(new Ui::mf1ics50WriteBlock) 13 | { 14 | ui->setupUi(this); 15 | 16 | /** key part*/ 17 | connect(ui->radioButtonKeyA, SIGNAL(toggled(bool)), this, SLOT(keySelect())); 18 | connect(ui->checkBoxKeyHide, SIGNAL(toggled(bool)), this, SLOT(keyHide())); 19 | ui->lineEditKeyB->setEnabled(false); 20 | ui->checkBoxKeyHide->setChecked(true); 21 | 22 | /** block */ 23 | connect(ui->checkBoxBlock0, SIGNAL(toggled(bool)), this, SLOT(blockCheck())); 24 | connect(ui->checkBoxBlock1, SIGNAL(toggled(bool)), this, SLOT(blockCheck())); 25 | connect(ui->checkBoxBlock2, SIGNAL(toggled(bool)), this, SLOT(blockCheck())); 26 | connect(ui->checkBoxBlock3, SIGNAL(toggled(bool)), this, SLOT(blockCheck())); 27 | ui->checkBoxBlock0->setChecked(true); 28 | ui->checkBoxBlock1->setChecked(true); 29 | ui->checkBoxBlock2->setChecked(true); 30 | ui->checkBoxBlock3->setChecked(false); 31 | 32 | /** write/read */ 33 | connect(ui->pushButtonReadBlock, SIGNAL(clicked()), this, SLOT(read())); 34 | connect(ui->pushButtonWriteBlock, SIGNAL(clicked()), this, SLOT(write())); 35 | 36 | /** Limit Line Edit Input(Regular Expression) */ 37 | QRegExp rx("[a-fA-F0-9]{,8}"); 38 | ui->lineEditBlock3Control->setValidator (new QRegExpValidator (rx, this)); 39 | 40 | rx = QRegExp("[a-fA-F0-9]{,12}"); 41 | ui->lineEditBlock3KeyA->setValidator (new QRegExpValidator (rx, this)); 42 | ui->lineEditBlock3KeyB->setValidator (new QRegExpValidator (rx, this)); 43 | ui->lineEditKeyA->setValidator (new QRegExpValidator (rx, this)); 44 | ui->lineEditKeyB->setValidator (new QRegExpValidator (rx, this)); 45 | 46 | rx = QRegExp("[a-fA-F0-9]{,32}"); 47 | ui->lineEditBlock0->setValidator (new QRegExpValidator (rx, this)); 48 | ui->lineEditBlock1->setValidator (new QRegExpValidator (rx, this)); 49 | ui->lineEditBlock2->setValidator (new QRegExpValidator (rx, this)); 50 | 51 | /** change default font of lineEdit */ 52 | QFontDatabase fdb; 53 | QStringList fl = fdb.families(); 54 | QString fn; 55 | if(fl.contains("Monospace")){ 56 | fn = "Monospace"; 57 | } 58 | if(fl.contains("Consolas")){ 59 | fn = "Consolas"; 60 | } 61 | if(!fn.isEmpty()){ 62 | qDebug() << "Set Font: " << fn; 63 | QFont f(fn); 64 | f.setPointSize(10); 65 | ui->lineEditBlock0->setFont(f); 66 | ui->lineEditBlock1->setFont(f); 67 | ui->lineEditBlock2->setFont(f); 68 | //ui->outputText->setFontPointSize(); 69 | } 70 | 71 | writeSector = new sectorData_t; 72 | writeSector->block = new blockData_t; 73 | writeSector->block->block0 = new QString(""); 74 | writeSector->block->block1 = new QString(""); 75 | writeSector->block->block2 = new QString(""); 76 | writeSector->block->blockControl = new QString(""); 77 | writeSector->block->blockKeyA = new QString(""); 78 | writeSector->block->blockKeyB = new QString(""); 79 | writeSector->key = new keyData_t; 80 | writeSector->key->keyData = new QString(""); 81 | 82 | readSector = new sectorData_t; 83 | readSector->block = new blockData_t; 84 | readSector->block->block0 = new QString(""); 85 | readSector->block->block1 = new QString(""); 86 | readSector->block->block2 = new QString(""); 87 | readSector->block->blockControl = new QString(""); 88 | readSector->block->blockKeyA = new QString(""); 89 | readSector->block->blockKeyB = new QString(""); 90 | readSector->key = new keyData_t; 91 | readSector->key->keyData = new QString(""); 92 | 93 | 94 | qDebug() << "mf1ics50 init"; 95 | } 96 | 97 | mf1ics50WriteBlock::~mf1ics50WriteBlock() 98 | { 99 | qDebug() << "mf1ics50 delete"; 100 | delete writeSector; 101 | delete readSector; 102 | delete ui; 103 | } 104 | 105 | void mf1ics50WriteBlock::keyHide() 106 | { 107 | if(ui->checkBoxKeyHide->isChecked()){ 108 | ui->lineEditKeyA->setEchoMode(QLineEdit::PasswordEchoOnEdit); 109 | ui->lineEditKeyB->setEchoMode(QLineEdit::Password); 110 | }else{ 111 | ui->lineEditKeyA->setEchoMode(QLineEdit::Normal); 112 | ui->lineEditKeyB->setEchoMode(QLineEdit::Normal); 113 | } 114 | } 115 | 116 | void mf1ics50WriteBlock :: keySelect() 117 | { 118 | if(ui->radioButtonKeyA->isChecked()){ 119 | ui->lineEditKeyA->setEnabled(true); 120 | ui->lineEditKeyB->setEnabled(false); 121 | }else if(ui->radioButtonKeyB->isChecked()){ 122 | ui->lineEditKeyB->setEnabled(true); 123 | ui->lineEditKeyA->setEnabled(false); 124 | } 125 | } 126 | 127 | void mf1ics50WriteBlock :: blockCheck() 128 | { 129 | if(ui->checkBoxBlock0->isChecked()){ 130 | ui->lineEditBlock0->setEnabled(true); 131 | }else{ 132 | ui->lineEditBlock0->setEnabled(false); 133 | } 134 | if(ui->checkBoxBlock1->isChecked()){ 135 | ui->lineEditBlock1->setEnabled(true); 136 | }else{ 137 | ui->lineEditBlock1->setEnabled(false); 138 | } 139 | if(ui->checkBoxBlock2->isChecked()){ 140 | ui->lineEditBlock2->setEnabled(true); 141 | }else{ 142 | ui->lineEditBlock2->setEnabled(false); 143 | } 144 | if(ui->checkBoxBlock3->isChecked()){ 145 | ui->lineEditBlock3Control->setEnabled(true); 146 | ui->lineEditBlock3KeyA->setEnabled(true); 147 | ui->lineEditBlock3KeyB->setEnabled(true); 148 | ui->lineEditBlock3KeyA->setStyleSheet("color: rgb(255, 0, 0)"); 149 | ui->lineEditBlock3KeyB->setStyleSheet("color: rgb(255, 0, 0)"); 150 | ui->lineEditBlock3Control->setStyleSheet("color: rgb(255, 0, 0)"); 151 | }else{ 152 | ui->lineEditBlock3Control->setEnabled(false); 153 | ui->lineEditBlock3KeyA->setEnabled(false); 154 | ui->lineEditBlock3KeyB->setEnabled(false); 155 | ui->lineEditBlock3KeyA->setStyleSheet(""); 156 | ui->lineEditBlock3KeyB->setStyleSheet(""); 157 | ui->lineEditBlock3Control->setStyleSheet(""); 158 | } 159 | } 160 | 161 | bool mf1ics50WriteBlock :: isKeyValid() 162 | { 163 | /** Check key length */ 164 | int keyLen = 0; 165 | if(ui->radioButtonKeyA->isChecked()){ 166 | keyLen = ui->lineEditKeyA->text().size(); 167 | }else if(ui->radioButtonKeyB->isChecked()){ 168 | keyLen = ui->lineEditKeyB->text().size(); 169 | } 170 | 171 | if(keyLen != 12){ 172 | QMessageBox::warning(this, tr("Error"), 173 | tr("Key length is too short.\n" 174 | "Must be 12 characters."), 175 | QMessageBox::Ok); 176 | return false; 177 | } 178 | 179 | /** Block Check */ 180 | if( !(ui->checkBoxBlock0->isChecked() || ui->checkBoxBlock1->isChecked() \ 181 | || ui->checkBoxBlock2->isChecked() || ui->checkBoxBlock3->isChecked())){ 182 | QMessageBox::warning(this, tr("Error"), 183 | tr("No block is selected\n"), 184 | QMessageBox::Ok); 185 | return false; 186 | } 187 | 188 | return true; 189 | } 190 | 191 | uint8_t mf1ics50WriteBlock :: isWriteBlockValid() 192 | { 193 | int blockMap = 0; 194 | 195 | if(ui->checkBoxBlock0->isChecked()){ 196 | blockMap |= 0x01; 197 | if(ui->lineEditBlock0->text().size() != 32){ 198 | QMessageBox::warning(this, tr("Error"), 199 | tr("Block 0 data must be 32 characters"), 200 | QMessageBox::Ok); 201 | return 0; 202 | } 203 | } 204 | if(ui->checkBoxBlock1->isChecked()){ 205 | blockMap |= 0x02; 206 | if(ui->lineEditBlock1->text().size() != 32){ 207 | QMessageBox::warning(this, tr("Error"), 208 | tr("Block 1 data must be 32 characters"), 209 | QMessageBox::Ok); 210 | return 0; 211 | } 212 | } 213 | if(ui->checkBoxBlock2->isChecked()){ 214 | blockMap |= 0x04; 215 | if(ui->lineEditBlock2->text().size() != 32){ 216 | QMessageBox::warning(this, tr("Error"), 217 | tr("Block 2 data must be 32 characters"), 218 | QMessageBox::Ok); 219 | return 0; 220 | } 221 | } 222 | if(ui->checkBoxBlock3->isChecked()){ 223 | blockMap |= 0x08; 224 | if(ui->lineEditBlock3Control->text().size() != 8){ 225 | QMessageBox::warning(this, tr("Error"), 226 | tr("Block3 control area must contain 8 characters"), 227 | QMessageBox::Ok); 228 | return 0; 229 | } 230 | if(ui->lineEditBlock3KeyB->text().size() != 12){ 231 | QMessageBox::warning(this, tr("Error"), 232 | tr("Block3 KeyA area must contain 12 characters"), 233 | QMessageBox::Ok); 234 | return 0; 235 | } 236 | if(ui->lineEditBlock3KeyA->text().size() != 12){ 237 | QMessageBox::warning(this, tr("Error"), 238 | tr("Block3 KeyB area must contain 12 characters"), 239 | QMessageBox::Ok); 240 | return 0; 241 | } 242 | 243 | /** check access bits format */ 244 | uint32_t ab = ui->lineEditBlock3Control->text().toUInt(NULL, 16); 245 | qDebug() << QString::number(ab, 16); 246 | uint8_t cxx[6]; 247 | ab >>= 8; 248 | for(int i=0; i<6; i++){ 249 | cxx[5-i] = (uint8_t)(ab & 0x0F); 250 | ab >>= 4; 251 | } 252 | if( (0x0F != cxx[0]+cxx[5]) || (0x0F != cxx[1]+cxx[2]) || (0x0F != cxx[3]+cxx[4]) ){ 253 | 254 | QMessageBox::warning(this, tr("Error"), 255 | tr("Access bits are in wrong format."), 256 | QMessageBox::Ok); 257 | return 0; 258 | } 259 | } 260 | 261 | if(blockMap == 0){ 262 | QMessageBox::warning(this, tr("Error"), 263 | tr("No block is selected."), 264 | QMessageBox::Ok); 265 | return 0; 266 | } 267 | 268 | return blockMap; 269 | } 270 | 271 | uint8_t mf1ics50WriteBlock :: isReadBlockValid() 272 | { 273 | int blockMap = 0; 274 | if(ui->checkBoxBlock0->isChecked()){ 275 | blockMap |= 0x01; 276 | } 277 | if(ui->checkBoxBlock1->isChecked()){ 278 | blockMap |= 0x02; 279 | } 280 | if(ui->checkBoxBlock2->isChecked()){ 281 | blockMap |= 0x04; 282 | } 283 | if(ui->checkBoxBlock3->isChecked()){ 284 | blockMap |= 0x08; 285 | } 286 | 287 | if(blockMap == 0){ 288 | QMessageBox::warning(this, tr("Error"), 289 | tr("No block is selected."), 290 | QMessageBox::Ok); 291 | } 292 | 293 | return blockMap; 294 | } 295 | 296 | void mf1ics50WriteBlock :: read() 297 | { 298 | if(!isKeyValid()){ 299 | return; 300 | } 301 | uint8_t bm = isReadBlockValid(); 302 | if(bm == 0){ 303 | return; 304 | } 305 | 306 | readSector->sector = ui->comboBoxSector->currentIndex(); 307 | readSector->block->blockMap = bm; 308 | if(ui->radioButtonKeyA->isChecked()){ 309 | readSector->key->type = MFC_KEY_A; 310 | *readSector->key->keyData = ui->lineEditKeyA->text(); 311 | }else{ 312 | readSector->key->type = MFC_KEY_B; 313 | *readSector->key->keyData = ui->lineEditKeyB->text(); 314 | } 315 | 316 | emit sendRead(readSector); 317 | 318 | qDebug() << "Read block(s) succeessfully."; 319 | } 320 | 321 | void mf1ics50WriteBlock :: write() 322 | { 323 | uint8_t bm; 324 | if(!isKeyValid()){ 325 | return; 326 | } 327 | bm = isWriteBlockValid(); 328 | if(bm == 0){ 329 | return; 330 | } 331 | 332 | writeSector->sector = ui->comboBoxSector->currentIndex(); 333 | writeSector->block->blockMap = bm; 334 | *writeSector->block->block0 = ui->lineEditBlock0->text(); 335 | *writeSector->block->block1 = ui->lineEditBlock1->text(); 336 | *writeSector->block->block2 = ui->lineEditBlock2->text(); 337 | *writeSector->block->blockKeyA = ui->lineEditBlock3KeyA->text(); 338 | *writeSector->block->blockKeyB = ui->lineEditBlock3KeyB->text(); 339 | *writeSector->block->blockControl = ui->lineEditBlock3Control->text(); 340 | if(ui->radioButtonKeyA->isChecked()){ 341 | writeSector->key->type = MFC_KEY_A; 342 | *writeSector->key->keyData = ui->lineEditKeyA->text(); 343 | }else{ 344 | writeSector->key->type = MFC_KEY_B; 345 | *writeSector->key->keyData = ui->lineEditKeyB->text(); 346 | } 347 | 348 | 349 | emit sendWrite(writeSector); 350 | 351 | qDebug() << "Write blocks succeessfully."; 352 | } 353 | 354 | void mf1ics50WriteBlock :: recieveRead(blockData_t *blockData, bool ret) 355 | { 356 | if(!ret){ 357 | QMessageBox::warning(this, tr("Error"), 358 | tr("Read block failed"), 359 | QMessageBox::Ok); 360 | return ; 361 | } 362 | 363 | if(blockData == NULL){ 364 | QMessageBox::warning(this, tr("Error"), 365 | tr("Read block failed"), 366 | QMessageBox::Ok); 367 | return ; 368 | } 369 | 370 | if(blockData->blockMap&0x01 && blockData->block0 != NULL){ 371 | ui->lineEditBlock0->setText(*blockData->block0); 372 | } 373 | if(blockData->blockMap&0x02 && blockData->block1 != NULL){ 374 | ui->lineEditBlock1->setText(*blockData->block1); 375 | } 376 | if(blockData->blockMap&0x04 && blockData->block2 != NULL){ 377 | ui->lineEditBlock2->setText(*blockData->block2); 378 | } 379 | if(blockData->blockMap&0x08){ 380 | if(blockData->blockKeyA != NULL){ 381 | ui->lineEditBlock3KeyA->setText(*blockData->blockKeyA); 382 | } 383 | if(blockData->blockKeyB != NULL){ 384 | ui->lineEditBlock3KeyB->setText(*blockData->blockKeyB); 385 | } 386 | if(blockData->blockControl != NULL){ 387 | ui->lineEditBlock3Control->setText(*blockData->blockControl); 388 | } 389 | } 390 | } 391 | 392 | void mf1ics50WriteBlock :: recieveWrite(bool sta) 393 | { 394 | if(!sta){ 395 | QMessageBox::warning(this, tr("Error"), 396 | tr("Write block failed"), 397 | QMessageBox::Ok); 398 | }else{ 399 | QMessageBox::information(this, tr("Error"), 400 | tr("Write block successed"), 401 | QMessageBox::Ok); 402 | } 403 | } 404 | 405 | void mf1ics50WriteBlock :: test() 406 | { 407 | recieveWrite(true); 408 | recieveWrite(false); 409 | } 410 | -------------------------------------------------------------------------------- /src/mf1ics50writeblock.h: -------------------------------------------------------------------------------- 1 | #ifndef MF1ICS50WRITEBLOCK_H 2 | #define MF1ICS50WRITEBLOCK_H 3 | 4 | #include 5 | #include 6 | 7 | typedef struct{ 8 | uint8_t blockMap; 9 | QString *block0; 10 | QString *block1; 11 | QString *block2; 12 | QString *blockKeyA; 13 | QString *blockControl; 14 | QString *blockKeyB; 15 | } blockData_t; 16 | 17 | typedef struct{ 18 | MifareClassicKeyType type; 19 | QString *keyData; 20 | }keyData_t; 21 | 22 | typedef struct{ 23 | uint8_t sector; 24 | blockData_t *block; 25 | keyData_t *key; 26 | }sectorData_t; 27 | 28 | namespace Ui { 29 | class mf1ics50WriteBlock; 30 | } 31 | 32 | class mf1ics50WriteBlock : public QDialog 33 | { 34 | Q_OBJECT 35 | 36 | 37 | public: 38 | explicit mf1ics50WriteBlock(QWidget *parent = 0); 39 | ~mf1ics50WriteBlock(); 40 | 41 | 42 | public slots: 43 | void recieveRead(blockData_t *blockData, bool ret); 44 | void recieveWrite(bool sta); 45 | signals: 46 | void sendRead(sectorData_t *); 47 | void sendWrite(sectorData_t *); 48 | 49 | private slots: 50 | void keyHide(void); 51 | void keySelect(void); 52 | void blockCheck(void); 53 | 54 | void write(void); 55 | void read(void); 56 | 57 | void test(void); 58 | private: 59 | bool isKeyValid(void); 60 | uint8_t isWriteBlockValid(void); 61 | uint8_t isReadBlockValid(void); 62 | 63 | Ui::mf1ics50WriteBlock *ui; 64 | sectorData_t *writeSector; 65 | sectorData_t *readSector; 66 | }; 67 | 68 | #endif // MF1ICS50WRITEBLOCK_H 69 | -------------------------------------------------------------------------------- /src/mf1ics50writeblock.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | mf1ics50WriteBlock 4 | 5 | 6 | 7 | 0 8 | 0 9 | 486 10 | 186 11 | 12 | 13 | 14 | 15 | 486 16 | 186 17 | 18 | 19 | 20 | 21 | 486 22 | 186 23 | 24 | 25 | 26 | Dialog 27 | 28 | 29 | 30 | 31 | 32 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 33 | 34 | 35 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 36 | 37 | 38 | 39 | 40 | 41 | 42 | Block 0 43 | 44 | 45 | 46 | 47 | 48 | 49 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 50 | 51 | 52 | 53 | 54 | 55 | 56 | Block 1 57 | 58 | 59 | 60 | 61 | 62 | 63 | FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF 64 | 65 | 66 | 67 | 68 | 69 | 70 | Block 2 71 | 72 | 73 | 74 | 75 | 76 | 77 | FFFFFFFFFFFF 78 | 79 | 80 | 81 | 82 | 83 | 84 | FF078069 85 | 86 | 87 | 88 | 89 | 90 | 91 | FFFFFFFFFFFF 92 | 93 | 94 | 95 | 96 | 97 | 98 | color: rgb(255, 0, 0); 99 | 100 | 101 | Block 3 102 | 103 | 104 | 105 | 106 | 107 | 108 | KEYA 109 | 110 | 111 | true 112 | 113 | 114 | buttonGroupKeySelect 115 | 116 | 117 | 118 | 119 | 120 | 121 | FFFFFFFFFFFF 122 | 123 | 124 | 125 | 126 | 127 | 128 | KEYB 129 | 130 | 131 | buttonGroupKeySelect 132 | 133 | 134 | 135 | 136 | 137 | 138 | FFFFFFFFFFFF 139 | 140 | 141 | 142 | 143 | 144 | 145 | Hide 146 | 147 | 148 | false 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Sector 0 157 | 158 | 159 | 160 | 161 | Sector 1 162 | 163 | 164 | 165 | 166 | Sector 2 167 | 168 | 169 | 170 | 171 | Sector 3 172 | 173 | 174 | 175 | 176 | Sector 4 177 | 178 | 179 | 180 | 181 | Sector 5 182 | 183 | 184 | 185 | 186 | Sector 6 187 | 188 | 189 | 190 | 191 | Sector 7 192 | 193 | 194 | 195 | 196 | Sector 8 197 | 198 | 199 | 200 | 201 | Sector 9 202 | 203 | 204 | 205 | 206 | Sector 10 207 | 208 | 209 | 210 | 211 | Sector 11 212 | 213 | 214 | 215 | 216 | Sector 12 217 | 218 | 219 | 220 | 221 | Sector 13 222 | 223 | 224 | 225 | 226 | Sector 14 227 | 228 | 229 | 230 | 231 | Sector 15 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | Read 240 | 241 | 242 | 243 | 244 | 245 | 246 | Write 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /src/pn532_extend_cmd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "pn532_extend_cmd.h" 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef Q_OS_WIN32 9 | #include 10 | #else 11 | #include 12 | #endif 13 | 14 | struct nfc_device_dual { 15 | const nfc_context *context; 16 | const struct nfc_driver *driver; 17 | void *driver_data; 18 | void *chip_data; 19 | 20 | /** Device name string, including device wrapper firmware */ 21 | char name[256]; 22 | /** Device connection string */ 23 | nfc_connstring connstring; 24 | /** Is the CRC automaticly added, checked and removed from the frames */ 25 | bool bCrc; 26 | /** Does the chip handle parity bits, all parities are handled as data */ 27 | bool bPar; 28 | /** Should the chip handle frames encapsulation and chaining */ 29 | bool bEasyFraming; 30 | /** Should the chip switch automatically activate ISO14443-4 when 31 | selecting tags supporting it? */ 32 | bool bAutoIso14443_4; 33 | /** Supported modulation encoded in a byte */ 34 | uint8_t btSupportByte; 35 | /** Last reported error */ 36 | int last_error; 37 | }; 38 | 39 | #ifdef Q_OS_WIN32 40 | struct serial_port_windows { 41 | HANDLE hPort; // Serial port handle 42 | DCB dcb; // Device control settings 43 | COMMTIMEOUTS ct; // Serial port time-out configuration 44 | }; 45 | #define UART_DATA( X ) ((struct serial_port_windows *) (X)) 46 | #else 47 | struct serial_port_unix { 48 | int fd; // Serial port file descriptor 49 | struct termios termios_backup; // Terminal info before using the port 50 | struct termios termios_new; // Terminal info during the transaction 51 | }; 52 | #define UART_DATA( X ) ((struct serial_port_unix *) (X)) 53 | #endif /** Q_OS_WIN32 */ 54 | 55 | typedef void *serial_port; 56 | // Internal data structs 57 | struct pn532_uart_data { 58 | serial_port port; 59 | #ifndef WIN32 60 | int iAbortFds[2]; 61 | #else 62 | volatile bool abort_flag; 63 | #endif 64 | }; 65 | 66 | #define DRIVER_DATA(pnd) ((struct pn532_uart_data*)((pnd)->driver_data)) 67 | 68 | pn532_extend_cmd::pn532_extend_cmd() 69 | { 70 | 71 | 72 | } 73 | 74 | int pn532_extend_cmd::sendCommand(nfc_device *pnd, uint8_t *buf, uint8_t len) 75 | { 76 | if(pnd==NULL){ 77 | return -1; 78 | } 79 | 80 | if(!len){ 81 | return -1; 82 | } 83 | 84 | uint8_t *frame = new uint8_t[len+8]; 85 | frame[0] = 0x00; 86 | frame[1] = 0x00; 87 | frame[2] = 0xFF; 88 | frame[3] = len + 1; 89 | frame[4] = ~(len+1) + 1; 90 | frame[5] = 0xD4; 91 | uint8_t sum = 0xD4; 92 | for(int i=0; iport)))->hPort, frame, len+8, &dwTxLen, NULL); 102 | #else 103 | int res = write( (UART_DATA((DRIVER_DATA(((nfc_device_dual *)pnd))->port)))->fd, frame, len+8); 104 | #endif 105 | 106 | delete [] frame; 107 | 108 | if(res != len+8){ 109 | return -1; 110 | } 111 | 112 | #ifdef WIN32 113 | if (!dwTxLen) 114 | return -1; 115 | #endif 116 | 117 | return 0; 118 | } 119 | 120 | int pn532_extend_cmd::beep(nfc_device *pnd) 121 | { 122 | uint8_t *buf = new uint8_t[1]; 123 | 124 | buf[0] = PN532_EX_CMD_BEEP; 125 | 126 | sendCommand(pnd, buf, 1); 127 | 128 | delete [] buf; 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /src/pn532_extend_cmd.h: -------------------------------------------------------------------------------- 1 | #ifndef PN532_EXTEND_CMD_H 2 | #define PN532_EXTEND_CMD_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PN532_EX_CMD_BEEP (0xA0) 9 | 10 | class pn532_extend_cmd 11 | { 12 | public: 13 | pn532_extend_cmd(); 14 | int sendCommand(nfc_device *pnd, uint8_t *buf, uint8_t len); 15 | int beep(nfc_device *pnd); 16 | }; 17 | 18 | #endif // PN532_EXTEND_CMD_H 19 | -------------------------------------------------------------------------------- /src/snepClient.cpp: -------------------------------------------------------------------------------- 1 | #include "QDebug" 2 | #include "snepClient.h" 3 | 4 | NDEFMessage snepClientThread :: msg=NDEFMessage(NDEFRecord::createUriRecord("http://elechouse.com")); 5 | QByteArray snepClientThread :: package; 6 | 7 | snepClientThread :: snepClientThread(nfc_device **device) 8 | { 9 | pnd = NULL; 10 | mac_link = NULL; 11 | llc_link = NULL; 12 | flag = false; 13 | device = device; 14 | 15 | connect(this, SIGNAL(finished()), this, SLOT(free())); 16 | } 17 | 18 | snepClientThread :: ~snepClientThread() 19 | { 20 | if(mac_link != NULL){ 21 | mac_link_free(mac_link); 22 | mac_link = NULL; 23 | } 24 | if(llc_link != NULL){ 25 | llc_link_free(llc_link); 26 | llc_link= NULL; 27 | } 28 | llcp_fini(); 29 | } 30 | 31 | void snepClientThread :: free() 32 | { 33 | qDebug() << "snepClientThread is stopped."; 34 | flag = false; 35 | if(mac_link != NULL){ 36 | mac_link_free(mac_link); 37 | mac_link = NULL; 38 | } 39 | if(llc_link != NULL){ 40 | llc_link_free(llc_link); 41 | llc_link= NULL; 42 | } 43 | } 44 | 45 | int snepClientThread :: init(nfc_device **device) 46 | { 47 | pnd = *device; 48 | 49 | if (llcp_init() < 0){ 50 | qDebug() << "llcp_init() failed."; 51 | return -1; 52 | } 53 | 54 | llc_link = llc_link_new(); 55 | if (!llc_link) { 56 | qDebug() << "Cannot allocate LLC link data structures"; 57 | } 58 | 59 | mac_link = mac_link_new(pnd, llc_link); 60 | if (!mac_link){ 61 | qDebug() << "Cannot create MAC link"; 62 | return -1; 63 | } 64 | 65 | struct llc_service *com_android_npp; 66 | if (!(com_android_npp = llc_service_new(NULL, snepService, NULL))){ 67 | qDebug() << "Cannot create com.android.npp service"; 68 | return -1; 69 | } 70 | llc_service_set_miu(com_android_npp, 512); 71 | llc_service_set_rw(com_android_npp, 2); 72 | 73 | int sap; 74 | if ((sap = llc_link_service_bind(llc_link, com_android_npp, 0x20)) < 0){ 75 | qDebug() << "Cannot create com.android.npp service"; 76 | return -1; 77 | } 78 | 79 | con = llc_outgoing_data_link_connection_new(llc_link, sap, LLCP_SNEP_SAP); 80 | if (!con){ 81 | qDebug() << "Connection created failed."; 82 | return -1; 83 | } 84 | 85 | qDebug() << "snep: flag set true"; 86 | flag = true; 87 | 88 | return 0; 89 | } 90 | 91 | void snepClientThread :: run() 92 | { 93 | /** wait */ 94 | while(!flag); 95 | qDebug() << "snepClientThread running."; 96 | 97 | if(mac_link == NULL || llc_link == NULL || con == NULL){ 98 | qDebug() << "Device is not initialed."; 99 | return; 100 | } 101 | 102 | if (mac_link_activate_as_initiator(mac_link) < 0) { 103 | qDebug() << "Cannot activate MAC link"; 104 | return; 105 | } 106 | 107 | if (llc_connection_connect(con) < 0){ 108 | qDebug() << "Cannot connect llc_connection"; 109 | } 110 | llc_connection_wait(con, NULL); 111 | 112 | llc_link_deactivate(llc_link); 113 | } 114 | 115 | void *snepClientThread ::snepService(void *arg) 116 | { 117 | qDebug() << "snepService"; 118 | struct llc_connection *connection = (struct llc_connection *) arg; 119 | uint8_t buf[1024]; 120 | int ret; 121 | uint8_t ssap; 122 | #if 0 123 | uint8_t frame[] = { 124 | 0x10, 0x02, 125 | 0x00, 0x00, 0x00, 33, 126 | 0xd1, 0x02, 0x1c, 0x53, 0x70, 0x91, 0x01, 0x09, 0x54, 0x02, 127 | 0x65, 0x6e, 0x4c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x51, 0x01, 128 | 0x0b, 0x55, 0x03, 0x6c, 0x69, 0x62, 0x6e, 0x66, 0x63, 0x2e, 129 | 0x6f, 0x72, 0x67 130 | }; 131 | 132 | llc_connection_send(connection, frame, sizeof(frame)); 133 | 134 | ret = llc_connection_recv(connection, buf, sizeof(buf), &ssap); 135 | if(ret>0){ 136 | printf("Send NDEF message done.\n"); 137 | }else if(ret == 0){ 138 | printf("Received no data\n"); 139 | }else{ 140 | printf("Error received data."); 141 | } 142 | 143 | sleep(2); 144 | uint8_t frame1[] = { 145 | 0x10, 0x02, 146 | 0x00, 0x00, 0x00, 33, 147 | 0xD1, 0x01, 0x1D, 0x55, 0x03, 0x67, 0x69, 0x74, 0x68, 0x75, 148 | 0x62, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x6A, 0x69, 0x61, 0x70, 149 | 0x65, 0x6E, 0x67, 0x6C, 0x69, 0x2F, 0x6C, 0x69, 0x62, 0x6C, 150 | 0x6C, 0x63, 0x70 151 | }; 152 | 153 | llc_connection_send(connection, frame1, sizeof(frame1)); 154 | ret = llc_connection_recv(connection, buf, sizeof(buf), &ssap); 155 | if(ret>0){ 156 | printf("Send NDEF message done.\n"); 157 | }else if(ret == 0){ 158 | printf("Received no data\n"); 159 | }else{ 160 | printf("Error received data."); 161 | } 162 | 163 | sleep(2); 164 | #endif 165 | if(msg.isValid()){ 166 | quint32 len = msg.toByteArray().size(); 167 | uint8_t header[6]; 168 | header[0] = 0x10; 169 | header[1] = 0x02; 170 | header[2] = (uint8_t)(len>>24); 171 | header[3] = (uint8_t)((len&0x00FFFFFF)>>16); 172 | header[4] = (uint8_t)((len&0x0000FFFF)>>8); 173 | header[5] = (uint8_t)(len&0x000000FF); 174 | package.clear(); 175 | package.append((char *)header, 6); 176 | package.append(msg.toByteArray()); 177 | 178 | qDebug() << QString(package.toHex().toUpper()); 179 | llc_connection_send(connection, (uint8_t *)package.data(), package.size()); 180 | ret = llc_connection_recv(connection, buf, sizeof(buf), &ssap); 181 | if(ret>0){ 182 | printf("Send NDEF message done.\n"); 183 | }else if(ret == 0){ 184 | printf("Received no data\n"); 185 | }else{ 186 | printf("Error received data."); 187 | } 188 | } 189 | 190 | llc_connection_stop(connection); 191 | 192 | return NULL; 193 | } 194 | 195 | bool snepClientThread::setNdefMessage(QString str) 196 | { 197 | /** set message */ 198 | 199 | msg.setRecord(NDEFRecord::createUriRecord(str)); 200 | return msg.isValid(); 201 | } 202 | -------------------------------------------------------------------------------- /src/snepClient.h: -------------------------------------------------------------------------------- 1 | #ifndef SNEPCLIENT_H 2 | #define SNEPCLIENT_H 3 | 4 | /** QT Headers */ 5 | #include 6 | 7 | /** libnfc headers */ 8 | #include 9 | #include 10 | 11 | /** libllcp headers */ 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /** libndef headers */ 19 | #include 20 | #include 21 | #include 22 | 23 | class snepClientThread : public QThread{ 24 | Q_OBJECT 25 | 26 | public: 27 | snepClientThread(nfc_device **device=NULL); 28 | ~snepClientThread(); 29 | int init(nfc_device **device); 30 | bool setNdefMessage(QString str); 31 | signals: 32 | 33 | 34 | protected: 35 | void run(); 36 | private slots: 37 | void free(); 38 | private: 39 | static void *snepService(void *arg); 40 | 41 | nfc_device *pnd; 42 | 43 | struct mac_link *mac_link; 44 | struct llc_link *llc_link; 45 | struct llc_connection *con; 46 | 47 | bool flag; 48 | 49 | static NDEFMessage msg; 50 | static QByteArray package; 51 | }; 52 | 53 | #endif // SNEPCLIENT_H 54 | -------------------------------------------------------------------------------- /src/snepServer.cpp: -------------------------------------------------------------------------------- 1 | #include "QDebug" 2 | #include "QDataStream" 3 | #include "snepServer.h" 4 | 5 | struct mac_link* snepServerThread :: mac_link; 6 | QString snepServerThread :: pl; 7 | snepServerThread * snepServerThread :: ptr; 8 | 9 | snepServerThread :: snepServerThread(nfc_device **device) 10 | { 11 | pnd = NULL; 12 | mac_link = NULL; 13 | llc_link = NULL; 14 | flag = false; 15 | device = device; 16 | 17 | connect(this, SIGNAL(finished()), this, SLOT(free())); 18 | ptr = this; 19 | } 20 | 21 | snepServerThread :: ~snepServerThread() 22 | { 23 | if(mac_link != NULL){ 24 | mac_link_free(mac_link); 25 | mac_link = NULL; 26 | } 27 | if(llc_link != NULL){ 28 | llc_link_free(llc_link); 29 | llc_link= NULL; 30 | } 31 | llcp_fini(); 32 | } 33 | 34 | void snepServerThread :: free() 35 | { 36 | qDebug() << "snepClientThread is stopped."; 37 | flag = false; 38 | if(mac_link != NULL){ 39 | mac_link_free(mac_link); 40 | mac_link = NULL; 41 | } 42 | if(llc_link != NULL){ 43 | llc_link_free(llc_link); 44 | llc_link= NULL; 45 | } 46 | } 47 | 48 | int snepServerThread :: init(nfc_device **device) 49 | { 50 | pnd = *device; 51 | 52 | if (llcp_init() < 0){ 53 | qDebug() << "llcp_init() failed."; 54 | return -1; 55 | } 56 | 57 | llc_link = llc_link_new(); 58 | if (!llc_link) { 59 | qDebug() << "Cannot allocate LLC link data structures"; 60 | return -1; 61 | } 62 | 63 | /** initial LLCP service struct */ 64 | struct llc_service *com_android_snep; 65 | if (!(com_android_snep = llc_service_new_with_uri(NULL, snepService, (char *)"urn:nfc:sn:snep", NULL))){ 66 | qDebug() << "Cannot create com.android.snep service"; 67 | } 68 | llc_service_set_miu(com_android_snep, 512); 69 | llc_service_set_rw(com_android_snep, 2); 70 | 71 | if (llc_link_service_bind(llc_link, com_android_snep, LLCP_SNEP_SAP) < 0){ 72 | qDebug() << "Cannot bind service"; 73 | } 74 | mac_link = mac_link_new(pnd, llc_link); 75 | if (!mac_link){ 76 | qDebug() << "Cannot create MAC link"; 77 | return -1; 78 | } 79 | 80 | qDebug() << "snep: flag set true"; 81 | flag = true; 82 | 83 | return 0; 84 | } 85 | 86 | void snepServerThread :: stop() 87 | { 88 | if(mac_link != NULL) 89 | mac_link_deactivate(mac_link, MAC_DEACTIVATE_ON_REQUEST); 90 | } 91 | 92 | void snepServerThread :: run() 93 | { 94 | /** wait */ 95 | while(!flag); 96 | qDebug() << "snepClientThread running."; 97 | 98 | if(mac_link == NULL || llc_link == NULL || con == NULL){ 99 | qDebug() << "Device is not initialed."; 100 | return; 101 | } 102 | 103 | if (mac_link_activate_as_target(mac_link) < 0) { 104 | qDebug() << "Cannot activate MAC link"; 105 | return; 106 | } 107 | 108 | void *err; 109 | mac_link_wait(mac_link, &err); 110 | } 111 | 112 | void *snepServerThread ::snepService(void *arg) 113 | { 114 | qDebug() << "snepService"; 115 | struct llc_connection *connection = (struct llc_connection *) arg; 116 | uint8_t buffer[1024], frame[1024]; 117 | 118 | int len; 119 | if ((len = llc_connection_recv(connection, buffer, sizeof(buffer), NULL)) < 0) 120 | return NULL; 121 | 122 | if (len < 2) // SNEP's header (2 bytes) and NDEF entry header (5 bytes) 123 | return NULL; 124 | 125 | size_t n = 0; 126 | 127 | // Header 128 | printf("SNEP version: %d.%d\n", (buffer[0]>>4), (buffer[0]&0x0F)); 129 | if (buffer[n++] != 0x10){ 130 | printf("snep-server is developed to support snep version 1.0, version %d.%d may be not supported.\n", (buffer[0]>>4), (buffer[0]&0x0F)); 131 | } 132 | switch(buffer[1]){ 133 | case 0x00: /** Continue */ 134 | break; 135 | case 0x01: /** GET */ 136 | break; 137 | case 0x02: /** PUT */ 138 | { 139 | uint32_t ndef_length = be32toh(*((uint32_t *)(buffer + 2))); // NDEF length 140 | if (((uint32_t)len - 6) < ndef_length) 141 | return NULL; // Less received bytes than expected ? 142 | 143 | /** return snep success response package */ 144 | frame[0] = 0x10; /** SNEP version */ 145 | frame[1] = 0x81; 146 | frame[2] = 0; 147 | frame[3] = 0; 148 | frame[4] = 0; 149 | frame[5] = 0; 150 | llc_connection_send(connection, frame, 6); 151 | 152 | QByteArray ba; 153 | ba.append((char *)buffer+6, ndef_length); 154 | pl.clear(); 155 | decodeNDEFMessage(ba); 156 | ptr->sendNdefMessage(pl); 157 | } 158 | break; 159 | } 160 | 161 | if ((len = llc_connection_recv(connection, buffer, sizeof(buffer), NULL)) < 0){ 162 | printf("Receiv nothing.\n"); 163 | mac_link_deactivate(mac_link, MAC_DEACTIVATE_ON_REQUEST); 164 | return NULL; 165 | } 166 | printf("len: %d\n", len); 167 | 168 | qDebug() << "sencond recv quit."; 169 | 170 | // TODO Stop the LLCP when this is reached 171 | llc_connection_stop(connection);\ 172 | 173 | return NULL; 174 | } 175 | 176 | QString snepServerThread :: toTypeNameFormat (int id) 177 | { 178 | switch(id) 179 | { 180 | case NDEFRecordType::NDEF_Empty: return QString("Empty"); break; 181 | case NDEFRecordType::NDEF_NfcForumRTD: return QString("NFC Forum well-known type"); break; 182 | case NDEFRecordType::NDEF_MIME: return QString("Media-type as defined in RFC 2046"); break; 183 | case NDEFRecordType::NDEF_URI: return QString("Absolute URI as defined in RFC 3986"); break; 184 | case NDEFRecordType::NDEF_ExternalRTD: return QString("NFC Forum external type"); break; 185 | case NDEFRecordType::NDEF_Unknown: return QString("Unknown"); break; 186 | case NDEFRecordType::NDEF_Unchanged: return QString("Unchanged"); break; 187 | case 7: return QString("Reserved"); break; 188 | } 189 | return QString("Invalid"); 190 | } 191 | 192 | void snepServerThread :: decodeNDEFMessage (const QByteArray data, int depth) 193 | { 194 | NDEFMessage msg = NDEFMessage::fromByteArray (data); 195 | QString prefix(""); 196 | for (int d=0; d 0) && (type_name == QString("act"))) 231 | { 232 | quint8 action = record.payload().at(0); 233 | qDebug() << prefix << "NDEF record (" << i << ") payload (action code): " << action << endl; 234 | } 235 | else if ((depth > 0) && (type_name == QString("s"))) 236 | { 237 | QDataStream stream(record.payload()); 238 | qint32 size; 239 | stream >> size; 240 | qDebug() << prefix << "NDEF record (" << i << ") payload (size): " << size << endl; 241 | } 242 | else if ((depth > 0) && (type_name == QString("t"))) 243 | { 244 | qDebug() << prefix << "NDEF record (" << i << ") payload (type): " << QString::fromUtf8(record.payload()) << endl; 245 | } 246 | else 247 | { 248 | qDebug() << prefix << "NDEF record (" << i << ") payload (hex): " << record.payload().toHex() << endl; 249 | } 250 | break; 251 | case NDEFRecordType::NDEF_MIME: 252 | default: 253 | qDebug() << prefix << "NDEF record (" << i << ") payload (hex): " << record.payload().toHex() << endl; 254 | } 255 | } 256 | } 257 | else 258 | { 259 | qDebug() << "Invalid NDEF message." << endl; 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/snepServer.h: -------------------------------------------------------------------------------- 1 | #ifndef SNEPSERVER_H 2 | #define SNEPSERVER_H 3 | /** QT Headers */ 4 | #include 5 | 6 | /** libnfc headers */ 7 | #include 8 | #include 9 | 10 | /** libllcp headers */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /** libndef headers */ 18 | #include 19 | #include 20 | #include 21 | 22 | #ifdef WIN32 23 | #include 24 | #include 25 | #define be32toh(x) ntohl(x) 26 | #endif 27 | 28 | class snepServerThread : public QThread{ 29 | Q_OBJECT 30 | 31 | public: 32 | snepServerThread(nfc_device **device=NULL); 33 | ~snepServerThread(); 34 | int init(nfc_device **device); 35 | void stop(); 36 | 37 | signals: 38 | void sendNdefMessage(QString); 39 | void serviceFinish(); 40 | 41 | protected: 42 | void run(); 43 | 44 | private slots: 45 | void free(); 46 | 47 | private: 48 | static void *snepService(void *arg); 49 | static QString toTypeNameFormat(int id); 50 | static void decodeNDEFMessage (const QByteArray data, int depth = 0); 51 | 52 | nfc_device *pnd; 53 | 54 | static struct mac_link *mac_link; 55 | struct llc_link *llc_link; 56 | struct llc_connection *con; 57 | 58 | bool flag; 59 | 60 | static QString pl; 61 | static snepServerThread *ptr; 62 | }; 63 | 64 | #endif // SNEPSERVER_H 65 | --------------------------------------------------------------------------------