|
|
|
@ -2,6 +2,7 @@ |
|
|
|
|
// Created by MightyPork on 2017/11/26.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include <utils/avrlibc.h> |
|
|
|
|
#include "platform.h" |
|
|
|
|
#include "utils/hexdump.h" |
|
|
|
|
#include "settings.h" |
|
|
|
@ -9,9 +10,13 @@ |
|
|
|
|
#include "system_settings.h" |
|
|
|
|
#include "utils/str_utils.h" |
|
|
|
|
|
|
|
|
|
// pre-declarations
|
|
|
|
|
static void savebuf_flush(PayloadBuilder *pb, bool final); |
|
|
|
|
static bool savebuf_ovhandler(PayloadBuilder *pb, uint32_t more); |
|
|
|
|
|
|
|
|
|
// This is the first entry in a valid config.
|
|
|
|
|
// Change with each breaking change to force config reset.
|
|
|
|
|
#define CONFIG_MARKER 0xA55C |
|
|
|
|
#define CONFIG_MARKER 0xA55D |
|
|
|
|
|
|
|
|
|
void settings_load(void) |
|
|
|
|
{ |
|
|
|
@ -32,6 +37,11 @@ void settings_load(void) |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint8_t version = pp_u8(&pp); // top level settings format version
|
|
|
|
|
|
|
|
|
|
{ // Settings
|
|
|
|
|
(void)version; // Conditional choices based on version
|
|
|
|
|
|
|
|
|
|
// System section
|
|
|
|
|
if (!systemsettings_load(&pp)) { |
|
|
|
|
dbg("!! System settings failed to load"); |
|
|
|
@ -42,6 +52,7 @@ void settings_load(void) |
|
|
|
|
dbg("!! Unit settings failed to load"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} // End settings
|
|
|
|
|
|
|
|
|
|
dbg("System settings loaded OK"); |
|
|
|
|
} |
|
|
|
@ -56,65 +67,6 @@ static uint32_t save_addr; |
|
|
|
|
#define fls_printf(fmt, ...) do {} while (0) |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flush the save buffer to flash, moving leftovers from uneven half-words |
|
|
|
|
* to the beginning and adjusting the CWPack curent pointer accordingly. |
|
|
|
|
* |
|
|
|
|
* @param ctx - pack context |
|
|
|
|
* @param final - if true, flush uneven leftovers; else move them to the beginning and keep for next call. |
|
|
|
|
*/ |
|
|
|
|
static void savebuf_flush(PayloadBuilder *pb, bool final) |
|
|
|
|
{ |
|
|
|
|
// TODO this might be buggy, was not tested cross-boundary yet
|
|
|
|
|
// TODO remove those printf's after verifying correctness
|
|
|
|
|
|
|
|
|
|
uint32_t bytes = (uint32_t) pb_length(pb); |
|
|
|
|
|
|
|
|
|
// Dump what we're flushing
|
|
|
|
|
fls_printf("Flush: "); |
|
|
|
|
for (uint32_t i = 0; i < bytes; i++) { |
|
|
|
|
fls_printf("%02X ", save_buffer[i]); |
|
|
|
|
} |
|
|
|
|
fls_printf("\r\n"); |
|
|
|
|
|
|
|
|
|
uint32_t halfwords = bytes >> 1; |
|
|
|
|
uint32_t remain = bytes & 1; // how many bytes won't be programmed
|
|
|
|
|
|
|
|
|
|
fls_printf("Halfwords: %d, Remain: %d, last? %d\r\n", (int)halfwords, (int)remain, final); |
|
|
|
|
|
|
|
|
|
uint16_t *hwbuf = (void*) &save_buffer[0]; |
|
|
|
|
|
|
|
|
|
for (; halfwords > 0; halfwords--) { |
|
|
|
|
uint16_t hword = *hwbuf++; |
|
|
|
|
|
|
|
|
|
fls_printf("%04X ", hword); |
|
|
|
|
|
|
|
|
|
HAL_StatusTypeDef res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, save_addr, hword); |
|
|
|
|
assert_param(HAL_OK == res); |
|
|
|
|
save_addr += 2; // advance
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// rewind the context buffer
|
|
|
|
|
pb->current = pb->start; |
|
|
|
|
|
|
|
|
|
if (remain) { |
|
|
|
|
// We have an odd byte left to write
|
|
|
|
|
if (final) { |
|
|
|
|
// We're done writing, this is the last call. Append the last byte to flash.
|
|
|
|
|
uint16_t hword = save_buffer[bytes-1]; |
|
|
|
|
fls_printf("& %02X ", hword); |
|
|
|
|
|
|
|
|
|
HAL_StatusTypeDef res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, save_addr, hword); |
|
|
|
|
assert_param(HAL_OK == res); |
|
|
|
|
} else { |
|
|
|
|
// Move the leftover to the beginning of the buffer for next call.
|
|
|
|
|
save_buffer[0] = save_buffer[bytes-1]; |
|
|
|
|
pb->current++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fls_printf("\r\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Save buffer overflow handler. |
|
|
|
|
* This should flush whatever is in the buffer and let CWPack continue |
|
|
|
@ -130,7 +82,7 @@ static bool savebuf_ovhandler(PayloadBuilder *pb, uint32_t more) |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Save settings to flash
|
|
|
|
|
/** Save settings to flash */ |
|
|
|
|
void settings_save(void) |
|
|
|
|
{ |
|
|
|
|
HAL_StatusTypeDef hst; |
|
|
|
@ -173,10 +125,15 @@ void settings_save(void) |
|
|
|
|
|
|
|
|
|
// Marker that this is a valid save
|
|
|
|
|
pb_u16(&pb, CONFIG_MARKER); |
|
|
|
|
pb_u8(&pb, 0); // Settings format version
|
|
|
|
|
|
|
|
|
|
{ // Settings
|
|
|
|
|
fls_printf("Saving system settings\r\n"); |
|
|
|
|
systemsettings_save(&pb); |
|
|
|
|
|
|
|
|
|
fls_printf("Saving units\r\n"); |
|
|
|
|
ureg_save_units(&pb); |
|
|
|
|
} // End settings
|
|
|
|
|
|
|
|
|
|
fls_printf("Final flush\r\n"); |
|
|
|
|
savebuf_flush(&pb, true); |
|
|
|
@ -193,18 +150,80 @@ void settings_save(void) |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Flush the save buffer to flash, moving leftovers from uneven half-words |
|
|
|
|
* to the beginning and adjusting the CWPack curent pointer accordingly. |
|
|
|
|
* |
|
|
|
|
* @param ctx - pack context |
|
|
|
|
* @param final - if true, flush uneven leftovers; else move them to the beginning and keep for next call. |
|
|
|
|
*/ |
|
|
|
|
static void savebuf_flush(PayloadBuilder *pb, bool final) |
|
|
|
|
{ |
|
|
|
|
// TODO this might be buggy, was not tested cross-boundary yet
|
|
|
|
|
// TODO remove those printf's after verifying correctness
|
|
|
|
|
|
|
|
|
|
uint32_t bytes = (uint32_t) pb_length(pb); |
|
|
|
|
|
|
|
|
|
// Dump what we're flushing
|
|
|
|
|
fls_printf("Flush: "); |
|
|
|
|
for (uint32_t i = 0; i < bytes; i++) { |
|
|
|
|
fls_printf("%02X ", save_buffer[i]); |
|
|
|
|
} |
|
|
|
|
fls_printf("\r\n"); |
|
|
|
|
|
|
|
|
|
uint32_t halfwords = bytes >> 1; |
|
|
|
|
uint32_t remain = bytes & 1; // how many bytes won't be programmed
|
|
|
|
|
|
|
|
|
|
fls_printf("Halfwords: %d, Remain: %d, last? %d\r\n", (int)halfwords, (int)remain, final); |
|
|
|
|
|
|
|
|
|
uint16_t *hwbuf = (void*) &save_buffer[0]; |
|
|
|
|
|
|
|
|
|
for (; halfwords > 0; halfwords--) { |
|
|
|
|
uint16_t hword = *hwbuf++; |
|
|
|
|
|
|
|
|
|
fls_printf("%04X ", hword); |
|
|
|
|
|
|
|
|
|
HAL_StatusTypeDef res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, save_addr, hword); |
|
|
|
|
assert_param(HAL_OK == res); |
|
|
|
|
save_addr += 2; // advance
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// rewind the context buffer
|
|
|
|
|
pb->current = pb->start; |
|
|
|
|
|
|
|
|
|
if (remain) { |
|
|
|
|
// We have an odd byte left to write
|
|
|
|
|
if (final) { |
|
|
|
|
// We're done writing, this is the last call. Append the last byte to flash.
|
|
|
|
|
uint16_t hword = save_buffer[bytes-1]; |
|
|
|
|
fls_printf("& %02X ", hword); |
|
|
|
|
|
|
|
|
|
HAL_StatusTypeDef res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, save_addr, hword); |
|
|
|
|
assert_param(HAL_OK == res); |
|
|
|
|
} else { |
|
|
|
|
// Move the leftover to the beginning of the buffer for next call.
|
|
|
|
|
save_buffer[0] = save_buffer[bytes-1]; |
|
|
|
|
pb->current++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
fls_printf("\r\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Write system settings to INI (without section) |
|
|
|
|
*/ |
|
|
|
|
void settings_build_ini(IniWriter *iw) |
|
|
|
|
{ |
|
|
|
|
// File header
|
|
|
|
|
iw_comment(iw, "CONFIG.INI"); |
|
|
|
|
iw_hdr_comment(iw, "CONFIG.INI"); |
|
|
|
|
iw_hdr_comment(iw, "GEX v%s on %s", GEX_VERSION, GEX_PLATFORM); |
|
|
|
|
iw_hdr_comment(iw, "built %s at %s", __DATE__, __TIME__); |
|
|
|
|
iw_cmt_newline(iw); |
|
|
|
|
|
|
|
|
|
iw_comment(iw, "Overwrite this file to change settings."); |
|
|
|
|
iw_comment(iw, "Close the LOCK jumper to save them to Flash."); |
|
|
|
|
|
|
|
|
|
systemsettings_build_ini(iw); |
|
|
|
|
iw_newline(iw); |
|
|
|
|
|
|
|
|
|
ureg_build_ini(iw); |
|
|
|
|
} |
|
|
|
@ -221,7 +240,8 @@ void settings_load_ini_begin(void) |
|
|
|
|
|
|
|
|
|
void settings_load_ini_key(const char *restrict section, const char *restrict key, const char *restrict value) |
|
|
|
|
{ |
|
|
|
|
// dbg("[%s] %s = %s", section, key, value);
|
|
|
|
|
dbg("[%s] %s = %s", section, key, value); |
|
|
|
|
static char namebuf[INI_KEY_MAX]; |
|
|
|
|
|
|
|
|
|
if (streq(section, "SYSTEM")) { |
|
|
|
|
// system is always at the top
|
|
|
|
@ -235,8 +255,15 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke |
|
|
|
|
// not a standard section, may be some unit config
|
|
|
|
|
// all unit sections contain the colon character [TYPE:NAME]
|
|
|
|
|
const char *nameptr = strchr(section, ':'); |
|
|
|
|
if (nameptr) { |
|
|
|
|
ureg_load_unit_ini_key(nameptr + 1, key, value); |
|
|
|
|
const char *csptr = strchr(section, '@'); |
|
|
|
|
|
|
|
|
|
dbg("cs = %s", csptr); |
|
|
|
|
if (nameptr && csptr) { |
|
|
|
|
strncpy(namebuf, nameptr+1, csptr - nameptr - 1); |
|
|
|
|
uint8_t cs = (uint8_t) avr_atoi(csptr + 1); |
|
|
|
|
dbg("cs is %d", cs); |
|
|
|
|
dbg("name is %s", namebuf); |
|
|
|
|
ureg_load_unit_ini_key(namebuf, key, value, cs); |
|
|
|
|
} else { |
|
|
|
|
dbg("! Bad config key: [%s] %s = %s", section, key, value); |
|
|
|
|
} |
|
|
|
|