From 7be17373834b33022ffc02810a6ed7fe9ef8a6b7 Mon Sep 17 00:00:00 2001 From: eddyem Date: Thu, 19 Sep 2019 19:41:46 +0300 Subject: [PATCH] Start with events storage in MCU flash --- F1-nolib/chronometer/Makefile | 8 +- F1-nolib/chronometer/chrono.bin | Bin 13348 -> 14948 bytes F1-nolib/chronometer/flash.c | 213 +++++++++++++++++----------- F1-nolib/chronometer/flash.h | 40 ++++-- F1-nolib/chronometer/hardware.c | 23 ++- F1-nolib/chronometer/hardware.h | 2 + F1-nolib/chronometer/main.c | 51 ++++--- F1-nolib/chronometer/stm32F103xB.ld | 97 +++++++++++++ F1-nolib/chronometer/str.c | 157 ++++++++++++++++---- F1-nolib/chronometer/str.h | 12 +- F1-nolib/chronometer/time.c | 2 +- F1-nolib/chronometer/time.h | 2 +- F1-nolib/chronometer/usart.c | 24 ++-- F1-nolib/chronometer/usart.h | 3 + F1-nolib/chronometer/usb.c | 18 ++- 15 files changed, 490 insertions(+), 162 deletions(-) create mode 100644 F1-nolib/chronometer/stm32F103xB.ld diff --git a/F1-nolib/chronometer/Makefile b/F1-nolib/chronometer/Makefile index b1946cb..b63f564 100644 --- a/F1-nolib/chronometer/Makefile +++ b/F1-nolib/chronometer/Makefile @@ -8,8 +8,8 @@ MCU ?= F103x8 # density (stm32f10x.h, lines 70-84) DENSITY ?= MD # change this linking script depending on particular MCU model, -LDSCRIPT ?= stm32f103xB.ld -DEFS = -DVERSION=\"0.0.1\" +LDSCRIPT ?= stm32F103xB.ld +DEFS = -DVERSION=\"0.0.2\" # debug #DEFS += -DEBUG # proxy GPS output over USART1 @@ -66,7 +66,7 @@ CFLAGS += $(ARCH_FLAGS) ############################################################################### # Linker flags -LDFLAGS += -nostartfiles --static -nostdlibs +LDFLAGS += --static -nostartfiles -nostdlibs LDFLAGS += -L$(LIB_DIR) -L$(TOOLCHLIB) LDFLAGS += -T$(LDSCRIPT) @@ -114,7 +114,7 @@ $(LIST): $(ELF) @echo " OBJDUMP $(LIST)" $(OBJDUMP) -S $(ELF) > $(LIST) -$(ELF): $(OBJDIR) $(OBJS) +$(ELF): $(OBJDIR) $(OBJS) $(LDSCRIPT) @echo " LD $(ELF)" $(LD) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $(ELF) diff --git a/F1-nolib/chronometer/chrono.bin b/F1-nolib/chronometer/chrono.bin index 11b041c8bddc8e49384e22a994aa469b3d4517d9..6d71fc24cde7e89d753546b37fb2197c9aeec4dd 100755 GIT binary patch delta 8031 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 // memcpy -extern uint32_t _edata, _etext, _sdata; -static int maxnum = FLASH_BLOCK_SIZE / sizeof(user_conf); +// max amount of records stored: Config & Logs +static int maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf); +static int maxLnum = FLASH_BLOCK_SIZE / sizeof(user_conf); +// common structure for all datatypes stored +/*typedef struct { + uint16_t userconf_sz; +} flash_storage;*/ -typedef struct{ - const user_conf all_stored; -} flash_storage; - -#define USERCONF_INITIALIZER { \ +#define USERCONF_INITIALIZER { \ +/* .magick = 0xAB, */ \ .userconf_sz = sizeof(user_conf) \ ,.dist_min = LIDAR_MIN_DIST \ ,.dist_max = LIDAR_MAX_DIST \ - ,.trig_pullups = 0xff \ ,.trigstate = 0 \ ,.trigpause = {400, 400, 400, 300, 300} \ ,.ADC_min = ADC_MIN_VAL \ ,.ADC_max = ADC_MAX_VAL \ + ,.USART_speed = USART1_DEFAULT_SPEED \ + ,.strendRN = 0 \ } -__attribute__((section(".myvars"))) static const flash_storage Flash_Storage = { - .all_stored = USERCONF_INITIALIZER -}; +// change to placement +/* +__attribute__ ((section(".logs"))) const uint32_t *logsstart; +__attribute__ ((section(".myvars"))) const user_conf *Flash_Data; +*/ -static const user_conf *Flash_Data = &Flash_Storage.all_stored; +static int erase_flash(const void*, const void*); +static int write2flash(const void*, const void*, int); + +const user_conf *Flash_Data = (const user_conf *)&__varsstart; +const event_log *logsstart = (event_log*) &__logsstart; user_conf the_conf = USERCONF_INITIALIZER; -static int erase_flash(); - static int currentconfidx = -1; // index of current configuration +static int currentlogidx = -1; // index of current logs record /** * @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 l, int r){ +static int binarySearch(int l, int r, uint8_t *start, int stor_size){ +/*DBG("start: "); printuhex(1, (uint32_t)start); +DBG("\nsizeof: "); printu(1, stor_size); +newline();*/ while(r >= l){ int mid = l + (r - l) / 2; - // If the element is present at the middle - // itself - uint16_t sz = Flash_Data[mid].userconf_sz; - if(sz == sizeof(user_conf)){ - if(Flash_Data[mid+1].userconf_sz == 0xffff){ -#if 0 - SEND("Found at "); printu(1, mid); newline(); -#endif + uint8_t *s = start + mid * stor_size; + if(*((uint16_t*)s) == stor_size){ + if(*((uint16_t*)(s + stor_size)) == 0xffff){ return mid; }else{ // element is to the right l = mid + 1; -#if 0 - SEND("To the right, L="); printu(1, l); newline(); -#endif } }else{ // element is to the left r = mid - 1; -#if 0 - SEND("To the left, R="); printu(1, r); newline(); -#endif } } - DBG("Not found!"); return -1; // not found } -static int get_gooddata(){ - static uint8_t firstrun = 1; - if(firstrun){ - firstrun = 0; - if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * 1024; // size in bytes - flsz -= (uint32_t)Flash_Data - FLASH_BASE; -#if 0 - SEND("All size: "); printu(1, flsz); newline(); -#endif - uint32_t usz = (sizeof(user_conf) + 1) / 2; - maxnum = flsz / 2 / usz; -#if 0 - SEND("Maxnum: "); printu(1, maxnum); newline(); -#endif - } +/** + * @brief flashstorage_init - initialization of user conf & logs storage + * run in once @ start + */ +void flashstorage_init(){ + maxCnum = ((uint32_t)&_varslen) / sizeof(user_conf); +//SEND("maxCnum="); printu(1, maxCnum); + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)logsstart - FLASH_BASE; + maxLnum = flsz / sizeof(event_log); +//SEND("\nmaxLnum="); printu(1, maxLnum); } - return binarySearch(0, maxnum-2); // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full -} - -void get_userconf(){ - const user_conf *c = Flash_Data; - int idx = get_gooddata(); - if(idx < 0) return; // no data stored - currentconfidx = idx; - memcpy(&the_conf, &c[idx], sizeof(user_conf)); + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch(0, maxCnum-2, (uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } + currentlogidx = binarySearch(0, maxLnum-2, (uint8_t*)logsstart, sizeof(event_log)); +SEND("\ncurrentconfidx="); printu(1, currentconfidx); +SEND("\ncurrentlogidx="); printu(1, currentlogidx); +newline(); } // store new configuration // @return 0 if all OK int store_userconf(){ - IWDG->KR = IWDG_REFRESH; - int ret = 0; - const user_conf *c = Flash_Data; - int idx = currentconfidx; // maxnum - 3 means that there always should be at least one empty record after last data - if(idx < 0 || idx > maxnum - 3){ // data corruption or there's no more place - idx = 0; + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > maxCnum - 3){ // there's no more place + currentconfidx = 0; DBG("Need to erase flash!"); - if(erase_flash()) return 1; - }else ++idx; // take next data position - currentconfidx = idx; + if(erase_flash(Flash_Data, &__varsend)) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) +SEND("store_userconf\n"); +SEND("\ncurrentconfidx="); printu(1, currentconfidx); +newline(); + return write2flash(&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +/** + * @brief store_log - save log record L into flash memory + * @param L - event log + * @return 0 if all OK + */ +int store_log(event_log *L){ + if(currentlogidx > maxLnum - 3){ // there's no more place + currentlogidx = 0; + DBG("Need to erase flash!"); + if(erase_flash(logsstart, NULL)) return 1; + }else ++currentlogidx; // take next data position (0 - within first run after firmware flashing) +SEND("sore_log\n"); +SEND("\ncurrentlogidx="); printu(1, currentlogidx); +newline(); + return write2flash(&logsstart[currentlogidx], L, sizeof(event_log)); +} + +/** + * @brief dump_log - dump N log records + * @param start - first record to show (if start<0, then first=last+start) + * @param Nlogs - amount of logs to show (if Nlogs<=0, then show all logs) + * @return 0 if all OK, 1 if there's no logs in flash + */ +int dump_log(int start, int Nlogs){ + if(currentlogidx < 0) return 1; + if(start < 0) start += currentlogidx; + if(start > currentlogidx) return 1; + int nlast; + if(Nlogs > 0){ + nlast = start + Nlogs; + if(nlast > currentlogidx) nlast = currentlogidx; + }else nlast = currentlogidx; + ++nlast; + const event_log *l = logsstart + start; + for(int i = start; i < nlast; ++i, ++l){ + IWDG->KR = IWDG_REFRESH; + USB_send(get_trigger_shot(i, l)); + } + return 0; +} + +static int write2flash(const void *start, const void *wrdata, int stor_size){ + int ret = 0; if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; @@ -158,10 +203,11 @@ int store_userconf(){ if(FLASH->SR & FLASH_SR_WRPRTERR) return 1; // write protection FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags FLASH->CR |= FLASH_CR_PG; - uint16_t *data = (uint16_t*) &the_conf; - uint16_t *address = (uint16_t*) &c[idx]; - uint32_t i, count = (sizeof(user_conf) + 1) / 2; + uint16_t *data = (uint16_t*) wrdata; + uint16_t *address = (uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; for (i = 0; i < count; ++i){ + IWDG->KR = IWDG_REFRESH; *(volatile uint16_t*)(address + i) = data[i]; while (FLASH->SR & FLASH_SR_BSY); if(FLASH->SR & FLASH_SR_PGERR) ret = 1; // program error - meet not 0xffff @@ -172,18 +218,29 @@ int store_userconf(){ return ret; } -static int erase_flash(){ +/** + * @brief erase_flash - erase N pages of flash memory + * @param start - first address + * @param end - last address (or NULL if need to erase all flash remaining) + * @return 0 if succeed + */ +static int erase_flash(const void *start, const void *end){ int ret = 0; - uint32_t nblocks = 1; - if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ - uint32_t flsz = FLASH_SIZE * 1024; // size in bytes - flsz -= (uint32_t)Flash_Data - FLASH_BASE; - nblocks = flsz / FLASH_BLOCK_SIZE; -#if 0 - SEND("N blocks:"); printu(1, nblocks); newline(); -#endif + uint32_t nblocks = 1, flsz = 0; + if(!end){ // erase all remaining + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)start - FLASH_BASE; + } + }else{ // erase a part + flsz = (uint32_t)end - (uint32_t)start; } + nblocks = flsz / FLASH_BLOCK_SIZE; + if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1; for(uint32_t i = 0; i < nblocks; ++i){ +#ifdef EBUG + SEND("Try to erase page #"); printu(1,i); newline(); +#endif IWDG->KR = IWDG_REFRESH; /* (1) Wait till no operation is on going */ /* (2) Clear error & EOP bits */ @@ -205,9 +262,6 @@ static int erase_flash(){ /* (5) Clear EOP flag by software by writing EOP at 1 */ /* (6) Reset the PER Bit to disable the page erase */ FLASH->CR |= FLASH_CR_PER; /* (1) */ -#if 0 - SEND("Delete block number "); printu(1, i); newline(); -#endif FLASH->AR = (uint32_t)Flash_Data + i*FLASH_BLOCK_SIZE; /* (2) */ FLASH->CR |= FLASH_CR_STRT; /* (3) */ while(!(FLASH->SR & FLASH_SR_EOP)); @@ -228,7 +282,6 @@ void dump_userconf(){ SEND("userconf_sz="); printu(1, the_conf.userconf_sz); SEND("\ndist_min="); printu(1, the_conf.dist_min); SEND("\ndist_max="); printu(1, the_conf.dist_max); - SEND("\ntrig_pullups="); printuhex(1, the_conf.trig_pullups); SEND("\ntrigstate="); printuhex(1, the_conf.trigstate); SEND("\ntrigpause={"); for(int i = 0; i < TRIGGERS_AMOUNT; ++i){ diff --git a/F1-nolib/chronometer/flash.h b/F1-nolib/chronometer/flash.h index cbbb452..f14789b 100644 --- a/F1-nolib/chronometer/flash.h +++ b/F1-nolib/chronometer/flash.h @@ -31,21 +31,45 @@ #define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) #define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) -typedef struct __attribute__((packed)){ +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(4))){ uint16_t userconf_sz; // "magick number" - uint32_t dist_min; // minimal distance for LIDAR - uint32_t dist_max; // maximal -//- - uint8_t trig_pullups; // trigger pullups: each bit ==0 to set OFF, ==1 to set ON pullup with given number - uint8_t trigstate; // level in `triggered` state - int32_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots int16_t ADC_min; // min&max values of ADC (shot when ADval > ADC_min && < ADC_max) int16_t ADC_max; // !!! BOTH ARE SIGNED! so you can include 0 & 4096 + uint8_t trigstate; // level in `triggered` state + uint8_t strendRN; // strings ends with "\r\n" instead of normal "\n" + uint8_t defflags; // default flags + uint32_t dist_min; // minimal distance for LIDAR + uint32_t dist_max; // maximal -//- + uint32_t USART_speed; // USART1 speed (115200 by default) + int32_t trigpause[TRIGGERS_AMOUNT]; // pause (ms) for false shots } user_conf; -extern user_conf the_conf; +// values for user_conf.defflags: +#define FLAG_SAVE_EVENTS (1 << 0) -void get_userconf(); +/* + * struct to save events logs + */ +typedef struct __attribute__((packed, aligned(4))){ + uint16_t elog_sz; + uint8_t trigno; + trigtime shottime; + int16_t triglen; + uint16_t lidar_dist; +} event_log; + +extern user_conf the_conf; +extern const user_conf *Flash_Data; +extern const event_log *logsstart; +extern uint32_t _varslen, __varsstart, __varsend, __logsstart; + +void flashstorage_init(); int store_userconf(); +int store_log(event_log *L); +int dump_log(int start, int Nlogs); #ifdef EBUG void dump_userconf(); diff --git a/F1-nolib/chronometer/hardware.c b/F1-nolib/chronometer/hardware.c index 3bc94a3..258235f 100644 --- a/F1-nolib/chronometer/hardware.c +++ b/F1-nolib/chronometer/hardware.c @@ -80,11 +80,8 @@ static inline void gpio_setup(){ uint16_t pin = trigpin[i]; // fill trigstate array uint8_t trgs = (the_conf.trigstate & (1<ODR |= pin; + trigport[i]->ODR |= pin; // turn on pullups EXTI->IMR |= pin; if(trgs){ // triggered @1 -> rising interrupt EXTI->RTSR |= pin; @@ -172,6 +169,7 @@ void fillunshotms(){ if(!trigger_shot) return; uint8_t X = 1; for(int i = 0; i < TRIGGERS_AMOUNT; ++i, X<<=1){ + IWDG->KR = IWDG_REFRESH; // check whether trigger is OFF but shot recently if(trigger_shot & X){ uint32_t len = Tms - shotms[i]; @@ -229,15 +227,26 @@ uint8_t gettrig(uint8_t N){ #endif void chk_buzzer(){ - if(!trigger_shot && BUZZER_GET()){ // should we turn off buzzer? + static uint32_t Ton = 0; // Time of first buzzer check + if(!BUZZER_GET()) return; // buzzer if OFF + if(!trigger_shot){ // should we turn off buzzer? uint8_t notrg = 1; for(int i = 0; i < DIGTRIG_AMOUNT; ++i){ uint8_t curval = (trigport[i]->IDR & trigpin[i]) ? 1 : 0; if(curval == trigstate[i]){ - notrg = 0; + notrg = 0; // cheep while digital trigger is ON break; } } - if(notrg) BUZZER_OFF(); // turn off buzzer when there's no trigger events + if(notrg){ // turn off buzzer when there's no trigger events & timeout came + if(Tms - Ton < BUZZER_CHEEP_TIME) return; + Ton = 0; + BUZZER_OFF(); + } + }else{ // buzzer is ON - check timer + if(Ton == 0){ + Ton = Tms; + if(!Ton) Ton = 1; + } } } diff --git a/F1-nolib/chronometer/hardware.h b/F1-nolib/chronometer/hardware.h index a54c01e..441c2b5 100644 --- a/F1-nolib/chronometer/hardware.h +++ b/F1-nolib/chronometer/hardware.h @@ -40,6 +40,8 @@ extern uint8_t buzzer_on; #define BUZZER_ON() do{if(buzzer_on)pin_set(BUZZER_port, BUZZER_pin);}while(0) #define BUZZER_OFF() pin_clear(BUZZER_port, BUZZER_pin) #define BUZZER_GET() (pin_read(BUZZER_port, BUZZER_pin)) +// minimal time to buzzer to cheep (ms) +#define BUZZER_CHEEP_TIME (500) // PPS pin - PA1 #define PPS_port GPIOA diff --git a/F1-nolib/chronometer/main.c b/F1-nolib/chronometer/main.c index f060690..d528bea 100644 --- a/F1-nolib/chronometer/main.c +++ b/F1-nolib/chronometer/main.c @@ -72,6 +72,7 @@ void iwdg_setup(){ char *parse_cmd(char *buf){ int32_t N; static char btns[] = "BTN0=0, BTN1=0, BTN2=0, PPS=0\n"; + event_log l = {.elog_sz = sizeof(event_log), .trigno = 2}; switch(*buf){ case '0': LED_off(); // LED0 off @dbg @@ -79,6 +80,14 @@ char *parse_cmd(char *buf){ case '1': LED_on(); // LED0 on @dbg break; + case 'a': + l.shottime.Time = current_time; + l.shottime.millis = Timer; + l.triglen = getADCval(1); + if(store_log(&l)) SEND("Error storing"); + else SEND("Store OK"); + newline(); + break; case 'b': btns[5] = gettrig(0) + '0'; btns[13] = gettrig(1) + '0'; @@ -100,6 +109,9 @@ char *parse_cmd(char *buf){ case 'd': dump_userconf(); break; + case 'D': + if(dump_log(0, -1)) DBG("Error dumping log: empty?"); + break; case 'p': pin_toggle(USBPU_port, USBPU_pin); SEND("USB pullup is "); @@ -140,9 +152,11 @@ char *parse_cmd(char *buf){ if(buf[1] != '\n') return buf; return "0/1 - turn on/off LED1\n" + "'a' - add test log record\n" "'b' - get buttons's state\n" "'c' - send cold start\n" "'d' - dump current user conf\n" + "'D' - dump log\n" "'p' - toggle USB pullup\n" "'C' - store userconf for N times\n" "'G' - get last LIDAR distance\n" @@ -167,10 +181,15 @@ static char *get_USB(){ if(!x) return NULL; curptr[x] = 0; USB_send(curptr); // echo + //USB_send("ENDOINPUT\n"); //if(x == 1 && *curptr < 32){USB_send("\n"); USB_send(u2str(*curptr)); USB_send("\n");} - if(curptr[x-1] == '\n'){ + if(curptr[x-1] == '\n' || curptr[x-1] == '\r'){ curptr = tmpbuf; rest = USBBUF; + // omit empty lines + if(tmpbuf[0] == '\n') return NULL; + // and wrong empty lines + if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL; return tmpbuf; } curptr += x; rest -= x; @@ -190,16 +209,10 @@ void linecoding_handler(usb_LineCoding __attribute__((unused)) *lc){ // get/set #endif } + +static uint8_t USBconn = 0; void clstate_handler(uint16_t __attribute__((unused)) val){ // lesser bits of val: RTS|DTR - static uint32_t Tlast = 0; - SEND("Tms/Tlast: "); - printu(1, Tms); - newline(); - printu(1, Tlast); - newline(); - if(Tms - Tlast < 500) return; - Tlast = Tms; - USB_send("Chronometer version " VERSION ".\n"); + USBconn = 1; #ifdef EBUG if(val & 2){ DBG("RTS set"); @@ -225,8 +238,6 @@ int main(void){ sysreset(); StartHSE(); SysTick_Config(SYSTICK_DEFCONF); // function SysTick_Config decrements argument! - // read data stored in flash - get_userconf(); // !!! hw_setup() should be the first in setup stage hw_setup(); USB_setup(); @@ -242,11 +253,17 @@ int main(void){ } #endif RCC->CSR |= RCC_CSR_RMVF; // remove reset flags + // read data stored in flash + flashstorage_init(); iwdg_setup(); while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(Timer > 499) LED_on(); // turn ON LED0 over 0.25s after PPS pulse + if(USBconn && Tms > 100){ // USB connection + USBconn = 0; + USB_send("Chronometer version " VERSION ".\n"); + } // check if triggers that was recently shot are off now fillunshotms(); if(lastT > Tms || Tms - lastT > 499){ @@ -301,17 +318,19 @@ int main(void){ } #endif } - //if(trigger_shot) show_trigger_shot(trigger_shot); IWDG->KR = IWDG_REFRESH; usb_proc(); IWDG->KR = IWDG_REFRESH; int r = 0; - char *txt; + char *txt = NULL; if((txt = get_USB())){ DBG("Received data over USB:"); DBG(txt); - if(parse_USBCMD(txt)) - USB_send("Bad command!"); + if(parse_USBCMD(txt)){ + USB_send("Bad command: "); + USB_send(txt); + USB_send("\n"); + } IWDG->KR = IWDG_REFRESH; } #if defined EBUG || defined USART1PROXY diff --git a/F1-nolib/chronometer/stm32F103xB.ld b/F1-nolib/chronometer/stm32F103xB.ld new file mode 100644 index 0000000..ad9d273 --- /dev/null +++ b/F1-nolib/chronometer/stm32F103xB.ld @@ -0,0 +1,97 @@ +/* +******************************************************************************** +* * +* Copyright (c) 2017 Andrea Loi * +* * +* Permission is hereby granted, free of charge, to any person obtaining a * +* copy of this software and associated documentation files (the "Software"), * +* to deal in the Software without restriction, including without limitation * +* the rights to use, copy, modify, merge, publish, distribute, sublicense, * +* and/or sell copies of the Software, and to permit persons to whom the * +* Software is furnished to do so, subject to the following conditions: * +* * +* The above copyright notice and this permission notice shall be included * +* in all copies or substantial portions of the Software. * +* * +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * +* DEALINGS IN THE SOFTWARE. * +* * +******************************************************************************** +*/ + +MEMORY +{ + rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/******************************************************************************/ +/* DON'T EDIT THIS FILE UNLESS YOU KNOW WHAT YOU'RE DOING! */ +/******************************************************************************/ + +/* _isrvectors_tend = 0x00000150; - different for different series */ + +ENTRY(reset_handler) + +SECTIONS { + .vector_table 0x08000000 : + { + _sisrvectors = .; + KEEP(*(.vector_table)) + /* ASSERT(. == _isrvectors_tend, "The vector table needs to be 84 elements long!"); */ + _eisrvectors = .; + } >rom + + .text : + { + . = ALIGN(4); + _stext = .; + *(.text*) + *(.rodata*) + . = ALIGN(4); + _etext = .; + } >rom + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } >rom + + .ARM : { + *(.ARM.exidx*) + } >rom + + .data : + { + . = ALIGN(4); + _sdata = .; + *(.data*) + . = ALIGN(4); + _edata = .; + } >ram AT >rom + + .myvars : + { + . = ALIGN(1024); + KEEP(*(.myvars)) + } > rom + + _ldata = LOADADDR(.data); + + .bss : + { + . = ALIGN(4); + _sbss = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _ebss = .; + } >ram +} + +PROVIDE(_stack = ORIGIN(ram) + LENGTH(ram)); diff --git a/F1-nolib/chronometer/str.c b/F1-nolib/chronometer/str.c index 462dc86..b1d8228 100644 --- a/F1-nolib/chronometer/str.c +++ b/F1-nolib/chronometer/str.c @@ -17,7 +17,6 @@ */ #include "adc.h" -#include "flash.h" #include "GPS.h" #include "lidar.h" #include "str.h" @@ -74,11 +73,10 @@ static void sendi(int32_t I){ * @brief showuserconf - show configuration over USB */ static void showuserconf(){ - USB_send("\nCONFIG:\nDISTMIN="); sendu(the_conf.dist_min); + USB_send("DISTMIN="); sendu(the_conf.dist_min); USB_send("\nDISTMAX="); sendu(the_conf.dist_max); USB_send("\nADCMIN="); sendi(the_conf.ADC_min); USB_send("\nADCMAX="); sendi(the_conf.ADC_max); - USB_send("\nPULLUPS="); sendu(the_conf.trig_pullups); USB_send("\nTRIGLVL="); sendu(the_conf.trigstate); USB_send("\nTRIGPAUSE={"); for(int i = 0; i < TRIGGERS_AMOUNT; ++i){ @@ -86,7 +84,15 @@ static void showuserconf(){ sendu(the_conf.trigpause[i]); } USB_send("}"); - USB_send("\nENDCONFIG\n"); + USB_send("\nUSART1SPD="); sendu(the_conf.USART_speed); + USB_send("\nSTREND="); + if(the_conf.strendRN) USB_send("RN"); + else USB_send("N"); + uint8_t f = the_conf.defflags; + USB_send("\nSAVE_EVENTS="); + if(f & FLAG_SAVE_EVENTS) USB_send("1"); + else USB_send("0"); + USB_send("\n"); } /** @@ -95,7 +101,7 @@ static void showuserconf(){ * @return 0 if got command, 1 if command not recognized */ int parse_USBCMD(char *cmd){ -#define CMP(a,b) cmpstr(a, b, sizeof(b)-1) +#define CMP(a,b) cmpstr(a, b, sizeof(b)) #define GETNUM(x) if(getnum(cmd+sizeof(x)-1, &N)) goto bad_number; static uint8_t conf_modified = 0; uint8_t succeed = 0; @@ -105,23 +111,28 @@ int parse_USBCMD(char *cmd){ if(*cmd == '?'){ // help USB_send("Commands:\n" CMD_ADCMAX " - max ADC value treshold for trigger\n" - CMD_ADCMIN " - min -//- (triggered when ADval>min & min & 3000000) goto bad_number; + if(the_conf.USART_speed != (uint32_t)N){ + the_conf.USART_speed = (uint32_t)N; + conf_modified = 1; + succeed = 1; + } + }else if(CMP(cmd, CMD_RESET) == 0){ + USB_send("Soft reset\n"); + NVIC_SystemReset(); + }else if(CMP(cmd, CMD_STREND) == 0){ + char c = cmd[sizeof(CMD_STREND) - 1]; + succeed = 1; + if(c == 'n' || c == 'N') the_conf.strendRN = 0; + else if(c == 'r' || c == 'R') the_conf.strendRN = 1; + else{ + succeed = 0; + USB_send("Bad letter, should be 'n' or 'r'\n"); + } + }else if(CMP(cmd, CMD_FLASH) == 0){ // show flash size + USB_send("FLASHSIZE="); + sendu(FLASH_SIZE); + USB_send("kB\nFLASH_BASE="); + sendu(FLASH_BASE); + USB_send("\nFlash_Data="); + sendu((uint32_t)Flash_Data); + USB_send("\nvarslen="); + sendu((uint32_t)&_varslen); + USB_send("\nvarsend="); + sendu((uint32_t)&__varsend); + USB_send("\nvarsstart="); + sendu((uint32_t)&__varsstart); + USB_send("\nlogsstart="); + sendu((uint32_t)logsstart); + USB_send("\n"); + }else if(CMP(cmd, CMD_SAVEEVTS) == 0){ + if('0' == cmd[sizeof(CMD_SAVEEVTS) - 1]) the_conf.defflags &= ~FLAG_SAVE_EVENTS; + else the_conf.defflags |= FLAG_SAVE_EVENTS; + succeed = 1; + }else if(CMP(cmd, CMD_DUMP) == 0){ + if(dump_log(0, -1)) USB_send("Event log empty!\n"); }else return 1; + /*else if(CMP(cmd, CMD_) == 0){ + ; + }*/ + IWDG->KR = IWDG_REFRESH; if(succeed) USB_send("Success!\n"); return 0; @@ -298,7 +357,38 @@ int parse_USBCMD(char *cmd){ } /** - * @brief show_trigger_shot - print on USB message about last trigger shot time + * @brief get_trigger_shot - print on USB message about last trigger shot time + * @param number - number of event (if > -1) + * @param logdata - record from event log + * @return string with data + */ +char *get_trigger_shot(int number, const event_log *logdata){ + static char buf[64]; + char *bptr = buf; + if(number > -1){ + bptr = strcp(bptr, u2str(number)); + bptr = strcp(bptr, ": "); + } + if(logdata->trigno == LIDAR_TRIGGER){ + bptr = strcp(bptr, "LIDAR, dist="); + bptr = strcp(bptr, u2str(logdata->lidar_dist)); + bptr = strcp(bptr, ", TRIG" STR(LIDAR_TRIGGER) "="); + }else{ + bptr = strcp(bptr, "TRIG"); + *bptr++ = '0' + logdata->trigno; + } + *bptr++ = '='; + IWDG->KR = IWDG_REFRESH; + bptr = strcp(bptr, get_time(&logdata->shottime.Time, logdata->shottime.millis)); + bptr = strcp(bptr, ", len="); + if(logdata->triglen < 0) bptr = strcp(bptr, ">1s"); + else bptr = strcp(bptr, u2str((uint32_t) logdata->triglen)); + *bptr++ = '\n'; *bptr++ = 0; + return buf; +} + +/** + * @brief show_trigger_shot printout @ USB data with all triggers shot recently (+ save it in flash) * @param tshot - each bit consists information about trigger */ void show_trigger_shot(uint8_t tshot){ @@ -307,20 +397,39 @@ void show_trigger_shot(uint8_t tshot){ IWDG->KR = IWDG_REFRESH; if(tshot & X) tshot &= ~X; else continue; - if(!triglen[i]) continue; // noice - if(i == LIDAR_TRIGGER){ - USB_send("LIDAR, dist="); - sendu(lidar_triggered_dist); - USB_send(", TRIG="); - }else{ - USB_send("TRIG"); - sendu(i); + event_log l; + l.elog_sz = sizeof(event_log); + l.trigno = i; + if(i == LIDAR_TRIGGER) l.lidar_dist = lidar_triggered_dist; + l.shottime = shottime[i]; + l.triglen = triglen[i]; + USB_send(get_trigger_shot(-1, &l)); + if(the_conf.defflags & FLAG_SAVE_EVENTS){ + if(store_log(&l)) USB_send("\n\nError saving event!\n\n"); } - USB_send("="); - USB_send(get_time(&shottime[i].Time, shottime[i].millis)); - USB_send(", len="); - if(triglen[i] < 0) USB_send(">1s"); - else sendu((uint32_t) triglen[i]); - USB_send("\n"); } } + +/** + * @brief strln == strlen + * @param s - string + * @return length + */ +int strln(const char *s){ + int i = 0; + while(*s++) ++i; + return i; +} + +/** + * @brief strcp - strcpy (be carefull: it doesn't checks destination length!) + * @param dst - destination + * @param src - source + * @return pointer to '\0' @ dst`s end + */ +char *strcp(char* dst, const char *src){ + int l = strln(src); + if(l < 1) return dst; + while((*dst++ = *src++)); + return dst - 1; +} diff --git a/F1-nolib/chronometer/str.h b/F1-nolib/chronometer/str.h index c3d7f48..9855ada 100644 --- a/F1-nolib/chronometer/str.h +++ b/F1-nolib/chronometer/str.h @@ -20,6 +20,7 @@ #define STR_H__ #include "stm32f1.h" +#include "flash.h" #include "hardware.h" // usb commands @@ -31,7 +32,6 @@ #define CMD_PRINTTIME "time" #define CMD_STORECONF "store" #define CMD_GPSSTR "gpsstring" -#define CMD_PULLUP "pullup" #define CMD_SHOWCONF "showconf" #define CMD_TRIGLVL "triglevel" #define CMD_TRGPAUSE "trigpause" @@ -43,12 +43,20 @@ #define CMD_GPSRESTART "gpsrestart" #define CMD_BUZZER "buzzer" #define CMD_GPSSTAT "gpsstat" +#define CMD_USARTSPD "usartspd" +#define CMD_RESET "reset" +#define CMD_STREND "strend" +#define CMD_FLASH "flash" +#define CMD_SAVEEVTS "saveevt" +#define CMD_DUMP "dump" extern uint8_t showGPSstr; +int strln(const char *s); +char *strcp(char* dst, const char *src); int cmpstr(const char *s1, const char *s2, int n); char *getchr(const char *str, char symbol); int parse_USBCMD(char *cmd); +char *get_trigger_shot(int number, const event_log *logdata); void show_trigger_shot(uint8_t trigger_shot); - #endif // STR_H__ diff --git a/F1-nolib/chronometer/time.c b/F1-nolib/chronometer/time.c index 7a562f6..d10ed81 100644 --- a/F1-nolib/chronometer/time.c +++ b/F1-nolib/chronometer/time.c @@ -102,7 +102,7 @@ static void ms2str(char **str, uint32_t T){ /** * print time: Tm - time structure, T - milliseconds */ -char *get_time(curtime *Tm, uint32_t T){ +char *get_time(const curtime *Tm, uint32_t T){ static char buf[64]; char *bstart = &buf[5], *bptr = bstart; int S = 0; diff --git a/F1-nolib/chronometer/time.h b/F1-nolib/chronometer/time.h index c76f081..a15e9fb 100644 --- a/F1-nolib/chronometer/time.h +++ b/F1-nolib/chronometer/time.h @@ -53,7 +53,7 @@ extern uint32_t trigger_ms[]; extern volatile int need_sync; -char *get_time(curtime *T, uint32_t m); +char *get_time(const curtime *T, uint32_t m); void set_time(const char *buf); void time_increment(); void systick_correction(); diff --git a/F1-nolib/chronometer/usart.c b/F1-nolib/chronometer/usart.c index 6a66524..93c2e8a 100644 --- a/F1-nolib/chronometer/usart.c +++ b/F1-nolib/chronometer/usart.c @@ -18,6 +18,7 @@ #include "stm32f1.h" +#include "flash.h" #include "usart.h" #include "lidar.h" @@ -169,7 +170,7 @@ static void usart_setup(int n, uint32_t BRR){ void usarts_setup(){ RCC->AHBENR |= RCC_AHBENR_DMA1EN; #if defined EBUG || defined USART1PROXY - usart_setup(1, 72000000 / 115200); // debug console or GPS proxy + usart_setup(1, 72000000 / the_conf.USART_speed); // debug console or GPS proxy #endif usart_setup(2, 36000000 / 9600); // GPS usart_setup(3, 36000000 / 115200); // LIDAR @@ -253,27 +254,20 @@ void usart3_isr(){ // return string buffer with val char *u2str(uint32_t val){ - static char bufa[11]; - char bufb[10]; - int l = 0, bpos = 0; - IWDG->KR = IWDG_REFRESH; + static char buf[11]; + char *bufptr = &buf[10]; + *bufptr = 0; if(!val){ - bufa[0] = '0'; - l = 1; + *(--bufptr) = '0'; }else{ while(val){ - bufb[l++] = val % 10 + '0'; + *(--bufptr) = val % 10 + '0'; val /= 10; } - int i; - bpos += l; - for(i = 0; i < l; ++i){ - bufa[--bpos] = bufb[i]; - } } - bufa[l + bpos] = 0; - return bufa; + return bufptr; } + // print 32bit unsigned int void printu(int n, uint32_t val){ usart_send(n, u2str(val)); diff --git a/F1-nolib/chronometer/usart.h b/F1-nolib/chronometer/usart.h index 638e5dd..6189c63 100644 --- a/F1-nolib/chronometer/usart.h +++ b/F1-nolib/chronometer/usart.h @@ -29,6 +29,9 @@ #define TIMEOUT_MS (1500) #endif +// USART1 default speed +#define USART1_DEFAULT_SPEED (115200) + #define STR_HELPER(s) #s #define STR(s) STR_HELPER(s) diff --git a/F1-nolib/chronometer/usb.c b/F1-nolib/chronometer/usb.c index 09730c5..8a8f27d 100644 --- a/F1-nolib/chronometer/usb.c +++ b/F1-nolib/chronometer/usb.c @@ -20,6 +20,7 @@ * MA 02110-1301, USA. * */ +#include "flash.h" #include "usb.h" #include "usb_lib.h" #include "usart.h" @@ -106,17 +107,26 @@ void USB_send(const char *buf){ DBG("USB not configured"); return; } + char tmpbuf[USB_TXBUFSZ]; uint16_t l = 0, ctr = 0; const char *p = buf; while(*p++) ++l; while(l){ - uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l; + uint16_t proc = 0, s = (l > USB_TXBUFSZ - 1) ? USB_TXBUFSZ - 1: l; + for(int i = 0; i < s; ++i, ++proc){ + char c = buf[ctr+proc]; + if(c == '\n' && the_conf.strendRN){ // add '\r' before '\n' + tmpbuf[i++] = '\r'; + if(i == s) ++s; + } + tmpbuf[i] = c; + } tx_succesfull = 0; - EP_Write(3, (uint8_t*)&buf[ctr], s); + EP_Write(3, (uint8_t*)tmpbuf, s); uint32_t ctra = 1000000; while(--ctra && tx_succesfull == 0); - l -= s; - ctr += s; + l -= proc; + ctr += proc; } }