@@ -1,56 +1,181 @@
/**
* @file config.cpp
* @brief Implementation of EEPROM and configuration-related functions .
* @brief EEPROM handling and configuration storage for the ChainLube firmware .
*
* This file contains functions for managing EEPROM storage and handling configuration data.
* It includes the definitions of configuration structures, EEPROM access, and utility functions.
* Responsibilities:
* - Bring-up of the external I²C EEPROM
* - Robust availability checks with optional bus recovery
* - Central processing of EEPROM requests (save/load/format/move page)
* - CRC32 utilities and debug dump helpers
*
* Design notes:
* - The device boots with sane in-RAM defaults so the system stays operable
* even when EEPROM is missing. Actual lube execution is gated by DTCs elsewhere.
* - The DTC DTC_NO_EEPROM_FOUND is set/cleared only in EEPROM_Process(), never here ad-hoc.
* - Background recovery is non-blocking and driven by millis().
*/
# include <Arduino.h>
# include <Wire.h>
# include "config.h"
# include "debugger.h"
# include "globals.h"
// Instance of I2C_eeprom for EEPROM access
// Recovery edge flag: set when availability changes 0 -> 1
static bool eeRecoveredOnce = false ;
// Non-blocking retry scheduling
static uint32_t eeNextTryMs = 0 ;
static uint32_t eeRetryIntervalMs = 2000 ; // ms between background attempts
// I²C EEPROM instance
I2C_eeprom ee ( 0x50 , EEPROM_SIZE_BYTES ) ;
// Configuration and persistence data structures
// Configuration and persistence data
LubeConfig_t LubeConfig ;
persistenceData_t PersistenceData ;
// EEPROM version identifier
const uint16_t eeVersion = EEPROM_STRUCTURE_REVISION ;
// EEPROM structure version (bumped when layout changes)
const uint16_t eeVersion = EEPROM_STRUCTURE_REVISION ;
// Flag indicating whether EEPROM is available
boolean eeAvailable = false ;
// Latched availability flag
static bool eeAvailable = false ;
// Offsets within EEPROM for LubeConfig and PersistenceData
// EEPROM layout offsets
const uint16_t startofLubeConfig = 16 ;
const uint16_t startofPersistence = 16 + sizeof ( LubeConfig ) + ( sizeof ( LubeConfig ) % 16 ) ;
// Function prototype to check EEPROM availability
boolean check EEPROMa vailable( ) ;
// availability probe
bool EEPROM_A vailable( bool recover = false , uint8_t attempts = 3 , uint16_t delay_ms = 25 ) ;
// Robust EEPROM handling (internal helpers)
void I2C_BusReset ( ) ;
bool TryRecoverEEPROM ( uint8_t attempts = 5 , uint16_t delay_ms = 50 ) ;
/**
* @brief Initializes EEPROM and checks its availability .
* @brief Initialize I²C and EEPROM driver, load in-RAM defaults .
*
* This function initializes the EEPROM using the I2C_eeprom instance and checks if it's available .
* Loads defaults into RAM to keep the application operational .
* Availability is checked but no DTC is set here—EEPROM_Process() is the single place
* that sets/clears DTC_NO_EEPROM_FOUND.
*/
void InitEEPROM ( )
{
LubeConfig = LubeConfig_defaults ;
PersistenceData = { 0 } ;
Wire . begin ( ) ;
ee . begin ( ) ;
checkEEPROMavailable ( ) ;
eeAvailable = ee . isConnected ( ) ;
}
/**
* @brief Processes EEPROM actions based on the request from the global state .
* @brief Try to free a stuck I²C bus and enforce a STOP condition .
*
* This function processes EEPROM actions based on the request from the global state .
* It performs actions such as saving, loading, and formatting EEPROM data for both configuration and persistenc e.
* Pulses SCL up to 9 times to release a held SDA, then issues a STOP (SDA ↑ while SCL ↑) .
* Finally returns control to Wir e.
*/
void I2C_BusReset ( )
{
pinMode ( SCL , OUTPUT_OPEN_DRAIN ) ;
pinMode ( SDA , INPUT_PULLUP ) ;
for ( int i = 0 ; i < 9 ; i + + )
{
digitalWrite ( SCL , LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( SCL , HIGH ) ;
delayMicroseconds ( 5 ) ;
}
pinMode ( SDA , OUTPUT_OPEN_DRAIN ) ;
digitalWrite ( SDA , LOW ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( SCL , HIGH ) ;
delayMicroseconds ( 5 ) ;
digitalWrite ( SDA , HIGH ) ;
delayMicroseconds ( 5 ) ;
pinMode ( SCL , INPUT ) ;
pinMode ( SDA , INPUT ) ;
}
/**
* @brief Attempt to recover EEPROM connectivity.
*
* Sequence per attempt:
* - I²C bus reset
* - Wire.begin()
* - ee.begin()
* - short settle delay
*
* On first successful probe (0->1) the eeRecoveredOnce flag is raised.
*
* @param attempts Number of attempts
* @param delay_ms Delay between attempts (after ee.begin())
* @return true if EEPROM is reachable after recovery, false otherwise
*/
bool TryRecoverEEPROM ( uint8_t attempts , uint16_t delay_ms )
{
for ( uint8_t n = 0 ; n < attempts ; n + + )
{
I2C_BusReset ( ) ;
// ESP8266 core: Wire.end() is not available; re-begin is sufficient
Wire . begin ( ) ;
delay ( 2 ) ;
ee . begin ( ) ;
delay ( delay_ms ) ;
if ( ee . isConnected ( ) )
{
if ( ! eeAvailable )
eeRecoveredOnce = true ; // edge 0 -> 1
eeAvailable = true ;
return true ;
}
}
eeAvailable = false ;
return false ;
}
/**
* @brief Central EEPROM task: background recovery, DTC handling, and request dispatch.
*
* Called periodically from the main loop. Non-blocking by design.
* - Schedules gentle recovery tries based on millis()
* - Sets DTC_NO_EEPROM_FOUND when unavailable
* - On successful recovery edge, clears DTC and reloads CFG/PDS exactly once
* - Executes requested actions (save/load/format/move)
*/
void EEPROM_Process ( )
{
// Background recovery (single soft attempt per interval)
const uint32_t now = millis ( ) ;
if ( ! EEPROM_Available ( ) & & now > = eeNextTryMs )
{
( void ) TryRecoverEEPROM ( 1 , 10 ) ;
eeNextTryMs = now + eeRetryIntervalMs ;
}
// Central DTC handling
if ( ! EEPROM_Available ( ) )
{
MaintainDTC ( DTC_NO_EEPROM_FOUND , true ) ;
}
// Recovery edge: clear DTC and reload persisted data exactly once
if ( EEPROM_Available ( ) & & eeRecoveredOnce )
{
MaintainDTC ( DTC_NO_EEPROM_FOUND , false ) ;
GetConfig_EEPROM ( ) ;
GetPersistence_EEPROM ( ) ;
eeRecoveredOnce = false ;
Debug_pushMessage ( " EEPROM recovered – reloaded CFG/PDS \n " ) ;
}
// Request dispatcher
switch ( globals . requestEEAction )
{
case EE_CFG_SAVE :
@@ -58,33 +183,39 @@ void EEPROM_Process()
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Stored EEPROM CFG \n " ) ;
break ;
case EE_CFG_LOAD :
GetConfig_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Loaded EEPROM CFG \n " ) ;
break ;
case EE_CFG_FORMAT :
FormatConfig_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
GetConfig_EEPROM ( ) ;
Debug_pushMessage ( " Formatted EEPROM CFG \n " ) ;
break ;
case EE_PDS_SAVE :
StorePersistence_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Stored EEPROM PDS \n " ) ;
break ;
case EE_PDS_LOAD :
GetPersistence_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Loaded EEPROM PDS \n " ) ;
break ;
case EE_PDS_FORMAT :
FormatPersistence_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
GetPersistence_EEPROM ( ) ;
Debug_pushMessage ( " Formatted EEPROM PDS \n " ) ;
break ;
case EE_FORMAT_ALL :
FormatConfig_EEPROM ( ) ;
FormatPersistence_EEPROM ( ) ;
@@ -93,73 +224,93 @@ void EEPROM_Process()
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Formatted EEPROM ALL \n " ) ;
break ;
case EE_ALL_SAVE :
StorePersistence_EEPROM ( ) ;
StoreConfig_EEPROM ( ) ;
globals . requestEEAction = EE_IDLE ;
Debug_pushMessage ( " Stored EEPROM ALL \n " ) ;
break ;
case EE_REINITIALIZE :
{
// quick burst of attempts
const bool ok = TryRecoverEEPROM ( 5 , 20 ) ;
if ( ok )
{
// Edge & reload are handled by the block above
Debug_pushMessage ( " EEPROM reinitialize OK \n " ) ;
}
else
{
MaintainDTC ( DTC_NO_EEPROM_FOUND , true ) ;
Debug_pushMessage ( " EEPROM reinitialize FAILED \n " ) ;
}
globals . requestEEAction = EE_IDLE ;
break ;
}
case EE_IDLE :
default :
globals . requestEEAction = EE_IDLE ;
break ;
}
}
/**
* @brief Stores the configuration data in EEPROM .
* @brief Store configuration to EEPROM (with CRC and sanity report) .
*
* This function calculates the checksum for the configuration data, updates it, and stores it in EEPROM.
* It also performs a sanity check on the configuration and raises a diagnostic trouble code (DTC) if needed .
* Writes only if EEPROM is available. On completion, DTC_EEPROM_CFG_SANITY is
* raised if any config fields are out of plausible bounds (bitmask payload) .
*/
void StoreConfig_EEPROM ( )
{
LubeConfig . checksum = 0 ;
LubeConfig . checksum = Checksum_EEPROM ( ( uint8_t * ) & LubeConfig , sizeof ( LubeConfig ) ) ;
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
ee . updateBlock ( startofLubeConfig , ( uint8_t * ) & LubeConfig , sizeof ( LubeConfig ) ) ;
uint32_t ConfigSanityCheckResult = ConfigSanityCheck ( false ) ;
if ( ConfigSanityCheckResult > 0 )
const uint32_t sanity = ConfigSanityCheck ( false ) ;
if ( sanity > 0 )
{
MaintainDTC ( DTC_EEPROM_CFG_SANITY , true , ConfigSanityCheckResult ) ;
MaintainDTC ( DTC_EEPROM_CFG_SANITY , true , sanity ) ;
}
}
/**
* @brief Retrieves the configuration data from EEPROM.
* @brief Load configuration from EEPROM and validate .
*
* This function reads the configuration data from EEPROM, performs a checksum validation,
* and conducts a sanity check on the configuration. It raises a diagnostic trouble code (DTC) if needed.
* Performs CRC check and sanity validation and raises the respective DTCs:
* - DTC_EEPROM_CFG_BAD if CRC fails
* - DTC_EEPROM_CFG_SANITY with bitmask payload if values are out of bounds
*/
void GetConfig_EEPROM ( )
{
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
ee . readBlock ( startofLubeConfig , ( uint8_t * ) & LubeConfig , sizeof ( LubeConfig ) ) ;
uint32_t checksum = LubeConfig . checksum ;
const uint32_t checksum = LubeConfig . checksum ;
LubeConfig . checksum = 0 ;
MaintainDTC ( DTC_EEPROM_CFG_BAD , ( Checksum_EEPROM ( ( uint8_t * ) & LubeConfig , sizeof ( LubeConfig ) ) ! = checksum ) ) ;
MaintainDTC ( DTC_EEPROM_CFG_BAD ,
( Checksum_EEPROM ( ( uint8_t * ) & LubeConfig , sizeof ( LubeConfig ) ) ! = checksum ) ) ;
LubeConfig . checksum = checksum ;
uint32_t ConfigSanityCheckResult = ConfigSanityCheck ( false ) ;
MaintainDTC ( DTC_EEPROM_CFG_SANITY , ( ConfigSanityCheckResult > 0 ) , ConfigSanityCheckResult ) ;
const uint32_t sanity = ConfigSanityCheck ( false ) ;
MaintainDTC ( DTC_EEPROM_CFG_SANITY , ( sanity > 0 ) , sanity ) ;
}
/**
* @brief Stores the persistence data in EEPROM .
* @brief Store persistence record to EEPROM (wear-levelled page) .
*
* This function i ncrements the write cycle counter, performs a checksum calculation on the persistence data,
* and stores it in EEPROM. It also handles EEPROM page movement when needed .
* I ncrements the write- cycle counter and moves the page if close to the limit.
* Writes only if EEPROM is available .
*/
void StorePersistence_EEPROM ( )
{
@@ -171,28 +322,27 @@ void StorePersistence_EEPROM()
PersistenceData . checksum = 0 ;
PersistenceData . checksum = Checksum_EEPROM ( ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ;
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
ee . updateBlock ( globals . eePersista nceAdress , ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ;
ee . updateBlock ( globals . eePersiste nceAdd ress , ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ;
}
/**
* @brief Retrieves the persistence data from EEPROM .
* @brief Load persistence record, validating address range and CRC .
*
* This function reads the EEPROM to get the start address of the persistence data.
* If the start address is out of range, it resets and stores defaults. Otherw ise,
* it reads from EEPROM and checks if the data is correct .
* If the stored start address is out of range, the persistence partition is reset,
* formatted, and DTC_EEPROM_PDSADRESS_BAD is ra ised.
* Otherwise, the record is read and checked; DTC_EEPROM_PDS_BAD is raised on CRC failure .
*/
void GetPersistence_EEPROM ( )
{
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
ee . readBlock ( 0 , ( uint8_t * ) & globals . eePersista nceAdress , sizeof ( globals . eePersista nceAdress ) ) ;
// if we got the StartAdress of Persistance and it's out of Range - we Reset it and store defaults
// oth erw ise we Read from eeprom and check if everything is correct
if ( globals . eePersistanceAdress < startofPersistence | | globals . eePersistanceAdress > ee . getDeviceSize ( ) )
ee . readBlock ( 0 , ( uint8_t * ) & globals . eePersiste nceAdd ress , sizeof ( globals . eePersiste nceAdd ress ) ) ;
if ( globals . eeP ers istenceAddress < startofPersistence | | globals . eePersistenceAddress > ee . getDeviceSize ( ) )
{
MovePersistencePage_EEPROM ( true ) ;
FormatPersistence_EEPROM ( ) ;
@@ -200,74 +350,65 @@ void GetPersistence_EEPROM()
}
else
{
ee . readBlock ( globals . eePersista nceAdress , ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ;
ee . readBlock ( globals . eePersiste nceAdd ress , ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ;
uint32_t checksum = PersistenceData . checksum ;
const uint32_t checksum = PersistenceData . checksum ;
PersistenceData . checksum = 0 ;
MaintainDTC ( DTC_EEPROM_PDS_BAD , ( Checksum_EEPROM ( ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ! = checksum ) ) ;
MaintainDTC ( DTC_EEPROM_PDS_BAD ,
( Checksum_EEPROM ( ( uint8_t * ) & PersistenceData , sizeof ( PersistenceData ) ) ! = checksum ) ) ;
PersistenceData . checksum = checksum ;
}
}
/**
* @brief Formats the configuration partition in EEPROM .
*
* This function resets the configuration data to defaults and stores it in EEPROM.
* @brief Reset the configuration partition to defaults and write it .
*/
void FormatConfig_EEPROM ( )
{
Debug_pushMessage ( " Formatting Config-P artition \n " ) ;
Debug_pushMessage ( " Formatting Config p artition \n " ) ;
LubeConfig = LubeConfig_defaults ;
LubeConfig . EEPROM_Version = eeVersion ;
StoreConfig_EEPROM ( ) ;
}
/**
* @brief Formats the persistence partition in EEPROM .
*
* This function resets the persistence data to defaults and stores it in EEPROM.
* @brief Reset the persistence partition and write an empty record .
*/
void FormatPersistence_EEPROM ( )
{
Debug_pushMessage ( " Formatting Persista nce-P artition \n " ) ;
Debug_pushMessage ( " Formatting Persiste nce p artition \n " ) ;
PersistenceData = { 0 } ;
// memset(&PersistenceData, 0, sizeof(PersistenceData));
StorePersistence_EEPROM ( ) ;
}
/**
* @brief Moves the persistence page in EEPROM .
* @brief Advance the persistence page (wear levelling) and store the new start address .
*
* This function adjusts the persistence page address and resets the write cycle counter .
* When end-of-device (or reset=true), wrap back to startofPersistence .
* Requires EEPROM availability.
*
* @param reset If true, the function resets the persistence page address to the start of the partition.
* @param reset If true, force wrap to the start of the partition.
*/
void MovePersistencePage_EEPROM ( boolean reset )
{
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
globals . eePersista nceAdress + = sizeof ( PersistenceData ) ;
globals . eePersiste nceAdd ress + = sizeof ( PersistenceData ) ;
PersistenceData . writeCycleCounter = 0 ;
// Check if we reached the end of the EEPROM and start over at the beginning
if ( ( globals . eePersistanceAdress + sizeof ( PersistenceData ) ) > ee . getDeviceSize ( ) | | reset )
if ( ( globals . eePersistenceAddress + sizeof ( PersistenceData ) ) > ee . getDeviceSize ( ) | | reset )
{
globals . eePersista nceAdress = startofPersistence ;
globals . eePersiste nceAdd ress = startofPersistence ;
}
ee . updateBlock ( 0 , ( uint8_t * ) & globals . eePersista nceAdress , sizeof ( globals . eePersista nceAdress ) ) ;
ee . updateBlock ( 0 , ( uint8_t * ) & globals . eePersiste nceAdd ress , sizeof ( globals . eePersiste nceAdd ress ) ) ;
}
/**
* @brief Calcula te CRC-32 checksum for a block of data .
*
* This function implements the CRC-32 algorithm.
*
* @param data Pointer to the data block.
* @param len Length of the data block in bytes.
* @return CRC-32 checksum.
* @brief Compu te CRC-32 (poly 0xEDB88320) over a byte buffer .
*/
uint32_t Checksum_EEPROM ( uint8_t const * data , size_t len )
{
@@ -275,55 +416,43 @@ uint32_t Checksum_EEPROM(uint8_t const *data, size_t len)
return 0 ;
uint32_t crc = 0xFFFFFFFF ;
uint32_t mask ;
while ( len - - )
{
crc ^ = * data + + ;
for ( uint8_t k = 0 ; k < 8 ; k + + )
{
mask = - ( crc & 1 ) ;
crc = ( crc > > 1 ) ^ ( 0xEDB88320 & mask ) ;
}
crc = ( crc > > 1 ) ^ ( 0xEDB88320 & ( - ( int32_t ) ( crc & 1 ) ) ) ;
}
return ~ crc ;
}
/**
* @brief Dump a port ion of EEPROM contents for debugging.
* @brief Print a hex/ASCII dump of a reg ion of the EEPROM for debugging.
*
* This function prints the contents of a specified portion of EEPROM in a formatted way.
*
* @param memoryAddress Starting address in EEPROM .
* @param length Number of bytes to dump.
* Output format:
* Address 00 01 02 ... 0F ASCII
* 0x00000: XX XX ... .... .
*/
void dumpEEPROM ( uint16_t memoryAddress , uint16_t length )
{
# define BLOCK_TO_LENGTH 16
if ( ! check EEPROMa vailable( ) )
if ( ! EEPROM_A vailable ( ) )
return ;
char ascii_buf [ BLOCK_TO_LENGTH + 1 ] ;
sprintf ( ascii_buf , " %*s " , BLOCK_TO_LENGTH , " ASCII " ) ;
// Print column headers
Debug_pushMessage ( PSTR ( " \n Address " ) ) ;
for ( int x = 0 ; x < BLOCK_TO_LENGTH ; x + + )
Debug_pushMessage ( " %3d " , x ) ;
// Align address and length to BLOCK_TO_LENGTH boundaries
memoryAddress = memoryAddress / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH ;
length = ( length + BLOCK_TO_LENGTH - 1 ) / BLOCK_TO_LENGTH * BLOCK_TO_LENGTH ;
memoryAddress = ( memoryAddress / BLOCK_TO_LENGTH ) * BLOCK_TO_LENGTH ;
length = ( ( length + BLOCK_TO_LENGTH - 1 ) / BLOCK_TO_LENGTH ) * BLOCK_TO_LENGTH ;
// Iterate through the specified portion of EEPROM
for ( unsigned int i = 0 ; i < length ; i + + )
{
int blockpoint = memoryAddress % BLOCK_TO_LENGTH ;
const int blockpoint = memoryAddress % BLOCK_TO_LENGTH ;
// Print ASCII representation header for each block
if ( blockpoint = = 0 )
{
ascii_buf [ BLOCK_TO_LENGTH ] = 0 ;
@@ -331,55 +460,54 @@ void dumpEEPROM(uint16_t memoryAddress, uint16_t length)
Debug_pushMessage ( " \n 0x%05X: " , memoryAddress ) ;
}
// Read and print each byte
ascii_buf [ blockpoint ] = ee . readByte ( memoryAddress ) ;
Debug_pushMessage ( " %02X " , ascii_buf [ blockpoint ] ) ;
// Replace non-printable characters with dots in ASCII representation
if ( ascii_buf [ blockpoint ] < 0x20 | | ascii_buf [ blockpoint ] > 0x7E )
ascii_buf [ blockpoint ] = ' . ' ;
memoryAddress + + ;
}
// Print a new line at the end of the dump
Debug_pushMessage ( " \n " ) ;
}
/**
* @brief Check if EEPROM is available and connected .
* @brief Unified availability probe with optional recovery .
*
* This function checks if the EEPROM is available and connected. If not, it triggers
* a diagnostic trouble code (DTC) indicating the absence of EEPROM .
* Fast path returns the latched availability flag. If not available,
* performs a direct probe and, optionally, a recovery sequence .
*
* @param recover If true, attempt recovery when not available (default: false).
* @param attempts Recovery attempts (default: 3).
* @param delay_ms Delay between attempts in ms (default: 25).
* @return true if EEPROM is available, false otherwise.
*/
boolean check EEPROMa vailable( )
bool EEPROM_A vailable( bool recover , uint8_t attempts , uint16_t delay_ms )
{
// Check if EEPROM is connected
if ( ! ee . isConnected ( ) )
if ( eeAvailable )
return true ;
if ( ee . isConnected ( ) )
{
// Trigger DTC for no EEPROM found
MaintainDTC ( DTC_NO_EEPROM_FOUND , true ) ;
return fals e;
eeAvailable = true ;
eeRecoveredOnce = true ; // edge 0 -> 1
return tru e;
}
// Clear DTC for no EEPROM found since it's available now
MaintainDTC ( DTC_NO_EEPROM_FOUND , false ) ;
if ( recover )
{
return TryRecoverEEPROM ( attempts , delay_ms ) ;
}
// EEPROM is available
return true ;
return false ;
}
/**
* @brief Perform sanity check on configuration setting s.
* @brief Validate config fields; return bitmask of invalid entrie s.
*
* This function checks the validity of various configuration settings and returns a bitmask
* indicating which settings need to be reset. If autocorrect is enabled, it resets the settings
* to their default values.
*
* @param autocorrect If true, automatically correct invalid settings by resetting to defaults.
* @return A bitmask indicating which settings need to be reset.
* If autocorrect is true, invalid fields are reset to default values.
* Each bit in the returned mask identifies a specific field-group that was out-of-bounds.
*/
uint32_t ConfigSanityCheck ( bool autocorrect )
{
@@ -513,22 +641,17 @@ uint32_t ConfigSanityCheck(bool autocorrect)
if ( autocorrect )
strncpy ( LubeConfig . wifi_client_password , LubeConfig_defaults . wifi_client_password , sizeof ( LubeConfig . wifi_client_password ) ) ;
}
// Return the bitmask indicating which settings need to be reset
return setting_reset_bits ;
}
/**
* @brief Validates whether a given string contains only characters allowed in WiFi SSIDs and passwords.
* @brief Validate that a string contains only characters allowed for Wi‑ Fi SSIDs/ passwords.
*
* This function checks each character in the provided string to ensure
* that it contains only characters allowed in WiFi SSIDs and passwords.
* It considers characters from 'A' to 'Z', 'a' to 'z', '0' to '9', as well as
* the following special characters: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
* Allowed: A‑ Z, a‑ z, 0‑ 9 and the printable ASCII punctuation: ! " # $ % & ' ( ) * + , - . / : ;
* < = > ? @ [ \ ] ^ _ ` { | } ~
*
* @param string Pointer to the string to be validated .
* @param size Size of the string including the null-terminator.
* @return true if the string contains only allowed characters or is NULL,
* false otherwise.
* @return true if valid (or empty), false otherwise .
*/
bool validateWiFiString ( char * string , size_t size )
{
@@ -539,10 +662,8 @@ bool validateWiFiString(char *string, size_t size)
{
char c = string [ i ] ;
if ( c = = ' \0 ' )
{
// Reached the end of the string, all characters were valid WiFi characters.
return true ;
}
return true ; // reached end with valid chars
if ( ! ( ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) | |
( c > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' ! ' | | c = = ' " ' | | c = = ' # ' | |
c = = ' $ ' | | c = = ' % ' | | c = = ' & ' | | c = = ' \' ' | | c = = ' ( ' | |
@@ -552,11 +673,9 @@ bool validateWiFiString(char *string, size_t size)
c = = ' \\ ' | | c = = ' ] ' | | c = = ' ^ ' | | c = = ' _ ' | | c = = ' ` ' | |
c = = ' { ' | | c = = ' | ' | | c = = ' } ' | | c = = ' ~ ' ) )
{
// Found a character that is not a valid WiFi character.
return false ;
}
}
// If the loop completes without finding a null terminator, the string i s invalid.
// No NUL within buffer: treat a s invalid
return false ;
}