├── .DS_Store ├── README.md ├── arduino ├── .DS_Store └── NFCSense4P_ArduinoUno_RC522_v1 │ ├── NFCSense4P_ArduinoUno_RC522_v1.ino │ ├── RFID.cpp │ └── RFID.h ├── docs └── NFCSenseCheatSheet_v1.png ├── download ├── .DS_Store └── OpenNFCSense4P-2.zip ├── examples ├── .DS_Store ├── episode1 │ ├── .DS_Store │ ├── e1_SingleTagEFan │ │ ├── .DS_Store │ │ ├── data │ │ │ └── tagProfile.csv │ │ └── e1_SingleTagEFan.pde │ ├── e1_SingleTagRoulette │ │ ├── .DS_Store │ │ ├── data │ │ │ └── tagProfile.csv │ │ └── e1_SingleTagRoulette.pde │ └── e1_SingleTagWheel │ │ ├── .DS_Store │ │ ├── data │ │ └── tagProfile.csv │ │ └── e1_SingleTagWheel.pde └── episode2 │ ├── .DS_Store │ ├── e1_SingleTagAlpha │ ├── .DS_Store │ ├── data │ │ └── tagProfile.csv │ └── e1_SingleTagAlpha.pde │ ├── e1_SingleTagLoops │ ├── .DS_Store │ ├── data │ │ ├── apple.png │ │ ├── banana.png │ │ ├── carrot.png │ │ └── tagProfile.csv │ └── e1_SingleTagLoops.pde │ ├── e1_SingleTagNumSym │ ├── .DS_Store │ ├── data │ │ ├── apple.png │ │ ├── banana.png │ │ ├── carrot.png │ │ └── tagProfile.csv │ └── e1_SingleTagNumSym.pde │ ├── e1_SingleTagNums │ ├── .DS_Store │ ├── data │ │ └── tagProfile.csv │ └── e1_SingleTagNums.pde │ └── e1_SingleTagSelfDefined │ ├── .DS_Store │ ├── data │ ├── .DS_Store │ ├── apple.png │ ├── banana.png │ ├── carrot.png │ └── tagProfile.csv │ └── e1_SingleTagSelfDefined.pde ├── figures ├── hardware.png └── playlist.png └── src ├── .DS_Store └── OpenNFCSense4P ├── NFCBit.java └── OpenNFCSense4P.java /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenNFCSense API 2 | Open-source API of NFCSense for the Processing programming environment (http://processing.org/). Please refer to the following workflow to start experiencing the NFCSense! 3 | 4 | by [Dr. Rong-Hao Liang](https://ronghaoliang.page) (Last update: May 26, 2021) 5 | 6 | _Now it's **V2: Basic Tutorial and Examples** are available!_ 7 | 8 | [![NFCSense Cheatsheet](/docs/NFCSenseCheatSheet_v1.png)](docs/NFCSenseCheatSheet_v1.png) 9 | 10 | ## NFCSense Project website: 11 | - [https://ronghaoliang.page/NFCSense/](https://ronghaoliang.page/NFCSense/) 12 | 13 | ### Check the Open Access Paper at ACM Digital Library: 14 | - [HTML](https://dl.acm.org/doi/fullHtml/10.1145/3411764.3445214) 15 | - [PDF](https://dl.acm.org/doi/pdf/10.1145/3411764.3445214) 16 | 17 | ## NFCSense Video Tutorials 18 | [![IMAGE ALT TEXT HERE](figures/playlist.png)](https://youtube.com/playlist?list=PLSgbdfV4TB2f16s4GMy_-1ZMu_zGP9QIH) 19 | - [Episode 2: Making Educational Toys with Lego Bricks](https://youtu.be/lkaZDMGdLuQ) 20 | - [Episode 1: Making Toys with Things That Rotate](https://youtu.be/jzElM6CWH4s) 21 | - [Episode 0: Setting Up the OpenNFCSense API](https://youtu.be/Gal2keOJShM) 22 | ### All the examples shown in the videos are in the /examples folder 23 | 24 | ## Prerequisite (for V2) 25 | - 1x Arduino Uno board 26 | - 1x RC522 NFC reader 27 | - A few NFC tags (e.g., Mifare 1k, NTAG213, NTAG215) 28 | - A computer installed Processing and Arduino IDEs 29 | 30 | ## Download (/download) 31 | The OpenNFCSense API V2 of the Processing Library (OpenNFCSense4P-2.zip) in zip format. 32 | 33 | ### Install the processing library - OpenNFCSense API 34 | - Video: [Episode 0: Setting Up the OpenNFCSense API](https://youtu.be/Gal2keOJShM) 35 | - Unzip and put the extracted OpenNFCSense folder into the libraries folder of your Processing sketches. Reference and examples are included in the OpenNFCSense folder. Then, Restart your Processing software. New examples can be found in the processing library. 36 | 37 | ## Preparation: Upload the Arduino code (/arduino) and Connect the Reader 38 | - Video: [Episode 0: Setting Up the OpenNFCSense API](https://youtu.be/Gal2keOJShM) 39 | - Upload the arduino code to your Arduino board first! This software works with a microcontroller connected to an RC522 NFC/RFID Reader and run the Arduino code: NFCSense4P_ArduinoUno_RC522_v1.ino. 40 | - Connect the RC522 NFC reader to the Arduino board as follows (via the Arduino's SPI) 41 | ![Hardware Configuration](/figures/hardware.png) 42 | 43 | ## Use the OpenNFCSense API by Examples 44 | ### e1_SingleTagRotation 45 | - Video: [Episode 1: Making Toys with Things That Rotate](https://youtu.be/jzElM6CWH4s) 46 | - Video: [Episode 2: Making Educational Toys with Lego Bricks](https://youtu.be/lkaZDMGdLuQ) 47 | - Open the example e1_SingleTagRotation.pde 48 | - Attach an NFC tag to anything that spins, such as a fidget spinner. 49 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Close the processing sketch. 50 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of "Black spinner" with yours, save the CSV file. 51 | - Run the processing sketch again, spin the your spinner, and then you will see the object info and the rotation frequecy shown on the screen as "Recent tag: [Label] is spinning at ? Hz". 52 | - In the data/tagProfile.csv, You may replace the "Black spinner" label to any name (avoid using comma). You can make another row with the same format to be able to recognize multiple spinners! 53 | 54 | ### e2_SingleTagSwinging 55 | - Open the example e2_SingleTagSwinging.pde 56 | - Attach an NFC tag to anything that swings, such as a finger. 57 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Close the processing sketch. 58 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of "Swing" with yours, save the CSV file. 59 | - Run the processing sketch again, spin the your spinner, and then you will see the object info and the rotation frequecy shown on the screen as "Recent tag: [Label] is swining at ? Hz". 60 | - In the data/tagProfile.csv, You may replace the "Swing" label to any name (avoid using comma). You can make another row with the same format to be able to recognize swinging objects! 61 | 62 | ### e3_TagSequence 63 | - Open the example e3_TagSequence.pde 64 | - Attach an NFC tag to the bottom of any objects, such as a duplo block that has a letter printed on its surface. Maintain z=8-25mm (for Mifare 1k or NTAG 213/215 tags) distance between the tag and the reader with an optional linear track for reliable tracking. 65 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Then, close the processing sketch. 66 | - Open the data/tagProfile.csv in the examples' folder, replace the UID with yours, save the CSV file. 67 | - Run the processing sketch again, scan your object, and then you will see object shown in list of a recent tag. 68 | - In the data/tagProfile.csv, You may replace the "A" label to any name (avoid using comma). Likewise, you add the 2nd, 3rd, and more object's UIDs and label to the CSV profile. Save the profile and run the processing sketch again, and your reader should be able to read all of them. 69 | - The list of "recent tag" will be cleared up when the reader does not read a new tag for 1000 ms (1 s) by default. You may change it to 2 seconds by setting up a parameter to the constructor as `nfcs = new OpenNFCSense4P(this, "demo.csv", 300, 300, 2000)` to set the TTL timer2 to 2000. 70 | 71 | ### e4_CompoundRotation 72 | - Open the example e4_TagSequence.pde 73 | - Attach __3__ NFC tags to anything that spins, such as a fidget spinner. Don't let the tags overlap. 74 | - Run the processing sketch, scan one of the tag, and keep the first tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Then, rotate the object counterclockwisely and get the second tag's 4-byte UID. Then rotate the object counterclockwisely and get the third tag's 4-byte UID. close the processing sketch. 75 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of the three "white spinner" tags with yours. The first tag goes first, and then the second and the third. Save the CSV file after it's done. 76 | - Run the processing sketch again, spin the object, and then you will see the object's info, the rotation direction and frequecy shown on the screen as "Recent tag: [Label] is spinning \n (counter)clockwise at ? Hz". In recent tags you also see the sequence of the tag presence. 77 | - In the data/tagProfile.csv, You may replace the "White spinner" label to any name (avoid using comma). Likewise, you add more object's UIDs and label to the CSV profile. Save the profile and run the processing sketch again, and your reader should be able to read all of them. 78 | 79 | ### e5_CompoundLinear 80 | - Open the example e5_CompoundLinear.pde 81 | - Attach __2__ NFC tags to anything that moves linearly, such as a trolley. Don't let the tags overlap. Maintain z=8-25mm (for Mifare 1k or NTAG 213/215 tags) distance between the tag and the reader with a linear track for reliable tracking. 82 | - Run the processing sketch, scan one of the tag, and keep the first tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Then, scan the second tag and get its 4-byte UID. Close the processing sketch. 83 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of the two "trolley" tags with yours. The first tag goes first, and then the second. Replace the number 34.0 of the both tag with the actual distance between the center of the two tags (e.g., set 38.0 when the distance is 38mm). Save the CSV file after it's done. 84 | - Run the processing sketch again, move the object linearly, and then you will see the object's info, the movement direction and speed shown on the screen as "Recent tag: [Label] is moving \n forward/backward at ? km/h". In recent tags you also see the sequence of the tag presence. 85 | - In the data/tagProfile.csv, You may replace the "Trollety" label to any name (avoid using comma). Likewise, you add more object's UIDs and label to the CSV profile. Save the profile and run the processing sketch again, and your reader should be able to read all of them. 86 | 87 | ### e6_SingleTagHovering 88 | - Open the example e6_SingleTagHovering.pde 89 | - Attach __1__ NFC tags to the top of anything that moves linearly, such as a boat. Maintain z = 7-25 mm (for Mifare 1k or NTAG 213/215 tags) distance between the tag and the reader with a linear track for reliable tracking. 90 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Close the processing sketch. 91 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of the "boat" tags with yours. Save the CSV file after it's done. 92 | - Run the processing sketch again, move the object linearly, and then you will see the object's info, the movement direction and speed shown on the screen as "Recent tag: [Label] is sliding at ? km/h". **Note: This speed is not correct yet.** We measure the tag activation path length using a ruler. By checking the moving bar on the screen, we can get the reader of the path activation length as X mm. 93 | - In the data/tagProfile.csv, replace the L1 from 43.0 to the X that you measured (e.g., 39.0 when X = 39mm). You may replace the "Boat" label to any name (avoid using comma). Save the profile and run the processing sketch again, and **your reader will be able to read the correct speed** of the tag movement. 94 | - Likewise, you can add more object's UIDs, label, and L1 to the CSV profile. 95 | 96 | ### e7_SingleTagSlidingHovering 97 | - Open the example e7_SingleTagSlidingHovering.pde 98 | - Attach __1__ NFC tags to the bottom of anything that moves linearly, such as a figurine. Maintain less than 6mm distance (for Mifare 1k or NTAG 213/215 tags) between the tag and the reader with a linear track. 99 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Close the processing sketch. 100 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of the "figurine" tags with yours. Save the CSV file after it's done. 101 | - Run the processing sketch again, move the object linearly, and then you will see the object's info, the movement direction and speed shown on the screen as "Recent tag: [Label] is sliding at ? km/h". **Note: This speed is not correct yet.** We need to measure the tag activation path lengths with a ruler. 102 | - Two tag activation path lengths have to be measured: 1) L1 for Sliding, and 2) L2 for Hovering. For L1 (sliding), since there will be 3 segments of activation that are observable, check the longest one on the screen so that you can get the L1 = X mm. For L2 (hovering), put a spacer below the tag to make the z>6mm. There will be only one segment of activation that is observable so that you can get L2 = Y mm. 103 | - In the data/tagProfile.csv, replace the L1 from 39.0 to the X that you measured and the L2 from 43.0 to the Y that you measured. You may replace the "Figurine" label to any name (avoid using comma). Save the profile and run the processing sketch again, and **your reader will be able to read the correct speed** of the tag movement in the both modes. The hovering speed can be less accurate if the object is above z=25mm. 104 | - Likewise, you can add more object's UIDs, label, L1 and L2 to the CSV profile. 105 | 106 | ### e8_SingleTiltedTagSliding 107 | - Open the example e8_SingleTiltedTagSliding.pde 108 | - Attach __1__ tilted (between 60-75 degree) NFC tags to the bottom of anything that moves linearly, such as a car. Maintain less than 22mm distance (for Mifare 1k or NTAG 213/215 tags) between the tag's center and the reader with a linear track. 109 | - Run the processing sketch, scan the tag, and keep the tag's 4-byte Universal ID (UID0,UID1,UID2,UID3) shown in the console. Close the processing sketch. 110 | - Open the data/tagProfile.csv in the examples' folder, replace the UID of the "Car" tags with yours. Save the CSV file after it's done. 111 | - Run the processing sketch again, move the object linearly, and then you will see the object's info, the movement direction and speed shown on the screen as "Recent tag: [Label] is sliding forward/backward at ? km/h". **Note: This speed is not correct yet.** We need to measure the tag activation path lengths with a ruler. 112 | - Since there will be 2 segments of activation that are observable, check the longest one on the screen so that you can get the L1 = X mm. 113 | - In the data/tagProfile.csv, replace the L1 from 31.0 to the X that you measured. You may replace the "Car" label to any name (avoid using comma). Save the profile and run the processing sketch again, and **your reader will be able to read the correct speed** of the tag movement in both directions. 114 | - Likewise, you can add more object's UIDs, label, L1 to the CSV profile. 115 | 116 | ### e9_Demo 117 | - Open the example e9_Demo.pde 118 | - Copy the lines that you just created from the tagProfile.csv files in the previous examples to the demo.csv. 119 | - Run the processing sketch, then every object's movement mode and it's correct speed can be detected. 120 | 121 | ### e0_App_Boilerplate 122 | - Open the example e0_App_Boilerplate.pde 123 | - Copy the lines that you just created from the tagProfile.csv or demo.csv files in the previous examples to the demo.csv. 124 | - Now you can use this processing sketch as a boilerplate to create your own applications. 125 | 126 | ## Cheatsheet (/docs) 127 | The 1-page Summary of how the proposed algorithm works. 128 | 129 | ### Documentation 130 | The full documentation will be available soon! 131 | 132 | ## Source (/src) 133 | The source code of the OpenNFCSense library (**GNU GPLv3 copyleft license**) 134 | 135 | ## Cite this Work: 136 | 137 | If you use this library, please cite the original NFCSense paper as following 138 | 139 | - ACM format: 140 | ``` 141 | Rong-Hao Liang and Zengrong Guo. 2021. NFCSense: Data-Defined Rich-ID Motion Sensing for Fluent Tangible Interaction Using a Commodity NFC Reader. In Proceedings of the 2021 CHI Conference on Human Factors in Computing Systems (CHI '21). Association for Computing Machinery, New York, NY, USA, Article 505, 1–14. DOI:https://doi.org/10.1145/3411764.3445214 142 | ``` 143 | - bibtex format: 144 | ``` 145 | @inproceedings{10.1145/3411764.3445214, 146 | author = {Liang, Rong-Hao and Guo, Zengrong}, 147 | title = {NFCSense: Data-Defined Rich-ID Motion Sensing for Fluent Tangible Interaction Using a Commodity NFC Reader}, 148 | year = {2021}, 149 | isbn = {9781450380966}, 150 | publisher = {Association for Computing Machinery}, 151 | address = {New York, NY, USA}, 152 | url = {https://doi.org/10.1145/3411764.3445214}, 153 | doi = {10.1145/3411764.3445214}, 154 | abstract = { This paper presents NFCSense, a data-defined rich-ID motion sensing technique for fluent tangible interaction design by using commodity near-field communication (NFC) tags and a single NFC tag reader. An NFC reader can reliably recognize the presence of an NFC tag at a high read rate (∼ 300 reads/s) with low latency, but such high-speed reading has rarely been exploited because the reader may not effectively resolve collisions of multiple tags. Therefore, its human–computer interface applications have been typically limited to a discrete, hands-on interaction style using one tag at a time. In this work, we realized fluent, hands-off, and multi-tag tangible interactions by leveraging gravity and anti-collision physical constraints, which support effortless user input and maximize throughput. Furthermore, our system provides hot-swappable interactivity that enables smooth transitions throughout extended use. Based on the design parameters explored through a series of studies, we present a design space with proof-of-concept implementations in various applications. }, 155 | booktitle = {Proceedings of the 2021 CHI Conference on Human Factors in Computing Systems}, 156 | articleno = {505}, 157 | numpages = {14}, 158 | keywords = {Tags, Rich-ID, Motion Sensing, Fluent, Tangible Interaction, Physical Constraints, NFC}, 159 | location = {Yokohama, Japan}, 160 | series = {CHI '21} 161 | } 162 | ``` 163 | 164 | ## License (GNU GPLv3 copyleft license) 165 | OpenNFCSense is an open-source software under the terms of **GNU GPLv3 copyleft license**. Anyone can use this, for any purpose. Since a **copyleft** license requires that the project developed around your software be distributed under the same (or similar) license, you must give all users of your work the freedom to carry out all of copying, distribution and modification activities if the work is based on OpenNFCSense. 166 | 167 | We also offer closed-source license which give you the ability not redistribute your software as open-source too. Contact the authors via (r.liang@tue.nl) if you are interested. 168 | 169 | In any form of copying, distribution and modification, you must include the following description in your source code, as mentioned in https://www.gnu.org/licenses/ 170 | 171 | ``` 172 | /*========================================================================== 173 | // OpenNFCSense4P (v1) - Open NFCSense API for Processing Language 174 | // Copyright (C) 2021 Dr. Rong-Hao Liang 175 | // This program is free software: you can redistribute it and/or modify 176 | // it under the terms of the GNU General Public License as published by 177 | // the Free Software Foundation, either version 3 of the License, or 178 | // (at your option) any later version. 179 | // 180 | // This program is distributed in the hope that it will be useful, 181 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 182 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 183 | // GNU General Public License for more details. 184 | // 185 | // You should have received a copy of the GNU General Public License 186 | // along with this program. If not, see . 187 | //==========================================================================*/ 188 | ``` 189 | 190 | -------------------------------------------------------------------------------- /arduino/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/arduino/.DS_Store -------------------------------------------------------------------------------- /arduino/NFCSense4P_ArduinoUno_RC522_v1/NFCSense4P_ArduinoUno_RC522_v1.ino: -------------------------------------------------------------------------------- 1 | //********************************************* 2 | // Arduino Codes for NFCSense, which is based on 3 | // - NXP MFRC522 NFC/RFID Reader (e.g., RFID RC522) 4 | // - RFID.cpp Library (created by Dr. Leong and Miguel Balboa) 5 | // for further information please check 6 | // our website: https://ronghaoliang.page/NFCSense 7 | // or contact Dr. Rong-Hao Liang (TU Eindhoven) via r.liang@tue.nl 8 | //********************************************* 9 | //Copyright <2021> Dr. Rong-Hao Liang 10 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 11 | //INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 12 | //IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 13 | //WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 14 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | #include 17 | #include "RFID.h" 18 | #define SS_PIN 10 19 | #define RST_PIN 9 20 | #define UID_BYTEBUM 4 //The 4-Byte UID 21 | 22 | #define REFRESH_RATE 300 //unit: Hz 23 | //Recommended parameters: 300 for Arduino Uno and Leonardo, 250 for ESP32, 200 for Teensy 3.2 24 | 25 | RFID rfid(SS_PIN, RST_PIN); 26 | int UID[UID_BYTEBUM]; //UID: Unique IDentifier 27 | char dataID[UID_BYTEBUM] = {'A','B','C','D'}; //data label 28 | long timer = micros(); //timer 29 | 30 | void setup() 31 | { 32 | Serial.begin(115200); 33 | SPI.begin(); 34 | rfid.init(); 35 | for (int i = 0 ; i < UID_BYTEBUM ; i++) UID[i] = -1; 36 | } 37 | 38 | void loop() 39 | { 40 | if (micros() - timer >= (1000000/REFRESH_RATE) ) { //Timer: send sensor data in every 10ms 41 | timer = micros(); 42 | if (rfid.isCard()) { // A tag is detected 43 | if (rfid.readCardSerial()) { // Read the tag's ID 44 | for (int i = 0 ; i < UID_BYTEBUM ; i++) UID[i] = rfid.serNum[i]; 45 | } 46 | } 47 | else { // No tag is detected. 48 | for (int i = 0 ; i < UID_BYTEBUM ; i++) UID[i] = 256; //256: absence 49 | } 50 | #if PRINT_IN_SERIAL_PLOTTER 51 | printInSerialPlotter(UID); 52 | #else 53 | for (int i = 0 ; i < UID_BYTEBUM ; i++) { 54 | sendDataToProcessing(dataID[i], UID[i]); 55 | } 56 | #endif 57 | rfid.halt(); //Halt the rfid reader 58 | } 59 | } 60 | 61 | void printInSerialPlotter(int UID[]) { //println(uid[0],uid[1],uid[2],uid[3],uid[4]); 62 | for(int i=0; i< UID_BYTEBUM; i++){ 63 | Serial.print(UID[i]); 64 | (i<(UID_BYTEBUM-1) ? Serial.print(','): Serial.println()); 65 | } 66 | } 67 | 68 | void sendDataToProcessing(char symbol, int data) { 69 | Serial.print(symbol); // symbol prefix of data type 70 | Serial.println(data); // the integer data with a carriage return 71 | } 72 | -------------------------------------------------------------------------------- /arduino/NFCSense4P_ArduinoUno_RC522_v1/RFID.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * RFID.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 3 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 4 | * Created by Miguel Balboa, Jan, 2012. 5 | * Released into the public domain. 6 | */ 7 | 8 | /****************************************************************************** 9 | * Includes 10 | ******************************************************************************/ 11 | #include 12 | #include "RFID.h" 13 | 14 | /****************************************************************************** 15 | * User API 16 | ******************************************************************************/ 17 | 18 | /** 19 | * Construct RFID 20 | * int chipSelectPin RFID /ENABLE pin 21 | */ 22 | RFID::RFID(int chipSelectPin, int NRSTPD) 23 | { 24 | _chipSelectPin = chipSelectPin; 25 | 26 | pinMode(_chipSelectPin,OUTPUT); // Set digital as OUTPUT to connect it to the RFID /ENABLE pin 27 | digitalWrite(_chipSelectPin, LOW); 28 | 29 | 30 | pinMode(NRSTPD,OUTPUT); // Set digital pin, Not Reset and Power-down 31 | digitalWrite(NRSTPD, HIGH); 32 | _NRSTPD = NRSTPD; 33 | } 34 | /****************************************************************************** 35 | * User API 36 | ******************************************************************************/ 37 | 38 | bool RFID::isCard() 39 | { 40 | unsigned char status; 41 | unsigned char str[MAX_LEN]; 42 | 43 | status = MFRC522Request(PICC_REQIDL, str); 44 | if (status == MI_OK) { 45 | return true; 46 | } else { 47 | return false; 48 | } 49 | } 50 | 51 | bool RFID::readCardSerial(){ 52 | 53 | unsigned char status; 54 | unsigned char str[MAX_LEN]; 55 | 56 | // Anti-colisión, devuelva el número de serie de tarjeta de 4 bytes 57 | status = anticoll(str); 58 | memcpy(serNum, str, 5); 59 | 60 | if (status == MI_OK) { 61 | return true; 62 | } else { 63 | return false; 64 | } 65 | 66 | } 67 | 68 | /****************************************************************************** 69 | * Dr.Leong ( WWW.B2CQSHOP.COM ) 70 | ******************************************************************************/ 71 | 72 | void RFID::init() 73 | { 74 | digitalWrite(_NRSTPD,HIGH); 75 | 76 | reset(); 77 | 78 | //Timer: TPrescaler*TreloadVal/6.78MHz = 24ms 79 | writeMFRC522(TModeReg, 0x80); //Tauto=1; f(Timer) = 6.78MHz/TPreScaler 80 | writeMFRC522(TPrescalerReg, 0x3E); //TModeReg[3..0] + TPrescalerReg 81 | writeMFRC522(TReloadRegL, 30); 82 | writeMFRC522(TReloadRegH, 0); 83 | 84 | writeMFRC522(TxAutoReg, 0x40); //100%ASK 85 | writeMFRC522(ModeReg, 0x3D); // CRC valor inicial de 0x6363 86 | 87 | //ClearBitMask(Status2Reg, 0x08); //MFCrypto1On=0 88 | //writeMFRC522(RxSelReg, 0x86); //RxWait = RxSelReg[5..0] 89 | writeMFRC522(RFCfgReg, 0x7F); //RxGain = 48dB 90 | 91 | antennaOn(); //Abre la antena 92 | 93 | 94 | } 95 | void RFID::reset() 96 | { 97 | writeMFRC522(CommandReg, PCD_RESETPHASE); 98 | } 99 | 100 | void RFID::writeMFRC522(unsigned char addr, unsigned char val) 101 | { 102 | digitalWrite(_chipSelectPin, LOW); 103 | 104 | //0XXXXXX0 formato de dirección 105 | SPI.transfer((addr<<1)&0x7E); 106 | SPI.transfer(val); 107 | 108 | digitalWrite(_chipSelectPin, HIGH); 109 | } 110 | 111 | void RFID::antennaOn(void) 112 | { 113 | unsigned char temp; 114 | 115 | temp = readMFRC522(TxControlReg); 116 | if (!(temp & 0x03)) 117 | { 118 | setBitMask(TxControlReg, 0x03); 119 | } 120 | } 121 | 122 | /* 123 | * Read_MFRC522 Nombre de la función: Read_MFRC522 124 | * Descripción: Desde el MFRC522 leer un byte de un registro de datos 125 | * Los parámetros de entrada: addr - la dirección de registro 126 | * Valor de retorno: Devuelve un byte de datos de lectura 127 | */ 128 | unsigned char RFID::readMFRC522(unsigned char addr) 129 | { 130 | unsigned char val; 131 | digitalWrite(_chipSelectPin, LOW); 132 | SPI.transfer(((addr<<1)&0x7E) | 0x80); 133 | val =SPI.transfer(0x00); 134 | digitalWrite(_chipSelectPin, HIGH); 135 | return val; 136 | } 137 | 138 | void RFID::setBitMask(unsigned char reg, unsigned char mask) 139 | { 140 | unsigned char tmp; 141 | tmp = readMFRC522(reg); 142 | writeMFRC522(reg, tmp | mask); // set bit mask 143 | } 144 | 145 | void RFID::clearBitMask(unsigned char reg, unsigned char mask) 146 | { 147 | unsigned char tmp; 148 | tmp = readMFRC522(reg); 149 | writeMFRC522(reg, tmp & (~mask)); // clear bit mask 150 | } 151 | 152 | void RFID::calculateCRC(unsigned char *pIndata, unsigned char len, unsigned char *pOutData) 153 | { 154 | unsigned char i, n; 155 | 156 | clearBitMask(DivIrqReg, 0x04); //CRCIrq = 0 157 | setBitMask(FIFOLevelReg, 0x80); //Claro puntero FIFO 158 | //Write_MFRC522(CommandReg, PCD_IDLE); 159 | 160 | //Escribir datos en el FIFO 161 | for (i=0; i MAX_LEN) 268 | { 269 | n = MAX_LEN; 270 | } 271 | 272 | //??FIFO??????? Lea los datos recibidos en el FIFO 273 | for (i=0; i anticoll 325 | * Anti-detección de colisiones, la lectura del número de serie de la tarjeta de tarjeta 326 | * @param serNum - devuelve el número de tarjeta 4 bytes de serie, los primeros 5 bytes de bytes de paridad 327 | * @return retorno exitoso MI_OK 328 | */ 329 | unsigned char RFID::anticoll(unsigned char *serNum) 330 | { 331 | unsigned char status; 332 | unsigned char i; 333 | unsigned char serNumCheck=0; 334 | unsigned int unLen; 335 | 336 | 337 | //ClearBitMask(Status2Reg, 0x08); //TempSensclear 338 | //ClearBitMask(CollReg,0x80); //ValuesAfterColl 339 | writeMFRC522(BitFramingReg, 0x00); //TxLastBists = BitFramingReg[2..0] 340 | 341 | serNum[0] = PICC_ANTICOLL; 342 | serNum[1] = 0x20; 343 | status = MFRC522ToCard(PCD_TRANSCEIVE, serNum, 2, serNum, &unLen); 344 | 345 | if (status == MI_OK) 346 | { 347 | //?????? Compruebe el número de serie de la tarjeta 348 | for (i=0; i<4; i++) 349 | { 350 | serNumCheck ^= serNum[i]; 351 | } 352 | if (serNumCheck != serNum[i]) 353 | { 354 | status = MI_ERR; 355 | } 356 | } 357 | 358 | //SetBitMask(CollReg, 0x80); //ValuesAfterColl=1 359 | 360 | return status; 361 | } 362 | 363 | /* 364 | * MFRC522Auth -> auth 365 | * Verificar la contraseña de la tarjeta 366 | * Los parámetros de entrada: AuthMode - Modo de autenticación de contraseña 367 | 0x60 = A 0x60 = validación KeyA 368 | 0x61 = B 0x61 = validación KeyB 369 | BlockAddr-- bloque de direcciones 370 | Sectorkey-- sector contraseña 371 | serNum--,4? Tarjeta de número de serie, 4 bytes 372 | * MI_OK Valor de retorno: el retorno exitoso MI_OK 373 | */ 374 | unsigned char RFID::auth(unsigned char authMode, unsigned char BlockAddr, unsigned char *Sectorkey, unsigned char *serNum) 375 | { 376 | unsigned char status; 377 | unsigned int recvBits; 378 | unsigned char i; 379 | unsigned char buff[12]; 380 | 381 | //????+???+????+???? Verifique la dirección de comandos de bloques del sector + + contraseña + número de la tarjeta de serie 382 | buff[0] = authMode; 383 | buff[1] = BlockAddr; 384 | for (i=0; i<6; i++) 385 | { 386 | buff[i+2] = *(Sectorkey+i); 387 | } 388 | for (i=0; i<4; i++) 389 | { 390 | buff[i+8] = *(serNum+i); 391 | } 392 | status = MFRC522ToCard(PCD_AUTHENT, buff, 12, buff, &recvBits); 393 | 394 | if ((status != MI_OK) || (!(readMFRC522(Status2Reg) & 0x08))) 395 | { 396 | status = MI_ERR; 397 | } 398 | 399 | return status; 400 | } 401 | 402 | /* 403 | * MFRC522Read -> read 404 | * Lectura de datos de bloque 405 | * Los parámetros de entrada: blockAddr - dirección del bloque; recvData - leer un bloque de datos 406 | * MI_OK Valor de retorno: el retorno exitoso MI_OK 407 | */ 408 | unsigned char RFID::read(unsigned char blockAddr, unsigned char *recvData) 409 | { 410 | unsigned char status; 411 | unsigned int unLen; 412 | 413 | recvData[0] = PICC_READ; 414 | recvData[1] = blockAddr; 415 | calculateCRC(recvData,2, &recvData[2]); 416 | status = MFRC522ToCard(PCD_TRANSCEIVE, recvData, 4, recvData, &unLen); 417 | 418 | if ((status != MI_OK) || (unLen != 0x90)) 419 | { 420 | status = MI_ERR; 421 | } 422 | 423 | return status; 424 | } 425 | 426 | /* 427 | * MFRC522Write -> write 428 | * La escritura de datos de bloque 429 | * blockAddr - dirección del bloque; WriteData - para escribir 16 bytes del bloque de datos 430 | * Valor de retorno: el retorno exitoso MI_OK 431 | */ 432 | unsigned char RFID::write(unsigned char blockAddr, unsigned char *writeData) 433 | { 434 | unsigned char status; 435 | unsigned int recvBits; 436 | unsigned char i; 437 | unsigned char buff[18]; 438 | 439 | buff[0] = PICC_WRITE; 440 | buff[1] = blockAddr; 441 | calculateCRC(buff, 2, &buff[2]); 442 | status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 4, buff, &recvBits); 443 | 444 | if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) 445 | { 446 | status = MI_ERR; 447 | } 448 | 449 | if (status == MI_OK) 450 | { 451 | for (i=0; i<16; i++) //?FIFO?16Byte?? Datos a la FIFO 16Byte escribir 452 | { 453 | buff[i] = *(writeData+i); 454 | } 455 | calculateCRC(buff, 16, &buff[16]); 456 | status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 18, buff, &recvBits); 457 | 458 | if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)) 459 | { 460 | status = MI_ERR; 461 | } 462 | } 463 | 464 | return status; 465 | } 466 | 467 | 468 | /* 469 | * MFRC522Halt -> halt 470 | * Cartas de Mando para dormir 471 | * Los parámetros de entrada: Ninguno 472 | * Valor devuelto: Ninguno 473 | */ 474 | void RFID::halt() 475 | { 476 | unsigned char status; 477 | unsigned int unLen; 478 | unsigned char buff[4]; 479 | 480 | buff[0] = PICC_HALT; 481 | buff[1] = 0; 482 | calculateCRC(buff, 2, &buff[2]); 483 | 484 | status = MFRC522ToCard(PCD_TRANSCEIVE, buff, 4, buff,&unLen); 485 | } 486 | -------------------------------------------------------------------------------- /arduino/NFCSense4P_ArduinoUno_RC522_v1/RFID.h: -------------------------------------------------------------------------------- 1 | /* RFID.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. 2 | * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) 3 | * Created by Miguel Balboa (circuitito.com), Jan, 2012. 4 | */ 5 | #ifndef RFID_h 6 | #define RFID_h 7 | 8 | #include 9 | #include 10 | 11 | /****************************************************************************** 12 | * Definitions 13 | ******************************************************************************/ 14 | #define MAX_LEN 16 // Largo m·ximo de la matriz 15 | 16 | //MF522 comando palabra 17 | #define PCD_IDLE 0x00 // NO action; Y cancelar el comando 18 | #define PCD_AUTHENT 0x0E // autenticaciÛn de clave 19 | #define PCD_RECEIVE 0x08 // recepciÛn de datos 20 | #define PCD_TRANSMIT 0x04 // Enviar datos 21 | #define PCD_TRANSCEIVE 0x0C // Enviar y recibir datos 22 | #define PCD_RESETPHASE 0x0F // reajustar 23 | #define PCD_CALCCRC 0x03 // CRC calcular 24 | 25 | //Mifare_One Tarjeta Mifare_One comando palabra 26 | #define PICC_REQIDL 0x26 // ¡rea de la antena no est· tratando de entrar en el estado de reposo 27 | #define PICC_REQALL 0x52 // Todas las cartas para encontrar el ·rea de la antena 28 | #define PICC_ANTICOLL 0x93 // anti-colisiÛn 29 | #define PICC_SElECTTAG 0x93 // elecciÛn de tarjeta 30 | #define PICC_AUTHENT1A 0x60 // verificaciÛn key A 31 | #define PICC_AUTHENT1B 0x61 // verificaciÛn Key B 32 | #define PICC_READ 0x30 // leer bloque 33 | #define PICC_WRITE 0xA0 // Escribir en el bloque 34 | #define PICC_DECREMENT 0xC0 // cargo 35 | #define PICC_INCREMENT 0xC1 // recargar 36 | #define PICC_RESTORE 0xC2 // Transferencia de datos de bloque de buffer 37 | #define PICC_TRANSFER 0xB0 // Guardar los datos en el b˙fer 38 | #define PICC_HALT 0x50 // inactividad 39 | 40 | //MF522 CÛdigo de error de comunicaciÛn cuando regresÛ 41 | #define MI_OK 0 42 | #define MI_NOTAGERR 1 43 | #define MI_ERR 2 44 | 45 | //------------------ MFRC522 registro--------------- 46 | //Page 0:Command and Status 47 | #define Reserved00 0x00 48 | #define CommandReg 0x01 49 | #define CommIEnReg 0x02 50 | #define DivlEnReg 0x03 51 | #define CommIrqReg 0x04 52 | #define DivIrqReg 0x05 53 | #define ErrorReg 0x06 54 | #define Status1Reg 0x07 55 | #define Status2Reg 0x08 56 | #define FIFODataReg 0x09 57 | #define FIFOLevelReg 0x0A 58 | #define WaterLevelReg 0x0B 59 | #define ControlReg 0x0C 60 | #define BitFramingReg 0x0D 61 | #define CollReg 0x0E 62 | #define Reserved01 0x0F 63 | //Page 1:Command 64 | #define Reserved10 0x10 65 | #define ModeReg 0x11 66 | #define TxModeReg 0x12 67 | #define RxModeReg 0x13 68 | #define TxControlReg 0x14 69 | #define TxAutoReg 0x15 70 | #define TxSelReg 0x16 71 | #define RxSelReg 0x17 72 | #define RxThresholdReg 0x18 73 | #define DemodReg 0x19 74 | #define Reserved11 0x1A 75 | #define Reserved12 0x1B 76 | #define MifareReg 0x1C 77 | #define Reserved13 0x1D 78 | #define Reserved14 0x1E 79 | #define SerialSpeedReg 0x1F 80 | //Page 2:CFG 81 | #define Reserved20 0x20 82 | #define CRCResultRegM 0x21 83 | #define CRCResultRegL 0x22 84 | #define Reserved21 0x23 85 | #define ModWidthReg 0x24 86 | #define Reserved22 0x25 87 | #define RFCfgReg 0x26 88 | #define GsNReg 0x27 89 | #define CWGsPReg 0x28 90 | #define ModGsPReg 0x29 91 | #define TModeReg 0x2A 92 | #define TPrescalerReg 0x2B 93 | #define TReloadRegH 0x2C 94 | #define TReloadRegL 0x2D 95 | #define TCounterValueRegH 0x2E 96 | #define TCounterValueRegL 0x2F 97 | //Page 3:TestRegister 98 | #define Reserved30 0x30 99 | #define TestSel1Reg 0x31 100 | #define TestSel2Reg 0x32 101 | #define TestPinEnReg 0x33 102 | #define TestPinValueReg 0x34 103 | #define TestBusReg 0x35 104 | #define AutoTestReg 0x36 105 | #define VersionReg 0x37 106 | #define AnalogTestReg 0x38 107 | #define TestDAC1Reg 0x39 108 | #define TestDAC2Reg 0x3A 109 | #define TestADCReg 0x3B 110 | #define Reserved31 0x3C 111 | #define Reserved32 0x3D 112 | #define Reserved33 0x3E 113 | #define Reserved34 0x3F 114 | //----------------------------------------------- 115 | 116 | class RFID 117 | { 118 | public: 119 | RFID(int chipSelectPin, int NRSTPD); 120 | 121 | bool isCard(); 122 | bool readCardSerial(); 123 | 124 | void init(); 125 | void reset(); 126 | void writeMFRC522(unsigned char addr, unsigned char val); 127 | void antennaOn(void); 128 | unsigned char readMFRC522(unsigned char addr); 129 | void setBitMask(unsigned char reg, unsigned char mask); 130 | void clearBitMask(unsigned char reg, unsigned char mask); 131 | void calculateCRC(unsigned char *pIndata, unsigned char len, unsigned char *pOutData); 132 | unsigned char MFRC522Request(unsigned char reqMode, unsigned char *TagType); 133 | unsigned char MFRC522ToCard(unsigned char command, unsigned char *sendData, unsigned char sendLen, unsigned char *backData, unsigned int *backLen); 134 | unsigned char anticoll(unsigned char *serNum); 135 | unsigned char auth(unsigned char authMode, unsigned char BlockAddr, unsigned char *Sectorkey, unsigned char *serNum); 136 | unsigned char read(unsigned char blockAddr, unsigned char *recvData); 137 | unsigned char write(unsigned char blockAddr, unsigned char *writeData); 138 | void halt(); 139 | 140 | unsigned char serNum[5]; // Constante para guardar el numero de serie leido. 141 | unsigned char AserNum[5]; // Constante para guardar el numero d serie de la secion actual. 142 | 143 | private: 144 | int _chipSelectPin; 145 | int _NRSTPD; 146 | 147 | }; 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /docs/NFCSenseCheatSheet_v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/docs/NFCSenseCheatSheet_v1.png -------------------------------------------------------------------------------- /download/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/download/.DS_Store -------------------------------------------------------------------------------- /download/OpenNFCSense4P-2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/download/OpenNFCSense4P-2.zip -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/.DS_Store -------------------------------------------------------------------------------- /examples/episode1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode1/.DS_Store -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagEFan/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode1/e1_SingleTagEFan/.DS_Store -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagEFan/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,129,153,Black spinner,2,2,0.0,0.0 3 | 136,4,8,152,Blue spinner,2,2,0.0,0.0 4 | 136,4,6,199,LED spinner,2,2,0.0,0.0 5 | 136,4,56,233,Hot wheels,2,2,0.0,0.0 6 | 136,4,145,150,E-fan,2,2,0.0,0.0 7 | 249,34,56,174,E-fan,2,2,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagEFan/e1_SingleTagEFan.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | float lastFreq = 0; 29 | long timer = 0; 30 | float[] lastFreqArray = new float[9]; 31 | 32 | float[] pushValue(float[] array, float v){ 33 | float[] _array = new float[array.length]; 34 | arrayCopy(array,_array); 35 | for(int i = 0; i < _array.length-1; i++){ 36 | _array[i+1] = array[i]; 37 | } 38 | _array[0] = v; 39 | return _array; 40 | } 41 | float medianFilter(float[] array){ 42 | float[] _array = new float[array.length]; 43 | arrayCopy(array,_array); 44 | _array=sort(_array); 45 | println(_array); 46 | return _array[floor(_array.length/2)]; 47 | } 48 | 49 | void setup() { 50 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 51 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 52 | //nfcs = new OpenNFCSense4P(this, "demo.csv", 250, 500, 2000); 53 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 54 | initSerial(); //Initialize the serial port 55 | /*== Put your codes below ==*/ 56 | timer = millis()-7000; 57 | /*== Put your codes above ==*/ 58 | } 59 | 60 | void draw() { 61 | nfcs.updateNFCBits(); //update the features of current bit 62 | /*== Put your codes below ==*/ 63 | ArrayList nbitList = nfcs.getNFCBits(); 64 | if (nbitList.size()>0) { 65 | String s = nbitList.get(0).getName(); 66 | if (lastString != s) { 67 | lastString = s; 68 | } 69 | if (lastString.equals("E-fan")){ 70 | lastFreqArray=pushValue(lastFreqArray, nbitList.get(0).getFrequency()); 71 | lastFreq = medianFilter(lastFreqArray); 72 | } 73 | timer = millis(); 74 | } 75 | println(lastString); 76 | /*== Put your codes above ==*/ 77 | background(255); //Refresh the screen 78 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 79 | 80 | drawLastBit(50, 100); //print the extra information of the last NFCBit in the console 81 | /*== Put your codes below ==*/ 82 | if (millis()-timer<1000) { 83 | if (lastString.equals("E-fan")) { 84 | if (lastFreq > 52) { 85 | drawString("Full Speed: 15-20 mins left", 50, height/4+100); 86 | } else if (lastFreq > 40 && lastFreq <= 52) { 87 | drawString("Mid Speed: 20-25 mins left", 50, height/4+100); 88 | } else if (lastFreq > 25 && lastFreq <= 40) { 89 | drawString("Low Speed: 25-30 mins left", 50, height/4+100); 90 | } else if (lastFreq <= 25 && lastFreq > 2) { 91 | drawString("...", 50, height/4+100); 92 | } else { 93 | drawString("Off.", 50, height/4+100); 94 | } 95 | } 96 | } else { 97 | if (lastString == "E-fan") { 98 | drawString("Off.", 50, height/4+100); 99 | } 100 | } 101 | /*== Put your codes above ==*/ 102 | //drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 103 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 104 | //printLastBit(); //print the extra information of the last NFCBit in the console 105 | //printCurrentTag(); //print the current tag read by the reader 106 | } 107 | 108 | /*Initialize the serial port*/ 109 | void initSerial() { 110 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 111 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 112 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 113 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 114 | port.clear(); // flush the Serial buffer 115 | } 116 | 117 | /*draw a formatted String*/ 118 | void drawString(String s, int x, int y) { //print the latest tag appearance 119 | pushStyle(); 120 | fill(0); 121 | textSize(48); 122 | text(s, x, y); 123 | popStyle(); 124 | } 125 | 126 | /*draw the basic information of the last NFCBit*/ 127 | void drawLastBit(int x, int y) { //print the latest tag appearance 128 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 129 | String objInfo = "Current object: ", motionInfo = ""; 130 | String tagID = ""; 131 | if (nbitList.size()>0) { 132 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 133 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 134 | objInfo += nb.getName(); 135 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 136 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 137 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 138 | } else { 139 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 140 | } 141 | } 142 | } 143 | pushStyle(); 144 | fill(0); 145 | textSize(48); 146 | text(objInfo, x, y); 147 | textSize(32); 148 | text(motionInfo, x, y+48); 149 | textSize(16); 150 | text(tagID, x, y+48+32); 151 | popStyle(); 152 | } 153 | 154 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 155 | void drawRecentBits(int x, int y) { 156 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 157 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 158 | String tagName = ""; 159 | String tagID = ""; 160 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 161 | for (int i = nbitList.size()-1; i >=0; i--) { 162 | NFCBit nb = nbitList.get(i); 163 | tagName += nb.getName(); 164 | tagID += "["+IDList.get(i)+"]"; 165 | if (i>0) { 166 | tagName += ", "; 167 | tagID += ", "; 168 | } 169 | } 170 | pushStyle(); 171 | fill(0); 172 | textSize(48); 173 | text("Recent objects: ", x, y); 174 | textSize(32); 175 | text(tagName, x, y+48); 176 | textSize(16); 177 | text(tagID, x, y+48+32); 178 | popStyle(); 179 | } 180 | 181 | /*draw the version, read rate, and TTL timer info*/ 182 | void drawInfo(int x, int y) { 183 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 184 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 185 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 186 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 187 | //set the above parameters in the constructor as indicated in setup(); 188 | pushStyle(); 189 | fill(100); 190 | textSize(12); 191 | textAlign(RIGHT, BOTTOM); 192 | text(info, x-5, y-5); 193 | popStyle(); 194 | } 195 | 196 | /*print the extra information of the recent NFCBits in the console*/ 197 | void printRecentBits() { 198 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 199 | for (int i = 0; i < nbitList.size(); i++) { 200 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 201 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 202 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 203 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 204 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 205 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 206 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 207 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 208 | //the features (speed and frequency) 209 | } 210 | println("==="); 211 | } 212 | 213 | /*print the extra information of the last NFCBit in the console*/ 214 | void printLastBit() { 215 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 216 | if (nbitList.size()>0) { 217 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 218 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 219 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 220 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 221 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 222 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 223 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 224 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 225 | //the features (speed and frequency) 226 | } 227 | println("==="); 228 | } 229 | 230 | /*The serial event handler processes the data from any NFC reader in the String format of 231 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 232 | //where every byte is an unsigned integer ranged between [0-256]. 233 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 234 | //================*/ 235 | 236 | void serialEvent(Serial port) { 237 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 238 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 239 | int i = inData.charAt(0)-'A'; 240 | int v = int(trim(inData.substring(1))); 241 | nfcs.rfid[i] = (v>255?-1:v); 242 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 243 | } 244 | return; 245 | } 246 | 247 | //print the current tag read by the reader 248 | void printCurrentTag() { 249 | if (nfcs.rfid[0]<0) println("No tag"); 250 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 251 | } 252 | -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagRoulette/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode1/e1_SingleTagRoulette/.DS_Store -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagRoulette/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,129,153,Black spinner,2,2,0.0,0.0 3 | 169,225,55,174,Papa John's,2,2,0.0,0.0 4 | 249,34,56,174,Domino's,2,2,0.0,0.0 5 | 9,121,66,174,Pizza hut,2,2,0.0,0.0 6 | 41,245,68,174,Tim Hortons,2,2,0.0,0.0 7 | 57,96,60,174,Starbucks,2,2,0.0,0.0 8 | 9,186,63,174,Subway,2,2,0.0,0.0 9 | 217,17,62,174,Burger king,2,2,0.0,0.0 10 | 57,78,56,174,KFC,2,2,0.0,0.0 11 | 233,196,65,174,Taco bell,2,2,0.0,0.0 12 | 249,140,70,174,Macdonld's,2,2,0.0,0.0 13 | 201,25,70,174,Panda exp,2,2,0.0,0.0 14 | 233,24,55,174,Wendy's,2,2,0.0,0.0 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagRoulette/e1_SingleTagRoulette.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | long timer = 0; 29 | 30 | void setup() { 31 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 32 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 33 | //nfcs = new OpenNFCSense4P(this, "demo.csv", 250, 500, 2000); 34 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 35 | initSerial(); //Initialize the serial port 36 | /*== Put your codes below ==*/ 37 | timer = millis()-7000; 38 | /*== Put your codes above ==*/ 39 | } 40 | 41 | void draw() { 42 | nfcs.updateNFCBits(); //update the features of current bit 43 | /*== Put your codes below ==*/ 44 | ArrayList nbitList = nfcs.getNFCBits(); 45 | if(nbitList.size()>0){ 46 | String s = nbitList.get(0).getName(); 47 | if(lastString != s){ 48 | lastString = s; 49 | timer = millis(); 50 | } 51 | } 52 | 53 | /*== Put your codes above ==*/ 54 | background(255); //Refresh the screen 55 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 56 | /*== Put your codes below ==*/ 57 | if(millis()-timer<1000){ 58 | //drawLastBit(50,100); //print the extra information of the last NFCBit in the console 59 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 60 | }else{ 61 | if(millis()-timer<7000){ 62 | drawString("Calling: "+lastString+" ...",50,100); 63 | }else{ 64 | drawString("Dash Roulette",50,100); 65 | } 66 | } 67 | /*== Put your codes above ==*/ 68 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 69 | //printLastBit(); //print the extra information of the last NFCBit in the console 70 | printCurrentTag(); //print the current tag read by the reader 71 | } 72 | 73 | /*Initialize the serial port*/ 74 | void initSerial() { 75 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 76 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 77 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 78 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 79 | port.clear(); // flush the Serial buffer 80 | } 81 | 82 | /*draw a formatted String*/ 83 | void drawString(String s, int x, int y) { //print the latest tag appearance 84 | pushStyle(); 85 | fill(0); 86 | textSize(48); 87 | text(s, x, y); 88 | popStyle(); 89 | } 90 | 91 | /*draw the basic information of the last NFCBit*/ 92 | void drawLastBit(int x, int y) { //print the latest tag appearance 93 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 94 | String objInfo = "Current object: ", motionInfo = ""; 95 | String tagID = ""; 96 | if (nbitList.size()>0) { 97 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 98 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 99 | objInfo += nb.getName(); 100 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 101 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 102 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 103 | } else { 104 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 105 | } 106 | } 107 | } 108 | pushStyle(); 109 | fill(0); 110 | textSize(48); 111 | text(objInfo, x, y); 112 | textSize(32); 113 | text(motionInfo, x, y+48); 114 | textSize(16); 115 | text(tagID, x, y+48+32); 116 | popStyle(); 117 | } 118 | 119 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 120 | void drawRecentBits(int x, int y){ 121 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 122 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 123 | String tagName = ""; 124 | String tagID = ""; 125 | for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 126 | //for (int i = nbitList.size()-1; i >=0; i--) { 127 | NFCBit nb = nbitList.get(i); 128 | tagName += nb.getName(); 129 | tagID += "["+IDList.get(i)+"]"; 130 | //if (i>0){ 131 | tagName += ", "; 132 | tagID += ", "; 133 | //} 134 | } 135 | pushStyle(); 136 | fill(0); 137 | textSize(48); 138 | text("Recent objects: ", x, y); 139 | textSize(32); 140 | text(tagName, x, y+48); 141 | textSize(16); 142 | text(tagID, x, y+48+32); 143 | popStyle(); 144 | } 145 | 146 | /*draw the version, read rate, and TTL timer info*/ 147 | void drawInfo(int x, int y) { 148 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 149 | info += "Read rate: "+nf(nfcs.getReadRate(),0,0)+" reads/sec\n"; // get the current read rate 150 | info += "TTL Timer1: "+nf(nfcs.getTimer1(),0,0)+" ms\n"; // get the current TTL timer1 151 | info += "TTL Timer2: "+nf(nfcs.getTimer2(),0,0)+" ms"; // get the current TTL timer2 152 | //set the above parameters in the constructor as indicated in setup(); 153 | pushStyle(); 154 | fill(100); 155 | textSize(12); 156 | textAlign(RIGHT,BOTTOM); 157 | text(info, x-5, y-5); 158 | popStyle(); 159 | } 160 | 161 | /*print the extra information of the recent NFCBits in the console*/ 162 | void printRecentBits() { 163 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 164 | for (int i = 0; i < nbitList.size(); i++) { 165 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 166 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 167 | print("[", i, "]",tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 168 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 169 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 170 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 171 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 172 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 173 | //the features (speed and frequency) 174 | } 175 | println("==="); 176 | } 177 | 178 | /*print the extra information of the last NFCBit in the console*/ 179 | void printLastBit() { 180 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 181 | if (nbitList.size()>0) { 182 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 183 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 184 | print(nb.getName(), tagID,":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 185 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 186 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 187 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 188 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 189 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 190 | //the features (speed and frequency) 191 | } 192 | println("==="); 193 | } 194 | 195 | /*The serial event handler processes the data from any NFC reader in the String format of 196 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 197 | //where every byte is an unsigned integer ranged between [0-256]. 198 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 199 | //================*/ 200 | 201 | void serialEvent(Serial port) { 202 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 203 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 204 | int i = inData.charAt(0)-'A'; 205 | int v = int(trim(inData.substring(1))); 206 | nfcs.rfid[i] = (v>255?-1:v); 207 | if(i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 208 | } 209 | return; 210 | } 211 | 212 | //print the current tag read by the reader 213 | void printCurrentTag(){ 214 | if(nfcs.rfid[0]<0 || nfcs.rfid[1]<0 || nfcs.rfid[2]<0 || nfcs.rfid[3]<0) println("No tag"); 215 | else println(nfcs.rfid[0],",",nfcs.rfid[1],",",nfcs.rfid[2],",",nfcs.rfid[3]); 216 | } 217 | -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagWheel/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode1/e1_SingleTagWheel/.DS_Store -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagWheel/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,129,153,Black spinner,2,2,0.0,0.0 3 | 136,4,8,152,Blue spinner,2,2,0.0,0.0 4 | 136,4,6,199,LED spinner,2,2,0.0,0.0 5 | 136,4,56,233,Hot wheels,2,2,0.0,0.0 6 | 136,4,145,150,E-fan,2,2,0.0,0.0 7 | 136,4,87,200,A,2,1,0.0,0.0 8 | 136,4,72,200,B,2,1,0.0,0.0 9 | 136,4,232,199,C,2,1,0.0,0.0 10 | 136,4,237,199,D,2,1,0.0,0.0 11 | 136,4,21,199,E,2,1,0.0,0.0 12 | 136,4,53,200,F,2,1,0.0,0.0 13 | 136,4,1,199,G,2,1,0.0,0.0 14 | 136,4,58,200,H,2,1,0.0,0.0 15 | 136,4,52,200,I,2,1,0.0,0.0 16 | 136,4,68,200,J,2,1,0.0,0.0 17 | 136,4,16,199,K,2,1,0.0,0.0 18 | 136,4,47,200,L,2,1,0.0,0.0 19 | 136,4,222,199,M,2,1,0.0,0.0 20 | 136,4,242,199,N,2,1,0.0,0.0 21 | 136,4,63,200,O,2,1,0.0,0.0 22 | 136,4,252,199,P,2,1,0.0,0.0 23 | 136,4,77,200,Q,2,1,0.0,0.0 24 | 136,4,227,199,R,2,1,0.0,0.0 25 | 136,4,92,200,S,2,1,0.0,0.0 26 | 136,4,48,200,T,2,1,0.0,0.0 27 | 136,4,247,199,U,2,1,0.0,0.0 28 | 136,4,27,200,V,2,1,0.0,0.0 29 | 136,4,82,200,W,2,1,0.0,0.0 30 | 136,4,31,199,X,2,1,0.0,0.0 31 | 136,4,37,200,Y,2,1,0.0,0.0 32 | 136,4,26,199,Z,2,1,0.0,0.0 33 | 136,4,129,200,0,2,1,0.0,0.0 34 | 136,4,32,200,1,2,1,0.0,0.0 35 | 136,4,126,199,2,2,1,0.0,0.0 36 | 136,4,111,199,3,2,1,0.0,0.0 37 | 136,4,121,199,4,2,1,0.0,0.0 38 | 136,4,116,199,5,2,1,0.0,0.0 39 | 136,4,101,199,6,2,1,0.0,0.0 40 | 136,4,91,199,7,2,1,0.0,0.0 41 | 136,4,96,199,8,2,1,0.0,0.0 42 | 136,4,106,199,9,2,1,0.0,0.0 43 | 136,4,107,200,Apple,2,1,0.0,0.0 44 | 136,4,112,200,2,2,1,0.0,0.0 45 | 136,4,117,200,Carrot,2,1,0.0,0.0 46 | 136,4,22,200,1,2,1,0.0,0.0 47 | 136,4,36,199,3,2,1,0.0,0.0 48 | 136,4,102,200,Banana,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode1/e1_SingleTagWheel/e1_SingleTagWheel.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | float lastFreq = 0; 29 | long timer = 0; 30 | float[] lastFreqArray = new float[9]; 31 | 32 | float temp=0; 33 | float pointerValue; 34 | 35 | float[] pushValue(float[] array, float v) { 36 | float[] _array = new float[array.length]; 37 | arrayCopy(array, _array); 38 | for (int i = 0; i < _array.length-1; i++) { 39 | _array[i+1] = array[i]; 40 | } 41 | _array[0] = v; 42 | return _array; 43 | } 44 | float medianFilter(float[] array) { 45 | float[] _array = new float[array.length]; 46 | arrayCopy(array, _array); 47 | _array=sort(_array); 48 | println(_array); 49 | return _array[floor(_array.length/2)]; 50 | } 51 | 52 | void setup() { 53 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 54 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 55 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 500); 56 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 57 | initSerial(); //Initialize the serial port 58 | /*== Put your codes below ==*/ 59 | timer = millis()-7000; 60 | /*== Put your codes above ==*/ 61 | } 62 | 63 | void draw() { 64 | nfcs.updateNFCBits(); //update the features of current bit 65 | /*== Put your codes below ==*/ 66 | ArrayList nbitList = nfcs.getNFCBits(); 67 | if (nbitList.size()>0) { 68 | String s = nbitList.get(0).getName(); 69 | if (lastString != s) { 70 | lastString = s; 71 | } 72 | if (lastString.equals("E-fan")) { 73 | lastFreqArray=pushValue(lastFreqArray, nbitList.get(0).getFrequency()); 74 | lastFreq = medianFilter(lastFreqArray); 75 | } 76 | if (lastString.equals("Hot wheels")){ 77 | temp = nbitList.get(0).getFrequency(); 78 | 79 | } 80 | timer = millis(); 81 | } 82 | println(lastString); 83 | /*== Put your codes above ==*/ 84 | background(255); //Refresh the screen 85 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 86 | 87 | drawLastBit(50, 100); //print the extra information of the last NFCBit in the console 88 | /*== Put your codes below ==*/ 89 | if (lastString.equals("E-fan")) { 90 | if (millis()-timer<1000) { 91 | if (lastFreq > 52) { 92 | drawString("Full Speed: 15-20 mins left", 50, height/4+100); 93 | } else if (lastFreq > 40 && lastFreq <= 52) { 94 | drawString("Mid Speed: 20-25 mins left", 50, height/4+100); 95 | } else if (lastFreq > 25 && lastFreq <= 40) { 96 | drawString("Low Speed: 25-30 mins left", 50, height/4+100); 97 | } else if (lastFreq <= 25 && lastFreq > 2) { 98 | drawString("Turning off...", 50, height/4+100); 99 | } else { 100 | drawString("Off.", 50, height/4+100); 101 | } 102 | } else { 103 | drawString("Off.", 50, height/4+100); 104 | } 105 | } 106 | 107 | if (lastString.equals("Hot wheels")) { 108 | if (millis()-timer>100) temp = 0; 109 | pointerValue = pointerValue*0.9 + temp*0.1; 110 | drawSpeedmeter(pointerValue, 500, 150, 200, 200, 100); 111 | } 112 | /*== Put your codes above ==*/ 113 | 114 | //drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 115 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 116 | //printLastBit(); //print the extra information of the last NFCBit in the console 117 | //printCurrentTag(); //print the current tag read by the reader 118 | } 119 | 120 | /*Initialize the serial port*/ 121 | void initSerial() { 122 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 123 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 124 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 125 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 126 | port.clear(); // flush the Serial buffer 127 | } 128 | 129 | /*draw a formatted String*/ 130 | void drawString(String s, int x, int y) { //print the latest tag appearance 131 | pushStyle(); 132 | fill(0); 133 | textSize(48); 134 | text(s, x, y); 135 | popStyle(); 136 | } 137 | 138 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 139 | float blight = 90; 140 | float r = _r; 141 | pushStyle(); 142 | colorMode(HSB, 140); 143 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 144 | float theta = radians(TacoValueMap); 145 | float x; 146 | float y; 147 | x = -r*cos(theta); 148 | y = -r*sin(theta); 149 | 150 | fill(30, 0, blight); 151 | textAlign(CENTER); 152 | textSize(50); 153 | 154 | pushMatrix(); 155 | translate(_x, _y); 156 | 157 | pushMatrix(); 158 | translate(_w/2, _h/2); 159 | rotate(-70 * PI / 180); 160 | strokeCap(SQUARE); 161 | strokeWeight(10); 162 | stroke(55, 99, 30); 163 | for (int i = 0; i < 7; i++) { 164 | rotate(40 * PI / 180); 165 | line(-r-10, 0, -r+33, 0); 166 | } 167 | popMatrix(); 168 | 169 | pushMatrix(); 170 | translate(_w/2, _h/2); 171 | rotate(-70 * PI / 180); 172 | strokeCap(ROUND); 173 | strokeWeight(8); 174 | stroke(55, 80, blight); 175 | for (int i = 0; i < 7; i++) { 176 | rotate(40 * PI / 180); 177 | line(-r-8, 0, -r+32, 0); 178 | } 179 | popMatrix(); 180 | 181 | pushMatrix(); 182 | translate(_w/2, _h/2); 183 | rotate(-30 * PI / 180); 184 | strokeCap(ROUND); 185 | strokeWeight(4); 186 | stroke(55, 80, blight); 187 | for (int i = 0; i < 24; i++) { 188 | rotate(10 * PI / 180); 189 | line(-r-8, 0, -r+10, 0); 190 | } 191 | popMatrix(); 192 | 193 | pushMatrix(); 194 | translate(_w/2, _h/2); 195 | rotate(-30 * PI / 180); 196 | strokeCap(ROUND); 197 | strokeWeight(4); 198 | stroke(55, 80, blight); 199 | for (int i = 0; i < 48; i++) { 200 | rotate(5 * PI / 180); 201 | line(-r-8, 0, -r, 0); 202 | } 203 | popMatrix(); 204 | 205 | pushMatrix(); 206 | translate(_w/2, _h/2); 207 | noFill(); 208 | stroke(0, 0, 50); 209 | strokeWeight(15); 210 | stroke(0, 99, 30); 211 | strokeWeight(12); 212 | strokeCap(ROUND); 213 | line(0, 0, x, y); 214 | stroke(0, 99, blight); 215 | strokeWeight(8); 216 | line(0, 0, x, y); 217 | stroke(0, 0, blight); 218 | strokeWeight(6); 219 | line(x/10, y/10, x/5, y/5); 220 | popMatrix(); 221 | 222 | stroke(0, 0, 30); 223 | strokeWeight(3); 224 | fill(0, 0, blight); 225 | ellipse(_w/2, _h/2, 44, 44); 226 | popMatrix(); 227 | popStyle(); 228 | println(TacoValueMap); 229 | } 230 | 231 | /*draw the basic information of the last NFCBit*/ 232 | void drawLastBit(int x, int y) { //print the latest tag appearance 233 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 234 | String objInfo = "Current object: ", motionInfo = ""; 235 | String tagID = ""; 236 | if (nbitList.size()>0) { 237 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 238 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 239 | objInfo += nb.getName(); 240 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 241 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 242 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 243 | } else { 244 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 245 | } 246 | } 247 | } 248 | pushStyle(); 249 | fill(0); 250 | textSize(48); 251 | text(objInfo, x, y); 252 | textSize(32); 253 | text(motionInfo, x, y+48); 254 | textSize(16); 255 | text(tagID, x, y+48+32); 256 | popStyle(); 257 | } 258 | 259 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 260 | void drawRecentBits(int x, int y) { 261 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 262 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 263 | String tagName = ""; 264 | String tagID = ""; 265 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 266 | for (int i = nbitList.size()-1; i >=0; i--) { 267 | NFCBit nb = nbitList.get(i); 268 | tagName += nb.getName(); 269 | tagID += "["+IDList.get(i)+"]"; 270 | if (i>0) { 271 | tagName += ", "; 272 | tagID += ", "; 273 | } 274 | } 275 | pushStyle(); 276 | fill(0); 277 | textSize(48); 278 | text("Recent objects: ", x, y); 279 | textSize(32); 280 | text(tagName, x, y+48); 281 | textSize(16); 282 | text(tagID, x, y+48+32); 283 | popStyle(); 284 | } 285 | 286 | /*draw the version, read rate, and TTL timer info*/ 287 | void drawInfo(int x, int y) { 288 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 289 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 290 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 291 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 292 | //set the above parameters in the constructor as indicated in setup(); 293 | pushStyle(); 294 | fill(100); 295 | textSize(12); 296 | textAlign(RIGHT, BOTTOM); 297 | text(info, x-5, y-5); 298 | popStyle(); 299 | } 300 | 301 | /*print the extra information of the recent NFCBits in the console*/ 302 | void printRecentBits() { 303 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 304 | for (int i = 0; i < nbitList.size(); i++) { 305 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 306 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 307 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 308 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 309 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 310 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 311 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 312 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 313 | //the features (speed and frequency) 314 | } 315 | println("==="); 316 | } 317 | 318 | /*print the extra information of the last NFCBit in the console*/ 319 | void printLastBit() { 320 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 321 | if (nbitList.size()>0) { 322 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 323 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 324 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 325 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 326 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 327 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 328 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 329 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 330 | //the features (speed and frequency) 331 | } 332 | println("==="); 333 | } 334 | 335 | /*The serial event handler processes the data from any NFC reader in the String format of 336 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 337 | //where every byte is an unsigned integer ranged between [0-256]. 338 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 339 | //================*/ 340 | 341 | void serialEvent(Serial port) { 342 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 343 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 344 | int i = inData.charAt(0)-'A'; 345 | int v = int(trim(inData.substring(1))); 346 | nfcs.rfid[i] = (v>255?-1:v); 347 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 348 | } 349 | return; 350 | } 351 | 352 | //print the current tag read by the reader 353 | void printCurrentTag() { 354 | if (nfcs.rfid[0]<0) println("No tag"); 355 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 356 | } 357 | -------------------------------------------------------------------------------- /examples/episode2/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagAlpha/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagAlpha/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagAlpha/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,87,200,A,2,1,0.0,0.0 3 | 136,4,72,200,B,2,1,0.0,0.0 4 | 136,4,232,199,C,2,1,0.0,0.0 5 | 136,4,237,199,D,2,1,0.0,0.0 6 | 136,4,21,199,E,2,1,0.0,0.0 7 | 136,4,53,200,F,2,1,0.0,0.0 8 | 136,4,1,199,G,2,1,0.0,0.0 9 | 136,4,58,200,H,2,1,0.0,0.0 10 | 136,4,52,200,I,2,1,0.0,0.0 11 | 136,4,68,200,J,2,1,0.0,0.0 12 | 136,4,16,199,K,2,1,0.0,0.0 13 | 136,4,47,200,L,2,1,0.0,0.0 14 | 136,4,222,199,M,2,1,0.0,0.0 15 | 136,4,242,199,N,2,1,0.0,0.0 16 | 136,4,63,200,O,2,1,0.0,0.0 17 | 136,4,252,199,P,2,1,0.0,0.0 18 | 136,4,77,200,Q,2,1,0.0,0.0 19 | 136,4,227,199,R,2,1,0.0,0.0 20 | 136,4,92,200,S,2,1,0.0,0.0 21 | 136,4,48,200,T,2,1,0.0,0.0 22 | 136,4,247,199,U,2,1,0.0,0.0 23 | 136,4,27,200,V,2,1,0.0,0.0 24 | 136,4,82,200,W,2,1,0.0,0.0 25 | 136,4,31,199,X,2,1,0.0,0.0 26 | 136,4,37,200,Y,2,1,0.0,0.0 27 | 136,4,26,199,Z,2,1,0.0,0.0 28 | 136,4,129,200,0,2,1,0.0,0.0 29 | 136,4,32,200,1,2,1,0.0,0.0 30 | 136,4,126,199,2,2,1,0.0,0.0 31 | 136,4,111,199,3,2,1,0.0,0.0 32 | 136,4,121,199,4,2,1,0.0,0.0 33 | 136,4,116,199,5,2,1,0.0,0.0 34 | 136,4,101,199,6,2,1,0.0,0.0 35 | 136,4,91,199,7,2,1,0.0,0.0 36 | 136,4,96,199,8,2,1,0.0,0.0 37 | 136,4,106,199,9,2,1,0.0,0.0 38 | 136,4,107,200,Apple,2,1,0.0,0.0 39 | 136,4,112,200,2,2,1,0.0,0.0 40 | 136,4,117,200,Carrot,2,1,0.0,0.0 41 | 136,4,22,200,1,2,1,0.0,0.0 42 | 136,4,36,199,3,2,1,0.0,0.0 43 | 136,4,102,200,Banana,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagAlpha/e1_SingleTagAlpha.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | String tempString = ""; 29 | long timer = 0; 30 | boolean bEntered = true; 31 | 32 | void setup() { 33 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 34 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 35 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 300); 36 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 37 | initSerial(); //Initialize the serial port 38 | /*== Put your codes below ==*/ 39 | /*== Put your codes above ==*/ 40 | } 41 | 42 | void draw() { 43 | nfcs.updateNFCBits(); //update the features of current bit 44 | /*== Put your codes below ==*/ 45 | ArrayList nbitList = nfcs.getNFCBits(); 46 | if (nbitList.size()>0) { 47 | lastString = ""; 48 | tempString = ""; 49 | for (int i = nbitList.size()-1; i >=0; i--) { 50 | NFCBit nb = nbitList.get(i); 51 | tempString += nb.getName(); 52 | } 53 | timer = millis(); 54 | bEntered = false; 55 | } 56 | /*== Put your codes above ==*/ 57 | background(255); //Refresh the screen 58 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 59 | /*== Put your codes below ==*/ 60 | if (millis()-timer>100 && bEntered == false) { 61 | lastString = tempString; 62 | bEntered = true; 63 | } 64 | if (millis()-timer>2000){ 65 | lastString = ""; 66 | } 67 | drawString(lastString,50,100); 68 | /*== Put your codes above ==*/ 69 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 70 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 71 | //printLastBit(); //print the extra information of the last NFCBit in the console 72 | //printCurrentTag(); //print the current tag read by the reader 73 | } 74 | 75 | /*Initialize the serial port*/ 76 | void initSerial() { 77 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 78 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 79 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 80 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 81 | port.clear(); // flush the Serial buffer 82 | } 83 | 84 | /*draw a formatted String*/ 85 | void drawString(String s, int x, int y) { //print the latest tag appearance 86 | pushStyle(); 87 | fill(0); 88 | textSize(48); 89 | text(s, x, y); 90 | popStyle(); 91 | } 92 | 93 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 94 | float blight = 90; 95 | float r = _r; 96 | pushStyle(); 97 | colorMode(HSB, 140); 98 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 99 | float theta = radians(TacoValueMap); 100 | float x; 101 | float y; 102 | x = -r*cos(theta); 103 | y = -r*sin(theta); 104 | 105 | fill(30, 0, blight); 106 | textAlign(CENTER); 107 | textSize(50); 108 | 109 | pushMatrix(); 110 | translate(_x, _y); 111 | 112 | pushMatrix(); 113 | translate(_w/2, _h/2); 114 | rotate(-70 * PI / 180); 115 | strokeCap(SQUARE); 116 | strokeWeight(10); 117 | stroke(55, 99, 30); 118 | for (int i = 0; i < 7; i++) { 119 | rotate(40 * PI / 180); 120 | line(-r-10, 0, -r+33, 0); 121 | } 122 | popMatrix(); 123 | 124 | pushMatrix(); 125 | translate(_w/2, _h/2); 126 | rotate(-70 * PI / 180); 127 | strokeCap(ROUND); 128 | strokeWeight(8); 129 | stroke(55, 80, blight); 130 | for (int i = 0; i < 7; i++) { 131 | rotate(40 * PI / 180); 132 | line(-r-8, 0, -r+32, 0); 133 | } 134 | popMatrix(); 135 | 136 | pushMatrix(); 137 | translate(_w/2, _h/2); 138 | rotate(-30 * PI / 180); 139 | strokeCap(ROUND); 140 | strokeWeight(4); 141 | stroke(55, 80, blight); 142 | for (int i = 0; i < 24; i++) { 143 | rotate(10 * PI / 180); 144 | line(-r-8, 0, -r+10, 0); 145 | } 146 | popMatrix(); 147 | 148 | pushMatrix(); 149 | translate(_w/2, _h/2); 150 | rotate(-30 * PI / 180); 151 | strokeCap(ROUND); 152 | strokeWeight(4); 153 | stroke(55, 80, blight); 154 | for (int i = 0; i < 48; i++) { 155 | rotate(5 * PI / 180); 156 | line(-r-8, 0, -r, 0); 157 | } 158 | popMatrix(); 159 | 160 | pushMatrix(); 161 | translate(_w/2, _h/2); 162 | noFill(); 163 | stroke(0, 0, 50); 164 | strokeWeight(15); 165 | stroke(0, 99, 30); 166 | strokeWeight(12); 167 | strokeCap(ROUND); 168 | line(0, 0, x, y); 169 | stroke(0, 99, blight); 170 | strokeWeight(8); 171 | line(0, 0, x, y); 172 | stroke(0, 0, blight); 173 | strokeWeight(6); 174 | line(x/10, y/10, x/5, y/5); 175 | popMatrix(); 176 | 177 | stroke(0, 0, 30); 178 | strokeWeight(3); 179 | fill(0, 0, blight); 180 | ellipse(_w/2, _h/2, 44, 44); 181 | popMatrix(); 182 | popStyle(); 183 | println(TacoValueMap); 184 | } 185 | 186 | /*draw the basic information of the last NFCBit*/ 187 | void drawLastBit(int x, int y) { //print the latest tag appearance 188 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 189 | String objInfo = "Current object: ", motionInfo = ""; 190 | String tagID = ""; 191 | if (nbitList.size()>0) { 192 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 193 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 194 | objInfo += nb.getName(); 195 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 196 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 197 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 198 | } else { 199 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 200 | } 201 | } 202 | } 203 | pushStyle(); 204 | fill(0); 205 | textSize(48); 206 | text(objInfo, x, y); 207 | textSize(32); 208 | text(motionInfo, x, y+48); 209 | textSize(16); 210 | text(tagID, x, y+48+32); 211 | popStyle(); 212 | } 213 | 214 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 215 | void drawRecentBits(int x, int y) { 216 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 217 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 218 | String tagName = ""; 219 | String tagID = ""; 220 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 221 | for (int i = nbitList.size()-1; i >=0; i--) { 222 | NFCBit nb = nbitList.get(i); 223 | tagName += nb.getName(); 224 | tagID += "["+IDList.get(i)+"]"; 225 | if (i>0) { 226 | tagName += ", "; 227 | tagID += ", "; 228 | } 229 | } 230 | pushStyle(); 231 | fill(0); 232 | textSize(48); 233 | text("Recent objects: ", x, y); 234 | textSize(32); 235 | text(tagName, x, y+48); 236 | textSize(16); 237 | text(tagID, x, y+48+32); 238 | popStyle(); 239 | } 240 | 241 | /*draw the version, read rate, and TTL timer info*/ 242 | void drawInfo(int x, int y) { 243 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 244 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 245 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 246 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 247 | //set the above parameters in the constructor as indicated in setup(); 248 | pushStyle(); 249 | fill(100); 250 | textSize(12); 251 | textAlign(RIGHT, BOTTOM); 252 | text(info, x-5, y-5); 253 | popStyle(); 254 | } 255 | 256 | /*print the extra information of the recent NFCBits in the console*/ 257 | void printRecentBits() { 258 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 259 | for (int i = 0; i < nbitList.size(); i++) { 260 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 261 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 262 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 263 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 264 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 265 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 266 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 267 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 268 | //the features (speed and frequency) 269 | } 270 | println("==="); 271 | } 272 | 273 | /*print the extra information of the last NFCBit in the console*/ 274 | void printLastBit() { 275 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 276 | if (nbitList.size()>0) { 277 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 278 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 279 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 280 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 281 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 282 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 283 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 284 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 285 | //the features (speed and frequency) 286 | } 287 | println("==="); 288 | } 289 | 290 | /*The serial event handler processes the data from any NFC reader in the String format of 291 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 292 | //where every byte is an unsigned integer ranged between [0-256]. 293 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 294 | //================*/ 295 | 296 | void serialEvent(Serial port) { 297 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 298 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 299 | int i = inData.charAt(0)-'A'; 300 | int v = int(trim(inData.substring(1))); 301 | nfcs.rfid[i] = (v>255?-1:v); 302 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 303 | } 304 | return; 305 | } 306 | 307 | //print the current tag read by the reader 308 | void printCurrentTag() { 309 | if (nfcs.rfid[0]<0) println("No tag"); 310 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 311 | } 312 | -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagLoops/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/data/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagLoops/data/apple.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/data/banana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagLoops/data/banana.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/data/carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagLoops/data/carrot.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,87,200,A,2,1,0.0,0.0 3 | 136,4,72,200,B,2,1,0.0,0.0 4 | 136,4,232,199,C,2,1,0.0,0.0 5 | 136,4,237,199,D,2,1,0.0,0.0 6 | 136,4,21,199,E,2,1,0.0,0.0 7 | 136,4,53,200,F,2,1,0.0,0.0 8 | 136,4,1,199,G,2,1,0.0,0.0 9 | 136,4,58,200,H,2,1,0.0,0.0 10 | 136,4,52,200,I,2,1,0.0,0.0 11 | 136,4,68,200,J,2,1,0.0,0.0 12 | 136,4,16,199,K,2,1,0.0,0.0 13 | 136,4,47,200,L,2,1,0.0,0.0 14 | 136,4,222,199,M,2,1,0.0,0.0 15 | 136,4,242,199,N,2,1,0.0,0.0 16 | 136,4,63,200,O,2,1,0.0,0.0 17 | 136,4,252,199,P,2,1,0.0,0.0 18 | 136,4,77,200,Q,2,1,0.0,0.0 19 | 136,4,227,199,R,2,1,0.0,0.0 20 | 136,4,92,200,S,2,1,0.0,0.0 21 | 136,4,48,200,T,2,1,0.0,0.0 22 | 136,4,247,199,U,2,1,0.0,0.0 23 | 136,4,27,200,V,2,1,0.0,0.0 24 | 136,4,82,200,W,2,1,0.0,0.0 25 | 136,4,31,199,X,2,1,0.0,0.0 26 | 136,4,37,200,Y,2,1,0.0,0.0 27 | 136,4,26,199,Z,2,1,0.0,0.0 28 | 136,4,129,200,0,2,1,0.0,0.0 29 | 136,4,32,200,1,2,1,0.0,0.0 30 | 136,4,126,199,2,2,1,0.0,0.0 31 | 136,4,111,199,3,2,1,0.0,0.0 32 | 136,4,121,199,4,2,1,0.0,0.0 33 | 136,4,116,199,5,2,1,0.0,0.0 34 | 136,4,101,199,6,2,1,0.0,0.0 35 | 136,4,91,199,7,2,1,0.0,0.0 36 | 136,4,96,199,8,2,1,0.0,0.0 37 | 136,4,106,199,9,2,1,0.0,0.0 38 | 136,4,107,200,Apple,2,1,0.0,0.0 39 | 136,4,112,200,2,2,1,0.0,0.0 40 | 136,4,117,200,Carrot,2,1,0.0,0.0 41 | 136,4,22,200,1,2,1,0.0,0.0 42 | 136,4,36,199,3,2,1,0.0,0.0 43 | 136,4,102,200,Banana,2,1,0.0,0.0 44 | 136,4,121,150,power2,2,1,0.0,0.0 45 | 136,4,130,150,power3,2,1,0.0,0.0 46 | 136,4,129,150,for,2,1,0.0,0.0 47 | 136,4,146,150,while,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagLoops/e1_SingleTagLoops.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | String tempString = ""; 29 | long timer = 0; 30 | boolean bEntered = true; 31 | 32 | String[] QStrings = {"16 = ", "9 = ", "27 = "}; 33 | String[] AStrings = {"4C", "3C", "3D"}; 34 | int qIndex = 0; 35 | boolean bCorrect = false; 36 | 37 | PImage[] img = new PImage[3]; 38 | int pw; 39 | 40 | void setup() { 41 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 42 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 43 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 300); 44 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 45 | initSerial(); //Initialize the serial port 46 | /*== Put your codes below ==*/ 47 | /*== Put your codes above ==*/ 48 | } 49 | 50 | void draw() { 51 | nfcs.updateNFCBits(); //update the features of current bit 52 | /*== Put your codes below ==*/ 53 | ArrayList nbitList = nfcs.getNFCBits(); 54 | if (nbitList.size()>0) { 55 | lastString = ""; 56 | tempString = ""; 57 | for (int i = nbitList.size()-1; i >=0; i--) { 58 | NFCBit nb = nbitList.get(i); 59 | if (nb.getName().equals("for")) tempString += "A"; 60 | else if (nb.getName().equals("while")) tempString += "B"; 61 | else tempString += nb.getName(); 62 | } 63 | timer = millis(); 64 | bEntered = false; 65 | } 66 | /*== Put your codes above ==*/ 67 | background(255); //Refresh the screen 68 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 69 | /*== Put your codes below ==*/ 70 | if (millis()-timer>100 && bEntered == false) { 71 | lastString = tempString; 72 | bEntered = true; 73 | } 74 | if (millis()-timer>5000) { 75 | lastString = ""; 76 | } 77 | if (lastString.equals("")) { 78 | drawString("Output:", 50, 50, color(0),48); 79 | drawString("0", 50, 100, color(0),48); 80 | drawString("Code:", 450, 50, color(0),48); 81 | drawString("int i=0", 450, 100+0*24, color(0),24); 82 | drawString("{", 450, 100+1*24, color(0),24); 83 | drawString(" print(i+\',\');", 450, 100+2*24, color(0),24); 84 | drawString("}", 450, 100+3*24, color(0),24); 85 | } else { 86 | if (lastString.charAt(0)=='A') { 87 | if (lastString.length()>=2) { 88 | int n1 = lastString.charAt(1)-'0'; 89 | int n2 = lastString.charAt(2)-'0'; 90 | int n3 = lastString.charAt(3)-'0'; 91 | String s = ""; 92 | int i = 0; 93 | for (i=n1; i=2) { 108 | int n1 = lastString.charAt(1)-'0'; 109 | String s = ""; 110 | int i = 0; 111 | while (i< n1){ 112 | s += i; 113 | s += ","; 114 | i += 1; 115 | } 116 | drawString("Output:", 50, 50, color(0),48); 117 | drawString(s, 50, 100, color(22, 160, 133),48); 118 | drawString("Code:", 450, 50, color(0),48); 119 | drawString("int i=0;", 450, 100+0*24, color(0),24); 120 | drawString("while (i<"+n1+") {", 450, 100+1*24, color(22, 160, 133),24); 121 | drawString(" print(i+\',\');", 450, 100+2*24, color(0),24); 122 | drawString(" i = i+1;", 450, 100+3*24, color(22, 160, 133),24); 123 | drawString("}", 450, 100+4*24, color(22, 160, 133),24); 124 | } 125 | } 126 | } 127 | /*== Put your codes above ==*/ 128 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 129 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 130 | //printLastBit(); //print the extra information of the last NFCBit in the console 131 | printCurrentTag(); //print the current tag read by the reader 132 | } 133 | 134 | /*Initialize the serial port*/ 135 | void initSerial() { 136 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 137 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 138 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 139 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 140 | port.clear(); // flush the Serial buffer 141 | } 142 | 143 | /*draw a formatted String*/ 144 | void drawString(String s, int x, int y, color c, float t) { //print the latest tag appearance 145 | pushStyle(); 146 | textAlign(LEFT, TOP); 147 | fill(c); 148 | textSize(t); 149 | text(s, x, y); 150 | popStyle(); 151 | } 152 | 153 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 154 | float blight = 90; 155 | float r = _r; 156 | pushStyle(); 157 | colorMode(HSB, 140); 158 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 159 | float theta = radians(TacoValueMap); 160 | float x; 161 | float y; 162 | x = -r*cos(theta); 163 | y = -r*sin(theta); 164 | 165 | fill(30, 0, blight); 166 | textAlign(CENTER); 167 | textSize(50); 168 | 169 | pushMatrix(); 170 | translate(_x, _y); 171 | 172 | pushMatrix(); 173 | translate(_w/2, _h/2); 174 | rotate(-70 * PI / 180); 175 | strokeCap(SQUARE); 176 | strokeWeight(10); 177 | stroke(55, 99, 30); 178 | for (int i = 0; i < 7; i++) { 179 | rotate(40 * PI / 180); 180 | line(-r-10, 0, -r+33, 0); 181 | } 182 | popMatrix(); 183 | 184 | pushMatrix(); 185 | translate(_w/2, _h/2); 186 | rotate(-70 * PI / 180); 187 | strokeCap(ROUND); 188 | strokeWeight(8); 189 | stroke(55, 80, blight); 190 | for (int i = 0; i < 7; i++) { 191 | rotate(40 * PI / 180); 192 | line(-r-8, 0, -r+32, 0); 193 | } 194 | popMatrix(); 195 | 196 | pushMatrix(); 197 | translate(_w/2, _h/2); 198 | rotate(-30 * PI / 180); 199 | strokeCap(ROUND); 200 | strokeWeight(4); 201 | stroke(55, 80, blight); 202 | for (int i = 0; i < 24; i++) { 203 | rotate(10 * PI / 180); 204 | line(-r-8, 0, -r+10, 0); 205 | } 206 | popMatrix(); 207 | 208 | pushMatrix(); 209 | translate(_w/2, _h/2); 210 | rotate(-30 * PI / 180); 211 | strokeCap(ROUND); 212 | strokeWeight(4); 213 | stroke(55, 80, blight); 214 | for (int i = 0; i < 48; i++) { 215 | rotate(5 * PI / 180); 216 | line(-r-8, 0, -r, 0); 217 | } 218 | popMatrix(); 219 | 220 | pushMatrix(); 221 | translate(_w/2, _h/2); 222 | noFill(); 223 | stroke(0, 0, 50); 224 | strokeWeight(15); 225 | stroke(0, 99, 30); 226 | strokeWeight(12); 227 | strokeCap(ROUND); 228 | line(0, 0, x, y); 229 | stroke(0, 99, blight); 230 | strokeWeight(8); 231 | line(0, 0, x, y); 232 | stroke(0, 0, blight); 233 | strokeWeight(6); 234 | line(x/10, y/10, x/5, y/5); 235 | popMatrix(); 236 | 237 | stroke(0, 0, 30); 238 | strokeWeight(3); 239 | fill(0, 0, blight); 240 | ellipse(_w/2, _h/2, 44, 44); 241 | popMatrix(); 242 | popStyle(); 243 | println(TacoValueMap); 244 | } 245 | 246 | /*draw the basic information of the last NFCBit*/ 247 | void drawLastBit(int x, int y) { //print the latest tag appearance 248 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 249 | String objInfo = "Current object: ", motionInfo = ""; 250 | String tagID = ""; 251 | if (nbitList.size()>0) { 252 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 253 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 254 | objInfo += nb.getName(); 255 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 256 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 257 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 258 | } else { 259 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 260 | } 261 | } 262 | } 263 | pushStyle(); 264 | fill(0); 265 | textSize(48); 266 | text(objInfo, x, y); 267 | textSize(32); 268 | text(motionInfo, x, y+48); 269 | textSize(16); 270 | text(tagID, x, y+48+32); 271 | popStyle(); 272 | } 273 | 274 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 275 | void drawRecentBits(int x, int y) { 276 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 277 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 278 | String tagName = ""; 279 | String tagID = ""; 280 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 281 | for (int i = nbitList.size()-1; i >=0; i--) { 282 | NFCBit nb = nbitList.get(i); 283 | tagName += nb.getName(); 284 | tagID += "["+IDList.get(i)+"]"; 285 | if (i>0) { 286 | tagName += ", "; 287 | tagID += ", "; 288 | } 289 | } 290 | pushStyle(); 291 | fill(0); 292 | textSize(48); 293 | text("Recent objects: ", x, y); 294 | textSize(32); 295 | text(tagName, x, y+48); 296 | textSize(16); 297 | text(tagID, x, y+48+32); 298 | popStyle(); 299 | } 300 | 301 | /*draw the version, read rate, and TTL timer info*/ 302 | void drawInfo(int x, int y) { 303 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 304 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 305 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 306 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 307 | //set the above parameters in the constructor as indicated in setup(); 308 | pushStyle(); 309 | fill(100); 310 | textSize(12); 311 | textAlign(RIGHT, BOTTOM); 312 | text(info, x-5, y-5); 313 | popStyle(); 314 | } 315 | 316 | /*print the extra information of the recent NFCBits in the console*/ 317 | void printRecentBits() { 318 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 319 | for (int i = 0; i < nbitList.size(); i++) { 320 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 321 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 322 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 323 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 324 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 325 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 326 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 327 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 328 | //the features (speed and frequency) 329 | } 330 | println("==="); 331 | } 332 | 333 | /*print the extra information of the last NFCBit in the console*/ 334 | void printLastBit() { 335 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 336 | if (nbitList.size()>0) { 337 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 338 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 339 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 340 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 341 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 342 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 343 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 344 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 345 | //the features (speed and frequency) 346 | } 347 | println("==="); 348 | } 349 | 350 | /*The serial event handler processes the data from any NFC reader in the String format of 351 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 352 | //where every byte is an unsigned integer ranged between [0-256]. 353 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 354 | //================*/ 355 | 356 | void serialEvent(Serial port) { 357 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 358 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 359 | int i = inData.charAt(0)-'A'; 360 | int v = int(trim(inData.substring(1))); 361 | nfcs.rfid[i] = (v>255?-1:v); 362 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 363 | } 364 | return; 365 | } 366 | 367 | //print the current tag read by the reader 368 | void printCurrentTag() { 369 | if (nfcs.rfid[0]<0) println("No tag"); 370 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 371 | } 372 | -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagNumSym/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/data/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagNumSym/data/apple.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/data/banana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagNumSym/data/banana.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/data/carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagNumSym/data/carrot.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,87,200,A,2,1,0.0,0.0 3 | 136,4,72,200,B,2,1,0.0,0.0 4 | 136,4,232,199,C,2,1,0.0,0.0 5 | 136,4,237,199,D,2,1,0.0,0.0 6 | 136,4,21,199,E,2,1,0.0,0.0 7 | 136,4,53,200,F,2,1,0.0,0.0 8 | 136,4,1,199,G,2,1,0.0,0.0 9 | 136,4,58,200,H,2,1,0.0,0.0 10 | 136,4,52,200,I,2,1,0.0,0.0 11 | 136,4,68,200,J,2,1,0.0,0.0 12 | 136,4,16,199,K,2,1,0.0,0.0 13 | 136,4,47,200,L,2,1,0.0,0.0 14 | 136,4,222,199,M,2,1,0.0,0.0 15 | 136,4,242,199,N,2,1,0.0,0.0 16 | 136,4,63,200,O,2,1,0.0,0.0 17 | 136,4,252,199,P,2,1,0.0,0.0 18 | 136,4,77,200,Q,2,1,0.0,0.0 19 | 136,4,227,199,R,2,1,0.0,0.0 20 | 136,4,92,200,S,2,1,0.0,0.0 21 | 136,4,48,200,T,2,1,0.0,0.0 22 | 136,4,247,199,U,2,1,0.0,0.0 23 | 136,4,27,200,V,2,1,0.0,0.0 24 | 136,4,82,200,W,2,1,0.0,0.0 25 | 136,4,31,199,X,2,1,0.0,0.0 26 | 136,4,37,200,Y,2,1,0.0,0.0 27 | 136,4,26,199,Z,2,1,0.0,0.0 28 | 136,4,129,200,0,2,1,0.0,0.0 29 | 136,4,32,200,1,2,1,0.0,0.0 30 | 136,4,126,199,2,2,1,0.0,0.0 31 | 136,4,111,199,3,2,1,0.0,0.0 32 | 136,4,121,199,4,2,1,0.0,0.0 33 | 136,4,116,199,5,2,1,0.0,0.0 34 | 136,4,101,199,6,2,1,0.0,0.0 35 | 136,4,91,199,7,2,1,0.0,0.0 36 | 136,4,96,199,8,2,1,0.0,0.0 37 | 136,4,106,199,9,2,1,0.0,0.0 38 | 136,4,107,200,Apple,2,1,0.0,0.0 39 | 136,4,112,200,2,2,1,0.0,0.0 40 | 136,4,117,200,Carrot,2,1,0.0,0.0 41 | 136,4,22,200,1,2,1,0.0,0.0 42 | 136,4,36,199,3,2,1,0.0,0.0 43 | 136,4,102,200,Banana,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNumSym/e1_SingleTagNumSym.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | String tempString = ""; 29 | float lastFreq = 0; 30 | long timer = 0; 31 | boolean bEntered = true; 32 | 33 | String[] QStrings = {"1A2B", "2B3C", "3C1A"}; 34 | String[] AStrings = {"1A2B", "2B3C", "3C1A"}; 35 | int qIndex = 0; 36 | boolean bCorrect = false; 37 | 38 | PImage[] img = new PImage[3]; 39 | int pw; 40 | 41 | void setup() { 42 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 43 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 44 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 300); 45 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 46 | initSerial(); //Initialize the serial port 47 | /*== Put your codes below ==*/ 48 | img[0] = loadImage("apple.png"); 49 | img[1] = loadImage("banana.png"); 50 | img[2] = loadImage("carrot.png"); 51 | pw = height/8; 52 | for (int i = 0; i < 3; i++) { 53 | img[i].resize(pw, pw); 54 | } 55 | /*== Put your codes above ==*/ 56 | } 57 | 58 | void draw() { 59 | nfcs.updateNFCBits(); //update the features of current bit 60 | /*== Put your codes below ==*/ 61 | ArrayList nbitList = nfcs.getNFCBits(); 62 | if (nbitList.size()>0) { 63 | lastString = ""; 64 | tempString = ""; 65 | for (int i = nbitList.size()-1; i >=0; i--) { 66 | NFCBit nb = nbitList.get(i); 67 | if (nb.getName().equals("Apple")) tempString += "A"; 68 | else if (nb.getName().equals("Banana")) tempString += "B"; 69 | else if (nb.getName().equals("Carrot")) tempString += "C"; 70 | else tempString += nb.getName(); 71 | } 72 | timer = millis(); 73 | bEntered = false; 74 | } 75 | /*== Put your codes above ==*/ 76 | background(255); //Refresh the screen 77 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 78 | /*== Put your codes below ==*/ 79 | if (millis()-timer>100 && bEntered == false) { 80 | lastString = tempString; 81 | bEntered = true; 82 | } 83 | if (millis()-timer>2000) { 84 | if (!lastString.equals("")) { 85 | if (bCorrect) { 86 | ++qIndex; 87 | qIndex %= QStrings.length; 88 | lastString = ""; 89 | } else { 90 | lastString = ""; 91 | } 92 | } 93 | } 94 | if (lastString.equals("")) { 95 | drawString("Q:", 50, 40, color(0)); 96 | drawString("A:", 50, 40+pw, color(0)); 97 | } else { 98 | if (lastString.equals(AStrings[qIndex])) bCorrect = true; 99 | else bCorrect = false; 100 | drawString("Q:", 50, 40, color(0)); 101 | if (bCorrect) drawString("A:", 50, 40+pw, color(22, 160, 133)); 102 | else drawString("A:", 50, 40+pw, color(231, 76, 60)); 103 | } 104 | int nq1 = (int)QStrings[qIndex].charAt(0)-'0'; 105 | int oq1 = (int)QStrings[qIndex].charAt(1)-'A'; 106 | int nq2 = (int)QStrings[qIndex].charAt(2)-'0'; 107 | int oq2 = (int)QStrings[qIndex].charAt(3)-'A'; 108 | for (int i = 0; i < nq1; i++) { 109 | image(img[oq1], 120+i*pw, 40); 110 | } 111 | for (int i = nq1; i < nq1+nq2; i++) { 112 | image(img[oq2], 120+i*pw, 40); 113 | } 114 | int n1 = 0; 115 | int o1 = 0; 116 | int n2 = 0; 117 | int o2 = 0; 118 | if(lastString.length()>=2){ 119 | n1 = lastString.charAt(0)-'0'; 120 | o1 = lastString.charAt(1)-'A'; 121 | } 122 | if(lastString.length()>=4){ 123 | n2 = lastString.charAt(2)-'0'; 124 | o2 = lastString.charAt(3)-'A'; 125 | } 126 | if (n1>0 && o1>=0) { 127 | for (int i = 0; i < n1; i++) { 128 | image(img[o1], 120+i*pw, 40+pw); 129 | } 130 | } 131 | if (n2>0 && o2>=0) { 132 | for (int i = n1; i < n1+n2; i++) { 133 | image(img[o2], 120+i*pw, 40+pw); 134 | } 135 | } 136 | /*== Put your codes above ==*/ 137 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 138 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 139 | //printLastBit(); //print the extra information of the last NFCBit in the console 140 | //printCurrentTag(); //print the current tag read by the reader 141 | } 142 | 143 | /*Initialize the serial port*/ 144 | void initSerial() { 145 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 146 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 147 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 148 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 149 | port.clear(); // flush the Serial buffer 150 | } 151 | 152 | /*draw a formatted String*/ 153 | void drawString(String s, int x, int y, color c) { //print the latest tag appearance 154 | pushStyle(); 155 | textAlign(LEFT,TOP); 156 | fill(c); 157 | textSize(48); 158 | text(s, x, y); 159 | popStyle(); 160 | } 161 | 162 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 163 | float blight = 90; 164 | float r = _r; 165 | pushStyle(); 166 | colorMode(HSB, 140); 167 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 168 | float theta = radians(TacoValueMap); 169 | float x; 170 | float y; 171 | x = -r*cos(theta); 172 | y = -r*sin(theta); 173 | 174 | fill(30, 0, blight); 175 | textAlign(CENTER); 176 | textSize(50); 177 | 178 | pushMatrix(); 179 | translate(_x, _y); 180 | 181 | pushMatrix(); 182 | translate(_w/2, _h/2); 183 | rotate(-70 * PI / 180); 184 | strokeCap(SQUARE); 185 | strokeWeight(10); 186 | stroke(55, 99, 30); 187 | for (int i = 0; i < 7; i++) { 188 | rotate(40 * PI / 180); 189 | line(-r-10, 0, -r+33, 0); 190 | } 191 | popMatrix(); 192 | 193 | pushMatrix(); 194 | translate(_w/2, _h/2); 195 | rotate(-70 * PI / 180); 196 | strokeCap(ROUND); 197 | strokeWeight(8); 198 | stroke(55, 80, blight); 199 | for (int i = 0; i < 7; i++) { 200 | rotate(40 * PI / 180); 201 | line(-r-8, 0, -r+32, 0); 202 | } 203 | popMatrix(); 204 | 205 | pushMatrix(); 206 | translate(_w/2, _h/2); 207 | rotate(-30 * PI / 180); 208 | strokeCap(ROUND); 209 | strokeWeight(4); 210 | stroke(55, 80, blight); 211 | for (int i = 0; i < 24; i++) { 212 | rotate(10 * PI / 180); 213 | line(-r-8, 0, -r+10, 0); 214 | } 215 | popMatrix(); 216 | 217 | pushMatrix(); 218 | translate(_w/2, _h/2); 219 | rotate(-30 * PI / 180); 220 | strokeCap(ROUND); 221 | strokeWeight(4); 222 | stroke(55, 80, blight); 223 | for (int i = 0; i < 48; i++) { 224 | rotate(5 * PI / 180); 225 | line(-r-8, 0, -r, 0); 226 | } 227 | popMatrix(); 228 | 229 | pushMatrix(); 230 | translate(_w/2, _h/2); 231 | noFill(); 232 | stroke(0, 0, 50); 233 | strokeWeight(15); 234 | stroke(0, 99, 30); 235 | strokeWeight(12); 236 | strokeCap(ROUND); 237 | line(0, 0, x, y); 238 | stroke(0, 99, blight); 239 | strokeWeight(8); 240 | line(0, 0, x, y); 241 | stroke(0, 0, blight); 242 | strokeWeight(6); 243 | line(x/10, y/10, x/5, y/5); 244 | popMatrix(); 245 | 246 | stroke(0, 0, 30); 247 | strokeWeight(3); 248 | fill(0, 0, blight); 249 | ellipse(_w/2, _h/2, 44, 44); 250 | popMatrix(); 251 | popStyle(); 252 | println(TacoValueMap); 253 | } 254 | 255 | /*draw the basic information of the last NFCBit*/ 256 | void drawLastBit(int x, int y) { //print the latest tag appearance 257 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 258 | String objInfo = "Current object: ", motionInfo = ""; 259 | String tagID = ""; 260 | if (nbitList.size()>0) { 261 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 262 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 263 | objInfo += nb.getName(); 264 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 265 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 266 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 267 | } else { 268 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 269 | } 270 | } 271 | } 272 | pushStyle(); 273 | fill(0); 274 | textSize(48); 275 | text(objInfo, x, y); 276 | textSize(32); 277 | text(motionInfo, x, y+48); 278 | textSize(16); 279 | text(tagID, x, y+48+32); 280 | popStyle(); 281 | } 282 | 283 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 284 | void drawRecentBits(int x, int y) { 285 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 286 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 287 | String tagName = ""; 288 | String tagID = ""; 289 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 290 | for (int i = nbitList.size()-1; i >=0; i--) { 291 | NFCBit nb = nbitList.get(i); 292 | tagName += nb.getName(); 293 | tagID += "["+IDList.get(i)+"]"; 294 | if (i>0) { 295 | tagName += ", "; 296 | tagID += ", "; 297 | } 298 | } 299 | pushStyle(); 300 | fill(0); 301 | textSize(48); 302 | text("Recent objects: ", x, y); 303 | textSize(32); 304 | text(tagName, x, y+48); 305 | textSize(16); 306 | text(tagID, x, y+48+32); 307 | popStyle(); 308 | } 309 | 310 | /*draw the version, read rate, and TTL timer info*/ 311 | void drawInfo(int x, int y) { 312 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 313 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 314 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 315 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 316 | //set the above parameters in the constructor as indicated in setup(); 317 | pushStyle(); 318 | fill(100); 319 | textSize(12); 320 | textAlign(RIGHT, BOTTOM); 321 | text(info, x-5, y-5); 322 | popStyle(); 323 | } 324 | 325 | /*print the extra information of the recent NFCBits in the console*/ 326 | void printRecentBits() { 327 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 328 | for (int i = 0; i < nbitList.size(); i++) { 329 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 330 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 331 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 332 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 333 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 334 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 335 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 336 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 337 | //the features (speed and frequency) 338 | } 339 | println("==="); 340 | } 341 | 342 | /*print the extra information of the last NFCBit in the console*/ 343 | void printLastBit() { 344 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 345 | if (nbitList.size()>0) { 346 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 347 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 348 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 349 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 350 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 351 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 352 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 353 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 354 | //the features (speed and frequency) 355 | } 356 | println("==="); 357 | } 358 | 359 | /*The serial event handler processes the data from any NFC reader in the String format of 360 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 361 | //where every byte is an unsigned integer ranged between [0-256]. 362 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 363 | //================*/ 364 | 365 | void serialEvent(Serial port) { 366 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 367 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 368 | int i = inData.charAt(0)-'A'; 369 | int v = int(trim(inData.substring(1))); 370 | nfcs.rfid[i] = (v>255?-1:v); 371 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 372 | } 373 | return; 374 | } 375 | 376 | //print the current tag read by the reader 377 | void printCurrentTag() { 378 | if (nfcs.rfid[0]<0) println("No tag"); 379 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 380 | } 381 | -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNums/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagNums/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNums/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,87,200,A,2,1,0.0,0.0 3 | 136,4,72,200,B,2,1,0.0,0.0 4 | 136,4,232,199,C,2,1,0.0,0.0 5 | 136,4,237,199,D,2,1,0.0,0.0 6 | 136,4,21,199,E,2,1,0.0,0.0 7 | 136,4,53,200,F,2,1,0.0,0.0 8 | 136,4,1,199,G,2,1,0.0,0.0 9 | 136,4,58,200,H,2,1,0.0,0.0 10 | 136,4,52,200,I,2,1,0.0,0.0 11 | 136,4,68,200,J,2,1,0.0,0.0 12 | 136,4,16,199,K,2,1,0.0,0.0 13 | 136,4,47,200,L,2,1,0.0,0.0 14 | 136,4,222,199,M,2,1,0.0,0.0 15 | 136,4,242,199,N,2,1,0.0,0.0 16 | 136,4,63,200,O,2,1,0.0,0.0 17 | 136,4,252,199,P,2,1,0.0,0.0 18 | 136,4,77,200,Q,2,1,0.0,0.0 19 | 136,4,227,199,R,2,1,0.0,0.0 20 | 136,4,92,200,S,2,1,0.0,0.0 21 | 136,4,48,200,T,2,1,0.0,0.0 22 | 136,4,247,199,U,2,1,0.0,0.0 23 | 136,4,27,200,V,2,1,0.0,0.0 24 | 136,4,82,200,W,2,1,0.0,0.0 25 | 136,4,31,199,X,2,1,0.0,0.0 26 | 136,4,37,200,Y,2,1,0.0,0.0 27 | 136,4,26,199,Z,2,1,0.0,0.0 28 | 136,4,129,200,0,2,1,0.0,0.0 29 | 136,4,32,200,1,2,1,0.0,0.0 30 | 136,4,126,199,2,2,1,0.0,0.0 31 | 136,4,111,199,3,2,1,0.0,0.0 32 | 136,4,121,199,4,2,1,0.0,0.0 33 | 136,4,116,199,5,2,1,0.0,0.0 34 | 136,4,101,199,6,2,1,0.0,0.0 35 | 136,4,91,199,7,2,1,0.0,0.0 36 | 136,4,96,199,8,2,1,0.0,0.0 37 | 136,4,106,199,9,2,1,0.0,0.0 38 | 136,4,107,200,Apple,2,1,0.0,0.0 39 | 136,4,112,200,2,2,1,0.0,0.0 40 | 136,4,117,200,Carrot,2,1,0.0,0.0 41 | 136,4,22,200,1,2,1,0.0,0.0 42 | 136,4,36,199,3,2,1,0.0,0.0 43 | 136,4,102,200,Banana,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagNums/e1_SingleTagNums.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | String tempString = ""; 29 | float lastFreq = 0; 30 | long timer = 0; 31 | boolean bEntered = true; 32 | 33 | String[] QStrings = {"77-65=", "777-654=", "7777-6543="}; 34 | String[] AStrings = {"12", "123", "1234"}; 35 | int qIndex = 0; 36 | boolean bCorrect = false; 37 | 38 | void setup() { 39 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 40 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 41 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 300); 42 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 43 | initSerial(); //Initialize the serial port 44 | /*== Put your codes below ==*/ 45 | /*== Put your codes above ==*/ 46 | } 47 | 48 | void draw() { 49 | nfcs.updateNFCBits(); //update the features of current bit 50 | /*== Put your codes below ==*/ 51 | ArrayList nbitList = nfcs.getNFCBits(); 52 | if (nbitList.size()>0) { 53 | lastString = ""; 54 | tempString = ""; 55 | for (int i = nbitList.size()-1; i >=0; i--) { 56 | NFCBit nb = nbitList.get(i); 57 | tempString += nb.getName(); 58 | } 59 | timer = millis(); 60 | bEntered = false; 61 | } 62 | /*== Put your codes above ==*/ 63 | background(255); //Refresh the screen 64 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 65 | /*== Put your codes below ==*/ 66 | if (millis()-timer>100 && bEntered == false) { 67 | lastString = tempString; 68 | bEntered = true; 69 | } 70 | if (millis()-timer>1000) { 71 | if (!lastString.equals("")) { 72 | if(bCorrect){ 73 | ++qIndex; 74 | qIndex %= QStrings.length; 75 | lastString = ""; 76 | }else{ 77 | lastString = ""; 78 | } 79 | } 80 | } 81 | if (lastString.equals("")) { 82 | drawString(QStrings[qIndex]+lastString, 50, 100, color(0)); 83 | } else { 84 | if (lastString.equals(AStrings[qIndex])) bCorrect = true; 85 | else bCorrect = false; 86 | if(bCorrect) drawString(QStrings[qIndex]+lastString, 50, 100,color(22, 160, 133)); 87 | else drawString(QStrings[qIndex]+lastString, 50, 100,color(231, 76, 60)); 88 | } 89 | /*== Put your codes above ==*/ 90 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 91 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 92 | //printLastBit(); //print the extra information of the last NFCBit in the console 93 | //printCurrentTag(); //print the current tag read by the reader 94 | } 95 | 96 | /*Initialize the serial port*/ 97 | void initSerial() { 98 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 99 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 100 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 101 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 102 | port.clear(); // flush the Serial buffer 103 | } 104 | 105 | /*draw a formatted String*/ 106 | void drawString(String s, int x, int y, color c) { //print the latest tag appearance 107 | pushStyle(); 108 | fill(c); 109 | textSize(48); 110 | text(s, x, y); 111 | popStyle(); 112 | } 113 | 114 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 115 | float blight = 90; 116 | float r = _r; 117 | pushStyle(); 118 | colorMode(HSB, 140); 119 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 120 | float theta = radians(TacoValueMap); 121 | float x; 122 | float y; 123 | x = -r*cos(theta); 124 | y = -r*sin(theta); 125 | 126 | fill(30, 0, blight); 127 | textAlign(CENTER); 128 | textSize(50); 129 | 130 | pushMatrix(); 131 | translate(_x, _y); 132 | 133 | pushMatrix(); 134 | translate(_w/2, _h/2); 135 | rotate(-70 * PI / 180); 136 | strokeCap(SQUARE); 137 | strokeWeight(10); 138 | stroke(55, 99, 30); 139 | for (int i = 0; i < 7; i++) { 140 | rotate(40 * PI / 180); 141 | line(-r-10, 0, -r+33, 0); 142 | } 143 | popMatrix(); 144 | 145 | pushMatrix(); 146 | translate(_w/2, _h/2); 147 | rotate(-70 * PI / 180); 148 | strokeCap(ROUND); 149 | strokeWeight(8); 150 | stroke(55, 80, blight); 151 | for (int i = 0; i < 7; i++) { 152 | rotate(40 * PI / 180); 153 | line(-r-8, 0, -r+32, 0); 154 | } 155 | popMatrix(); 156 | 157 | pushMatrix(); 158 | translate(_w/2, _h/2); 159 | rotate(-30 * PI / 180); 160 | strokeCap(ROUND); 161 | strokeWeight(4); 162 | stroke(55, 80, blight); 163 | for (int i = 0; i < 24; i++) { 164 | rotate(10 * PI / 180); 165 | line(-r-8, 0, -r+10, 0); 166 | } 167 | popMatrix(); 168 | 169 | pushMatrix(); 170 | translate(_w/2, _h/2); 171 | rotate(-30 * PI / 180); 172 | strokeCap(ROUND); 173 | strokeWeight(4); 174 | stroke(55, 80, blight); 175 | for (int i = 0; i < 48; i++) { 176 | rotate(5 * PI / 180); 177 | line(-r-8, 0, -r, 0); 178 | } 179 | popMatrix(); 180 | 181 | pushMatrix(); 182 | translate(_w/2, _h/2); 183 | noFill(); 184 | stroke(0, 0, 50); 185 | strokeWeight(15); 186 | stroke(0, 99, 30); 187 | strokeWeight(12); 188 | strokeCap(ROUND); 189 | line(0, 0, x, y); 190 | stroke(0, 99, blight); 191 | strokeWeight(8); 192 | line(0, 0, x, y); 193 | stroke(0, 0, blight); 194 | strokeWeight(6); 195 | line(x/10, y/10, x/5, y/5); 196 | popMatrix(); 197 | 198 | stroke(0, 0, 30); 199 | strokeWeight(3); 200 | fill(0, 0, blight); 201 | ellipse(_w/2, _h/2, 44, 44); 202 | popMatrix(); 203 | popStyle(); 204 | println(TacoValueMap); 205 | } 206 | 207 | /*draw the basic information of the last NFCBit*/ 208 | void drawLastBit(int x, int y) { //print the latest tag appearance 209 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 210 | String objInfo = "Current object: ", motionInfo = ""; 211 | String tagID = ""; 212 | if (nbitList.size()>0) { 213 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 214 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 215 | objInfo += nb.getName(); 216 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 217 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 218 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 219 | } else { 220 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 221 | } 222 | } 223 | } 224 | pushStyle(); 225 | fill(0); 226 | textSize(48); 227 | text(objInfo, x, y); 228 | textSize(32); 229 | text(motionInfo, x, y+48); 230 | textSize(16); 231 | text(tagID, x, y+48+32); 232 | popStyle(); 233 | } 234 | 235 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 236 | void drawRecentBits(int x, int y) { 237 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 238 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 239 | String tagName = ""; 240 | String tagID = ""; 241 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 242 | for (int i = nbitList.size()-1; i >=0; i--) { 243 | NFCBit nb = nbitList.get(i); 244 | tagName += nb.getName(); 245 | tagID += "["+IDList.get(i)+"]"; 246 | if (i>0) { 247 | tagName += ", "; 248 | tagID += ", "; 249 | } 250 | } 251 | pushStyle(); 252 | fill(0); 253 | textSize(48); 254 | text("Recent objects: ", x, y); 255 | textSize(32); 256 | text(tagName, x, y+48); 257 | textSize(16); 258 | text(tagID, x, y+48+32); 259 | popStyle(); 260 | } 261 | 262 | /*draw the version, read rate, and TTL timer info*/ 263 | void drawInfo(int x, int y) { 264 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 265 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 266 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 267 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 268 | //set the above parameters in the constructor as indicated in setup(); 269 | pushStyle(); 270 | fill(100); 271 | textSize(12); 272 | textAlign(RIGHT, BOTTOM); 273 | text(info, x-5, y-5); 274 | popStyle(); 275 | } 276 | 277 | /*print the extra information of the recent NFCBits in the console*/ 278 | void printRecentBits() { 279 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 280 | for (int i = 0; i < nbitList.size(); i++) { 281 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 282 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 283 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 284 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 285 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 286 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 287 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 288 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 289 | //the features (speed and frequency) 290 | } 291 | println("==="); 292 | } 293 | 294 | /*print the extra information of the last NFCBit in the console*/ 295 | void printLastBit() { 296 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 297 | if (nbitList.size()>0) { 298 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 299 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 300 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 301 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 302 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 303 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 304 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 305 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 306 | //the features (speed and frequency) 307 | } 308 | println("==="); 309 | } 310 | 311 | /*The serial event handler processes the data from any NFC reader in the String format of 312 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 313 | //where every byte is an unsigned integer ranged between [0-256]. 314 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 315 | //================*/ 316 | 317 | void serialEvent(Serial port) { 318 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 319 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 320 | int i = inData.charAt(0)-'A'; 321 | int v = int(trim(inData.substring(1))); 322 | nfcs.rfid[i] = (v>255?-1:v); 323 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 324 | } 325 | return; 326 | } 327 | 328 | //print the current tag read by the reader 329 | void printCurrentTag() { 330 | if (nfcs.rfid[0]<0) println("No tag"); 331 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 332 | } 333 | -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagSelfDefined/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/data/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagSelfDefined/data/.DS_Store -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/data/apple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagSelfDefined/data/apple.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/data/banana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagSelfDefined/data/banana.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/data/carrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/examples/episode2/e1_SingleTagSelfDefined/data/carrot.png -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/data/tagProfile.csv: -------------------------------------------------------------------------------- 1 | UID0,UID1,UID2,UID3,Label,Ttype,Mtype,L1,L2 2 | 136,4,87,200,A,2,1,0.0,0.0 3 | 136,4,72,200,B,2,1,0.0,0.0 4 | 136,4,232,199,C,2,1,0.0,0.0 5 | 136,4,237,199,D,2,1,0.0,0.0 6 | 136,4,21,199,E,2,1,0.0,0.0 7 | 136,4,53,200,F,2,1,0.0,0.0 8 | 136,4,1,199,G,2,1,0.0,0.0 9 | 136,4,58,200,H,2,1,0.0,0.0 10 | 136,4,52,200,I,2,1,0.0,0.0 11 | 136,4,68,200,J,2,1,0.0,0.0 12 | 136,4,16,199,K,2,1,0.0,0.0 13 | 136,4,47,200,L,2,1,0.0,0.0 14 | 136,4,222,199,M,2,1,0.0,0.0 15 | 136,4,242,199,N,2,1,0.0,0.0 16 | 136,4,63,200,O,2,1,0.0,0.0 17 | 136,4,252,199,P,2,1,0.0,0.0 18 | 136,4,77,200,Q,2,1,0.0,0.0 19 | 136,4,227,199,R,2,1,0.0,0.0 20 | 136,4,92,200,S,2,1,0.0,0.0 21 | 136,4,48,200,T,2,1,0.0,0.0 22 | 136,4,247,199,U,2,1,0.0,0.0 23 | 136,4,27,200,V,2,1,0.0,0.0 24 | 136,4,82,200,W,2,1,0.0,0.0 25 | 136,4,31,199,X,2,1,0.0,0.0 26 | 136,4,37,200,Y,2,1,0.0,0.0 27 | 136,4,26,199,Z,2,1,0.0,0.0 28 | 136,4,129,200,0,2,1,0.0,0.0 29 | 136,4,32,200,1,2,1,0.0,0.0 30 | 136,4,126,199,2,2,1,0.0,0.0 31 | 136,4,111,199,3,2,1,0.0,0.0 32 | 136,4,121,199,4,2,1,0.0,0.0 33 | 136,4,116,199,5,2,1,0.0,0.0 34 | 136,4,101,199,6,2,1,0.0,0.0 35 | 136,4,91,199,7,2,1,0.0,0.0 36 | 136,4,96,199,8,2,1,0.0,0.0 37 | 136,4,106,199,9,2,1,0.0,0.0 38 | 136,4,107,200,Apple,2,1,0.0,0.0 39 | 136,4,112,200,2,2,1,0.0,0.0 40 | 136,4,117,200,Carrot,2,1,0.0,0.0 41 | 136,4,22,200,1,2,1,0.0,0.0 42 | 136,4,36,199,3,2,1,0.0,0.0 43 | 136,4,102,200,Banana,2,1,0.0,0.0 44 | 136,4,121,150,power2,2,1,0.0,0.0 45 | 136,4,130,150,power3,2,1,0.0,0.0 46 | 136,4,129,150,for,2,1,0.0,0.0 47 | 136,4,146,150,while,2,1,0.0,0.0 -------------------------------------------------------------------------------- /examples/episode2/e1_SingleTagSelfDefined/e1_SingleTagSelfDefined.pde: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v2) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // e1_SingleTagRotation.pde: 18 | // This software works with a microcontroller running Arduino code and connected to an RC522 NFC/RFID Reader 19 | // OpenNFCSense API Github repository: https://github.com/howieliang/OpenNFCSense 20 | // NFCSense Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | import processing.serial.*; 23 | import OpenNFCSense4P.*; 24 | Serial port; 25 | OpenNFCSense4P nfcs; 26 | 27 | String lastString = ""; 28 | String tempString = ""; 29 | long timer = 0; 30 | boolean bEntered = true; 31 | 32 | String[] QStrings = {"16 = ", "9 = ", "27 = "}; 33 | String[] AStrings = {"4C", "3C", "3D"}; 34 | int qIndex = 0; 35 | boolean bCorrect = false; 36 | 37 | PImage[] img = new PImage[3]; 38 | int pw; 39 | 40 | void setup() { 41 | size(800, 600, P2D); //Start a 800x600 px canvas (using P2D renderer) 42 | //nfcs = new OpenNFCSense4P(this, "tagProfile.csv"); //Initialize OpenNFCSense with the tag profiles (*.csv) in /data 43 | nfcs = new OpenNFCSense4P(this, "tagProfile.csv", 300, 300, 300); 44 | ////set frame rate to 250fps, TTL timer1 to 500ms, and TTL timer2 to 2000ms 45 | initSerial(); //Initialize the serial port 46 | /*== Put your codes below ==*/ 47 | /*== Put your codes above ==*/ 48 | } 49 | 50 | void draw() { 51 | nfcs.updateNFCBits(); //update the features of current bit 52 | /*== Put your codes below ==*/ 53 | ArrayList nbitList = nfcs.getNFCBits(); 54 | if (nbitList.size()>0) { 55 | lastString = ""; 56 | tempString = ""; 57 | for (int i = nbitList.size()-1; i >=0; i--) { 58 | NFCBit nb = nbitList.get(i); 59 | if (nb.getName().equals("power2")) tempString += "C"; 60 | else if (nb.getName().equals("power3")) tempString += "D"; 61 | else tempString += nb.getName(); 62 | } 63 | timer = millis(); 64 | bEntered = false; 65 | } 66 | /*== Put your codes above ==*/ 67 | background(255); //Refresh the screen 68 | nfcs.drawMotionModeRecords(50, 2*height/3, 2*width/3, height/3-50); //draw the motion mode record of last second (x,y,width,height) 69 | /*== Put your codes below ==*/ 70 | if (millis()-timer>100 && bEntered == false) { 71 | lastString = tempString; 72 | bEntered = true; 73 | } 74 | if (millis()-timer>2000) { 75 | if (!lastString.equals("")) { 76 | if (bCorrect) { 77 | ++qIndex; 78 | qIndex %= QStrings.length; 79 | lastString = ""; 80 | } else { 81 | lastString = ""; 82 | } 83 | } 84 | } 85 | if (lastString.equals("")) { 86 | drawString(QStrings[qIndex]+lastString, 50, 100, color(0)); 87 | } else { 88 | if (lastString.equals(AStrings[qIndex])) bCorrect = true; 89 | else bCorrect = false; 90 | if (bCorrect) { 91 | if (lastString.length()>=2) { 92 | int n1 = lastString.charAt(0)-'0'; 93 | int o1 = lastString.charAt(1)-'A'; 94 | drawString(QStrings[qIndex]+n1+(o1==2?'\u00B2':'\u00B3'), 50, 100, color(22, 160, 133)); 95 | } 96 | } else { 97 | if (lastString.length()>=2) { 98 | int n1 = lastString.charAt(0)-'0'; 99 | int o1 = lastString.charAt(1)-'A'; 100 | drawString(QStrings[qIndex]+n1+(o1==2?'\u00B2':'\u00B3'), 50, 100, color(231, 76, 60)); 101 | } 102 | } 103 | } 104 | /*== Put your codes above ==*/ 105 | drawRecentBits(50, height/4+100); //draw the basic information of the recent NFCBits (within Timer2) 106 | drawInfo(width, height); //draw the version, read rate, and TTL timer info 107 | //printLastBit(); //print the extra information of the last NFCBit in the console 108 | printCurrentTag(); //print the current tag read by the reader 109 | } 110 | 111 | /*Initialize the serial port*/ 112 | void initSerial() { 113 | for (int i = 0; i < Serial.list().length; i++) println("[", i, "]:", Serial.list()[i]); //print the serial port 114 | port = new Serial(this, Serial.list()[Serial.list().length-1], 115200); //for Mac and Linux 115 | // port = new Serial(this, Serial.list()[0], 115200); // for PC 116 | port.bufferUntil('\n'); // arduino ends each data packet with a carriage return 117 | port.clear(); // flush the Serial buffer 118 | } 119 | 120 | /*draw a formatted String*/ 121 | void drawString(String s, int x, int y, color c) { //print the latest tag appearance 122 | pushStyle(); 123 | textAlign(LEFT, TOP); 124 | fill(c); 125 | textSize(48); 126 | text(s, x, y); 127 | popStyle(); 128 | } 129 | 130 | void drawSpeedmeter(float TacoValue, float _x, float _y, float _w, float _h, float _r) { 131 | float blight = 90; 132 | float r = _r; 133 | pushStyle(); 134 | colorMode(HSB, 140); 135 | float TacoValueMap = map(TacoValue, 0, 30, -40, 220); 136 | float theta = radians(TacoValueMap); 137 | float x; 138 | float y; 139 | x = -r*cos(theta); 140 | y = -r*sin(theta); 141 | 142 | fill(30, 0, blight); 143 | textAlign(CENTER); 144 | textSize(50); 145 | 146 | pushMatrix(); 147 | translate(_x, _y); 148 | 149 | pushMatrix(); 150 | translate(_w/2, _h/2); 151 | rotate(-70 * PI / 180); 152 | strokeCap(SQUARE); 153 | strokeWeight(10); 154 | stroke(55, 99, 30); 155 | for (int i = 0; i < 7; i++) { 156 | rotate(40 * PI / 180); 157 | line(-r-10, 0, -r+33, 0); 158 | } 159 | popMatrix(); 160 | 161 | pushMatrix(); 162 | translate(_w/2, _h/2); 163 | rotate(-70 * PI / 180); 164 | strokeCap(ROUND); 165 | strokeWeight(8); 166 | stroke(55, 80, blight); 167 | for (int i = 0; i < 7; i++) { 168 | rotate(40 * PI / 180); 169 | line(-r-8, 0, -r+32, 0); 170 | } 171 | popMatrix(); 172 | 173 | pushMatrix(); 174 | translate(_w/2, _h/2); 175 | rotate(-30 * PI / 180); 176 | strokeCap(ROUND); 177 | strokeWeight(4); 178 | stroke(55, 80, blight); 179 | for (int i = 0; i < 24; i++) { 180 | rotate(10 * PI / 180); 181 | line(-r-8, 0, -r+10, 0); 182 | } 183 | popMatrix(); 184 | 185 | pushMatrix(); 186 | translate(_w/2, _h/2); 187 | rotate(-30 * PI / 180); 188 | strokeCap(ROUND); 189 | strokeWeight(4); 190 | stroke(55, 80, blight); 191 | for (int i = 0; i < 48; i++) { 192 | rotate(5 * PI / 180); 193 | line(-r-8, 0, -r, 0); 194 | } 195 | popMatrix(); 196 | 197 | pushMatrix(); 198 | translate(_w/2, _h/2); 199 | noFill(); 200 | stroke(0, 0, 50); 201 | strokeWeight(15); 202 | stroke(0, 99, 30); 203 | strokeWeight(12); 204 | strokeCap(ROUND); 205 | line(0, 0, x, y); 206 | stroke(0, 99, blight); 207 | strokeWeight(8); 208 | line(0, 0, x, y); 209 | stroke(0, 0, blight); 210 | strokeWeight(6); 211 | line(x/10, y/10, x/5, y/5); 212 | popMatrix(); 213 | 214 | stroke(0, 0, 30); 215 | strokeWeight(3); 216 | fill(0, 0, blight); 217 | ellipse(_w/2, _h/2, 44, 44); 218 | popMatrix(); 219 | popStyle(); 220 | println(TacoValueMap); 221 | } 222 | 223 | /*draw the basic information of the last NFCBit*/ 224 | void drawLastBit(int x, int y) { //print the latest tag appearance 225 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 226 | String objInfo = "Current object: ", motionInfo = ""; 227 | String tagID = ""; 228 | if (nbitList.size()>0) { 229 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 230 | tagID = "["+nfcs.getIDTable().get(0)+"]"; // get the ID string of the latest tag 231 | objInfo += nb.getName(); 232 | if (nb.getMode()!=NFCBit.NA) { // if the feature is ready (mode!=NA=0) 233 | if (nb.isFrequency()) { // if the NFCBit is a frequency bit 234 | motionInfo += nb.getModeString()+" at "+nf(nb.getFrequency(), 0, 2)+" Hz"; //show the motion mode and the motion frequency 235 | } else { 236 | motionInfo += nb.getModeString()+" at "+nf(nb.getSpeed(), 0, 2)+" km/h"; //show the motion mode and the motion speed 237 | } 238 | } 239 | } 240 | pushStyle(); 241 | fill(0); 242 | textSize(48); 243 | text(objInfo, x, y); 244 | textSize(32); 245 | text(motionInfo, x, y+48); 246 | textSize(16); 247 | text(tagID, x, y+48+32); 248 | popStyle(); 249 | } 250 | 251 | /*draw the basic information of the recent NFCBits (within timer 2)*/ 252 | void drawRecentBits(int x, int y) { 253 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 254 | ArrayList IDList = nfcs.getIDTable(); // get the ID string of the recent NFCBits 255 | String tagName = ""; 256 | String tagID = ""; 257 | //for (int i = 0; i < nbitList.size(); i++) { // to reverse the order 258 | for (int i = nbitList.size()-1; i >=0; i--) { 259 | NFCBit nb = nbitList.get(i); 260 | tagName += nb.getName(); 261 | tagID += "["+IDList.get(i)+"]"; 262 | if (i>0) { 263 | tagName += ", "; 264 | tagID += ", "; 265 | } 266 | } 267 | pushStyle(); 268 | fill(0); 269 | textSize(48); 270 | text("Recent objects: ", x, y); 271 | textSize(32); 272 | text(tagName, x, y+48); 273 | textSize(16); 274 | text(tagID, x, y+48+32); 275 | popStyle(); 276 | } 277 | 278 | /*draw the version, read rate, and TTL timer info*/ 279 | void drawInfo(int x, int y) { 280 | String info = "[Open NFCSense] ver. "+OpenNFCSense4P.version()+"\n"; //get the current library version 281 | info += "Read rate: "+nf(nfcs.getReadRate(), 0, 0)+" reads/sec\n"; // get the current read rate 282 | info += "TTL Timer1: "+nf(nfcs.getTimer1(), 0, 0)+" ms\n"; // get the current TTL timer1 283 | info += "TTL Timer2: "+nf(nfcs.getTimer2(), 0, 0)+" ms"; // get the current TTL timer2 284 | //set the above parameters in the constructor as indicated in setup(); 285 | pushStyle(); 286 | fill(100); 287 | textSize(12); 288 | textAlign(RIGHT, BOTTOM); 289 | text(info, x-5, y-5); 290 | popStyle(); 291 | } 292 | 293 | /*print the extra information of the recent NFCBits in the console*/ 294 | void printRecentBits() { 295 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 296 | for (int i = 0; i < nbitList.size(); i++) { 297 | NFCBit nb = nbitList.get(i); // get the latest NFCBit at index i 298 | String tagID = "["+nfcs.getIDTable().get(i)+"]"; //get the ID string of the latest tag 299 | print("[", i, "]", tagID, nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 300 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 301 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 302 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 303 | //the type of motion (e.g., linear translation, rotation, shm, compound+motion) 304 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 305 | //the features (speed and frequency) 306 | } 307 | println("==="); 308 | } 309 | 310 | /*print the extra information of the last NFCBit in the console*/ 311 | void printLastBit() { 312 | ArrayList nbitList = nfcs.getNFCBits(); // get all of the recent NFCBits 313 | if (nbitList.size()>0) { 314 | NFCBit nb = nbitList.get(0); // get the latest NFCBit 315 | String tagID = "["+nfcs.getIDTable().get(0)+"]"; //get the ID string of the latest tag 316 | print(nb.getName(), tagID, ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 317 | //print the name of tag, the ID, the mode of motion depending on the motion type (mode=0: not ready), determined by the m and n in the algorithm. 318 | print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 319 | //print the type of token (e.g., zz*, theta>theta*, d_gap>d_gap*) 320 | //the type of motion (e.g., linear translation, rotation, shm, compound, compound+motion) 321 | println("V=", nf(nb.getSpeed(), 0, 2), "km/h; f=", nf(nb.getFrequency(), 0, 2), "Hz"); 322 | //the features (speed and frequency) 323 | } 324 | println("==="); 325 | } 326 | 327 | /*The serial event handler processes the data from any NFC reader in the String format of 328 | // "A[Byte_0]\n, B[Byte_1]\n, C[Byte_2]\n, or D[Byte_3]\n", 329 | //where every byte is an unsigned integer ranged between [0-256]. 330 | //When a tag is present: Byte_i=[0-255]; Otherwise, when a tag is absent: [256]. 331 | //================*/ 332 | 333 | void serialEvent(Serial port) { 334 | String inData = port.readStringUntil('\n'); // read the serial string until seeing a carriage return 335 | if (inData.charAt(0) >= 'A' && inData.charAt(0) <= 'D') { 336 | int i = inData.charAt(0)-'A'; 337 | int v = int(trim(inData.substring(1))); 338 | nfcs.rfid[i] = (v>255?-1:v); 339 | if (i==3) nfcs.checkTagID(); // process the tag ID when a sequence is collected completely. 340 | } 341 | return; 342 | } 343 | 344 | //print the current tag read by the reader 345 | void printCurrentTag() { 346 | if (nfcs.rfid[0]<0) println("No tag"); 347 | else println(nfcs.rfid[0], ",", nfcs.rfid[1], ",", nfcs.rfid[2], ",", nfcs.rfid[3]); 348 | } 349 | -------------------------------------------------------------------------------- /figures/hardware.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/figures/hardware.png -------------------------------------------------------------------------------- /figures/playlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/figures/playlist.png -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/howieliang/OpenNFCSense/54d46c78eeea5ab69c925fb5cd67e82963c019ba/src/.DS_Store -------------------------------------------------------------------------------- /src/OpenNFCSense4P/NFCBit.java: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v1) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // This software works with a microcontroller connected to an RC522 NFC/RFID Reader 18 | // and run the Arduino code 19 | // Github repository: https://github.com/howieliang/NFCSense 20 | // Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | package OpenNFCSense4P; 23 | 24 | import java.util.ArrayList; 25 | 26 | //##NFCBits 27 | public class NFCBit { 28 | final public static int NA = 0; 29 | final public static int BELOW_Z_STAR = 1; 30 | final public static int ABOVE_Z_STAR = 2; 31 | final public static int ABOVE_THETA_STAR = 3; 32 | 33 | final public static int L_MOTION = 1; 34 | final public static int ROTATION = 2; 35 | final public static int SHM = 3; 36 | final public static int COMPOUND_R1 = 4; 37 | final public static int COMPOUND_R2 = 5; 38 | final public static int COMPOUND_R3 = 6; 39 | final public static int COMPOUND_L1 = 7; 40 | final public static int COMPOUND_L2 = 8; 41 | 42 | int tokenType = ABOVE_Z_STAR; //default 43 | int motionType = ROTATION; //default 44 | float[] l_onArray = new float[]{44}; 45 | String[] stateStrArray = new String[]{"default"}; 46 | String[] modeStringArray = new String[]{""}; 47 | String[] tTypeStringArray = new String[]{"","zz*","theta>theta*"}; 48 | String[] mTypeStringArray = new String[]{"","linear motion","rotation","s.h.m.", 49 | "compound_r1","compound_r2","compound_r3","compound_l1","compound_l2"}; 50 | 51 | ArrayList profile = new ArrayList(); 52 | int n=0, m=0; 53 | float t_I=0, t_IBI=0, t_M=0, f=0, V=0; 54 | int mode=NA; 55 | 56 | NFCBit() { 57 | //apply all default settings 58 | } 59 | 60 | NFCBit(int tType, int mType) { 61 | tokenType = tType; 62 | motionType = mType; 63 | } 64 | 65 | NFCBit(int tType, int mType, float[] la, String[] sa) { 66 | tokenType = tType; 67 | motionType = mType; 68 | l_onArray = la; 69 | stateStrArray = sa; 70 | } 71 | 72 | void reset() { 73 | n=0; 74 | m=0; 75 | t_I=0; 76 | t_IBI=0; 77 | t_M=0; 78 | f=0; 79 | V=0; 80 | mode=NA; 81 | profile.clear(); 82 | } 83 | void getInfo() { 84 | //implemented by the extended classes 85 | } 86 | 87 | void printInfo() { 88 | //implemented by the extended classes 89 | } 90 | 91 | void getFeatures(int lastType) { 92 | //implemented by the extended classes 93 | } 94 | 95 | void setTokenType(int tType) { 96 | tokenType = tType; 97 | } 98 | void setMotionType(int mType) { 99 | motionType = mType; 100 | } 101 | void setL_onArray(float[] la) { 102 | l_onArray = la; 103 | } 104 | void setStateStrArray(String[] sa) { 105 | stateStrArray = sa; 106 | } 107 | float[] getL_onArray() { 108 | return l_onArray; 109 | } 110 | String[] getStateStrArray() { 111 | return stateStrArray; 112 | } 113 | 114 | public boolean isFrequency() { 115 | if (motionType == ROTATION || motionType == SHM || motionType == COMPOUND_R1 || motionType == COMPOUND_R2 || motionType == COMPOUND_R3) 116 | return true; 117 | else 118 | return false; 119 | } 120 | public boolean isSpeed() { 121 | if (motionType == ROTATION || motionType == SHM || motionType == COMPOUND_R1 || motionType == COMPOUND_R2 || motionType == COMPOUND_R3) 122 | return false; 123 | else 124 | return true; 125 | } 126 | public String getName() { 127 | return stateStrArray[0]; 128 | } 129 | public float getFrequency() { 130 | return f; 131 | } 132 | public float getSpeed() { 133 | return V; 134 | } 135 | public float getNumOfSegments() { 136 | return n; 137 | } 138 | public float getMainComponentIndex() { 139 | return m; 140 | } 141 | public int getMode() { 142 | return mode; 143 | } 144 | public String getModeString() { 145 | return modeStringArray[mode]; 146 | } 147 | public int getTokenType() { 148 | return tokenType; 149 | } 150 | public String getTokenTypeString() { 151 | return tTypeStringArray[tokenType]; 152 | } 153 | public int getMotionType() { 154 | return motionType; 155 | } 156 | public String getMotionTypeString() { 157 | return mTypeStringArray[motionType]; 158 | } 159 | } -------------------------------------------------------------------------------- /src/OpenNFCSense4P/OpenNFCSense4P.java: -------------------------------------------------------------------------------- 1 | /*========================================================================== 2 | // OpenNFCSense4P (v1) - Open NFCSense API for Processing Language 3 | // Copyright (C) 2021 Dr. Rong-Hao Liang 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | //==========================================================================*/ 17 | // This software works with a microcontroller connected to an RC522 NFC/RFID Reader 18 | // and run the Arduino code 19 | // Github repository: https://github.com/howieliang/NFCSense 20 | // Project website: https://ronghaoliang.page/NFCSense/ 21 | 22 | package OpenNFCSense4P; 23 | 24 | import java.util.ArrayList; 25 | 26 | import processing.core.*; 27 | import processing.data.*; 28 | 29 | /** 30 | * OpenNFCSense 31 | * 32 | * @example Hello 33 | */ 34 | 35 | public class OpenNFCSense4P implements PConstants { 36 | 37 | // pa is a reference to the parent sketch 38 | PApplet pa; 39 | public final static String VERSION = "##library.prettyVersion##"; 40 | 41 | final int IDBitNum = 4; 42 | final int MotionTypeNum = 8; 43 | 44 | float SAMPLE_RATE = 300.0f; // reads per second 45 | float TTL1_THLD = 300.0f; //ttl_timer 1 threshold 46 | float TTL2_THLD = 1000.0f; //ttl_timer 2 threshold 47 | 48 | boolean DEBUG_ID = false; 49 | boolean DEBUG_TIMER = false; 50 | 51 | int idNum = 0; 52 | ArrayList id_db = new ArrayList(); 53 | 54 | 55 | public int[] rfid = new int[IDBitNum]; 56 | int[] lastRFID = new int[IDBitNum]; 57 | 58 | int[] ibiCounter, tOnCounter, ibiLastEventTS; 59 | float[] lastIBI; 60 | float[][] idArray, mTypeArray, idSCntArray, tOnCntrArray; 61 | 62 | public float[][] RFIDHist; 63 | int streamSize = (int) SAMPLE_RATE; 64 | float[] modeArray = new float[streamSize]; 65 | float[] eventArray = new float[streamSize]; 66 | ArrayList lastIDList; 67 | 68 | // GLOBAL Variables 69 | public int lastRead = -1; // GLOBAL variable of last read. 70 | public int lastID = -1; // GLOBAL. Only for control. 71 | public int lastIDIndex = -1; 72 | public String IDModeString = ""; 73 | public String lastIDString = ""; 74 | public int ts = 0; 75 | public boolean profileReady = false; 76 | public int colNum = 3; 77 | public int gH, gW; 78 | public String[] fontList; 79 | public int fontSize = 24; 80 | public int tSize = 64; 81 | public PFont font; 82 | 83 | // TTL timers 84 | int last_t1 = 0; 85 | int last_t2 = 0; 86 | int ttl1 = 0; 87 | int ttl2 = 0; 88 | 89 | 90 | // Container 91 | ArrayList nbits; 92 | 93 | /** 94 | * OpenNFCSense Constructor 95 | * 96 | * @param theParent the parent PApplet 97 | */ 98 | public OpenNFCSense4P(PApplet theParent, String fileName) { 99 | pa = theParent; 100 | initNFCBits(fileName); 101 | welcome(); 102 | } 103 | 104 | public OpenNFCSense4P(PApplet theParent, String fileName, float sample_rate) { 105 | pa = theParent; 106 | initNFCBits(fileName); 107 | SAMPLE_RATE = sample_rate; 108 | welcome(); 109 | } 110 | 111 | public OpenNFCSense4P(PApplet theParent, String fileName, float sample_rate, int timer1, int timer2) { 112 | pa = theParent; 113 | initNFCBits(fileName); 114 | SAMPLE_RATE = sample_rate; 115 | TTL1_THLD = timer1; //ttl_timer 1 threshold 116 | TTL2_THLD = timer2; //ttl_timer 2 threshold 117 | welcome(); 118 | } 119 | 120 | private void welcome() { 121 | System.out.println("##library.name## ##library.prettyVersion## by ##author##"); 122 | } 123 | 124 | /** 125 | * return the version of the Library. 126 | * 127 | * @return String 128 | */ 129 | public static String version() { 130 | return VERSION; 131 | } 132 | 133 | public void pre() { 134 | // updateNFCBits(); 135 | } 136 | 137 | // ##Init 138 | void initNFCBits(String fileName) { 139 | Table csvData = pa.loadTable(fileName, "header"); 140 | nbits = new ArrayList(); 141 | if (csvData != null) { 142 | int n = csvData.getRowCount(); 143 | // ArrayList uids = new ArrayList(); 144 | for (int r = 0; r < n; r++) { 145 | TableRow newRow = csvData.getRow(r); 146 | int uid0 = newRow.getInt("UID0"); 147 | int uid1 = newRow.getInt("UID1"); 148 | int uid2 = newRow.getInt("UID2"); 149 | int uid3 = newRow.getInt("UID3"); 150 | String tagName = newRow.getString("Label"); 151 | int tType = newRow.getInt("Ttype"); 152 | int mType = newRow.getInt("Mtype"); 153 | float lon1 = newRow.getFloat("L1"); 154 | float lon2 = newRow.getFloat("L2"); 155 | int[] _rfid = { uid0, uid1, uid2, uid3, 0 }; 156 | id_db.add(IDtoLong(_rfid)); 157 | 158 | if (tType == NFCBit.BELOW_Z_STAR && mType == NFCBit.L_MOTION) { 159 | nbits.add(new NFCBitB(new float[] { lon1, lon2 }, new String[] { tagName })); 160 | } 161 | if (tType == NFCBit.ABOVE_THETA_STAR && mType == NFCBit.L_MOTION) { 162 | nbits.add(new NFCBitT(new float[] { lon1, lon2 }, new String[] { tagName })); 163 | } 164 | if (tType == NFCBit.ABOVE_Z_STAR && mType == NFCBit.L_MOTION) { 165 | nbits.add(new NFCBitAL(new float[] { lon1, lon2 }, new String[] { tagName })); 166 | } 167 | if (tType == NFCBit.ABOVE_Z_STAR && mType == NFCBit.ROTATION) { 168 | nbits.add(new NFCBitAR(new float[] { lon1, lon2 }, new String[] { tagName })); 169 | } 170 | if (tType == NFCBit.ABOVE_Z_STAR && mType == NFCBit.SHM) { 171 | nbits.add(new NFCBitAS(new float[] { lon1, lon2 }, new String[] { tagName })); 172 | } 173 | if (mType == NFCBit.COMPOUND_R1 || mType == NFCBit.COMPOUND_R2 || mType == NFCBit.COMPOUND_R3) { 174 | nbits.add(new NFCBitCR(new float[] { lon1, lon2 }, new String[] { tagName }, mType)); 175 | } 176 | if (mType == NFCBit.COMPOUND_L1 || mType == NFCBit.COMPOUND_L2) { 177 | nbits.add(new NFCBitCL(new float[] { lon1, lon2 }, new String[] { tagName }, mType)); 178 | } 179 | } 180 | } 181 | 182 | initParam(); 183 | } 184 | 185 | void initParam() { 186 | fontList = PFont.list(); 187 | font = pa.createFont("Lucida Sans Regular", 72); 188 | pa.textFont(font); 189 | gH = pa.height; 190 | gW = pa.width; 191 | last_t1 = pa.millis(); 192 | last_t2 = pa.millis(); 193 | 194 | idNum = id_db.size(); // new 195 | lastIDList = new ArrayList(); 196 | 197 | ibiCounter = new int[idNum]; 198 | tOnCounter = new int[idNum]; 199 | ibiLastEventTS = new int[idNum]; 200 | lastIBI = new float[idNum]; 201 | 202 | rfid = new int[IDBitNum]; 203 | lastRFID = new int[IDBitNum]; 204 | idSCntArray = new float[idNum][streamSize]; // history data to show 205 | tOnCntrArray = new float[idNum][streamSize]; // history data to show 206 | 207 | // RFIDHist = new float[IDBitNum][streamSize]; //history data to show 208 | idArray = new float[idNum][streamSize]; 209 | mTypeArray = new float[MotionTypeNum][streamSize]; 210 | modeArray = new float[streamSize]; // To show activated or not 211 | eventArray = new float[streamSize]; // To show activated or not 212 | 213 | for (int i = 0; i < idNum; i++) { 214 | for (int j = 0; j < streamSize; j++) { 215 | idArray[i][j] = -1; // history data to show 216 | } 217 | tOnCounter[i] = 0; 218 | ibiLastEventTS[i] = 0; 219 | } 220 | 221 | for (int i = 0; i < MotionTypeNum; i++) { 222 | for (int j = 0; j < streamSize; j++) { 223 | mTypeArray[i][j] = -1; // history data to show 224 | } 225 | } 226 | 227 | for (int i = 0; i < streamSize; i++) { 228 | modeArray[i] = -1; 229 | eventArray[i] = -1; 230 | } 231 | 232 | for (int i = 0; i < IDBitNum; i++) { 233 | rfid[i] = -1; 234 | lastRFID[i] = -1; 235 | } 236 | 237 | lastIDString = ""; 238 | lastIDIndex = -1; 239 | ts = 0; 240 | } 241 | 242 | // ##Draw 243 | 244 | void drawIDInfo(String str) { 245 | if (str == "") 246 | showInfo("Waiting for the first tag...", gW / 2, 20, 20); 247 | else 248 | showInfo("Last Tag: " + str + " is recognized as:", gW / 2, 20, 20); 249 | } 250 | 251 | void drawLMotionSignals(int n) { 252 | lineGraph2(tOnCntrArray[n], 300, 0, 0, 2 * gH / colNum, gW, gH / (colNum * 2), n); // history of signal 253 | barGraph(modeArray, 0, 3 * gH / colNum, gW, gH / (colNum * 2)); 254 | } 255 | 256 | void drawRotationSignals(int n) { 257 | lineGraph2(idSCntArray[n], 20, 0, 0, 2 * gH / colNum, gW, gH / colNum, n); // history of signal 258 | } 259 | 260 | void drawSHMSignals(int n) { 261 | lineGraph2(tOnCntrArray[n], 300, 0, 0, 2 * gH / colNum, gW, gH / colNum, n); // history of signal 262 | } 263 | 264 | void drawIDStream(int n) { 265 | barGraph(idArray[n], 0, 2 * gH / colNum - n * gH / (colNum * idNum), gW, gH / (colNum * idNum), n); // history 266 | // of signal 267 | } 268 | 269 | public void drawResults() { 270 | pa.pushStyle(); 271 | drawIDInfo(lastIDString); 272 | for (int n = 0; n < idNum; n++) { 273 | NFCBit nb = nbits.get(n); 274 | int mType = nb.getMotionType(); 275 | drawIDStream(n); 276 | if (lastIDIndex == n && IDModeString.length() > 0) { 277 | switch (mType) { 278 | case NFCBit.L_MOTION: 279 | drawLMotionSignals(n); 280 | if (profileReady) { 281 | nb.getInfo(); 282 | } 283 | break; 284 | case NFCBit.ROTATION: 285 | drawRotationSignals(n); 286 | nb.getInfo(); 287 | break; 288 | case NFCBit.SHM: 289 | drawSHMSignals(n); 290 | nb.getInfo(); 291 | break; 292 | default: 293 | drawRotationSignals(n); 294 | nb.getInfo(); 295 | break; 296 | } 297 | } 298 | } 299 | pa.noFill(); 300 | pa.stroke(0); 301 | for (int i = 0; i < colNum; i++) 302 | pa.line(0, i * pa.height / colNum, pa.width, i * pa.height / colNum); 303 | pa.popStyle(); 304 | } 305 | 306 | void showInfo(String s, float x, float y, float fs) { 307 | pa.pushStyle(); 308 | pa.textAlign(CENTER, TOP); 309 | pa.fill(0); 310 | pa.textSize(fs); 311 | pa.text(s, x, y); 312 | pa.popStyle(); 313 | } 314 | 315 | // Draw a bar graph to visualize the modeArray 316 | // barGraph(float[] data, float x, float y, float width, float height) 317 | void barGraph(float[] data, float _x, float _y, float _w, float _h) { 318 | int colors[] = { pa.color(155, 89, 182), pa.color(63, 195, 128), pa.color(214, 69, 65), pa.color(82, 179, 217), 319 | pa.color(52, 73, 94), pa.color(242, 121, 53), pa.color(0, 121, 53), pa.color(128, 128, 0), pa.color(52, 0, 128), 320 | pa.color(128, 52, 0) }; 321 | pa.pushStyle(); 322 | pa.noStroke(); 323 | float delta = _w / data.length; 324 | for (int p = 0; p < data.length; p++) { 325 | float i = data[p]; 326 | int cIndex = (int) i % 10;// min(, colors.length-1); 327 | if (i < 0) 328 | pa.fill(255); 329 | else { 330 | if (i >= 10) { 331 | pa.fill(colors[cIndex]); 332 | } else { 333 | pa.fill(colors[cIndex], 52); 334 | } 335 | } 336 | float h = PApplet.map(0, -1, 0, 0, _h); 337 | pa.rect(_x, _y - h, delta, h); 338 | _x = _x + delta; 339 | } 340 | pa.popStyle(); 341 | } 342 | 343 | void barGraph(float[] data, float _x, float _y, float _w, float _h, int ci) { 344 | int colors[] = { pa.color(155, 89, 182), pa.color(63, 195, 128), pa.color(214, 69, 65), pa.color(82, 179, 217), 345 | pa.color(52, 73, 94), pa.color(242, 121, 53), pa.color(0, 121, 53), pa.color(128, 128, 0), pa.color(52, 0, 128), 346 | pa.color(128, 52, 0), pa.color(0) }; 347 | pa.pushStyle(); 348 | pa.noStroke(); 349 | float delta = _w / data.length; 350 | for (int p = 1; p nbitList = getNFCBits(); 422 | for (int i = 0; i < nbitList.size(); i++) { 423 | NFCBit nb = nbitList.get(i); 424 | PApplet.print("[", i, "]", nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 425 | PApplet.print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 426 | PApplet.println("V=", PApplet.nf(nb.getSpeed(), 0, 2), "km/h; f=", PApplet.nf(nb.getFrequency(), 0, 2), "Hz"); 427 | } 428 | PApplet.println("==="); 429 | } 430 | 431 | public void printLastBit() { //print the latest tag appearance 432 | ArrayList nbitList = getNFCBits(); 433 | if (nbitList.size()>0) { 434 | NFCBit nb = nbitList.get(0); 435 | PApplet.print(nb.getName(), ":", nb.getModeString(), "(mode= ", nb.getMode(), ") "); 436 | PApplet.print(nb.getTokenTypeString(), nb.getMotionTypeString(), "|"); 437 | PApplet.println("V=", PApplet.nf(nb.getSpeed(), 0, 2), "km/h; f=", PApplet.nf(nb.getFrequency(), 0, 2), "Hz"); 438 | } 439 | PApplet.println("==="); 440 | } 441 | 442 | // #NFCSense Algorithm 443 | 444 | public void updateNFCBits() { 445 | if (lastIDList.size() > 0) { 446 | int lastID = lastIDList.get(lastIDList.size() - 1); 447 | NFCBit nbit = nbits.get(lastID); 448 | int previousMType = -1; 449 | if (lastIDList.size() > 1) 450 | previousMType = nbits.get(lastIDList.get(lastIDList.size() - 2)).getMotionType(); 451 | nbit.getFeatures(previousMType); 452 | } 453 | } 454 | 455 | public ArrayList getNFCBits() { 456 | ArrayList nbList = new ArrayList(); 457 | for (int i=lastIDList.size()-1; i>=0; i--) { 458 | nbList.add(nbits.get(lastIDList.get(i))); 459 | } 460 | return nbList; 461 | } 462 | 463 | int searchID(ArrayList id_db, long id) { 464 | int index = -1; 465 | for (int i = 0; i < id_db.size(); i++) { 466 | if (id_db.get(i) == id) { 467 | index = i; 468 | break; 469 | } 470 | } 471 | return index; 472 | } 473 | 474 | long IDtoLong(int[] b) { 475 | return (long) b[0] * 256 * 256 * 256 + (long) b[1] * 256 * 256 + (long) b[2] * 256 + (long) b[3]; 476 | } 477 | 478 | String decoder(long l) { 479 | return (l / (256 * 256 * 256)) % 256 + "," + (l / (256 * 256)) % 256 + "," + (l / (256)) % 256 + "," + l % 256; 480 | } 481 | 482 | public void drawMotionModeRecords(float x, float y, float gW, float gH) { 483 | String[] mTypeItems={"LIN", "ROT", "SHM", "CR1", "CR2", "CR3", "CL1", "CL2"}; 484 | int colors[] = { 485 | pa.color(155, 89, 182), pa.color(63, 195, 128), pa.color(214, 69, 65), 486 | pa.color(82, 179, 217), pa.color(52, 73, 94), pa.color(242, 121, 53), 487 | pa.color(0, 121, 53), pa.color(128, 128, 0), pa.color(52, 0, 128), 488 | pa.color(128, 52, 0), pa.color(0) 489 | }; 490 | for (int n=0; n getIDTable() { 521 | ArrayList ids = new ArrayList(); 522 | for(int i = 0; i < lastIDList.size();i++) { 523 | ids.add(decoder(id_db.get(lastIDList.get(i)))); 524 | } 525 | return ids; 526 | } 527 | 528 | public ArrayList getNFCBitTable() { 529 | return nbits; 530 | } 531 | 532 | public void setReadRate(float v) { 533 | SAMPLE_RATE = v; 534 | } 535 | 536 | public void setTimer1(float v) { 537 | TTL1_THLD = v; 538 | } 539 | 540 | public void setTimer2(float v) { 541 | TTL2_THLD = v; 542 | } 543 | 544 | public float getReadRate() { 545 | return SAMPLE_RATE; 546 | } 547 | 548 | public float getTimer1() { 549 | return TTL1_THLD; 550 | } 551 | 552 | public float getTimer2() { 553 | return TTL2_THLD; 554 | } 555 | 556 | public void checkTagID() { // called in Serial so that it won't be limited by the 60fps refresh rate 557 | int id_read = searchID(id_db, IDtoLong(rfid)); 558 | updateOnTimers(id_read); 559 | updateIntervals(id_read); 560 | updateMTypes(id_read); 561 | lastRead = id_read; // update lastRead after the interval is obtained. 562 | if (id_read >= 0) { 563 | if (id_read != lastIDIndex) { 564 | IDModeString = nbits.get(id_read).getStateStrArray()[0]; 565 | for (int i = lastIDList.size() - 1; i >= 0; i--) { 566 | if (id_read == lastIDList.get(i)) 567 | lastIDList.remove(i); 568 | } 569 | lastIDList.add(id_read); 570 | lastIDIndex = id_read; 571 | } 572 | } 573 | if (DEBUG_ID) 574 | PApplet.println(rfid[0], rfid[1], rfid[2], rfid[3]); 575 | ++ts; //increase the timestep 576 | } 577 | 578 | void updateOnTimers(int id_read) { // t1, t2, and idOnCounters 579 | // ====ON TIMER BEGIN====// 580 | ttl1 = pa.millis() - last_t1; 581 | 582 | if (id_read >= 0) { // id_read>=0 583 | lastIDString = "[" + rfid[0] + "," + rfid[1] + "," + rfid[2] + "," + rfid[3] + "]"; 584 | NFCBit nb = nbits.get(id_read); 585 | if (lastID != id_read) { // edge of different tags 586 | for (int n = modeArray.length - 1; n >= 0; n--) 587 | modeArray[n] = -1; 588 | } 589 | // Calc T_on begin 590 | if (lastRead != id_read) { 591 | nb.reset(); 592 | appendArray(modeArray, idNum + id_read); 593 | tOnCounter[id_read] = 1; // for single-tag pattern and orientation 594 | } else { // lastRead == id_read 595 | appendArray(modeArray, id_read); 596 | ++tOnCounter[id_read]; // for single-tag pattern and orientation 597 | } 598 | // Calc T_on end 599 | last_t2 = pa.millis(); // reset t2 600 | 601 | // Calc T_ibi begin 602 | if (lastID != id_read) { // was a different tag 603 | if (ibiCounter[id_read] == 0) { // 604 | if (ibiLastEventTS[id_read] != 0) 605 | lastIBI[id_read] = ts - ibiLastEventTS[id_read]; 606 | ibiLastEventTS[id_read] = ts; 607 | ++ibiCounter[id_read]; 608 | last_t1 = pa.millis(); 609 | profileReady = false; 610 | } 611 | if (lastIDIndex > 0) 612 | nb.t_IBI = ibiLastEventTS[id_read] - ibiLastEventTS[lastIDIndex]; 613 | } else { // was the same tag 614 | if (ibiCounter[id_read] == 0) { 615 | if (ibiLastEventTS[id_read] != 0) { 616 | lastIBI[id_read] = ts - ibiLastEventTS[id_read]; 617 | ++ibiCounter[id_read]; 618 | last_t1 = pa.millis(); 619 | profileReady = false; 620 | } 621 | ibiLastEventTS[id_read] = ts; 622 | } 623 | nb.t_I = (int) lastIBI[id_read]; // update tI 624 | } 625 | // Calc T_ibi end 626 | } else { // id_read<0 627 | ttl2 = pa.millis() - last_t2; // start counting t2 628 | if (lastRead >= 0) { // push last t_on 629 | for (int n = 0; n < tOnCounter[lastRead]; n++) { 630 | appendArray(tOnCntrArray[lastRead], tOnCounter[lastRead]); // line graph 631 | } 632 | tOnCounter[lastRead] = 0; 633 | ibiCounter[lastRead] = 0; 634 | last_t1 = pa.millis(); 635 | } 636 | 637 | if (ttl1 > TTL1_THLD) { 638 | for (int n = 0; n < idNum; n++) { // reset params 639 | ibiCounter[n] = 0; 640 | lastIBI[n] = 0; 641 | ibiLastEventTS[n] = 0; 642 | } 643 | 644 | if (!profileReady) { // count the modeArray from the back 645 | int ptr = modeArray.length - 1; 646 | if (lastID >= 0) { 647 | NFCBit nb = nbits.get(lastID); 648 | nb.profile.clear(); 649 | for (int n = modeArray.length - 1; n >= 0; n--) { 650 | if (modeArray[n] >= idNum) { 651 | int d = ptr - n; 652 | if (d > 0) 653 | nb.profile.add(d); 654 | ptr = n; 655 | } 656 | } 657 | } 658 | profileReady = true; 659 | } 660 | 661 | if (ttl2 > TTL2_THLD) { 662 | if (lastIDIndex >= 0) { 663 | lastIDString = ""; 664 | lastIDIndex = -1; 665 | for(int i = 0 ; i TTL1_THLD, ttl2, ttl2 > TTL2_THLD, lastRead, id_read); 681 | // ====ON TIMER END====// 682 | } 683 | 684 | void updateIntervals(int id_read) { 685 | if (id_read >= 0) { 686 | if (lastID != id_read) { // edge of different tags 687 | lastID = id_read; 688 | for (int n = 0; n < idNum; n++) { 689 | if (n == id_read) { 690 | appendArray(idArray[n], idNum + n); // ???lastID != id_read 691 | } else { 692 | appendArray(idArray[n], -1); // not the current id_read. 693 | } 694 | } 695 | appendArray(eventArray, 10 + id_read); // 696 | } else { // lastID == id_read 697 | 698 | for (int n = 0; n < idNum; n++) { 699 | if (n == id_read) { 700 | appendArray(idArray[n], n); // lastID == id_read 701 | } else { 702 | appendArray(idArray[n], -1); 703 | } 704 | } 705 | appendArray(eventArray, id_read); 706 | } 707 | } else { 708 | appendArray(eventArray, -1); 709 | for (int n = 0; n < idNum; n++) { 710 | appendArray(idArray[n], -1); // update idArray 711 | } 712 | } 713 | 714 | for (int n = 0; n < idNum; n++) { 715 | appendArray(idSCntArray[n], (lastIBI[n] > 0 ? 300 / lastIBI[n] : 0)); 716 | } 717 | // ====INTERVAL END====// 718 | } 719 | 720 | void updateMTypes(int id_read) { 721 | if (id_read >= 0) { 722 | int m = nbits.get(id_read).getMotionType()-1; 723 | for (int n = 0; n < MotionTypeNum; n++) { 724 | if (n == m) { 725 | appendArray(mTypeArray[n], n); // ???lastID != id_read 726 | } else { 727 | appendArray(mTypeArray[n], -1); // not the current id_read. 728 | } 729 | } 730 | } else { 731 | for (int n = 0; n < MotionTypeNum; n++) { 732 | appendArray(mTypeArray[n], -1); 733 | } 734 | } 735 | // ====INTERVAL END====// 736 | } 737 | 738 | class NFCBitAL extends NFCBit { 739 | final static int NA = 0; 740 | final static int SLIDING = 1; 741 | NFCBitAL(float[] la, String[] sa) { 742 | super(NFCBit.ABOVE_Z_STAR, L_MOTION, la, sa); 743 | mode = SLIDING; 744 | modeStringArray = new String[]{"", "sliding"}; 745 | } 746 | void getInfo() { 747 | showInfo(IDModeString, gW/2, 40, tSize); 748 | showInfo("at "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr", gW/2, 40+tSize, 48); 749 | } 750 | void printInfo() { 751 | PApplet.print(IDModeString); 752 | PApplet.println(" @ "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr"); 753 | } 754 | void getFeatures(int lastType) { 755 | t_M = 0; 756 | n = profile.size(); //num of segments 757 | for (int i : profile) t_M += i; //the sum of all components (for robustness) 758 | if (n>=1) { 759 | V = (float)(t_M > 0 ? (l_onArray[0] * 0.0036) * SAMPLE_RATE / t_M : 0); 760 | mode = SLIDING; 761 | } else { 762 | V = 0; 763 | mode = NA; 764 | } 765 | m=1; 766 | } 767 | } 768 | 769 | class NFCBitAR extends NFCBit { 770 | final static int SPINNING = 1; 771 | NFCBitAR(float[] la, String[] sa) { 772 | super(NFCBit.ABOVE_Z_STAR, ROTATION, la, sa); 773 | mode = SPINNING; 774 | modeStringArray = new String[]{"", "spinning"}; 775 | } 776 | void getInfo() { 777 | showInfo(IDModeString, gW/2, 40, tSize); 778 | showInfo("at "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz", gW/2, 40+tSize, 48); 779 | } 780 | void printInfo() { 781 | PApplet.print(IDModeString); 782 | PApplet.println(" @ "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz"); 783 | } 784 | void getFeatures(int lastType) { 785 | n = profile.size(); //num of segments 786 | f = (t_I>1 ? SAMPLE_RATE / t_I : 0); //tI = self IBI 787 | if(f>0) mode = SPINNING; 788 | else mode = NA; 789 | } 790 | } 791 | 792 | class NFCBitAS extends NFCBit { 793 | final static int SWINGING = 1; 794 | NFCBitAS(float[] la, String[] sa) { 795 | super(NFCBit.ABOVE_Z_STAR, SHM, la, sa); 796 | mode = SWINGING; 797 | modeStringArray = new String[]{"", "swinging"}; 798 | } 799 | void getInfo() { 800 | showInfo(IDModeString, gW/2, 40, tSize); 801 | showInfo("at "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz", gW/2, 40+tSize, 48); 802 | } 803 | void printInfo() { 804 | PApplet.print(IDModeString); 805 | PApplet.println(" @ "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz"); 806 | } 807 | void getFeatures(int lastType) { 808 | n = profile.size(); //num of segments 809 | f = (float)((t_I>1 ? SAMPLE_RATE / t_I : 0)/2.); 810 | if(f>0) mode = SWINGING; 811 | else mode = NA; 812 | } 813 | } 814 | 815 | class NFCBitB extends NFCBit { 816 | final static int SLIDING = 1; 817 | final static int HOVERING = 2; 818 | NFCBitB(float[] la, String[] sa) { 819 | super(NFCBit.BELOW_Z_STAR, NFCBit.L_MOTION, la, sa); 820 | modeStringArray = new String[]{"", "sliding", "hovering"}; 821 | } 822 | void getInfo() { 823 | showInfo(IDModeString+": "+modeStringArray[mode], gW/2, 40, tSize); 824 | showInfo("at "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr", gW/2, 40+tSize, 48); 825 | } 826 | void printInfo() { 827 | PApplet.print(IDModeString+": "+modeStringArray[mode]); 828 | PApplet.println(" @ "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr"); 829 | } 830 | void getFeatures(int lastType) { 831 | n = profile.size(); //num of segments 832 | t_M = 0; 833 | for (int i=0; it_M) { 836 | t_M = t; //major component 837 | m=i+1; //index of major component (start counting from 1) 838 | } 839 | } 840 | if (n>1) { 841 | V = (float)(t_M > 0 ? (l_onArray[0] * 0.0036) * SAMPLE_RATE / t_M : 0);//temporal 842 | mode = SLIDING; 843 | } else if (n==1) { 844 | V = (float)(t_M > 0 ? (l_onArray[1] * 0.0036) * SAMPLE_RATE / t_M : 0); 845 | mode = HOVERING; 846 | } else { 847 | V=0; 848 | mode=NA; 849 | } 850 | } 851 | } 852 | 853 | class NFCBitCL extends NFCBit { 854 | final static int NA = 0; 855 | final static int FORWARD = 1; 856 | final static int BACKWARD = 2; 857 | NFCBitCL(float[] la, String[] sa, int motionType) { 858 | super(NFCBit.ABOVE_Z_STAR, motionType, la, sa); 859 | modeStringArray = new String[]{"", "moving forward", "moving backward"}; 860 | } 861 | void getInfo() { 862 | showInfo(IDModeString+": "+modeStringArray[mode], gW/2, 40, tSize); 863 | showInfo("at "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr", gW/2, 40+tSize, 48); 864 | } 865 | void printInfo() { 866 | PApplet.print(IDModeString+": "+modeStringArray[mode]); 867 | PApplet.println(" @ "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr"); 868 | } 869 | void getFeatures(int lastType) { 870 | n = profile.size(); //num of segments 871 | m = (n==0?0:1); 872 | V = 0; 873 | switch(motionType) { 874 | case COMPOUND_L1: 875 | if (lastType==COMPOUND_L2) { 876 | V = (float)(t_IBI > 0 ? (l_onArray[0] * 0.0036) * SAMPLE_RATE / t_IBI : 0); 877 | mode = BACKWARD; 878 | } 879 | break; 880 | case COMPOUND_L2: 881 | if (lastType==COMPOUND_L1) { 882 | V = (float)(t_IBI > 0 ? (l_onArray[0] * 0.0036) * SAMPLE_RATE / t_IBI : 0); 883 | mode = FORWARD; 884 | } 885 | break; 886 | } 887 | if (V==0) mode = NA; 888 | } 889 | } 890 | 891 | class NFCBitCR extends NFCBit { 892 | final static int NA = 0; 893 | final static int CW = 1; 894 | final static int CCW = 2; 895 | NFCBitCR(float[] la, String[] sa, int motionType) { 896 | super(NFCBit.ABOVE_Z_STAR, motionType, la, sa); 897 | modeStringArray = new String[]{"", "clockwise spinning", "counterclockwise spinning"}; 898 | } 899 | void getInfo() { 900 | showInfo(IDModeString+": "+modeStringArray[mode], gW/2, 40, tSize); 901 | showInfo("at "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz", gW/2, 40+tSize, 48); 902 | } 903 | void printInfo() { 904 | PApplet.print(IDModeString+": "+modeStringArray[mode]); 905 | PApplet.println(" @ "+(f>=0? PApplet.nf(f, 0, 2):"---")+" Hz"); 906 | } 907 | void getFeatures(int lastType) { 908 | n = profile.size(); //num of segments 909 | m = (n==0?0:1); //major component 910 | f = (t_I>1 ? SAMPLE_RATE / t_I : 0); //t_I:self_IBI 911 | if (f>0) { 912 | switch(motionType) { 913 | case NFCBit.COMPOUND_R1: 914 | if (lastType == NFCBit.COMPOUND_R3) mode=CCW; 915 | if (lastType == NFCBit.COMPOUND_R2) mode=CW; 916 | break; 917 | case NFCBit.COMPOUND_R2: 918 | if (lastType == NFCBit.COMPOUND_R1) mode=CCW; 919 | if (lastType == NFCBit.COMPOUND_R3) mode=CW; 920 | break; 921 | case NFCBit.COMPOUND_R3: 922 | if (lastType == NFCBit.COMPOUND_R2) mode=CCW; 923 | if (lastType == NFCBit.COMPOUND_R1) mode=CW; 924 | break; 925 | } 926 | } else { 927 | mode=NA; 928 | } 929 | } 930 | } 931 | 932 | 933 | class NFCBitT extends NFCBit { 934 | final static int NA = 0; 935 | final static int FORWARD = 1; 936 | final static int BACKWARD = 2; 937 | NFCBitT(float[] la, String[] sa) { 938 | super(NFCBit.ABOVE_THETA_STAR, L_MOTION, la, sa); 939 | modeStringArray = new String[]{"", "moving forward", "moving backward"}; 940 | } 941 | void getInfo() { 942 | showInfo(IDModeString+": "+modeStringArray[mode], gW/2, 40, tSize); 943 | showInfo("at "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr", gW/2, 40+tSize, 48); 944 | } 945 | void printInfo() { 946 | PApplet.print(IDModeString+": "+modeStringArray[mode]); 947 | PApplet.println(" @ "+(V>=0? PApplet.nf(V, 0, 2):"---")+" km/hr"); 948 | } 949 | void getFeatures(int lastType) { 950 | n = profile.size(); //num of segments 951 | t_M = 0; 952 | for (int i=0; it_M) { 955 | t_M = t; //major component 956 | m=i+1; //index of major component (start counting from 1) 957 | } 958 | } 959 | if (n>1) { 960 | V = (float)(t_M > 0 ? (l_onArray[0] * 0.0036) * SAMPLE_RATE / t_M : 0); 961 | mode=(m>=2 ? FORWARD : BACKWARD); 962 | } else { 963 | V=0; 964 | mode=NA; 965 | } 966 | } 967 | } 968 | 969 | 970 | 971 | 972 | } 973 | --------------------------------------------------------------------------------