SP8EBC-ParaTNC/src/backup_registers.c

713 wiersze
14 KiB
C

/*
* backup_registers.cpp
*
* Created on: Oct 19, 2023
* Author: mateusz
*/
#include "backup_registers.h"
#include "variant.h"
#ifdef STM32L471xx
#define REGISTER RTC->BKP0R
#define REGISTER_LAST_SLEEP RTC->BKP1R
#define REGISTER_LAST_WKUP RTC->BKP2R
#define REGISTER_COUNTERS RTC->BKP4R
#define REGISTER_LAST_SLTIM RTC->BKP6R
#define REGISTER_PACKET_COUNTERS RTC->BKP7R
#define REGISTER_RESET_CHECK_FAIL RTC->BKP8R
#define REGISTER_ASSERT RTC->BKP9R
#endif
#define BACKUP_REG_INHIBIT_PWR_SWITCH_PERIODIC_H 1u
#define BACKUP_REG_ALL_PWRSAVE_STATES_BITMASK (0xFFu << 2)
// backup registers (ParaTNC)
// 0 ->
// 2 -> boot and hard fault count
// 3 -> controller configuration status
// 4 -> telemetry counter
// 5 ->
// 6 -> weather counters
// backup registers (ParaMETEO)
// 0 -> powersave status
// 1 -> last sleep rtc time
// 2 -> last wakeup rtc time
// 3 -> controller configuration status
// 4 -> wakeup events MSB, sleep events LSB
// 5 -> monitor
// 6 -> last sleep time
// 7 -> weather and telemetry timers & counters
// 8 -> counters of resets caused by validation checks failures
// 9 -> assert register
// 7th register map
// xxxxyyAA - telemetry frames counter
// xxxxyAyy - value of packet_tx_meteo_counter limited to 15
// xxxxAyyy - value of packet_tx_meteo_gsm_counter limited to 15
// xxAAyyyy - value of packet_tx_beacon_counter
// Axxxyyyy - checksum
// 8th register map
// xxxxyyAA - resets caused by 'aprsis_check_connection_attempt_alive()'
// xxxxAAyy - resets caused by 'rte_wx_check_weather_measurements()'
// xxAAyyyy - resets caused by value of 'rte_wx_dallas_degraded_counter'
// AAxxyyyy - resets caused by 'system_is_rtc_ok()'
static void backup_reg_unclock(void) {
// enable access to backup domain
PWR->CR1 |= PWR_CR1_DBP;
}
static void backup_reg_lock(void) {
PWR->CR1 &= (0xFFFFFFFFu ^ PWR_CR1_DBP);
}
/**
* Calculates checksum from register content
* @param reg
* @return
*/
inline static uint8_t backup_reg_calculate_checksum(uint32_t reg) {
uint8_t out = 0u;
uint32_t temp = 0u;
temp += (reg & 0xFu);
temp += ((reg & 0xF0u) >> 4);
temp += ((reg & 0xF00u) >> 8);
temp += ((reg & 0xF000u) >> 12);
temp += ((reg & 0xF0000u) >> 16);
temp += ((reg & 0xF00000u) >> 20);
temp += ((reg & 0xF000000u) >> 24);
temp = ~temp;
out = (temp & 0xFu);
return out;
}
inline static uint8_t backup_reg_get_checksum(uint32_t reg) {
uint8_t out = 0u;
out = ((reg & 0xF0000000u) >> 28);
return out;
}
inline static void backup_reg_set_checksum(volatile uint32_t * reg, const uint8_t checksum) {
if (variant_validate_is_within_ram((void*)reg) != 0) {
// clear existing checksum
(*reg) &= (0xFFFFFFFF ^ 0xF0000000);
// store new checksum
(*reg) |= ((checksum & 0xF) << 28);
}
}
/**
* Get the value of a register keeping a status which configuration
* sector is valid, and which is loaded
* @return
*/
uint32_t backup_reg_get_configuration(void) {
uint32_t out = 0;
#ifdef PARATNC
out = BKP->DR3;
#endif
#ifdef PARAMETEO
out = RTC->BKP3R;
#endif
return out;
}
/**
* Set a register, which contains an information which configuration sector
* is valid, and which one has been loaded. It is mostly used to reset
* the register back to zero.
* @param value
*/
void backup_reg_set_configuration(uint32_t value) {
backup_reg_unclock();
#ifdef PARATNC
BKP->DR3 = value;
#endif
#ifdef PARAMETEO
RTC->BKP3R = value;
#endif
backup_reg_lock();
}
/**
* Set certain bit in the register containing current configuration state.
* This is used to store a state of all configuration sectors.
* @param value
*/
void backup_reg_set_bits_configuration(uint32_t value) {
#ifdef PARATNC
BKP->DR3 |= value;
#endif
#ifdef PARAMETEO
// enable access to backup domain
backup_reg_unclock();
RTC->BKP3R |= value;
backup_reg_lock();
#endif
}
/**
* Clears certain bit in the register containing current configuration state.
* This is used to keep information that CRC checksum of a sector is no longer
* valid.
* @param value
*/
void backup_reg_clear_bits_configuration(uint32_t value) {
// enable access to backup domain
backup_reg_unclock();
#ifdef PARATNC
BKP->DR3 &= (0xFFFF ^ value);
#endif
#ifdef PARAMETEO
RTC->BKP3R &= (0xFFFFFFFFu ^ value);
#endif
backup_reg_lock();
}
/**
* Resets all powersave mode flags.
*/
void backup_reg_reset_all_powersave_states(void) {
backup_reg_unclock();
#ifdef PARAMETEO
REGISTER &= 0xFFFFFFFFu ^ BACKUP_REG_ALL_PWRSAVE_STATES_BITMASK;
#endif
backup_reg_lock();
}
/**
* Checks if controller is currently in given powersave mode using
* information from dedicated backup register
* @param state
* @return one if controller is in given powersave state
*/
int backup_reg_is_in_powersave_state(uint32_t state) {
int out = 0;
#ifdef PARAMETEO
if ((REGISTER & BACKUP_REG_ALL_PWRSAVE_STATES_BITMASK) == state) {
out = 1;
}
#endif
return out;
}
/**
* Set that controller is currently in given powersave state, it should be
* used along with \link #backup_reg_reset_all_powersave_states
* @param state
*/
void backup_reg_set_powersave_state(uint32_t state) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER |= state;
backup_reg_lock();
#endif
}
/**
* Returns current powersave state
* @return
*/
uint16_t backup_reg_get_powersave_state(void) {
int out = 0;
#ifdef PARAMETEO
out = (uint16_t)(REGISTER & BACKUP_REG_ALL_PWRSAVE_STATES_BITMASK);
#endif
return out;
}
/**
* Return counter value with current number of wakeup events
* @return
*/
uint32_t backup_reg_get_wakeup_counter(void) {
uint32_t out = 0;
#ifdef PARAMETEO
out = (uint32_t)((REGISTER_COUNTERS & 0xFFFF0000u) >> 16);
#endif
return out;
}
/**
* Set current value of wakeup events
* @param in
*/
void backup_reg_set_wakeup_counter(uint32_t in) {
backup_reg_unclock();
#ifdef PARAMETEO
REGISTER_COUNTERS = (REGISTER_COUNTERS & 0x0000FFFFu) | ((in & 0xFFFFu) << 16);
#endif
backup_reg_lock();
}
/**
* Return counter value with current number of sleep events
* @return
*/
uint32_t backup_reg_get_sleep_counter(void) {
uint32_t out = 0;
#ifdef PARAMETEO
out = (uint16_t)(REGISTER_COUNTERS & 0xFFFFu);
#endif
return out;
}
/**
* Set current value of sleep events
* @param in
*/
void backup_reg_set_sleep_counter(uint32_t in) {
backup_reg_unclock();
#ifdef PARAMETEO
REGISTER_COUNTERS = (REGISTER_COUNTERS & 0xFFFF0000u) | (uint16_t)(in & 0xFFFFu);
#endif
backup_reg_lock();
}
/**
* Returns a timestamp of last sleep event
*/
uint32_t backup_reg_get_last_sleep_timestamp(void) {
uint32_t out = 0;
#ifdef PARAMETEO
out = REGISTER_LAST_SLEEP;
#endif
return out;
}
/**
* Stores a timestamp of a sleep event from current RTC time
*/
void backup_reg_set_last_sleep_timestamp(void) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER_LAST_SLEEP = RTC->TR;
backup_reg_lock();
#endif
}
/**
* Disables an inhibition of VBATT_S switching, when controller is in
* powersave mode in which weather sensors shall be kept powered down.
*/
void backup_reg_reset_inhibit_periodic_pwr_switch(void) {
backup_reg_unclock();
#ifdef PARAMETEO
REGISTER &= 0xFFFFFFFFu ^ BACKUP_REG_INHIBIT_PWR_SWITCH_PERIODIC_H;
#endif
backup_reg_lock();
}
/**
* Enables an inhibition of VBATT_S switching, when controller is in
* powersave mode in which weather sensors shall be kept powered down.
*/
void backup_reg_inhibit_periodic_pwr_switch(void) {
backup_reg_unclock();
#ifdef PARAMETEO
REGISTER |= BACKUP_REG_INHIBIT_PWR_SWITCH_PERIODIC_H;
#endif
backup_reg_lock();
}
/**
* Returns if VBATT_S switching inhibition is currently enabled
* @return
*/
uint32_t backup_reg_is_periodic_pwr_switch_inhibited(void) {
int out = 0;
#ifdef PARAMETEO
if ((REGISTER & BACKUP_REG_INHIBIT_PWR_SWITCH_PERIODIC_H) != 0) {
out = 1u;
}
#endif
return out;
}
/**
* gets last wakeup timestamp
* @return
*/
uint32_t backup_reg_get_last_wakeup_timestamp(void) {
uint32_t out = 0;
#ifdef PARAMETEO
out = REGISTER_LAST_WKUP;
#endif
return out;
}
/**
* Stores a timestamp of a wakeup event from current RTC time
*/
void backup_reg_set_last_wakeup_timestamp(void) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER_LAST_WKUP = RTC->TR;
backup_reg_lock();
#endif
}
/**
*
* @return
*/
uint32_t backup_reg_get_last_sleep_duration(void) {
uint32_t out = 0;
#ifdef PARAMETEO
out = REGISTER_LAST_SLTIM;
#endif
return out;
}
/**
*
* @param in
*/
void backup_reg_set_last_sleep_duration(uint32_t in) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER_LAST_SLTIM = in;
backup_reg_lock();
#endif
}
/**
* Set register containing packet counters, used when a configuration
* is reset to default
*/
void backup_reg_reset_counters(void) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER_PACKET_COUNTERS = 0u;
backup_reg_lock();
#endif
}
/**
* Gets last telemetry frames counter stored in backup registers
* @return last telemetry counter or zero if backup registers contains crap
*/
uint8_t backup_reg_get_telemetry(void) {
uint8_t out = 0u;
#ifdef PARAMETEO
uint32_t reg_value = REGISTER_PACKET_COUNTERS;
// calculate checksum from register value
uint8_t calculated_checksum = backup_reg_calculate_checksum(reg_value);
uint8_t checksum_from_reg = backup_reg_get_checksum(reg_value);
// check if checksum is ok
if (calculated_checksum == checksum_from_reg) {
out = (uint8_t)(reg_value & 0xFFu);
}
else {
; // return zero if checksum is wrong
}
#endif
return out;
}
/**
*
*/
void backup_reg_set_telemetry(uint16_t in) {
backup_reg_unclock();
if (in > 255) {
in = 0;
}
const uint8_t narrowed_in = (uint8_t)(in & 0xFFu);
#ifdef PARAMETEO
// get current value
uint32_t reg_value = REGISTER_PACKET_COUNTERS;
// clear current telemetry counter using the bitmask
reg_value &= (0xFFFFFFFFu ^ 0xFFu);
// store updated value
reg_value |= narrowed_in;
// recalculate checksum
const uint8_t new_checksum = backup_reg_calculate_checksum(reg_value);
// store new checksum
backup_reg_set_checksum(&reg_value, new_checksum);
REGISTER_PACKET_COUNTERS = reg_value;
#endif
backup_reg_lock();
}
/**
*
* @param beacon_counter
* @param meteo_counter
* @param meteo_gsm_counter
*/
void backup_reg_get_packet_counters(uint8_t * beacon_counter, uint8_t * meteo_counter, uint8_t * meteo_gsm_counter) {
#ifdef PARAMETEO
uint32_t reg_value = REGISTER_PACKET_COUNTERS;
// calculate checksum from register value
uint8_t calculated_checksum = backup_reg_calculate_checksum(reg_value);
uint8_t checksum_from_reg = backup_reg_get_checksum(reg_value);
// check if checksum is ok
if (calculated_checksum == checksum_from_reg) {
*meteo_counter = ((reg_value & 0x00000F00u) >> 8);
*meteo_gsm_counter = ((reg_value & 0x0000F000u) >> 12);
*beacon_counter = ((reg_value & 0x00FF0000u) >> 16);
}
else {
// if it is not ok revert to default values
*beacon_counter = 0u;
*meteo_counter = 2u;
*meteo_gsm_counter = 0u;
// and save it back into backup register
backup_reg_set_packet_counters(*beacon_counter, *meteo_counter, *meteo_gsm_counter);
}
#endif
}
/**
*
* @param beacon_counter
* @param meteo_counter
* @param meteo_gsm_counter
*/
void backup_reg_set_packet_counters(uint8_t beacon_counter, uint8_t meteo_counter, uint8_t meteo_gsm_counter) {
#ifdef PARAMETEO
volatile uint32_t reg_value = REGISTER_PACKET_COUNTERS;
// clear existing content
reg_value &= (0xFFFFFFFFu ^ 0x00FFFF00u);
// check if meteo_counter doesn't overflow
if (meteo_counter > 15) {
meteo_counter = 15;
}
if (meteo_gsm_counter > 15) {
meteo_gsm_counter = 15;
}
// put new values
reg_value |= ((beacon_counter << 16) | (meteo_gsm_counter << 12) | (meteo_counter << 8));
// calculate new checksum
const uint8_t new_checksum = backup_reg_calculate_checksum(reg_value);
// put new checksum value
backup_reg_set_checksum(&reg_value, new_checksum);
backup_reg_unclock();
REGISTER_PACKET_COUNTERS = reg_value;
backup_reg_lock();
#endif
}
void backup_reg_increment_aprsis_check_reset(void) {
#ifdef PARAMETEO
// REGISTER_RESET_CHECK_FAIL
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
// get existing value
uint8_t counter = (uint8_t)(reg_value & 0xFFU);
// increment it
counter++;
// clear existing value from register
reg_value &= 0xFFFFFF00U;
// add incremented counter value
reg_value |= counter;
backup_reg_unclock();
REGISTER_RESET_CHECK_FAIL = reg_value;
backup_reg_lock();
#endif
}
void backup_reg_increment_weather_measurements_check_reset(void) {
#ifdef PARAMETEO
// REGISTER_RESET_CHECK_FAIL
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
// get existing value
uint8_t counter = (uint8_t)((reg_value & 0xFF00U) >> 8U);
// increment it
counter++;
// clear existing value from register
reg_value &= 0xFFFF00FFU;
// add incremented counter value
reg_value |= ((uint32_t)counter << 8U);
backup_reg_unclock();
REGISTER_RESET_CHECK_FAIL = reg_value;
backup_reg_lock();
#endif
}
void backup_reg_increment_dallas_degraded_reset(void) {
#ifdef PARAMETEO
// REGISTER_RESET_CHECK_FAIL
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
// get existing value
uint8_t counter = (uint8_t)((reg_value & 0xFF0000U) >> 16U);
// increment it
counter++;
// clear existing value from register
reg_value &= 0xFF00FFFFU;
// add incremented counter value
reg_value |= ((uint32_t)counter << 16U);
backup_reg_unclock();
REGISTER_RESET_CHECK_FAIL = reg_value;
backup_reg_lock();
#endif
}
void backup_reg_increment_is_rtc_ok_check_reset(void) {
#ifdef PARAMETEO
// REGISTER_RESET_CHECK_FAIL
volatile uint32_t reg_value = REGISTER_RESET_CHECK_FAIL;
// get existing value
uint8_t counter = (uint8_t)((reg_value & 0xFF000000U) >> 24U);
// increment it
counter++;
// clear existing value from register
reg_value &= 0x00FFFFFFU;
// add incremented counter value
reg_value |= ((uint32_t)counter << 24U);
backup_reg_unclock();
REGISTER_RESET_CHECK_FAIL = reg_value;
backup_reg_lock();
#endif
}
void backup_assert(uint32_t assert) {
#ifdef PARAMETEO
backup_reg_unclock();
REGISTER_ASSERT |= assert;
backup_reg_lock();
NVIC_SystemReset();
#endif
}