bbdcc1e623
- main.c: file-header comment describing the hardware and operation, logic split into named phases (sleep_until_interrupt, wake_peripheral_rails, take_counts_snapshot, send_wheel_counts_report, handle_minute_alarm, init_all_hardware); shared state renamed to say what it is and made static. - rfm69.c: reorganized into six labeled sections; cond_1/2/3 and hash scratch globals replaced by a reply_acknowledges() helper with clear locals; packet layout and every init register write documented. - LOG() macro (compiled out when DO_UART is off) replaces the #if DO_UART blocks that obscured the logic. - Drivers: file-header comments; named RTC_REG_*/RTC_ALM_MASK_BIT constants; EEPROM spool scheme documented; ADC_CHANNEL_BANDGAP named; repeated pin if/else helpers collapsed to SET_PIN_TO(). - Removed unused globals/buffers and commented-out code; ran clang-format with the project style. Register writes and radio protocol are byte-identical. Builds clean under -Wall -Wextra on gnu17 and c23; flash 13028 -> 12830 B, static RAM 1038 -> 999 B. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YVJKatfeMJjAmuH9KYiLuv
121 lines
3.8 KiB
C
121 lines
3.8 KiB
C
// ST25DV NFC tag driver. The tag holds a single NDEF text record of the form
|
|
// "<name>,<wheel diameter>", 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);
|
|
}
|