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
162 lines
4.1 KiB
C
162 lines
4.1 KiB
C
// M95128 SPI EEPROM used as a LIFO spool for unacknowledged radio packets.
|
|
//
|
|
// Page 0, byte 0: depth of the spool (the highest page currently in use;
|
|
// 0 means empty)
|
|
// Pages 1..N: one 64-byte packet each -- 60 msg bytes followed by
|
|
// flags, from, to, dtype
|
|
//
|
|
// write_struct_to_last_page() pushes, read_struct_last_page() peeks, and
|
|
// delete_last_page() pops.
|
|
|
|
#include "m95128.h"
|
|
|
|
uint8_t read_value;
|
|
// EEPROM chip select (PB0, active low)
|
|
void spi_eeprom_select(bool state)
|
|
{
|
|
SET_PIN_OUT(DDRB, DDB0);
|
|
SET_PIN_TO(PORTB, PB0, !state);
|
|
}
|
|
|
|
void eeprom_write(uint8_t page, unsigned const char* msg, uint8_t msg_len)
|
|
{
|
|
spi_rfm69_select(false);
|
|
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_WREN);
|
|
spi_eeprom_select(false);
|
|
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_WRITE);
|
|
write_page_address(page);
|
|
|
|
for (int i = 0; i < msg_len; i++) {
|
|
spi_write(msg[i]);
|
|
}
|
|
|
|
spi_eeprom_select(false);
|
|
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_WRDI);
|
|
spi_eeprom_select(false);
|
|
|
|
// Poll the write-in-progress bit, but give up rather than spin forever if
|
|
// the EEPROM is unpowered or absent.
|
|
for (uint16_t attempts = 0; attempts < EEPROM_POLL_TIMEOUT_MS; attempts++) {
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_RDSR);
|
|
read_value = spi_read();
|
|
spi_eeprom_select(false);
|
|
if ((read_value & EEPROM_STATUS_WIP) == 0) {
|
|
return;
|
|
}
|
|
_delay_ms(1);
|
|
}
|
|
}
|
|
|
|
void eeprom_read(uint8_t page, unsigned char* msg, uint8_t msg_len)
|
|
{
|
|
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_WRDI);
|
|
spi_eeprom_select(false);
|
|
|
|
spi_eeprom_select(true);
|
|
spi_write(EEPROM_READ);
|
|
write_page_address(page);
|
|
|
|
for (int i = 0; i < msg_len; i++) {
|
|
msg[i] = spi_read();
|
|
}
|
|
spi_eeprom_select(false);
|
|
}
|
|
|
|
void delete_last_page(void)
|
|
{
|
|
uint8_t old_last_page = get_last_page();
|
|
if (old_last_page == 0) // If we have nothing, no need to delete anything
|
|
{
|
|
return;
|
|
}
|
|
write_last_page_value(old_last_page - 1);
|
|
eeprom_clear_page(old_last_page);
|
|
}
|
|
|
|
uint8_t get_last_page(void)
|
|
{
|
|
memset(DATA_BUFFER_65, 0, 1);
|
|
eeprom_read(0, DATA_BUFFER_65, 1);
|
|
return (uint8_t)DATA_BUFFER_65[0];
|
|
}
|
|
|
|
void write_last_page_value(uint8_t page)
|
|
{
|
|
DATA_BUFFER_7[0] = page;
|
|
eeprom_write(0, DATA_BUFFER_7, 1);
|
|
}
|
|
|
|
void write_page_address(uint8_t page)
|
|
{
|
|
uint16_t addr = page * 0x40; // Each page starts at 64 byte intervals. And 64 byte is 0x40 or
|
|
// 0b01000000;
|
|
spi_write((addr >> 8) & 0xFF);
|
|
spi_write(addr & 0xFF);
|
|
}
|
|
|
|
void eeprom_write_tx_data(uint8_t page, tx_rx_data_struct tx_data_in)
|
|
{
|
|
if (page == 0) {
|
|
return;
|
|
}
|
|
memset(DATA_BUFFER_65, ' ', 64);
|
|
DATA_BUFFER_65[64] = '\0';
|
|
memcpy(DATA_BUFFER_65, tx_data_in.msg, 60);
|
|
DATA_BUFFER_65[60] = tx_data_in.flags;
|
|
DATA_BUFFER_65[61] = tx_data_in.from;
|
|
DATA_BUFFER_65[62] = tx_data_in.to;
|
|
DATA_BUFFER_65[63] = tx_data_in.dtype;
|
|
|
|
eeprom_write(page, DATA_BUFFER_65, 64);
|
|
}
|
|
|
|
tx_rx_data_struct eeprom_read_tx_data(uint8_t page)
|
|
{
|
|
reset_txrx_struct(&TX_DATA);
|
|
memset(DATA_BUFFER_65, ' ', 64);
|
|
DATA_BUFFER_65[64] = '\0';
|
|
eeprom_read(page, DATA_BUFFER_65, 64);
|
|
memcpy(TX_DATA.msg, DATA_BUFFER_65, 60);
|
|
TX_DATA.flags = DATA_BUFFER_65[60];
|
|
TX_DATA.from = DATA_BUFFER_65[61];
|
|
TX_DATA.to = DATA_BUFFER_65[62];
|
|
TX_DATA.dtype = DATA_BUFFER_65[63];
|
|
TX_DATA.len = 60;
|
|
return TX_DATA;
|
|
}
|
|
|
|
tx_rx_data_struct read_struct_last_page(void)
|
|
{
|
|
uint8_t page_num = get_last_page();
|
|
return eeprom_read_tx_data(page_num);
|
|
}
|
|
|
|
void write_struct_to_last_page(tx_rx_data_struct tx_data_in)
|
|
{
|
|
uint8_t page_val = get_last_page();
|
|
uint8_t next_page_val;
|
|
if (page_val == 255) {
|
|
next_page_val = 1;
|
|
} else {
|
|
next_page_val = page_val + 1;
|
|
}
|
|
|
|
eeprom_write_tx_data(next_page_val, tx_data_in);
|
|
write_last_page_value(next_page_val);
|
|
}
|
|
|
|
void eeprom_clear_page(uint8_t page)
|
|
{
|
|
memset(DATA_BUFFER_65, ' ', 64);
|
|
eeprom_write(page, DATA_BUFFER_65, 64);
|
|
}
|