diff --git a/F1:F103/AS3935-lightning/as3935.bin b/F1:F103/AS3935-lightning/as3935.bin index 69e28a7..255e37e 100755 Binary files a/F1:F103/AS3935-lightning/as3935.bin and b/F1:F103/AS3935-lightning/as3935.bin differ diff --git a/F1:F103/AS3935-lightning/as3935.c b/F1:F103/AS3935-lightning/as3935.c index 6615d01..5513073 100644 --- a/F1:F103/AS3935-lightning/as3935.c +++ b/F1:F103/AS3935-lightning/as3935.c @@ -26,7 +26,7 @@ extern uint32_t Tms; // read one register -static int as3935_read(uint8_t reg, uint8_t *data){ +int as3935_read(uint8_t reg, uint8_t *data){ uint8_t word[2]; word[0] = MODE_READ | (reg & MODE_MASK); word[1] = 0; @@ -35,7 +35,7 @@ static int as3935_read(uint8_t reg, uint8_t *data){ return TRUE; } -static int as3935_write(uint8_t reg, uint8_t data){ +int as3935_write(uint8_t reg, uint8_t data){ uint8_t word[2]; word[0] = MODE_WRITE | (reg & MODE_MASK); word[1] = data; @@ -100,33 +100,26 @@ int as3935_gain(uint8_t n){ } #endif -#include "usb_dev.h" -#include "strfunc.h" -// starting calibration +// calibrate RCO int as3935_calib_rco(){ t_tun_disp t; - USB_sendstr("1\n"); if(!as3935_read(TUN_DISP, &t.u8)) return FALSE; - USB_sendstr("2\n"); if(!as3935_write(CALIB_RCO, DIRECT_COMMAND)) return FALSE; - USB_sendstr("3\n"); t.DISP_LCO = t.DISP_TRCO = 0; t.DISP_SRCO = 1; if(!as3935_write(TUN_DISP, t.u8)) return FALSE; - USB_sendstr("4\n"); uint32_t Tstart = Tms; while(Tms - Tstart < 3) IWDG->KR = 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"