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 11b041c..6d71fc2 100755 Binary files a/F1-nolib/chronometer/chrono.bin and b/F1-nolib/chronometer/chrono.bin differ diff --git a/F1-nolib/chronometer/flash.c b/F1-nolib/chronometer/flash.c index a0b3b6f..3f1f096 100644 --- a/F1-nolib/chronometer/flash.c +++ b/F1-nolib/chronometer/flash.c @@ -39,117 +39,162 @@ #include "adc.h" #include "flash.h" #include "lidar.h" +#include "str.h" #include "usart.h" // DBG +#include "usb.h" // printout #include // 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; } }