From 40c8f23e36ef6b203be52555c768608ad9585ec7 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Tue, 14 Apr 2026 23:42:52 +0300 Subject: [PATCH] seems like it works; later TODO: add USART for RS232 --- F1:F103/AS3935-lightning/as3935.bin | Bin 17764 -> 13460 bytes F1:F103/AS3935-lightning/as3935.c | 25 +-- F1:F103/AS3935-lightning/as3935.creator.user | 2 +- F1:F103/AS3935-lightning/as3935.h | 8 +- F1:F103/AS3935-lightning/commproto.cpp | 172 +++++++++++++++---- F1:F103/AS3935-lightning/commproto.h | 2 + F1:F103/AS3935-lightning/flash.c | 169 ++++++++++++++++++ F1:F103/AS3935-lightning/flash.h | 67 ++++++++ F1:F103/AS3935-lightning/main.c | 48 ++++-- F1:F103/AS3935-lightning/spi.c | 3 + F1:F103/AS3935-lightning/spi.h | 2 + F1:F103/AS3935-lightning/usb_descr.c | 23 ++- F1:F103/AS3935-lightning/usb_descr.h | 7 +- F1:F103/AS3935-lightning/usb_lib.c | 1 + F1:F103/AS3935-lightning/version.inc | 4 +- 15 files changed, 455 insertions(+), 78 deletions(-) create mode 100644 F1:F103/AS3935-lightning/flash.c create mode 100644 F1:F103/AS3935-lightning/flash.h diff --git a/F1:F103/AS3935-lightning/as3935.bin b/F1:F103/AS3935-lightning/as3935.bin index 69e28a7c2c233ea15ba7cca92a32fbf4a1ce6789..255e37e760440b2816a87de3dee04f7a85b38904 100755 GIT binary patch literal 13460 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

