Raspberry Pi Weighting Control System
This project serves as a simple weighting control system, that was realized as a Bachelor Thesis
rfid_reader.cpp
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <queue>
5 #include <chrono>
6 #include <spdlog/spdlog.h>
7 #include "rfid_reader.h"
8 #include "rc522.h"
9 #include "app_workspace.h"
10 
11 #define REPEATING_FLAG_DELAY 500 //in ms
12 #define RFID_READ_INTERVAL 100000
13 
14 namespace rfid_reader {
15  std::queue<rfid_event> event_queue;
16  std::mutex eq_mutex;
17 
18  std::unique_ptr<spi_config_t> spi_config;
19  std::unique_ptr<SPI> my_spi = nullptr;
20  bool reading_cards = true;
21 
22 
23  void push_event(rfid_tag tag, uint8_t flags);
24 
25  int init(const char* device, uint8_t mode = 0, uint32_t speed = 1000000, uint16_t delay = 0, uint8_t bits_per_word = 8) {
26  spi_config = std::unique_ptr<spi_config_t>(new spi_config_t());
27  spi_config->mode = mode;
28  spi_config->speed = speed;
29  spi_config->delay = delay;
30  spi_config->bits_per_word = bits_per_word;
31 
32  spdlog::info("rfid_reader.cpp - Initializing SPI RFID Reader (RC522)");
33 
34  my_spi = std::unique_ptr<SPI>(new SPI(device, spi_config.get()));
35 
36  if (!my_spi->begin()) {
37  spdlog::critical("rfid_reader.cpp - Failed to start SPI communication for RC522");
38  return 1;
39  }
40 
41  spdlog::info("rfid_reader.cpp - Successfully initialized SPI RFID Reader (RC522)");
42  InitRc522(my_spi.get());
43  return 0;
44  }
45 
47  app_workspace_ns::spi_config *config = &(app_workspace::get_instance()->main_config->rfid_conf);
48  spdlog::info("rfid_reader.cpp - Initializing SPI RFID Reader (RC522) with config (enable debug to print config)");
49  spdlog::debug("rfid_reader.cpp - dev: {0}" , config->dev);
50  spdlog::debug("rfid_reader.cpp - mode: {0}" , config->config->mode);
51  spdlog::debug("rfid_reader.cpp - bits_p_w: {0}", config->config->bits_per_word);
52  spdlog::debug("rfid_reader.cpp - speed: {0}" , config->config->speed);
53  spdlog::debug("rfid_reader.cpp - delay: {0}" , config->config->delay);
54 
55  my_spi = std::unique_ptr<SPI>(new SPI(config->dev.c_str(), config->config.get()));
56 
57  if (!my_spi->begin()) {
58  spdlog::critical("rfid_reader.cpp - Failed to start SPI communication for RC522");
59  return 1;
60  }
61 
62  spdlog::info("rfid_reader.cpp - Successfully initialized SPI RFID Reader (RC522)");
63  InitRc522(my_spi.get());
64  return 0;
65  }
66 
68  spdlog::debug("rfid_reader.cpp - Read RFID tag. Serial:");
69  // printf isn't very elegant, but this is a debug function anyway
70  for (int i = 0; i < tag->serial_size; i++) {
71  printf("%d", tag->serial[i]);
72  }
73  printf("\n");
74  }
75 
77  uint8_t flags;
78  int rv;
79  rfid_tag tag;
80  std::chrono::time_point<std::chrono::high_resolution_clock> last_read =
81  std::chrono::high_resolution_clock::now();
82  std::chrono::time_point<std::chrono::high_resolution_clock> current_read;
83 
84  while (reading_cards) {
85  flags = RFID_FLAGS_NONE;
86  rv = read_tag(&tag);
87  current_read = std::chrono::high_resolution_clock::now();
88 
89  if (rv != TAG_OK) {
90  spdlog::error("rfid_reader.cpp - read_tag() finished but returned error state");
91  } else {
92  spdlog::info("rfid_reader.cpp - Successfully read RFID tag. Pushing into RFID event queue.");
93 
94  std::chrono::duration<double, std::milli> diff = last_read - current_read;
95  if (diff.count() > REPEATING_FLAG_DELAY) {
96  flags |= RFID_FLAGS_REPEATING;
97  }
98  //print_card_serial(&tag);
99  push_event(tag, flags);
100  }
101 
102  last_read = current_read; //maybe change its to ::now()
103  }
104  }
105 
106  void clean() {
107  spdlog::info("rfid_reader.cpp - Cleaning SPI RFID Reader (RC522)");
108  reading_cards = false;
109  // my_spi is unique_ptr, should destruct automatically
110  }
111 
112  char detect_tag(uint16_t *tag_type, uint8_t *buff) {
113  char status;
114  status = PcdRequest(PICC_REQALL, buff);
115 
116  if (status == TAG_OK) {
117  *tag_type = buff[0] << 8 | buff[1];
118  }
119 
120  return status;
121  }
122 
123  char read_tag_serialn(uint8_t *serial, uint8_t *serial_size, uint8_t *ser_ack, uint8_t *buff) {
124  /* get basic UID from card */
125  if (PcdAnticoll(PICC_ANTICOLL1, buff) != TAG_OK) return TAG_ERR;
126 
127  /* select the card */
128  if (PcdSelect(PICC_ANTICOLL1, buff, ser_ack) != TAG_OK) return TAG_ERR;
129 
130  if (buff[0]== 0x88) { // 0x88 is CT = Cascade Tag (means next level to get UID)
131 
132  //copy UID0, UID1, UID2
133  memcpy(serial, &buff[1],3);
134 
135  // 0x95 => get cascade level 2 and select
136  if (PcdAnticoll(PICC_ANTICOLL2, buff)!= TAG_OK) return TAG_ERR;
137 
138  if (PcdSelect(PICC_ANTICOLL2, buff, ser_ack) != TAG_OK) return TAG_ERR;
139 
140  if (buff[0]==0x88)
141  {
142  // add UID3, UID4 and UID5
143  memcpy(serial + 3, &buff[1], 3);
144 
145  // 0x97 => get even more extended serial number
146 
147  if (PcdAnticoll(PICC_ANTICOLL3, buff) != TAG_OK) return TAG_ERR;
148 
149  if (PcdSelect(PICC_ANTICOLL3, buff, ser_ack) != TAG_OK) return TAG_ERR;
150 
151  // add UID6, UID7, UID8 UID9
152  memcpy(serial + 6, buff, 4);
153  *serial_size = 10; // 10 byte UID (triple size UID) PSS
154  } else {
155  // add UID3, UID4, UID5 UID6
156  memcpy(serial + 3, buff, 4);
157  /* 7 byte UID (double size) Mifare Ultralight, Ultralight C, Desfire
158  * Desfire EV1 and Mifare Plus (7 B UID)
159  */
160  *serial_size = 7; // 7 byte Unique ID (double size UID)
161  }
162  } else {
163  //copy UID0, UID1, UID2, UID3
164  memcpy(serial, &buff[0], 4);
165  /* 4 byte non-unique ID (single byte UID) - discontinued end 2010
166  * were set at manufacturing.
167  * used on Mifare Classic 1K, Mifare Classic 4K and some Mifare Plus versions
168  */
169  *serial_size = 4;
170  }
171 
172  return TAG_OK;
173  }
174 
175  int read_tag(rfid_tag *tag) {
176  int status;
177  uint8_t buff[MAXRLEN];
178  //rfid_tag tag;
179  //p_printf(BLUE,"Hold your card for the reader "); // debug "reding card"
180 
181  do {
182  status = detect_tag(&(tag->tag_type), buff);
183 
184  if (status == TAG_NOTAG) { // no card - wait
185  usleep(RFID_READ_INTERVAL);
186  continue;
187  } else if (status != TAG_OK && status != TAG_COLLISION) {
188  // issue with tag reading ?
189  spdlog::debug("rfid_reader.cpp - Issue reading tag, trying again...");
190  usleep(RFID_READ_INTERVAL / 2);
191  continue;
192  }
193 
194  //maybe set buff mem to 0?
195 
196  // read serial number & SAK
197  status = read_tag_serialn(tag->serial, &(tag->serial_size), tag->ser_ack, buff);
198 
199  } while (status != TAG_OK && reading_cards);
200 
201  spdlog::debug("rfid_reader.cpp - Found card");
202 
203  /* determine memory details
204  * but this is very cryptic and hard to exactly discover
205  * SAK = Select acknowledgement has card details in it but still...
206  * nearly mission impossible
207  */
208 
209  tag->max_blocks = 0;
210 
211  switch (tag->tag_type) {
212  case 0x4400:
213 
214  if (tag->ser_ack[0] == 0x0) {
215  spdlog::debug("rfid_reader.cpp - Ultralight card");
216  spdlog::debug("rfid_reader.cpp - NOT supported by this program");
217  } else if (tag->ser_ack[0] == 0x8) {
218  spdlog::debug("rfid_reader.cpp - Mifare Classic(1K) or PLUS card (2K)");
219  spdlog::debug("rfid_reader.cpp - In case of PLUS card, we will only read the first 1K (64 blocks)");
220  tag->max_blocks=64;
221  tag->page_step=1; // increment to read the card
222  } else if (tag->ser_ack[0] == 0x9) {// 20 blocks (5 sectors x 4 blocks) x 16 bytes
223  spdlog::debug("rfid_reader.cpp - Mifare MINI(0.3K)");
224  tag->max_blocks=20;
225  tag->page_step=1; // increment to read the card
226  } else if (tag->ser_ack[0] == 0x18) {
227  spdlog::debug("rfid_reader.cpp - PLUS card (4K)");
228  spdlog::debug("rfid_reader.cpp - Can only access the first 128 blocks (NOT last 8 sectore with 16 blocks)");
229  tag->max_blocks=128;
230  tag->page_step=1; // increment to read the card
231  }
232  break;
233 
234  case 0x0400:
235  if (tag->ser_ack[0] == 0x8) { // 64 blocks of 16 bytes / Ul card
236  spdlog::debug("rfid_reader.cpp - Mifare Classic(1K) or SmartMX with MIFARE 1K emulation");
237  tag->max_blocks=64;
238  tag->page_step=1; // increment to read the card
239  } else if (tag->ser_ack[0] == 0x9) { // 20 blocks (5 sectors x 4 blocks) x 16 bytes
240  spdlog::debug("rfid_reader.cpp - Mifare MINI(0.3K)");
241  tag->max_blocks=20;
242  tag->page_step=1; // increment to read the card
243  }
244  break;
245 
246  case 0x0200:
247  if (tag->ser_ack[0] == 0x18) { // 64 blocks of 16 bytes / Ul card
248  spdlog::debug("rfid_reader.cpp - Mifare Classic(4K) or SmartMX with MIFARE 4K emulation");
249  spdlog::debug("rfid_reader.cpp - Can only access the first 128 blocks (NOT last 8 sectore with 16 blocks)");
250  tag->max_blocks=127;
251  tag->page_step=1; // increment to read the card
252  } else if (tag->ser_ack[0] == 0x9) { // 20 blocks (5 sectors x 4 blocks) x 16 bytes
253  spdlog::debug("rfid_reader.cpp - Mifare MINI(0.3K)");
254  tag->max_blocks=20;
255  tag->page_step=1; // increment to read the card
256  }
257  break;
258  }
259 
260  if (tag->max_blocks == 0) {
261  spdlog::error("rfid_reader.cpp - Read card, BUT card type not known");
262  //PcdHalt();
263  // set card reading loop var to false - stop reading cards?
264  }
265 
266  return status;
267  }
268 
270  void push_event(rfid_tag tag, uint8_t flags) {
271  rfid_event event = {};
272 
273  event.tag = tag;
274  event.flags = flags;
275  event_queue.push(event);
276  }
277 
279  if (event_queue.size() <= 0)
280  return NULL;
281 
282  // probably don't need to lock thread for poll, but better safe than sorry
283  std::lock_guard<std::mutex> eq_guard(eq_mutex);
284 
285  rfid_event* res = &event_queue.front();
286  event_queue.pop();
287 
288  return res;
289  }
290 
292  for (size_t i = 0; i < event_queue.size(); i++) {
293  event_queue.pop();
294  }
295  }
296 }
static std::unique_ptr< app_workspace > & get_instance()
Get the instance app_workspace which is a singleton.
int init(const char *device, uint8_t mode=0, uint32_t speed=1000000, uint16_t delay=0, uint8_t bits_per_word=8)
RFID reader init through values.
Definition: rfid_reader.cpp:25
int init_from_conf()
RFID reader init from loaded configuration.
Definition: rfid_reader.cpp:46
std::unique_ptr< SPI > my_spi
Definition: rfid_reader.cpp:19
std::queue< rfid_event > event_queue
Definition: rfid_reader.cpp:15
char read_tag_serialn(uint8_t *serial, uint8_t *serial_size, uint8_t *ser_ack, uint8_t *buff)
This function reads the serial number of RIFD tag put near the reader.
std::unique_ptr< spi_config_t > spi_config
Definition: rfid_reader.cpp:18
void clean()
Stops the reading thread.
void clear_event_queue()
Clears event queue, discarding all waiting events.
std::mutex eq_mutex
Definition: rfid_reader.cpp:16
int read_tag(rfid_tag *tag)
This function is a loop handling the scanner.
rfid_event * poll_event()
Polls event from RFID event_queue.
char detect_tag(uint16_t *tag_type, uint8_t *buff)
This function detects if a RFID tag was put near the reader.
void print_card_serial(rfid_tag *tag)
Definition: rfid_reader.cpp:67
void start_reading_cards()
Loop that is run in its own thread, reading the RFID reader.
Definition: rfid_reader.cpp:76
bool reading_cards
Definition: rfid_reader.cpp:20
void push_event(rfid_tag tag, uint8_t flags)
char PcdAnticoll(uint8_t cascade, uint8_t *pSnr)
Definition: rc522.cpp:89
void InitRc522(SPI *p_spi)
Definition: rc522.cpp:39
char PcdRequest(uint8_t req_code, uint8_t *pTagType)
Definition: rc522.cpp:47
char PcdSelect(uint8_t cascade, uint8_t *pSnr, uint8_t *SAK)
Definition: rc522.cpp:187
#define TAG_ERR
Definition: rc522.h:127
#define PICC_ANTICOLL3
Definition: rc522.h:51
#define TAG_OK
Definition: rc522.h:125
#define PICC_REQALL
Definition: rc522.h:48
#define MAXRLEN
Definition: rc522.h:64
#define TAG_NOTAG
Definition: rc522.h:126
#define TAG_COLLISION
Definition: rc522.h:129
#define PICC_ANTICOLL2
Definition: rc522.h:50
#define PICC_ANTICOLL1
Definition: rc522.h:49
#define REPEATING_FLAG_DELAY
Definition: rfid_reader.cpp:11
#define RFID_READ_INTERVAL
Definition: rfid_reader.cpp:12
@ RFID_FLAGS_REPEATING
Definition: rfid_reader.h:93
@ RFID_FLAGS_NONE
Definition: rfid_reader.h:92
Structure holding SPI device and SPI config which is a library structure "spi_config_t".
std::unique_ptr< spi_config_t > config
Structure used for RFID event. This structure contains read tag and flags of the event.
Definition: rfid_reader.h:100
rfid_reader::rfid_tag tag
Definition: rfid_reader.h:101
RFID tag structure. Stores data read from SPI.
Definition: rfid_reader.h:12
uint8_t serial[10]
Definition: rfid_reader.h:14