// ST25DV NFC tag driver. The tag holds a single NDEF text record of the form // ",", which get_nugget_data() parses into IDENTIFIER. #include "st25dv.h" #define IDENT_NAME_MAX (sizeof(IDENTIFIER.name_str) - 1) #define IDENT_DIAM_MAX (sizeof(IDENTIFIER.diameter_str) - 1) static void set_identifier(const char* name, uint8_t name_len, const char* diam, uint8_t diam_len) { if (name_len > IDENT_NAME_MAX) { name_len = IDENT_NAME_MAX; } if (diam_len > IDENT_DIAM_MAX) { diam_len = IDENT_DIAM_MAX; } memcpy(IDENTIFIER.name_str, name, name_len); IDENTIFIER.name_str[name_len] = '\0'; IDENTIFIER.name_len = name_len; memcpy(IDENTIFIER.diameter_str, diam, diam_len); IDENTIFIER.diameter_str[diam_len] = '\0'; IDENTIFIER.diameter_len = diam_len; IDENTIFIER.hashed = hash(IDENTIFIER.name_str, 0, 59); } identifier_results get_nugget_data(void) { NDEF_MSG = rfid_read_first_ndef_entry(); // readNDEFText reports parse failures through success; without this check a // missing or malformed tag leaves stale/uninitialised bytes in payload and // we transmit them as the node identity. if (NDEF_MSG.success != 0) { #if DO_UART uart_print_uint8(NDEF_MSG.success, "NDEF parse failed, code "); #endif set_identifier("UNKNOWN", 7, "N/A", 3); return IDENTIFIER; } TRIMMED_STRING = remove_spaces(NDEF_MSG.payload, NDEF_MSG.payload_len); char* delim_ptr = strchr(TRIMMED_STRING.str, ','); if (delim_ptr != NULL) { uint8_t index_comma = (uint8_t)(delim_ptr - TRIMMED_STRING.str); // The diameter is what follows the comma, so its length is the // remainder of the string -- not the whole string's length, which read // off the end of the 21-byte buffer. uint8_t diam_len = (uint8_t)(TRIMMED_STRING.length - index_comma - 1); set_identifier(TRIMMED_STRING.str, index_comma, delim_ptr + 1, diam_len); } else { set_identifier(TRIMMED_STRING.str, (uint8_t)TRIMMED_STRING.length, "N/A", 3); } return IDENTIFIER; } trimmed_string_struct remove_spaces(char* str, uint8_t len_str) { const uint8_t max_len = sizeof(TRIMMED_STRING.str) - 1; uint8_t j = 0; memset(TRIMMED_STRING.str, 0, sizeof(TRIMMED_STRING.str)); for (uint8_t i = 0; (i < len_str) && str[i]; i++) { if ((str[i] != ' ') && (j < max_len)) { TRIMMED_STRING.str[j++] = str[i]; } } // Callers run strchr() over this, so it has to be terminated. TRIMMED_STRING.str[j] = '\0'; TRIMMED_STRING.length = j; return TRIMMED_STRING; } // LPD pin: high puts the tag's I2C interface into low-power mode void rfid_set_low_power_down(bool state) { SET_PIN_OUT(DDRD, DDD5); SET_PIN_TO(PORTD, PD5, state); } ndef_message rfid_read_first_ndef_entry(void) { rfid_set_low_power_down(false); rfid_set_i2c_power(true); _delay_ms(1); // static: a 65-byte frame here sat on top of an already deep call chain and // was a large part of the stack overrun. static unsigned char DATA_BUFFER_INTERNAL[NDEF_READ_LEN]; memset(DATA_BUFFER_INTERNAL, 0, sizeof(DATA_BUFFER_INTERNAL)); rfid_read_memory(DATA_BUFFER_INTERNAL, NDEF_READ_LEN, 0x0000 + 4); NDEF_MSG = readNDEFText(DATA_BUFFER_INTERNAL, NDEF_READ_LEN); rfid_set_low_power_down(true); rfid_set_i2c_power(false); return NDEF_MSG; } uint8_t rfid_read_system_register(void) { return read_one_byte_16bit_addr_no_err_register(I2C_SYSTEM_ADDR, 0x0000); } // Switched supply for the tag's I2C side void rfid_set_i2c_power(bool state) { SET_PIN_OUT(DDRE, DDE0); SET_PIN_TO(PORTE, PE0, state); } uint8_t rfid_read_memory(uint8_t* data, uint8_t num_bytes, uint16_t address) { return read_n_bytes_16bit_addr(I2C_USER_ADDR, address, data, num_bytes); }