2024-03-16 22:28:04 +08:00
|
|
|
#include "stm32f4xx_flash.h"
|
|
|
|
|
#include "partition.h"
|
2024-12-29 15:41:38 +08:00
|
|
|
#include "led.h"
|
2024-03-16 22:28:04 +08:00
|
|
|
#include "file.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "ff.h"
|
|
|
|
|
|
|
|
|
|
static struct file_config_s file_config_flash;
|
|
|
|
|
static struct file_config_s file_config_sd;
|
|
|
|
|
|
|
|
|
|
static void file_config_write(uint32_t addr, struct file_config_s *cfg)
|
|
|
|
|
{
|
|
|
|
|
volatile uint32_t *p;
|
|
|
|
|
|
|
|
|
|
p = (volatile uint32_t *)cfg;
|
|
|
|
|
FLASH_Unlock();
|
|
|
|
|
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | \
|
|
|
|
|
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR|FLASH_FLAG_PGSERR);
|
|
|
|
|
for (uint32_t i = 0; i < 4; i++) {
|
|
|
|
|
if (FLASH_ProgramWord(addr + i * 4, p[i]) != FLASH_COMPLETE) {
|
2024-12-29 15:41:38 +08:00
|
|
|
led_indicate_error();
|
2024-03-16 22:28:04 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FLASH_Lock();
|
|
|
|
|
p = (volatile uint32_t *)addr;
|
|
|
|
|
if (p[0] != addr || (p[0] + p[1] + p[2]) != p[3]) {
|
|
|
|
|
/* program flash error */
|
2024-12-29 15:41:38 +08:00
|
|
|
led_indicate_error();
|
2024-03-16 22:28:04 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t str10_to_uint(uint8_t *str)
|
|
|
|
|
{
|
|
|
|
|
uint32_t val = 0;
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
uint8_t c = str[i++];
|
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
|
c = c - '0';
|
|
|
|
|
val *= 10;
|
|
|
|
|
val += c;
|
|
|
|
|
} else {
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint32_t str16_to_uint(uint8_t *str)
|
|
|
|
|
{
|
|
|
|
|
uint32_t val = 0;
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
|
uint8_t c = str[i++];
|
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
|
c = c - '0';
|
|
|
|
|
} else if (c >= 'A' && c <= 'F') {
|
|
|
|
|
c = c - 'A' + 10;
|
|
|
|
|
} else if (c >= 'a' && c <= 'f') {
|
|
|
|
|
c = c - 'a' + 10;
|
|
|
|
|
} else {
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
val *= 16;
|
|
|
|
|
val += c;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void file_config_parse(uint8_t *p, uint32_t len, struct file_config_s *cfg)
|
|
|
|
|
{
|
|
|
|
|
uint32_t item = 0; /* 0:null, 1:addr, 2:baudrate, 3:parity, 4:stopbits */
|
|
|
|
|
uint32_t stage = 0; /* 0:null, 1:name_ing, 2:name_end, 3:numing, 4:num_end */
|
|
|
|
|
uint32_t i = 0; /* index of every char */
|
|
|
|
|
uint32_t j = 0; /* index in one word */
|
|
|
|
|
uint32_t val32;
|
|
|
|
|
uint8_t val[16];
|
|
|
|
|
|
|
|
|
|
for (uint32_t k=0; k<sizeof(val); k++) {
|
|
|
|
|
val[k] = 0;
|
|
|
|
|
}
|
|
|
|
|
p[len] = 0;
|
|
|
|
|
/* default value */
|
|
|
|
|
cfg->baudrate = UART_DEFAULT_BAUDRATE;
|
|
|
|
|
cfg->parity = UART_DEFAULT_PARITY;
|
|
|
|
|
cfg->stopbits = UART_DEFAULT_STOPBITS;
|
|
|
|
|
cfg->addr = UART_DEFAULT_ADDR;
|
|
|
|
|
/* state machine for parse config file */
|
|
|
|
|
while (1) {
|
|
|
|
|
if (stage == 0) { /* null */
|
|
|
|
|
if (p[i] == 'a' || p[i] == 'A') {
|
|
|
|
|
item = 1; /* addr */
|
|
|
|
|
stage = 1; /* name_ing */
|
|
|
|
|
j = 1;
|
|
|
|
|
} else if (p[i] == 'b' || p[i] == 'B') {
|
|
|
|
|
item = 2; /* baudrate */
|
|
|
|
|
stage = 1; /* name_ing */
|
|
|
|
|
j = 1;
|
|
|
|
|
} else if (p[i] == 'p' || p[i] == 'P') {
|
|
|
|
|
item = 3; /* parity */
|
|
|
|
|
stage = 1; /* name_ing */
|
|
|
|
|
j = 1;
|
|
|
|
|
} else if (p[i] == 's' || p[i] == 'S') {
|
|
|
|
|
item = 4; /* stopbits */
|
|
|
|
|
stage = 1; /* name_ing */
|
|
|
|
|
j = 1;
|
|
|
|
|
} else {
|
|
|
|
|
item = 0; /* null */
|
|
|
|
|
}
|
|
|
|
|
} else if (stage == 1) { /* name_ing */
|
|
|
|
|
if (item == 1) {
|
|
|
|
|
if (p[i] == "addr"[j] || p[i] == "ADDR"[j]) {
|
|
|
|
|
if (j < 3) {
|
|
|
|
|
j++;
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
stage = 2; /* name_end */
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (item == 2) {
|
|
|
|
|
if (p[i] == "baudrate"[j] || p[i] == "BAUDRATE"[j]) {
|
|
|
|
|
if (j < 7) {
|
|
|
|
|
j++;
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
stage = 2; /* name_end */
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (item == 3) {
|
|
|
|
|
if (p[i] == "parity"[j] || p[i] == "PARITY"[j]) {
|
|
|
|
|
if (j < 5) {
|
|
|
|
|
j++;
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
stage = 2; /* name_end */
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (item == 4) {
|
|
|
|
|
if (p[i] == "stopbits"[j] || p[i] == "STOPBITS"[j]) {
|
|
|
|
|
if (j < 7) {
|
|
|
|
|
j++;
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
stage = 2; /* name_end */
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (stage == 2) { /* name_end */
|
|
|
|
|
if (item == 1 || item == 2 || item == 4) { /* addr, baudrate, stopbits */
|
|
|
|
|
if (p[i] >= '0' && p[i] <= '9') {
|
|
|
|
|
stage = 3; /* numing */
|
|
|
|
|
j = 1;
|
|
|
|
|
val[0] = p[i];
|
|
|
|
|
}
|
|
|
|
|
} else if (item == 3) { /* parity */
|
|
|
|
|
if (p[i] == 'N' || p[i] == 'n') {
|
|
|
|
|
cfg->parity = UART_PARITY_NONE;
|
|
|
|
|
stage = 4; /* num_end */
|
|
|
|
|
} else if (p[i] == 'O' || p[i] == 'o') {
|
|
|
|
|
cfg->parity = UART_PARITY_ODD;
|
|
|
|
|
stage = 4; /* num_end */
|
|
|
|
|
} else if (p[i] == 'E' || p[i] == 'e') {
|
|
|
|
|
cfg->parity = UART_PARITY_EVEN;
|
|
|
|
|
stage = 4; /* num_end */
|
|
|
|
|
} else {
|
|
|
|
|
if (p[i] == '\n' || p[i] == '\r') {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
} else if (stage == 3) { /* numing */
|
|
|
|
|
if ((p[i] >= '0' && p[i] <= '9') || \
|
|
|
|
|
(p[i] >= 'A' && p[i] <= 'F') || \
|
|
|
|
|
(p[i] >= 'a' && p[i] <= 'f') || \
|
|
|
|
|
p[i] == 'x' || p[i] == 'X') {
|
|
|
|
|
val[j++] = p[i];
|
|
|
|
|
} else { /* num_end */
|
|
|
|
|
val[j] = 0; /* set 0 for the end of string */
|
|
|
|
|
if (val[1] == 'x' || val[1] == 'X') { /* 16, hexadecimal */
|
|
|
|
|
val32 = str16_to_uint(val + 2);
|
|
|
|
|
} else { /* 10, decimalism */
|
|
|
|
|
val32 = str10_to_uint(val);
|
|
|
|
|
}
|
|
|
|
|
if (item == 1) { /* addr */
|
|
|
|
|
cfg->addr = (uint8_t)(val32 & 0xFF);
|
|
|
|
|
} else if (item == 2) { /* baudrate */
|
|
|
|
|
cfg->baudrate = val32;
|
|
|
|
|
} else if (item == 4) { /* stopbits */
|
|
|
|
|
cfg->stopbits = (uint8_t)(val32 & 0xFF);
|
|
|
|
|
}
|
|
|
|
|
stage = 4; /* num_end */
|
|
|
|
|
}
|
|
|
|
|
} else if (stage == 4) { /* num_end */
|
|
|
|
|
j = 0;
|
|
|
|
|
item = 0;
|
|
|
|
|
stage = 0;
|
|
|
|
|
} else {
|
|
|
|
|
stage = 0;
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
if (i > len) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void file_config_copy(struct file_config_s *dst, struct file_config_s *src)
|
|
|
|
|
{
|
|
|
|
|
uint32_t *s, *d;
|
|
|
|
|
|
|
|
|
|
s = (uint32_t *)src;
|
|
|
|
|
d = (uint32_t *)dst;
|
|
|
|
|
for (uint32_t i = 0; i < sizeof(struct file_config_s) / 4; i++) {
|
|
|
|
|
*d = *s;
|
|
|
|
|
s++;
|
|
|
|
|
d++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t file_config_get_free_addr(struct file_config_s *cfg)
|
|
|
|
|
{
|
|
|
|
|
uint32_t addr;
|
|
|
|
|
volatile uint32_t *p;
|
|
|
|
|
|
|
|
|
|
addr = ADDR_CONFIG;
|
|
|
|
|
p = (volatile uint32_t *)addr;
|
|
|
|
|
/* first run or data was dirty */
|
|
|
|
|
if (p[0] != addr || (p[0] + p[1] + p[2]) != p[3]) {
|
|
|
|
|
file_secctor_erase(SECTOR_CONFIG);
|
|
|
|
|
p = (volatile uint32_t *)cfg;
|
|
|
|
|
cfg->id = addr;
|
|
|
|
|
cfg->baudrate = UART_DEFAULT_BAUDRATE;
|
|
|
|
|
cfg->parity = UART_DEFAULT_PARITY;
|
|
|
|
|
cfg->stopbits = UART_DEFAULT_STOPBITS;
|
|
|
|
|
cfg->addr = UART_DEFAULT_ADDR;
|
|
|
|
|
cfg->resv = UART_DEFAULT_RESV;
|
|
|
|
|
cfg->checksum = p[0] + p[1] + p[2];
|
|
|
|
|
file_config_write(addr, cfg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (addr = ADDR_CONFIG; addr < (ADDR_CONFIG + SIZE_CONFIG - sizeof(struct file_config_s)); addr += sizeof(struct file_config_s)) {
|
|
|
|
|
p = (volatile uint32_t *)addr;
|
|
|
|
|
if (addr == p[0]) {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (0xFFFFFFFF == p[0]) {
|
|
|
|
|
file_config_copy(cfg, (struct file_config_s *)(addr - sizeof(struct file_config_s)));
|
|
|
|
|
return addr;
|
|
|
|
|
} else {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void file_config_update(void)
|
|
|
|
|
{
|
|
|
|
|
FRESULT ret;
|
|
|
|
|
UINT bc;
|
|
|
|
|
uint32_t addr;
|
|
|
|
|
volatile uint32_t *p;
|
|
|
|
|
|
|
|
|
|
ret = f_open(&f, file_name[FILE_IDX_CONFIG], FA_READ);
|
|
|
|
|
if (ret != FR_OK) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ret = f_read(&f, file_buffer, FILE_BUFF_SIZE, &bc);
|
|
|
|
|
if (ret != FR_OK || bc == 0) {
|
|
|
|
|
f_close(&f);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
f_close(&f);
|
|
|
|
|
file_config_parse(file_buffer, (uint32_t)bc, &file_config_sd);
|
|
|
|
|
addr = file_config_get_free_addr(&file_config_flash);
|
|
|
|
|
if ((file_config_sd.baudrate == file_config_flash.baudrate) && \
|
|
|
|
|
(file_config_sd.parity == file_config_flash.parity) && \
|
|
|
|
|
(file_config_sd.stopbits == file_config_flash.stopbits) && \
|
|
|
|
|
(file_config_sd.addr == file_config_flash.addr)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
/* sector full or dtaa dirty */
|
|
|
|
|
if (addr == 0) {
|
|
|
|
|
file_secctor_erase(SECTOR_CONFIG);
|
|
|
|
|
addr = ADDR_CONFIG;
|
|
|
|
|
}
|
|
|
|
|
p = (volatile uint32_t *)(&file_config_sd);
|
|
|
|
|
file_config_sd.id = addr;
|
|
|
|
|
file_config_sd.resv = UART_DEFAULT_RESV;
|
|
|
|
|
file_config_sd.checksum = p[0] + p[1] + p[2];
|
|
|
|
|
file_config_write(addr, &file_config_sd);
|
|
|
|
|
}
|