fixes
This commit is contained in:
+73
-22
@@ -52,6 +52,17 @@
|
||||
// Erased EEPROM reads back as 0xFF; anything else is a real spool depth.
|
||||
#define EEPROM_LAST_PAGE_UNINIT 0xFF
|
||||
|
||||
// The NFC identity is cached; re-read the tag every 4th send (~1 h), so a
|
||||
// renamed nugget still takes effect without a reset.
|
||||
#define TAG_REREAD_SEND_CYCLES 4
|
||||
|
||||
// Re-request the time daily even when the RTC is running, to bound its drift.
|
||||
#define TIME_RESYNC_SEND_CYCLES 96 // 96 x 15 min = 24 h
|
||||
|
||||
// How many spooled packets one successful cycle may retry, so a huge backlog
|
||||
// cannot keep the node awake for minutes.
|
||||
#define SPOOL_DRAIN_MAX 10
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// State shared with the interrupt handlers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -63,6 +74,8 @@ static volatile uint16_t wheel_counts[WHEEL_COUNT_SLOTS]; // Revolutions per min
|
||||
|
||||
// Whether we ever got a valid timestamp from the base station
|
||||
static RTC_RFM69_STATUS time_sync_status;
|
||||
static uint8_t sends_since_tag_read = 0;
|
||||
static uint8_t sends_since_time_sync = 0;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Interrupt handlers
|
||||
@@ -155,16 +168,33 @@ static void wake_peripheral_rails(void)
|
||||
// Measurement helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Battery level via the internal 1.1 V bandgap: the first conversions after
|
||||
// enabling the ADC read low, so take three and keep the last.
|
||||
static uint16_t read_battery_level(void)
|
||||
// Battery voltage in millivolts, measured by reading the 1.1 V internal
|
||||
// bandgap against the AVcc (battery) reference: Vcc = 1100 mV * 1023 / raw.
|
||||
// The first conversions after enabling the ADC read low, so take three and
|
||||
// keep the last. Returns 0 when the ADC fails, which the base station can
|
||||
// recognise as "no reading".
|
||||
static uint16_t read_battery_millivolts(void)
|
||||
{
|
||||
adc_Enable();
|
||||
adc_GetConversion(ADC_CHANNEL_BANDGAP);
|
||||
adc_GetConversion(ADC_CHANNEL_BANDGAP);
|
||||
uint16_t level = adc_GetConversion(ADC_CHANNEL_BANDGAP);
|
||||
uint16_t raw = adc_GetConversion(ADC_CHANNEL_BANDGAP);
|
||||
adc_Disable();
|
||||
return level;
|
||||
|
||||
if (raw == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (uint16_t)((1100UL * 1023UL) / raw);
|
||||
}
|
||||
|
||||
// Spread nodes out: a name-hash-derived delay (0-236 ms) before transmitting
|
||||
// keeps two nodes that woke on the same RTC second from colliding on every
|
||||
// single cycle.
|
||||
static void tx_backoff_delay(void)
|
||||
{
|
||||
for (uint8_t i = 0; i < IDENTIFIER.hashed; i++) {
|
||||
_delay_ms(4);
|
||||
}
|
||||
}
|
||||
|
||||
// Atomically hand out the collected counts and start the next collection
|
||||
@@ -186,19 +216,30 @@ static void take_counts_snapshot(uint16_t snapshot[WHEEL_COUNT_SLOTS])
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Build and send the periodic counts packet. Unacknowledged packets go to the
|
||||
// EEPROM spool; each acknowledged one buys a retry of one spooled packet.
|
||||
// EEPROM spool; each acknowledged send buys retries of spooled packets.
|
||||
static void send_wheel_counts_report(void)
|
||||
{
|
||||
rfm69_init();
|
||||
rfid_set_low_power_down(false);
|
||||
_delay_ms(1);
|
||||
|
||||
// Re-read the tag each period so a renamed nugget takes effect without a
|
||||
// reset.
|
||||
IDENTIFIER = get_nugget_data();
|
||||
// Reading the tag costs an I2C transaction and a tag power-up, so use the
|
||||
// cached identity and only re-read about once an hour -- or immediately, if
|
||||
// the last read failed to parse.
|
||||
sends_since_tag_read++;
|
||||
if ((sends_since_tag_read >= TAG_REREAD_SEND_CYCLES) || (NDEF_MSG.success != 0)) {
|
||||
IDENTIFIER = get_nugget_data();
|
||||
sends_since_tag_read = 0;
|
||||
}
|
||||
|
||||
if (time_sync_status == RTC_RFM69_SET_TIME_FAILED) {
|
||||
// Sync time when we never got it, and re-sync daily to bound RTC drift.
|
||||
if (sends_since_time_sync < 255) {
|
||||
sends_since_time_sync++;
|
||||
}
|
||||
if ((time_sync_status == RTC_RFM69_SET_TIME_FAILED)
|
||||
|| (sends_since_time_sync >= TIME_RESYNC_SEND_CYCLES)) {
|
||||
time_sync_status = set_time_from_rfm69(IDENTIFIER);
|
||||
if (time_sync_status == RTC_RFM69_SET_TIME_SUCCESS) {
|
||||
sends_since_time_sync = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t counts_snapshot[WHEEL_COUNT_SLOTS];
|
||||
@@ -206,12 +247,13 @@ static void send_wheel_counts_report(void)
|
||||
|
||||
reset_txrx_struct(&TX_DATA);
|
||||
TX_DATA = generate_wheel_counts_message(
|
||||
IDENTIFIER, rtc_read_time(), read_battery_level(), counts_snapshot);
|
||||
IDENTIFIER, rtc_read_time(), read_battery_millivolts(), counts_snapshot);
|
||||
LOG("TX DATA Sent\n");
|
||||
#if DO_UART
|
||||
uart_print_tx_rx_data(TX_DATA);
|
||||
#endif
|
||||
|
||||
tx_backoff_delay();
|
||||
DATA_SEND_STATUS result = send_message(TX_DATA);
|
||||
if (result == DATA_NOT_SENT) {
|
||||
LOG(" TX DATA not sent, writing to SPI\n");
|
||||
@@ -219,14 +261,16 @@ static void send_wheel_counts_report(void)
|
||||
return;
|
||||
}
|
||||
|
||||
// The base station is listening -- use the chance to drain one packet from
|
||||
// the spool.
|
||||
if (get_last_page() > 0) {
|
||||
// The base station is listening -- drain the spool while sends keep
|
||||
// succeeding, capped at SPOOL_DRAIN_MAX per cycle. At one per cycle a long
|
||||
// outage took days to catch up.
|
||||
for (uint8_t drained = 0; (drained < SPOOL_DRAIN_MAX) && (get_last_page() > 0); drained++) {
|
||||
reset_txrx_struct(&TX_DATA);
|
||||
TX_DATA = read_struct_last_page();
|
||||
TX_DATA.flags = MSG_RESENT_COUNTS;
|
||||
_delay_ms(250);
|
||||
|
||||
tx_backoff_delay();
|
||||
result = send_message(TX_DATA);
|
||||
LOG("TX DATA From SPI Memory\n");
|
||||
#if DO_UART
|
||||
@@ -235,11 +279,11 @@ static void send_wheel_counts_report(void)
|
||||
|
||||
// Only drop the spooled page once it is actually acknowledged;
|
||||
// deleting on failure would lose the data.
|
||||
if (result == DATA_SEND_SUCCESS) {
|
||||
delete_last_page();
|
||||
} else {
|
||||
if (result != DATA_SEND_SUCCESS) {
|
||||
LOG(" SPI not sent\n");
|
||||
break;
|
||||
}
|
||||
delete_last_page();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,6 +335,10 @@ static void init_all_hardware(void)
|
||||
init_spi();
|
||||
adc_Initialize();
|
||||
|
||||
// Gate the clocks of everything unused; adc_Enable() lifts the ADC's gate
|
||||
// for the duration of each battery reading.
|
||||
shutdown_all_peripherals();
|
||||
|
||||
set_up_reed_interrupt();
|
||||
set_up_minute_interrupt();
|
||||
LOG("Set up AVR interrupts\n");
|
||||
@@ -348,10 +396,13 @@ int main(void)
|
||||
// Ask the base station for the current time and load it into the RTC
|
||||
time_sync_status = set_time_from_rfm69(IDENTIFIER);
|
||||
blink_time_sync_result(time_sync_status == RTC_RFM69_SET_TIME_SUCCESS);
|
||||
LOG(time_sync_status == RTC_RFM69_SET_TIME_SUCCESS ? "Success in get time \n"
|
||||
: "Failed to get time \n");
|
||||
if (time_sync_status == RTC_RFM69_SET_TIME_SUCCESS) {
|
||||
LOG("Success in get time \n");
|
||||
} else {
|
||||
LOG("Failed to get time \n");
|
||||
}
|
||||
|
||||
read_battery_level(); // Throwaway read to settle the ADC path
|
||||
read_battery_millivolts(); // Throwaway read to settle the ADC path
|
||||
|
||||
while (1) {
|
||||
sleep_until_interrupt();
|
||||
|
||||
Reference in New Issue
Block a user