Files
wheel_rfm69_counter/avr_code/st25dv.c
T
thebears bbdcc1e623 Refactor firmware for clarity; no functional changes
- 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
2026-08-31 23:04:00 -04:00

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);
}