{5W=_{yNm1h|cj2x6I{hj5y8Zql1ql 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 = IWDG_REFRESH; // sleep for ~2ms t.DISP_SRCO = 0; - USB_sendstr("5\n"); if(!as3935_write(TUN_DISP, t.u8)) return FALSE; - while(Tms - Tstart < 300) IWDG->KR = IWDG_REFRESH; // sleep for ~2ms + return TRUE; +} + +int as3935_get_calib(uint8_t *n){ t_calib srco, trco; - USB_sendstr("6\n"); if(!as3935_read(CALIB_TRCO, &trco.u8)) return FALSE; - USB_sendstr(uhex2str(trco.u8)); newline(); if(!as3935_read(CALIB_SRCO, &srco.u8)) return FALSE; - USB_sendstr(uhex2str(srco.u8)); newline(); - if(!srco.CALIB_DONE || !trco.CALIB_DONE) return FALSE; + *n = (!srco.CALIB_DONE || !trco.CALIB_DONE) ? 0 : 1; return TRUE; } @@ -136,7 +129,7 @@ int as3935_wakeup(){ if(!as3935_read(AFE_GAIN, &g.u8)) return FALSE; g.PWD = 0; if(!as3935_write(AFE_GAIN, g.u8)) return FALSE; - return as3935_calib_rco(); + return TRUE; } // set amplifier gain diff --git a/F1:F103/AS3935-lightning/as3935.creator.user b/F1:F103/AS3935-lightning/as3935.creator.user index 22f7fa6..7d88ed0 100644 --- a/F1:F103/AS3935-lightning/as3935.creator.user +++ b/F1:F103/AS3935-lightning/as3935.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F1:F103/AS3935-lightning/as3935.h b/F1:F103/AS3935-lightning/as3935.h index 876971c..79691cb 100644 --- a/F1:F103/AS3935-lightning/as3935.h +++ b/F1:F103/AS3935-lightning/as3935.h @@ -121,14 +121,18 @@ typedef union{ // distance out of range #define DIST_OUT_OF_RANGE (0x3f) +int as3935_read(uint8_t reg, uint8_t *data); +int as3935_write(uint8_t reg, uint8_t data); +int as3935_wakeup(); +int as3935_get_calib(uint8_t *n); +int as3935_calib_rco(); + int as3935_displco(uint8_t n); int as3935_get_displco(uint8_t *n); int as3935_tuncap(uint8_t n); int as3935_get_tuncap(uint8_t *n); int as3935_gain(uint8_t n); int as3935_get_gain(uint8_t *n); -int as3935_wakeup(); -int as3935_calib_rco(); //int as3935_set_gain(uint8_t g); int as3935_wdthres(uint8_t t); int as3935_get_wdthres(uint8_t *t); diff --git a/F1:F103/AS3935-lightning/commproto.cpp b/F1:F103/AS3935-lightning/commproto.cpp index 0810a3e..2dd4a61 100644 --- a/F1:F103/AS3935-lightning/commproto.cpp +++ b/F1:F103/AS3935-lightning/commproto.cpp @@ -24,6 +24,7 @@ extern "C"{ #include "adc.h" #include "as3935.h" #include "commproto.h" +#include "flash.h" #include "hardware.h" #include "spi.h" #include "strfunc.h" @@ -36,10 +37,6 @@ extern volatile uint32_t Tms; static uint8_t curbuf[MAXSTRLEN]; -// COMMAND(dumpconf, "dump global configuration") -// COMMAND(eraseflash, "erase full flash storage") -// COMMAND(readconf, "re-read config from flash") -// COMMAND(saveconf, "save current user configuration into flash") // COMMAND(USART, "Read USART data or send (USART=hex)") // list of all commands and handlers @@ -47,21 +44,28 @@ static uint8_t curbuf[MAXSTRLEN]; COMMAND(clearstat, "clear amount of lightnings for last 15 min") \ COMMAND(displco, "display on LCO: 0- nothing, 1- TRCO, 2- SRCO, 3- LCO") \ COMMAND(distance, "distance to lightning, km") \ + COMMAND(dumpconf, "dump current configuration") \ COMMAND(energy, "energy of last lightning") \ + COMMAND(eraseflash, "erase full flash storage") \ COMMAND(gain, "change sensor's gain (0..1f)") \ COMMAND(help, "show this help") \ COMMAND(intcode, "last interrupt code") \ + COMMAND(iscalib, "check if sensor x calibrated") \ COMMAND(lco_fdiv, "set Fdiv of antenna LCO") \ COMMAND(maskdist, "mask (1) or unmask (0) disturber") \ COMMAND(mcutemp, "get MCU temperature (degC*10)") \ COMMAND(mcureset, "reset MCU") \ COMMAND(minnumlig, "ninimal lightnings number (0..2)") \ COMMAND(nflev, "noice floor level (0..7)") \ + COMMAND(readconf, "read configuration from given sensor") \ COMMAND(resetdef, "reset sensor to defaults") \ + COMMAND(restonstart,"restore sensors configuration on start") \ + COMMAND(saveconf, "save current configuration into flash") \ + COMMAND(setiface, "set USB interface name (max 16 symbols)") \ COMMAND(SPI, "transfer SPI data: SPIx=data (hex)") \ COMMAND(srej, "spike rejection (0..15)") \ COMMAND(time, "show current time (ms)") \ - COMMAND(tuncap, "set 'tune capasitors' to given value") \ + COMMAND(tuncap, "set 'tune capasitors' to given value (0..15)") \ COMMAND(vdd, "get approx Vdd value (V*100)") \ COMMAND(wakeup, "wake-up given sensor and make its calibration") \ COMMAND(wdthres, "watchdog threshold (0..15)" ) @@ -93,7 +97,7 @@ static const char* errtxt[ERR_AMOUNT] = { [ERR_OVERFLOW] = "OVERFLOW\n", }; -static const char *EQ = " = "; // equal sign for getters +const char *EQ = " = "; // equal sign for getters // send `command = ` #define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0) @@ -141,47 +145,128 @@ static bool argsvals(char *args, int32_t *parno, int32_t *parval){ return false; } -static errcodes_t cmd_time(const char *cmd, char _U_ *args){ +static errcodes_t cmd_time(const char *cmd, char*){ CMDEQ(); SEND(u2str(Tms)); SEND("\n"); return ERR_AMOUNT; } -static errcodes_t cmd_mcureset(const char _U_ *cmd, char _U_ *args){ +static errcodes_t cmd_mcureset(const char*, char*){ NVIC_SystemReset(); return ERR_CANTRUN; // never reached } -#if 0 -static errcodes_t cmd_readconf(const char _U_ *cmd, char _U_ *args){ - flashstorage_init(); - return ERR_OK; -} -static errcodes_t cmd_saveconf(const char _U_ *cmd, char _U_ *args){ +static errcodes_t cmd_saveconf(const char*, char*){ if(store_userconf()) return ERR_CANTRUN; return ERR_OK; } -static errcodes_t cmd_eraseflash(const char _U_ *cmd, char _U_ *args){ - if(erase_storage()) return ERR_CANTRUN; +static errcodes_t cmd_eraseflash(const char*, char*){ + if(erase_storage(-1)) return ERR_CANTRUN; return ERR_OK; } -#endif +static errcodes_t cmd_readconf(const char*, char* args){ + int32_t CHno = -1; + splitargs(args, &CHno); + if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; + as3935_channel = static_cast(CHno); + uint8_t par; + if(!as3935_get_gain(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].AFE_GB = par; + if(!as3935_get_wdthres(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].WDTH = par; + if(!as3935_get_nflev(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].NF_LEV = par; + if(!as3935_get_srej(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].SREJ = par; + if(!as3935_get_minnumlig(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].MIN_NUM_LIG = par; + if(!as3935_get_maskdist(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].MASK_DIST = par; + if(!as3935_get_lco_fdiv(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].LCO_FDIV = par; + if(!as3935_get_tuncap(&par)) return ERR_CANTRUN; + the_conf.spars[CHno].TUN_CAP = par; + return ERR_OK; +} -static errcodes_t cmd_mcutemp(const char *cmd, char _U_ *args){ +static errcodes_t cmd_setiface(const char* cmd, char* args){ + char *ifname = splitargs(args, NULL); + if(ifname){ // setter + int l = strlen(ifname); + if(l > MAX_IINTERFACE_SZ) return ERR_BADPAR; // too long + the_conf.iIlength = (uint8_t) l * 2; + char *ptr = (char*)the_conf.iInterface; + for(int i = 0; i < l; ++i){ + *ptr++ = *ifname++; + *ptr++ = 0; + } + } + // getter + CMDEQ(); + int l = the_conf.iIlength / 2; + char *ptr = (char*)the_conf.iInterface; + for(int i = 0; i < l; ++i){ + SEND(ptr); // next is always zero + ptr += 2; + } + SEND("\n"); + return ERR_AMOUNT; +} + +static errcodes_t cmd_restonstart(const char* cmd, char* args){ + int32_t val; + if(argsvals(args, NULL, &val)){ // setter + if(!val) the_conf.flags.restore = 0; + else the_conf.flags.restore = 1; + } + CMDEQ(); + SEND(u2str(the_conf.flags.restore)); + SEND("\n"); + return ERR_AMOUNT; +} + +static void showpar(const char *par, uint8_t n, uint8_t v){ + char c[2]; + c[0] = '0' + n; c[1] = 0; + SEND(par); SEND(c); SEND(EQ); + SEND(u2str(v)); +} + +static errcodes_t cmd_dumpconf(const char*, char*){ + SEND("userconf_sz="); SEND(u2str(the_conf.userconf_sz)); + SEND("\ncurr_idx="); SEND(u2str(currentconfidx)); + SEND("\ncapacity="); SEND(u2str(maxCnum-2)); + cmd_setiface("\nsetiface", NULL); + cmd_restonstart("restonstart", NULL); + for(int i = 0; i < SENSORS_AMOUNT; ++i){ + showpar("gain", i, the_conf.spars[i].AFE_GB); + showpar("\nlco_fdiv", i, the_conf.spars[i].LCO_FDIV); + showpar("\nmaskdist", i, the_conf.spars[i].MASK_DIST); + showpar("\nminnumlig", i, the_conf.spars[i].MIN_NUM_LIG); + showpar("\nnflev", i, the_conf.spars[i].NF_LEV); + showpar("\nsrej", i, the_conf.spars[i].SREJ); + showpar("\ntuncap", i, the_conf.spars[i].TUN_CAP); + showpar("\nwdthres", i, the_conf.spars[i].WDTH); + SEND("\n"); + } + return ERR_AMOUNT; +} + +static errcodes_t cmd_mcutemp(const char *cmd, char*){ CMDEQ(); SEND(i2str(getMCUtemp())); SEND("\n"); return ERR_AMOUNT; } -static errcodes_t cmd_vdd(const char *cmd, char _U_ *args){ +static errcodes_t cmd_vdd(const char *cmd, char*){ CMDEQ(); SEND(u2str(getVdd())); SEND("\n"); return ERR_AMOUNT; } -static errcodes_t cmd_help(const char _U_ *cmd, char _U_ *args){ +static errcodes_t cmd_help(const char*, char*){ SEND(REPOURL); for(size_t i = 0; i < sizeof(cmdInfo)/sizeof(cmdInfo[0]); i++){ SEND(cmdInfo[i].name); @@ -194,9 +279,8 @@ static errcodes_t cmd_help(const char _U_ *cmd, char _U_ *args){ static errcodes_t senscmd8(int32_t CHno, int (*cmd)(uint8_t), int32_t arg){ if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; uint8_t par = static_cast(arg); - CS(CHno); + as3935_channel = static_cast(CHno); int ans = cmd(par); - CS_OFF(); if(ans) return ERR_OK; return ERR_CANTRUN; } @@ -204,9 +288,8 @@ static errcodes_t senscmd8(int32_t CHno, int (*cmd)(uint8_t), int32_t arg){ static errcodes_t getta(const char *cmd, int32_t CHno, int (*fn)(uint8_t*)){ if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; uint8_t par; - CS(CHno); + as3935_channel = static_cast(CHno); int ans = fn(&par); - CS_OFF(); if(!ans) return ERR_CANTRUN; CMDEQP(CHno); SEND(u2str(par)); SEND("\n"); return ERR_AMOUNT; @@ -214,9 +297,8 @@ static errcodes_t getta(const char *cmd, int32_t CHno, int (*fn)(uint8_t*)){ static errcodes_t senscmd(int32_t CHno, int (*cmd)()){ if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; - CS(CHno); + as3935_channel = static_cast(CHno); int ans = cmd(); - CS_OFF(); if(ans) return ERR_OK; return ERR_CANTRUN; } @@ -249,7 +331,6 @@ AS3935_FN8(srej) AS3935_FN8(minnumlig) AS3935_FN8(maskdist) AS3935_FN8(lco_fdiv) -AS3935_FN(wakeup) AS3935_FN(clearstat) AS3935_FN(resetdef) @@ -258,7 +339,8 @@ static errcodes_t cmd_ ## nm(const char* cmd, char* args){ \ int32_t CHno = -1; uint8_t par;\ splitargs(args, &CHno); \ if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; \ - CS(CHno); int ans = as3935_ ## nm(&par); CS_OFF(); \ + as3935_channel = static_cast(CHno); \ + int ans = as3935_ ## nm(&par); \ if(!ans) return ERR_CANTRUN; \ CMDEQP(CHno); SEND(u2str(par)); SEND("\n"); \ return ERR_AMOUNT; } @@ -266,12 +348,27 @@ static errcodes_t cmd_ ## nm(const char* cmd, char* args){ \ AS3935_GU8(intcode) AS3935_GU8(distance) +static errcodes_t cmd_iscalib(const char* cmd, char* args){ + int32_t CHno = -1; + splitargs(args, &CHno); + return getta(cmd, CHno, as3935_get_calib); +} + +static errcodes_t cmd_wakeup(const char*, char* args){ + int32_t CHno = -1; + splitargs(args, &CHno); + if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; + as3935_channel = static_cast(CHno); + if(!as3935_wakeup() || !as3935_calib_rco()) return ERR_CANTRUN; + return ERR_OK; +} + static errcodes_t cmd_energy(const char* cmd, char* args){ int32_t CHno = -1; uint32_t par; splitargs(args, &CHno); if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; - CS(CHno); int ans = as3935_energy(&par); CS_OFF(); - if(!ans) return ERR_CANTRUN; + as3935_channel = static_cast(CHno); + if(!as3935_energy(&par)) return ERR_CANTRUN; CMDEQP(CHno); SEND(u2str(par)); SEND("\n"); return ERR_AMOUNT; } @@ -317,7 +414,7 @@ static int parse_hex_data(char *input, uint8_t *output, int max_len){ return out_idx; } -static errcodes_t cmd_SPI(const char _U_ *cmd, char *args){ +static errcodes_t cmd_SPI(const char* cmd, char *args){ if(!args) return ERR_BADVAL; if(!(SPI1->CR1 & SPI_CR1_SPE)) return ERR_CANTRUN; int32_t CHno; @@ -326,9 +423,8 @@ static errcodes_t cmd_SPI(const char _U_ *cmd, char *args){ if(CHno < 0 || CHno >= SENSORS_AMOUNT) return ERR_BADPAR; int len = parse_hex_data(setter, curbuf, MAXSTRLEN); if(len <= 0) return ERR_BADVAL; - CS(CHno); + as3935_channel = static_cast(CHno); uint8_t ret = SPI_transmit(curbuf, len); - CS_OFF(); if(!ret) return ERR_BUSY; CMDEQP(CHno); if(len > 8) SEND("\n"); @@ -359,3 +455,13 @@ const char *parse_cmd(int (*sendfun)(const char *), char *str){ if(ecode < ERR_AMOUNT) return errtxt[ecode]; return NULL; } + +// show lightning information +void lightning_info(int (*sendfun)(const char*), uint8_t CHno){ + if(!sendfun || CHno >= SENSORS_AMOUNT) return; + char c[2]; + c[0] = '0' + CHno; c[1] = 0; + SEND = sendfun; + cmd_energy("energy", c); + cmd_distance("distance", c); +} diff --git a/F1:F103/AS3935-lightning/commproto.h b/F1:F103/AS3935-lightning/commproto.h index 6e585dd..2efe1ce 100644 --- a/F1:F103/AS3935-lightning/commproto.h +++ b/F1:F103/AS3935-lightning/commproto.h @@ -49,4 +49,6 @@ typedef enum{ // maximal string length includint terminating zero #define MAXSTRLEN 256 +extern const char *EQ; const char *parse_cmd(int (*sendfun)(const char*), char *buf); +void lightning_info(int (*sendfun)(const char*), uint8_t CHno); diff --git a/F1:F103/AS3935-lightning/flash.c b/F1:F103/AS3935-lightning/flash.c new file mode 100644 index 0000000..c0c406a --- /dev/null +++ b/F1:F103/AS3935-lightning/flash.c @@ -0,0 +1,169 @@ +/* + * This file is part of the as3935 project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include // memcpy + +#include "flash.h" +#include "strfunc.h" + +extern const uint32_t _BLOCKSIZE; +extern const user_conf __varsstart; + +static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; +uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here + +static int write2flash(const void*, const void*, uint32_t); +const user_conf *Flash_Data = (const user_conf *)(&__varsstart); +user_conf the_conf = { + .userconf_sz = sizeof(user_conf), +}; + +int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * any struct searched should have its sizeof() @ the first field!!! + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @param start - starting address + * @param stor_size - size of structure to search + * @return index of non-empty cell or -1 + */ +static int binarySearch(int r, const uint8_t *start, int stor_size){ + int l = 0; + while(r >= l){ + int mid = l + (r - l) / 2; + const uint8_t *s = start + mid * stor_size; + if(*((const uint16_t*)s) == stor_size){ + if(*((const uint16_t*)(s + stor_size)) == 0xffff){ // next is free + return mid; + }else{ // element is to the right + l = mid + 1; + } + }else{ // element is to the left + r = mid - 1; + } + } + return -1; // not found +} + +/** + * @brief flashstorage_init - initialization of user conf storage + * run in once @ start + */ +void flashstorage_init(){ + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; + maxCnum = flsz / sizeof(user_conf); + } + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } +} + +// store new configuration +// @return 0 if all OK +int store_userconf(){ + // maxnum - 3 means that there always should be at least one empty record after last data + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > (int)maxCnum - 3){ // there's no more place + currentconfidx = 0; + if(erase_storage(-1)) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) + return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){ + int ret = 0; + if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while (FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags + FLASH->CR |= FLASH_CR_PG; + const uint16_t *data = (const uint16_t*) wrdata; + volatile uint16_t *address = (volatile uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; + for(i = 0; i < count; ++i){ + *(volatile uint16_t*)(address + i) = data[i]; + while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + if(*(volatile uint16_t*)(address + i) != data[i]){ + ret = 1; + break; + } + if(FLASH->SR & FLASH_SR_PGERR){ + ret = 1; // program error - meet not 0xffff + break; + } + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; + } + FLASH->CR &= ~(FLASH_CR_PG); + return ret; +} + +// erase Nth page of flash storage (flash should be prepared!) +static int erase_pageN(int N){ + int ret = 0; + FLASH->AR = (uint32_t)Flash_Data + N*FLASH_blocksize; + FLASH->CR |= FLASH_CR_STRT; + while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP; + if(FLASH->SR & FLASH_SR_WRPRTERR){ /* Check Write protection error */ + ret = 1; + FLASH->SR = FLASH_SR_WRPRTERR; /* Clear the flag by software by writing it at 1*/ + } + return ret; +} + +// erase full storage (npage < 0) or its nth page; @return 0 if all OK +int erase_storage(int npage){ + int ret = 0; + uint32_t end = 1, start = 0, flsz = 0; + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)Flash_Data - FLASH_BASE; + } + end = flsz / FLASH_blocksize; + if(end == 0 || end >= FLASH_SIZE) return 1; + if(npage > -1){ // erase only one page + if((uint32_t)npage >= end) return 1; + start = npage; + end = start + 1; + } + if((FLASH->CR & FLASH_CR_LOCK) != 0){ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; + FLASH->CR |= FLASH_CR_PER; + for(uint32_t i = start; i < end; ++i){ + if(erase_pageN(i)){ + ret = 1; + break; + } + } + FLASH->CR &= ~FLASH_CR_PER; + return ret; +} + diff --git a/F1:F103/AS3935-lightning/flash.h b/F1:F103/AS3935-lightning/flash.h new file mode 100644 index 0000000..e6b5eee --- /dev/null +++ b/F1:F103/AS3935-lightning/flash.h @@ -0,0 +1,67 @@ +/* + * This file is part of the as3935 project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include "hardware.h" // for SENSORS_AMOUNT + +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +// maximal size (in letters) of iInterface for settings +#define MAX_IINTERFACE_SZ (16) + +typedef struct{ + // t_afe_gain + uint8_t AFE_GB : 5; + // t_threshold + uint8_t WDTH : 4; + uint8_t NF_LEV : 3; + // t_lightning_reg + uint8_t SREJ : 4; + uint8_t MIN_NUM_LIG : 2; + // t_int_mask_ant + uint8_t MASK_DIST : 1; + uint8_t LCO_FDIV : 2; + // t_tun_disp + uint8_t TUN_CAP : 4; +} sens_pars_t; + +typedef struct{ + uint8_t restore : 1; // restore sensors' parameters on start +} flags_t; + +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(4))){ + uint16_t userconf_sz; // "magick number" + uint16_t iInterface[MAX_IINTERFACE_SZ]; // interface name + uint8_t iIlength; // length in symbols + sens_pars_t spars[SENSORS_AMOUNT]; // sensors' stored flags + flags_t flags; // common flags +} user_conf; + +extern uint32_t maxCnum; +extern user_conf the_conf; +extern int currentconfidx; + +void flashstorage_init(); +int store_userconf(); +int erase_storage(int npage); diff --git a/F1:F103/AS3935-lightning/main.c b/F1:F103/AS3935-lightning/main.c index 077b30b..02c2848 100644 --- a/F1:F103/AS3935-lightning/main.c +++ b/F1:F103/AS3935-lightning/main.c @@ -17,8 +17,10 @@ */ #include "as3935.h" +#include "flash.h" #include "hardware.h" #include "commproto.h" +#include "flash.h" #include "spi.h" #include "strfunc.h" #include "usb_dev.h" @@ -41,6 +43,7 @@ int main(){ hw_setup(); USBPU_OFF(); SysTick_Config(72000); + flashstorage_init(); USB_setup(); #ifndef EBUG iwdg_setup(); @@ -48,10 +51,21 @@ int main(){ //usart_setup(); USBPU_ON(); // wake-up all sensors and run auto-calibration - for(int ch = 0; ch < SENSORS_AMOUNT; ++ch){ - CS(ch); + for(uint8_t ch = 0; ch < SENSORS_AMOUNT; ++ch){ + as3935_channel = ch; as3935_wakeup(); - CS_OFF(); + as3935_calib_rco(); + if(the_conf.flags.restore){ + sens_pars_t *p = &the_conf.spars[ch]; + as3935_gain(p->AFE_GB); + as3935_wdthres(p->WDTH); + as3935_nflev(p->NF_LEV); + as3935_srej(p->SREJ); + as3935_minnumlig(p->MIN_NUM_LIG); + as3935_maskdist(p->MASK_DIST); + as3935_lco_fdiv(p->LCO_FDIV); + as3935_tuncap(p->TUN_CAP); + } } while(1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog @@ -65,24 +79,26 @@ int main(){ const char *ans = parse_cmd(USB_sendstr, inbuff); if(ans) USB_sendstr(ans); } - for(int ch = 0; ch < SENSORS_AMOUNT; ++ch){ - if(DISPLCO[ch] == DISPLCO_NOTHING) continue; // don't check IRQ in if it used as clock output + for(uint8_t ch = 0; ch < SENSORS_AMOUNT; ++ch){ + if(DISPLCO[ch] != DISPLCO_NOTHING) continue; // don't check IRQ in if it used as clock output if(CHK_INT(ch)){ if(oldint[ch] == 0){ oldint[ch] = 1; - USB_sendstr("INTERRUPT @ "); USB_putbyte('0'+ch); newline(); uint8_t code; - CS(ch); + as3935_channel = ch; int result = as3935_intcode(&code); - CS_OFF(); - if(!result) USB_sendstr("Can't get code\n"); - else{ - USB_sendstr("Code: "); - switch(code){ - case INT_NH: USB_sendstr("Noice too high\n"); break; - case INT_D: USB_sendstr("Disturber detected\n"); break; - case INT_L: USB_sendstr("Lightning interrupt\n"); break; - default: USB_sendstr("Unknown\n"); break; + if(!result) USB_sendstr("CANTGET\n"); + else if(code){ + uint8_t savedcode = code; + USB_sendstr("INTERRUPT"); USB_putbyte('0'+ch); USB_putbyte('='); + const char *delim = NULL, *comma = ","; + if(code & INT_NH){ USB_sendstr("NOICE"); delim = comma; code &= ~INT_NH; } + if(code & INT_D){ USB_sendstr(delim); USB_sendstr("DISTURBER"); delim = comma; code &= ~INT_D; } + if(code & INT_L){ USB_sendstr(delim); USB_sendstr("LIGHTNING"); code &= ~INT_L; } + if(code) USB_sendstr(u2str(code)); + newline(); + if(savedcode == INT_L){ // clear lightning - show distance and power + lightning_info(USB_sendstr, ch); } } } diff --git a/F1:F103/AS3935-lightning/spi.c b/F1:F103/AS3935-lightning/spi.c index cf1be4b..4c0b84f 100644 --- a/F1:F103/AS3935-lightning/spi.c +++ b/F1:F103/AS3935-lightning/spi.c @@ -26,6 +26,7 @@ static const uint32_t SPI_CR1 = SPI_CR1_MSTR | SPI_CR1_BR_2 | SPI_CR1_BR_0 | SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_CPHA /* | SPI_CR1_CPOL*/; spiStatus SPI_status = SPI_NOTREADY; +uint8_t as3935_channel = 0; void spi_setup(){ // master, no slave select, BR=F/16, CPOL/CPHA - polarity. @@ -46,6 +47,7 @@ volatile uint32_t wctr; uint8_t SPI_transmit(uint8_t *buf, uint8_t len){ if(!buf || !len) return 0; // bad data format if(SPI_status != SPI_READY) return 0; // spi not ready to transmit data + CS(as3935_channel); for(uint8_t x = 0; x < len; ++x){ WAITX(!(SPI1->SR & SPI_SR_TXE)); SPI1->DR = buf[x]; @@ -53,6 +55,7 @@ uint8_t SPI_transmit(uint8_t *buf, uint8_t len){ WAITX(!(SPI1->SR & SPI_SR_RXNE)); buf[x] = SPI1->DR; } + CS_OFF(); return len; } diff --git a/F1:F103/AS3935-lightning/spi.h b/F1:F103/AS3935-lightning/spi.h index 6e4a2f7..a95f1aa 100644 --- a/F1:F103/AS3935-lightning/spi.h +++ b/F1:F103/AS3935-lightning/spi.h @@ -27,6 +27,8 @@ typedef enum{ } spiStatus; extern spiStatus SPI_status; +// SPI channel number for `CS` macro +extern uint8_t as3935_channel; void spi_setup(); uint8_t SPI_transmit(uint8_t *buf, uint8_t len); diff --git a/F1:F103/AS3935-lightning/usb_descr.c b/F1:F103/AS3935-lightning/usb_descr.c index f6cc65c..cfa715c 100644 --- a/F1:F103/AS3935-lightning/usb_descr.c +++ b/F1:F103/AS3935-lightning/usb_descr.c @@ -15,6 +15,9 @@ * along with this program. If not, see . */ +#include // memcpy + +#include "flash.h" // MAX_IINTERFACE_SZ, the_conf #include "usb_descr.h" // low/high for uint16_t @@ -143,14 +146,22 @@ _USB_LANG_ID_(LD, LANG_US); _USB_STRING_(SD, u"0.0.1"); _USB_STRING_(MD, u"eddy@sao.ru"); _USB_STRING_(PD, u"AS3935 lightning detector"); -_USB_STRING_(ID, u"lightning_det"); + +// iInterface will change on initialisation by config +#define _USB_IIDESCR_(str) {sizeof(str), 0x03, str} +typedef struct{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bString[MAX_IINTERFACE_SZ]; +}iidescr_t; +static iidescr_t iid = _USB_IIDESCR_(u"lightning_det"); static const void* const StringDescriptor[iDESCR_AMOUNT] = { [iLANGUAGE_DESCR] = &LD, [iMANUFACTURER_DESCR] = &MD, [iPRODUCT_DESCR] = &PD, [iSERIAL_DESCR] = &SD, - [iINTERFACE_DESCR1] = &ID + [iINTERFACE_DESCR1] = &iid }; static void wr0(const uint8_t *buf, uint16_t size, uint16_t askedsize){ @@ -208,3 +219,11 @@ void get_descriptor(config_pack_t *pack){ break; } } + +void setup_interfaces(){ + if(the_conf.iIlength){ + iid.bLength = the_conf.iIlength + 2; // +2 - for bLength and bDescriptorType + memcpy(iid.bString, the_conf.iInterface, the_conf.iIlength); + } + iid.bDescriptorType = 0x03; +} diff --git a/F1:F103/AS3935-lightning/usb_descr.h b/F1:F103/AS3935-lightning/usb_descr.h index 0874763..55f7ad5 100644 --- a/F1:F103/AS3935-lightning/usb_descr.h +++ b/F1:F103/AS3935-lightning/usb_descr.h @@ -56,13 +56,8 @@ enum{ iPRODUCT_DESCR, iSERIAL_DESCR, iINTERFACE_DESCR1, - /* iINTERFACE_DESCR2, - iINTERFACE_DESCR3, - iINTERFACE_DESCR4, - iINTERFACE_DESCR5, - iINTERFACE_DESCR6, - iINTERFACE_DESCR7,*/ iDESCR_AMOUNT }; void get_descriptor(config_pack_t *pack); +void setup_interfaces(); diff --git a/F1:F103/AS3935-lightning/usb_lib.c b/F1:F103/AS3935-lightning/usb_lib.c index 3e7189e..41ea6da 100644 --- a/F1:F103/AS3935-lightning/usb_lib.c +++ b/F1:F103/AS3935-lightning/usb_lib.c @@ -424,6 +424,7 @@ void USB_setup(){ USB->BCDR |= USB_BCDR_DPPU; // turn ON DP pullup NVIC_EnableIRQ(USB_UCPD1_2_IRQn); #endif + setup_interfaces(); } diff --git a/F1:F103/AS3935-lightning/version.inc b/F1:F103/AS3935-lightning/version.inc index 34c03ee..e839456 100644 --- a/F1:F103/AS3935-lightning/version.inc +++ b/F1:F103/AS3935-lightning/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "25" -#define BUILD_DATE "2026-04-11" +#define BUILD_NUMBER "43" +#define BUILD_DATE "2026-04-14"