diff --git a/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_prl b/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_prl index 09d6bbb..3371732 100644 --- a/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_prl +++ b/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_prl @@ -67,6 +67,12 @@ "visible_layers": "fffffff_ffffffff", "zone_display_mode": 0 }, + "git": { + "repo_password": "", + "repo_type": "", + "repo_username": "", + "ssh_key": "" + }, "meta": { "filename": "stm32.kicad_prl", "version": 3 diff --git a/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_pro b/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_pro index e2ed6ea..7235be6 100644 --- a/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_pro +++ b/F0:F030,F042,F072/usbcan/kicad/stm32.kicad_pro @@ -187,6 +187,13 @@ "zones_allow_external_fillets": false, "zones_use_no_outline": true }, + "ipc2581": { + "dist": "", + "distpn": "", + "internal_id": "", + "mfg": "", + "mpn": "" + }, "layer_presets": [], "viewports": [] }, @@ -588,14 +595,75 @@ "gencad": "", "idf": "", "netlist": "stm32.net", + "plot": "", + "pos_files": "", "specctra_dsn": "", "step": "", + "svg": "", "vrml": "" }, "page_layout_descr_file": "" }, "schematic": { "annotate_start_num": 0, + "bom_fmt_presets": [], + "bom_fmt_settings": { + "field_delimiter": ",", + "keep_line_breaks": false, + "keep_tabs": false, + "name": "CSV", + "ref_delimiter": ",", + "ref_range_delimiter": "", + "string_delimiter": "\"" + }, + "bom_presets": [], + "bom_settings": { + "exclude_dnp": false, + "fields_ordered": [ + { + "group_by": false, + "label": "Reference", + "name": "Reference", + "show": true + }, + { + "group_by": true, + "label": "Value", + "name": "Value", + "show": true + }, + { + "group_by": false, + "label": "Datasheet", + "name": "Datasheet", + "show": true + }, + { + "group_by": false, + "label": "Footprint", + "name": "Footprint", + "show": true + }, + { + "group_by": false, + "label": "Qty", + "name": "${QUANTITY}", + "show": true + }, + { + "group_by": true, + "label": "DNP", + "name": "${DNP}", + "show": true + } + ], + "filter_string": "", + "group_symbols": true, + "name": "Grouped By Value", + "sort_asc": true, + "sort_field": "Обозначение" + }, + "connection_grid_size": 50.0, "drawing": { "dashed_lines_dash_length_ratio": 12.0, "dashed_lines_gap_length_ratio": 3.0, @@ -612,6 +680,11 @@ "intersheets_ref_suffix": "", "junction_size_choice": 3, "label_size_ratio": 0.3, + "operating_point_overlay_i_precision": 3, + "operating_point_overlay_i_range": "~A", + "operating_point_overlay_v_precision": 3, + "operating_point_overlay_v_range": "~V", + "overbar_offset_ratio": 1.23, "pin_symbol_size": 25.0, "text_offset_ratio": 0.3 }, @@ -637,6 +710,7 @@ "spice_external_command": "spice \"%I\"", "spice_model_current_sheet_as_root": true, "spice_save_all_currents": false, + "spice_save_all_dissipations": false, "spice_save_all_voltages": false, "subpart_first_id": 65, "subpart_id_separator": 0 diff --git a/F1:F103/FX3U/adc.c b/F1:F103/FX3U/adc.c index ee10071..466e7e0 100644 --- a/F1:F103/FX3U/adc.c +++ b/F1:F103/FX3U/adc.c @@ -18,7 +18,7 @@ #include "adc.h" -uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9]; +uint16_t ADC_array[ADC_CHANNELS*9]; void adc_setup(){ uint32_t ctr = 0; @@ -29,7 +29,7 @@ void adc_setup(){ // DMA configuration DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); DMA1_Channel1->CMAR = (uint32_t)(ADC_array); - DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9; + DMA1_Channel1->CNDTR = ADC_CHANNELS * 9; DMA1_Channel1->CCR = DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC | DMA_CCR_PL | DMA_CCR_EN; RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_ADCPRE)) | RCC_CFGR_ADCPRE_DIV8; // ADC clock = RCC / 8 @@ -38,7 +38,7 @@ void adc_setup(){ ADC1->SMPR1 = ADC_SMPR1_SMP16 | ADC_SMPR1_SMP17; // sequence order: 0 -> 16 -> 17 ADC1->SQR3 = (0 << 0) | (16<<5) | (17 << 10); - ADC1->SQR1 = (NUMBER_OF_ADC_CHANNELS - 1) << 20; // amount of conversions + ADC1->SQR1 = (ADC_CHANNELS - 1) << 20; // amount of conversions ADC1->CR1 = ADC_CR1_SCAN; // scan mode // DMA, continuous mode; enable vref & Tsens; enable SWSTART as trigger ADC1->CR2 = ADC_CR2_DMA | ADC_CR2_TSVREFE | ADC_CR2_CONT | ADC_CR2_EXTSEL | ADC_CR2_EXTTRIG; @@ -68,7 +68,7 @@ uint16_t getADCval(int nch){ #define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } #define PIX_SWAP(a,b) { register uint16_t temp=(a);(a)=(b);(b)=temp; } uint16_t p[9]; - for(i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS){ // first we should prepare array for optmed + for(i = 0; i < 9; ++i, addr += ADC_CHANNELS){ // first we should prepare array for optmed p[i] = ADC_array[addr]; } PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ; @@ -95,7 +95,7 @@ uint32_t getADCvoltage(int nch){ int32_t getMCUtemp(){ // Temp = (V25 - Vsense)/Avg_Slope + 25 // V_25 = 1.45V, Slope = 4.3e-3 - int32_t Vsense = getVdd() * getADCval(CHTSENS); + int32_t Vsense = getVdd() * getADCval(ADC_CH_TSEN); int32_t temperature = 593920 - Vsense; // 593920 == 145*4096 temperature /= 172; // == /(4096*10*4.3e-3), 10 - to convert from *100 to *10 temperature += 250; @@ -105,6 +105,6 @@ int32_t getMCUtemp(){ // return Vdd * 100 (V) uint32_t getVdd(){ uint32_t vdd = 120 * 4096; // 1.2V - vdd /= getADCval(CHVDD); + vdd /= getADCval(ADC_CH_VDD); return vdd; } diff --git a/F1:F103/FX3U/adc.h b/F1:F103/FX3U/adc.h index b3539cd..cf7b82b 100644 --- a/F1:F103/FX3U/adc.h +++ b/F1:F103/FX3U/adc.h @@ -20,19 +20,16 @@ #include -#define NUMBER_OF_ADC_CHANNELS (3) - -// Vsen voltage channel -#define CHVSEN (0) -// channels for Tsens and Vdd -#define CHTSENS (1) -#define CHVDD (2) +// ADC channels in array +enum{ + ADC_CH_VSEN = 0, // ADC_ch0 + ADC_CH_TSEN, // T sensor + ADC_CH_VDD, // Vdd sensor + ADC_CHANNELS +}; /** - * @brief ADC_array - array for ADC channels with median filtering: - * 0 - Isensor voltage - * 1 - internal Tsens - * 2 - Vdd + * @brief ADC_array - array for ADC channels with median filtering */ extern uint16_t ADC_array[]; diff --git a/F1:F103/FX3U/can.c b/F1:F103/FX3U/can.c index ff837d4..1c1bb21 100644 --- a/F1:F103/FX3U/can.c +++ b/F1:F103/FX3U/can.c @@ -17,19 +17,31 @@ */ #include "can.h" +#include "canproto.h" +#include "flash.h" // CANID #include "hardware.h" #include "proto.h" +#include "strfunc.h" #include "usart.h" // REMAPPED to PD0/PD1!!! #include // memcpy +// CAN bus oscillator frequency: 36MHz +#define CAN_F_OSC (36000000UL) +// timing values TBS1 and TBS2 (in BTR [TBS1-1] and [TBS2-1]) +// use 3 and 2 to get 6MHz +#define CAN_TBS1 (3) +#define CAN_TBS2 (2) +// bitrate oscillator frequency +#define CAN_BIT_OSC (CAN_F_OSC / (1+CAN_TBS1+CAN_TBS2)) + // circular buffer for received messages static CAN_message messages[CAN_INMESSAGE_SIZE]; static uint8_t first_free_idx = 0; // index of first empty cell static int8_t first_nonfree_idx = -1; // index of first data cell -static uint16_t oldspeed = 100; // speed of last init +static uint32_t oldspeed = 100000; // speed of last init static CAN_status can_status = CAN_STOP; @@ -44,9 +56,11 @@ CAN_status CAN_get_status(){ // push next message into buffer; return 1 if buffer overfull static int CAN_messagebuf_push(CAN_message *msg){ //MSG("Try to push\n"); +/* #ifdef EBUG usart_send("push\n"); #endif +*/ if(first_free_idx == first_nonfree_idx){ #ifdef EBUG usart_send("INBUF OVERFULL\n"); @@ -72,7 +86,7 @@ CAN_message *CAN_messagebuf_pop(){ return msg; } -void CAN_reinit(uint16_t speed){ +void CAN_reinit(uint32_t speed){ CAN1->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; @@ -100,12 +114,11 @@ so if TBS1=4 and TBS2=3, sum=8, bit sampling freq is 48/8 = 6MHz 1MBps - 6 */ -// speed - in kbps -void CAN_setup(uint16_t speed){ +// speed - in bps +void CAN_setup(uint32_t speed){ if(speed == 0) speed = oldspeed; - else if(speed < 50) speed = 50; - else if(speed > 3000) speed = 3000; - oldspeed = speed; + else if(speed < CAN_MIN_SPEED) speed = CAN_MIN_SPEED; + else if(speed > CAN_MAX_SPEED) speed = CAN_MAX_SPEED; uint32_t tmout = 16000000; // Configure GPIO: PD0 - CAN_Rx, PD1 - CAN_Tx AFIO->MAPR |= AFIO_MAPR_CAN_REMAP_REMAP3; @@ -122,7 +135,7 @@ void CAN_setup(uint16_t speed){ /* (6) Wait the init mode leaving */ /* (7) Enter filter init mode, (16-bit + mask, bank 0 for FIFO 0) */ /* (8) Acivate filter 0 for two IDs */ - /* (9) Identifier list mode */ + /* (9) Identifier mode for bank#0, mask mode for #1 */ /* (10) Set the Id list */ /* (12) Leave filter init */ /* (13) Set error interrupts enable (& bus off) */ @@ -131,19 +144,26 @@ void CAN_setup(uint16_t speed){ if(--tmout == 0) break; CAN1->MCR &=~ CAN_MCR_SLEEP; /* (3) */ CAN1->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */ - - CAN1->BTR = 2 << 20 | 3 << 16 | (4500/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */ + CAN1->BTR = (CAN_TBS2-1) << 20 | (CAN_TBS1-1) << 16 | (CAN_BIT_OSC/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */ + oldspeed = CAN_BIT_OSC/(uint32_t)((CAN1->BTR & CAN_BTR_BRP) + 1); +#ifdef EBUG + usart_send("canspeed->"); usart_send(u2str(oldspeed)); newline(); +#endif CAN1->MCR &= ~CAN_MCR_INRQ; /* (5) */ tmout = 16000000; while((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) /* (6) */ if(--tmout == 0) break; - // accept ALL + // accept depending of monitor flag CAN1->FMR = CAN_FMR_FINIT; /* (7) */ - CAN1->FA1R = CAN_FA1R_FACT0 | CAN_FA1R_FACT1; /* (8) */ - // set to 1 all needed bits of CAN1->FFA1R to switch given filters to FIFO1 - CAN1->sFilterRegister[0].FR1 = (1<<21)|(1<<5); // all odd IDs - CAN1->FFA1R = 2; // filter 1 for FIFO1, filter 0 - for FIFO0 - CAN1->sFilterRegister[1].FR1 = (1<<21); // all even IDs + CAN1->FA1R = CAN_FA1R_FACT0; /* (8) */ + CAN1->FM1R = CAN_FM1R_FBM0; + // filter 0 for FIFO0 + CAN1->sFilterRegister[0].FR1 = the_conf.CANID << 5; // (10) CANID and 0 + if(flags.can_monitor){ /* (11) */ + CAN1->FA1R |= CAN_FA1R_FACT1; // activate filter1 + CAN1->sFilterRegister[1].FR1 = 0; // all packets + CAN1->FFA1R = 2; // filter 1 for FIFO1 + } CAN1->FMR &= ~CAN_FMR_FINIT; /* (12) */ CAN1->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1 | CAN_IER_BOFIE; /* (13) */ @@ -158,7 +178,45 @@ void CAN_setup(uint16_t speed){ can_status = CAN_READY; } -void can_proc(){ +/** + * @brief CAN_sniffer - reconfigure CAN in sniffer or normal mode + * @param issniffer - ==0 for normal mode + */ +void CAN_sniffer(uint8_t issniffer){ + flags.can_monitor = issniffer; + CAN_reinit(0); +} + +void CAN_printerr(){ + uint32_t last_err_code = CAN1->ESR; + if(!last_err_code){ + usart_send("No errors\n"); + return; + } + usart_send("Receive error counter: "); + usart_send(u2str((last_err_code & CAN_ESR_REC)>>24)); + usart_send("\nTransmit error counter: "); + usart_send(u2str((last_err_code & CAN_ESR_TEC)>>16)); + usart_send("\nLast error code: "); + int lec = (last_err_code & CAN_ESR_LEC) >> 4; + const char *errmsg = "No"; + switch(lec){ + case 1: errmsg = "Stuff"; break; + case 2: errmsg = "Form"; break; + case 3: errmsg = "Ack"; break; + case 4: errmsg = "Bit recessive"; break; + case 5: errmsg = "Bit dominant"; break; + case 6: errmsg = "CRC"; break; + case 7: errmsg = "(set by software)"; break; + } + usart_send(errmsg); usart_send(" error\n"); + if(last_err_code & CAN_ESR_BOFF) usart_send("Bus off "); + if(last_err_code & CAN_ESR_EPVF) usart_send("Passive error limit "); + if(last_err_code & CAN_ESR_EWGF) usart_send("Error counter limit"); + newline(); +} + +void CAN_proc(){ // check for messages in FIFO0 & FIFO1 if(CAN1->RF0R & CAN_RF0R_FMP0){ can_process_fifo(0); @@ -168,22 +226,32 @@ void can_proc(){ } IWDG->KR = IWDG_REFRESH; if(CAN1->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS - usart_send("\nToo much errors, restarting CAN!\n"); - // request abort for all mailboxes - CAN1->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; - // reset CAN bus - RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; - RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; - CAN_setup(0); + if(flags.can_printoff){ + usart_send("error=canerr\n"); + CAN_printerr(); + } + CAN_reinit(0); } } -CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){ - uint8_t mailbox = 0; - // check first free mailbox - if(CAN1->TSR & (CAN_TSR_TME)){ - mailbox = (CAN1->TSR & CAN_TSR_CODE) >> 24; - }else{ // no free mailboxes +CAN_status CAN_send(CAN_message *message){ + if(!message) return CAN_ERR; + uint8_t *msg = message->data; + uint8_t len = message->length; + uint16_t target_id = message->ID; + uint8_t mailbox = 0xff; + uint32_t Tstart = Tms; + while(Tms - Tstart < SEND_TIMEOUT_MS/10){ + IWDG->KR = IWDG_REFRESH; + if(CAN1->TSR & (CAN_TSR_TME)){ + mailbox = (CAN1->TSR & CAN_TSR_CODE) >> 24; + break; + } + } + if(mailbox == 0xff){// no free mailboxes +#ifdef EBUG + usart_send("No free mailboxes\n"); +#endif return CAN_BUSY; } CAN_TxMailBox_TypeDef *box = &CAN1->sTxMailBox[mailbox]; @@ -220,6 +288,28 @@ CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){ return CAN_OK; } +/** + * @brief parseCANcommand - parser + * @param msg - incoming message @ my CANID + * FORMAT: + * 0 1 2 3 4 5 6 7 + * [CMD][PAR][errcode][VALUE] + * CMD - uint16_t, PAR - uint8_t, errcode - one of CAN_errcodes, VALUE - int32_t + * `errcode` of incoming message doesn't matter + * incoming data may have variable length + */ +TRUE_INLINE void parseCANcommand(CAN_message *msg){ + msg->ID = the_conf.CANID; // set own ID for broadcast messages + // check PING + if(msg->length != 0) run_can_cmd(msg); + uint32_t Tstart = Tms; + while(Tms - Tstart < SEND_TIMEOUT_MS){ + if(CAN_OK == CAN_send(msg)) return; + IWDG->KR = IWDG_REFRESH; + } + usart_send("error=canbusy\n"); +} + static void can_process_fifo(uint8_t fifo_num){ if(fifo_num > 1) return; CAN_FIFOMailBox_TypeDef *box = &CAN1->sFIFOMailBox[fifo_num]; @@ -263,7 +353,9 @@ static void can_process_fifo(uint8_t fifo_num){ dat[0] = lb & 0xff; } } - if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later + // run command for my or broadcast ID + if(msg.ID == the_conf.CANID || msg.ID == 0) parseCANcommand(&msg); + if(flags.can_monitor && CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later *RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message } //if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0; diff --git a/F1:F103/FX3U/can.h b/F1:F103/FX3U/can.h index 087bb75..c7a9a44 100644 --- a/F1:F103/FX3U/can.h +++ b/F1:F103/FX3U/can.h @@ -20,10 +20,12 @@ #include -// amount of filter banks in STM32F0 -#define STM32F0FBANKNO 28 -// flood period in milliseconds -#define FLOOD_PERIOD_MS 5 +// min/max speeds in bps +#define CAN_MAX_SPEED ((uint32_t)3000000UL) +#define CAN_MIN_SPEED ((uint32_t)9600UL) + +// wait to send not more tnah +#define SEND_TIMEOUT_MS (100) // incoming message buffer size #define CAN_INMESSAGE_SIZE (8) @@ -46,11 +48,12 @@ typedef enum{ CAN_status CAN_get_status(); -void CAN_reinit(uint16_t speed); -void CAN_setup(uint16_t speed); +void CAN_reinit(uint32_t speed); +void CAN_setup(uint32_t speed); -CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id); -void can_proc(); -void printCANerr(); +CAN_status CAN_send(CAN_message *message); +void CAN_proc(); +void CAN_printerr(); +void CAN_sniffer(uint8_t issniffer); CAN_message *CAN_messagebuf_pop(); diff --git a/F1:F103/FX3U/canproto.c b/F1:F103/FX3U/canproto.c new file mode 100644 index 0000000..2df7fb0 --- /dev/null +++ b/F1:F103/FX3U/canproto.c @@ -0,0 +1,248 @@ +/* + * This file is part of the fx3u project. + * Copyright 2024 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 "adc.h" +#include "canproto.h" +#include "flash.h" +#include "hardware.h" +#include "proto.h" +#include "strfunc.h" +#include "usart.h" + +#define FIXDL(m) do{m->length = 8;}while(0) + +/*********** START of all common functions list (for `funclist`) ***********/ +// reset MCU + +static errcodes reset(CAN_message _U_ *msg){ + usart_send("Soft reset\n"); + usart_transmit(); + NVIC_SystemReset(); + return ERR_OK; // never reached +} +// get/set Tms +static errcodes time_getset(CAN_message *msg){ + if(ISSETTER(msg->data)){ + Tms = *(uint32_t*)&msg->data[4]; + }else FIXDL(msg); + *(uint32_t*)&msg->data[4] = Tms; + return ERR_OK; +} +// get MCU T +static errcodes mcut(CAN_message *msg){ + FIXDL(msg); + *(int32_t*)&msg->data[4] = getMCUtemp(); + return ERR_OK; +} +// get ADC raw values +static errcodes adcraw(CAN_message *msg){ + FIXDL(msg); + uint8_t no = msg->data[2] & ~SETTER_FLAG; + if(no >= ADC_CHANNELS) return ERR_BADPAR; + *(uint32_t*)&msg->data[4] = getADCval(no); + return ERR_OK; +} +// get ADC voltage +static errcodes adcv(CAN_message *msg){ + FIXDL(msg); + uint8_t no = msg->data[2] & ~SETTER_FLAG; + if(no >= ADC_CH_TSEN) return ERR_BADPAR; + float v = getADCvoltage(no) /** the_conf.adcmul[no] * 100.f*/; + *(uint32_t*)&msg->data[4] = (uint32_t) v; + return ERR_OK; +} +// get/set CAN ID +static errcodes canid(CAN_message *msg){ + if(ISSETTER(msg->data)){ + the_conf.CANID = *(uint32_t*)&msg->data[4]; + CAN_reinit(0); // setup with new ID + }else FIXDL(msg); + *(uint32_t*)&msg->data[4] = the_conf.CANID; + return ERR_OK; +} +/* +// get/set ADC multiplier +static errcodes adcmul(CAN_message *msg){ + uint8_t no = msg->data[2] & ~SETTER_FLAG; + if(no >= ADC_TSENS) return ERR_BADPAR; + if(ISSETTER(msg->data)){ + the_conf.adcmul[no] = ((float)*(uint32_t*)&msg->data[4])/1000.f; + }else FIXDL(msg); + *(uint32_t*)&msg->data[4] = (uint32_t)(1000.f * the_conf.adcmul[no]); + return ERR_OK; +} +*/ +// save config +static errcodes saveconf(CAN_message _U_ *msg){ + if(0 == store_userconf()) return ERR_OK; + return ERR_CANTRUN; +} +// erase storage +static errcodes erasestor(CAN_message _U_ *msg){ + if(0 == erase_storage(-1)) return ERR_OK; + return ERR_CANTRUN; +} +/* +// relay management +static errcodes relay(CAN_message *msg){ + if(ISSETTER(msg->data)){ + if(msg->data[4] == 1) RELAY_ON(); + else RELAY_OFF(); + }else FIXDL(msg); + *(uint32_t*)&msg->data[4] = RELAY_GET(); + return ERR_OK; +} +// blocking ESW get status +static errcodes eswblk(CAN_message *msg){ + uint8_t no = msg->data[2] & ~SETTER_FLAG; + if(no > 1) return ERR_BADPAR; + FIXDL(msg); + *(uint32_t*)&msg->data[4] = getSwitches(no); + return ERR_OK; +} +// bounce-free ESW get status +static errcodes esw(CAN_message *msg){ + uint8_t no = msg->data[2] & ~SETTER_FLAG; + if(no > 1) return ERR_BADPAR; + FIXDL(msg); + *(uint32_t*)&msg->data[4] = getESW(no); + return ERR_OK; +} +*/ + +// common uint32_t setter/getter +static errcodes u32setget(CAN_message *msg){ + uint16_t idx = *(uint16_t*)msg->data; + uint32_t *ptr = NULL; + switch(idx){ + case CMD_CANSPEED: ptr = &the_conf.CANspeed; CAN_reinit(*(uint32_t*)&msg->data[4]); break; + //case CMD_BOUNCE: ptr = &the_conf.bounce_ms; break; + case CMD_USARTSPEED: ptr = &the_conf.usartspeed; break; + default: break; + } + if(!ptr) return ERR_CANTRUN; // unknown error + if(ISSETTER(msg->data)){ + *ptr = *(uint32_t*)&msg->data[4]; + }else FIXDL(msg); + *(uint32_t*)&msg->data[4] = *ptr; + return ERR_OK; +} + +/* +// common bitflag setter/getter +static errcodes flagsetget(CAN_message *msg){ + uint16_t idx = *(uint16_t*)msg->data; + uint8_t bit = 32; + switch(idx){ + case CMD_ENCISSSI: bit = FLAGBIT(ENC_IS_SSI); break; + case CMD_EMULPEP: bit = FLAGBIT(EMULATE_PEP); break; + default: break; + } + if(bit > 31) return ERR_CANTRUN; // unknown error + if(ISSETTER(msg->data)){ + if(msg->data[4]) the_conf.flags |= 1<data[4] = (the_conf.flags & (1<length; + uint8_t *data = msg->data; +#ifdef EBUG + DBG("Get data: "); + for(int i = 0; i < msg->length; ++i){ + usart_send(uhex2str(msg->data[i])); usart_putchar(' '); + } + //for(int i = msg->length-1; i < 8; ++i) msg->data[i] = 0; + newline(); +#endif + if(datalen < 2){ + FORMERR(msg, ERR_WRONGLEN); + return; + } + uint16_t idx = *(uint16_t*)data; + if(idx >= CMD_AMOUNT || funclist[idx].fn == NULL){ // bad command index + FORMERR(msg, ERR_BADCMD); return; + } + // check minimal length + if(funclist[idx].datalen > datalen){ + FORMERR(msg, ERR_WRONGLEN); return; + } + if(datalen > 3 && (data[2] & SETTER_FLAG)){ + // check setter's length + if(datalen != 8){ FORMERR(msg, ERR_WRONGLEN); return; } + // check setter's values + if(funclist[idx].maxval != funclist[idx].minval){ + int32_t newval = *(int32_t*)&data[4]; + if(newval < funclist[idx].minval || newval > funclist[idx].maxval){ + FORMERR(msg, ERR_BADVAL); return; + } + } + } + data[3] = funclist[idx].fn(msg); // set error field as result of function + data[2] &= ~SETTER_FLAG; // and clear setter flag +#ifdef EBUG + DBG("Return data: "); + for(int i = 0; i < msg->length; ++i){ + usart_send(uhex2str(msg->data[i])); usart_putchar(' '); + } + newline(); +#endif +} diff --git a/F1:F103/FX3U/canproto.h b/F1:F103/FX3U/canproto.h new file mode 100644 index 0000000..e3604ff --- /dev/null +++ b/F1:F103/FX3U/canproto.h @@ -0,0 +1,75 @@ +/* + * This file is part of the fx3u project. + * Copyright 2024 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 "can.h" + +// command parameter flag means this is a setter +#define SETTER_FLAG (0x80) +#define ISSETTER(data) ((data[2] & SETTER_FLAG)) +// parameter number 127 means there no parameter number at all (don't need paremeter or get all) +#define NO_PARNO (0x1f) +// base value of parameter (even if it is a setter) +#define PARBASE(x) (x & 0x7f) + +// make error for CAN answer +#define FORMERR(m, err) do{m->data[3] = err; if(m->length < 4) m->length = 4;}while(0) + +// error codes for answer message +typedef enum{ + ERR_OK, // 0 - all OK + ERR_BADPAR, // 1 - parameter's value is wrong + ERR_BADVAL, // 2 - wrong parameter's value + ERR_WRONGLEN, // 3 - wrong message length + ERR_BADCMD, // 4 - unknown command + ERR_CANTRUN, // 5 - can't run given command due to bad parameters or other + ERR_AMOUNT // amount of error codes +} errcodes; + +// CAN commands indexes +enum{ + CMD_RESET, // 0 - reset MCU + CMD_TIME, // 1 - get/set Tms + CMD_MCUTEMP, // 2 - get MCU temperature (*10) + CMD_ADCRAW, // 3 - get ADC raw values + CMD_ADCV, // 4 - get ADC voltage (*100) + CMD_CANSPEED, // 5 - get/set CAN speed (kbps) + CMD_CANID, // 6 - get/set CAN ID + CMD_ADCMUL, // 7 - get/set ADC multipliers 0..4 + CMD_SAVECONF, // 8 - save configuration + CMD_ERASESTOR, // 9 - erase all flash storage + CMD_RELAY, // 10 - switch relay ON/OFF + CMD_GETESW_BLK, // 11 - blocking read of ESW + CMD_GETESW, // 12 - current ESW state, bounce-free + CMD_BOUNCE, // 13 - get/set bounce constant (ms) + CMD_USARTSPEED, // 14 - get/set USART1 speed (if encoder on RS-422) + CMD_ENCISSSI, // 15 - encoder is SSI (1) or RS-422 (0) + CMD_SPIINIT, // 16 - init SPI2 + CMD_SPISEND, // 17 - send 1..4 bytes over SPI + CMD_ENCGET, // 18 - get encoder value + CMD_EMULPEP, // 19 - emulate (1) / not (0) PEP + CMD_ENCREINIT, // 20 - reinit encoder + CMD_TIMESTAMP, // 21 - 2mks 24-bit timestamp + CMD_SPIDEINIT, // 22 - turn off SPI2 + // should be the last: + CMD_AMOUNT // amount of CAN commands +}; + +void run_can_cmd(CAN_message *msg); diff --git a/F1:F103/FX3U/flash.c b/F1:F103/FX3U/flash.c index d81beea..5e74f87 100644 --- a/F1:F103/FX3U/flash.c +++ b/F1:F103/FX3U/flash.c @@ -24,21 +24,21 @@ #include // memcpy extern const uint32_t __varsstart, _BLOCKSIZE; -static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; +const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here #define USERCONF_INITIALIZER { \ .userconf_sz = sizeof(user_conf) \ - ,.canspeed = 250 \ - ,.canID = 0xAA \ - ,.rs232speed = 115200 \ + ,.CANspeed = 250000 \ + ,.CANID = 1 \ + ,.usartspeed = 115200 \ } static int write2flash(const void*, const void*, uint32_t); const user_conf *Flash_Data = (const user_conf *)(&__varsstart); user_conf the_conf = USERCONF_INITIALIZER; -static int currentconfidx = -1; // index of current configuration +int currentconfidx = -1; // index of current configuration /** * @brief binarySearch - binary search in flash for last non-empty cell @@ -181,11 +181,3 @@ int erase_storage(int npage){ return ret; } -void dump_userconf(){ - usart_send("userconf_sz="); printu(the_conf.userconf_sz); - usart_send("\ncurrentconfidx="); usart_send(u2str(currentconfidx)); - usart_send("\nCAN_speed="); printu(the_conf.canspeed); - usart_send("\nCAN_ID="); printu(the_conf.canID); - usart_send("\nRS_232_speed="); printu(the_conf.rs232speed); - usart_send("\n"); -} diff --git a/F1:F103/FX3U/flash.h b/F1:F103/FX3U/flash.h index 7e6baf8..f64db19 100644 --- a/F1:F103/FX3U/flash.h +++ b/F1:F103/FX3U/flash.h @@ -26,16 +26,18 @@ /* * struct to save user configurations */ -typedef struct __attribute__((packed, aligned(4))){ +typedef struct __attribute__((aligned(4))){ uint16_t userconf_sz; // "magick number" - uint16_t canspeed; // CAN bus speed - uint16_t canID; // CAN bus device ID - uint32_t rs232speed; // speed of RS-232 + uint16_t CANID; // CAN bus device ID + uint32_t usartspeed; // RS-232 speed + uint32_t CANspeed; // CAN bus speed } user_conf; extern user_conf the_conf; +extern const uint32_t FLASH_blocksize; +extern const user_conf *Flash_Data; +extern int currentconfidx; void flashstorage_init(); int store_userconf(); int erase_storage(int npage); -void dump_userconf(); diff --git a/F1:F103/FX3U/fx3u.bin b/F1:F103/FX3U/fx3u.bin index 045d90a..96485bf 100755 Binary files a/F1:F103/FX3U/fx3u.bin and b/F1:F103/FX3U/fx3u.bin differ diff --git a/F1:F103/FX3U/fx3u.creator.user b/F1:F103/FX3U/fx3u.creator.user index dc4772c..f3e42e0 100644 --- a/F1:F103/FX3U/fx3u.creator.user +++ b/F1:F103/FX3U/fx3u.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F1:F103/FX3U/fx3u.files b/F1:F103/FX3U/fx3u.files index f964000..accf1c5 100644 --- a/F1:F103/FX3U/fx3u.files +++ b/F1:F103/FX3U/fx3u.files @@ -3,6 +3,8 @@ adc.h buttons.c can.c can.h +canproto.c +canproto.h flash.c flash.h hardware.c diff --git a/F1:F103/FX3U/main.c b/F1:F103/FX3U/main.c index e3a34bf..0b38cb5 100644 --- a/F1:F103/FX3U/main.c +++ b/F1:F103/FX3U/main.c @@ -38,19 +38,20 @@ int main(void){ flashstorage_init(); gpio_setup(); // should be run before other peripherial setup adc_setup(); - usart_setup(the_conf.rs232speed); - CAN_setup(the_conf.canspeed); + usart_setup(the_conf.usartspeed); + CAN_setup(the_conf.CANspeed); RCC->CSR |= RCC_CSR_RMVF; // remove reset flags #ifndef EBUG iwdg_setup(); #endif + usart_send("START\n"); while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(Tms - lastT > 499){ // throw out short messages twice per second usart_transmit(); lastT = Tms; } - can_proc(); + CAN_proc(); CAN_status st = CAN_get_status(); if(st == CAN_FIFO_OVERRUN){ usart_send("CAN bus fifo overrun occured!\n"); @@ -58,8 +59,8 @@ int main(void){ usart_send("Some CAN error occured\n"); } while((can_mesg = CAN_messagebuf_pop())){ + DBG("got CAN message\n"); IWDG->KR = IWDG_REFRESH; - // TODO: check ID and process messages if(flags.can_monitor){ lastT = Tms; if(!lastT) lastT = 1; @@ -77,10 +78,7 @@ int main(void){ char *str; int g = usart_getline(&str); if(g < 0) usart_send("USART IN buffer overflow!\n"); - else if(g > 0){ - const char *ans = cmd_parser(str); - if(ans) usart_send(ans); - } + else if(g > 0) cmd_parser(str); } return 0; } diff --git a/F1:F103/FX3U/proto.c b/F1:F103/FX3U/proto.c index b50013d..fee514c 100644 --- a/F1:F103/FX3U/proto.c +++ b/F1:F103/FX3U/proto.c @@ -18,6 +18,8 @@ #include "adc.h" #include "can.h" +#include "canproto.h" +#include "flash.h" #include "hardware.h" #include "proto.h" #include "strfunc.h" @@ -25,62 +27,68 @@ #include "version.inc" flags_t flags = { - .can_monitor = 0 + 0 }; -/* -static void printans(int res){ - if(res) usart_send("OK"); - else usart_send("FAIL"); -} - -// setters of uint/int -static void usetter(int(*fn)(uint32_t), char* str){ - uint32_t d = 0; - if(str == getnum(str, &d)) printans(FALSE); - else printans(fn(d)); -} -static void isetter(int(*fn)(int32_t), char* str){ - int32_t d = 0; - if(str == getint(str, &d)) printans(FALSE); - else printans(fn(d)); -} -*/ - -// parno - number of parameter (or -1); cargs - string with arguments (after '=') (==NULL for getter), iarg - integer argument -static int goodstub(const char *cmd, int parno, const char *carg, int32_t iarg){ - usart_send("cmd="); usart_send(cmd); - usart_send(", parno="); usart_send(i2str(parno)); - usart_send(", args="); usart_send(carg); - usart_send(", intarg="); usart_send(i2str(iarg)); newline(); - return RET_GOOD; -} +// text-only commans indexes (0 is prohibited) +typedef enum{ + TCMD_PROHIBITED, // prohibited + TCMD_WDTEST, // test watchdog + TCMD_DUMPCONF, // dump configuration + TCMD_CANSEND, // send CAN message + TCMD_CANSNIFFER, // sniff all CAN messages + TCMD_CANBUSERRPRNT, // pring all errors of bus + TCMD_AMOUNT +} text_cmd; typedef struct{ - int (*fn)(const char*, int, const char*, int32_t); - const char *cmd; - const char *help; -} commands; + const char *cmd; // command, if NULL - only display help message + int idx; // index in CAN cmd or text cmd list (if negative) + const char *help; // help message +} funcdescr; -static commands cmdlist[] = { - {goodstub, "stub", "simple stub"}, - {NULL, "Different commands", NULL}, -// {adcval, "ADC", "get ADCx value (without x - for all)"}, -// {adcvoltage, "ADCv", "get ADCx voltage (without x - for all)"}, -// {mcut, "mcut", "get MCU temperature"}, - {NULL, NULL, NULL} +// list of all text functions; should be sorted and can be grouped (`help` is header when cmd == NULL) +static const funcdescr funclist[] = { +// {"adcmul", CMD_ADCMUL, "get/set ADC multipliers 0..3 (*1000)"}, +// {"adcraw", CMD_ADCRAW, "get raw ADC values of channel 0..4"}, +// {"adcv", CMD_ADCV, "get ADC voltage of channel 0..3 (*100V)"}, +// {"bounce", CMD_BOUNCE, "get/set bounce constant (ms)"}, + {"canbuserr", -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"}, + {"canid", CMD_CANID, "get/set CAN ID"}, + {"cansniff", -TCMD_CANSNIFFER, "switch CAN sniffer mode"}, + {"canspeed", CMD_CANSPEED, "get/set CAN speed (bps)"}, + {"dumpconf", -TCMD_DUMPCONF, "dump current configuration"}, + {"esw", CMD_GETESW, "anti-bounce read ESW of channel 0 or 1"}, + {"eraseflash", CMD_ERASESTOR, "erase all flash storage"}, + {"mcutemp", CMD_MCUTEMP, "get MCU temperature (*10degrC)"}, + {"relay", CMD_RELAY, "get/set relay state (0 - off, 1 - on)"}, + {"reset", CMD_RESET, "reset MCU"}, + {"s", -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"}, + {"saveconf", CMD_SAVECONF, "save configuration"}, + {"time", CMD_TIME, "get/set time (1ms, 32bit)"}, + {"usartspeed", CMD_USARTSPEED, "get/set USART1 speed"}, + {"wdtest", -TCMD_WDTEST, "test watchdog"}, + {NULL, 0, NULL} // last record }; static void printhelp(){ - commands *c = cmdlist; + const funcdescr *c = funclist; usart_send("https://github.com/eddyem/stm32samples/tree/master/F1:F103/FX3U#" BUILD_NUMBER " @ " BUILD_DATE "\n"); - while(c->cmd){ - if(!c->fn){ // header + usart_send("commands format: parameter[number][=setter]\n"); + usart_send("parameter [CAN idx] - help\n"); + usart_send("--------------------------\n"); + while(c->help){ + if(!c->cmd){ // header usart_send("\n "); - usart_send(c->cmd); + usart_send(c->help); usart_putchar(':'); }else{ usart_send(c->cmd); + if(c->idx > -1){ + usart_send(" ["); + usart_send(u2str(c->idx)); + usart_putchar(']'); + } usart_send(" - "); usart_send(c->help); } @@ -89,52 +97,224 @@ static void printhelp(){ } } -/** - * @brief parsecmd - parse text commands over RS-232 - * @param str - input string - * @return answer code - */ -static int parsecmd(const char *str){ - char cmd[CMD_MAXLEN + 1]; - //USB_sendstr("cmd="); USB_sendstr(str); USB_sendstr("__\n"); - if(!str || !*str) return RET_CMDNOTFOUND; - int i = 0; - while(*str > '@' && i < CMD_MAXLEN){ cmd[i++] = *str++; } - cmd[i] = 0; - int parno = -1; - int32_t iarg = __INT32_MAX__; - if(*str){ - uint32_t N; - const char *nxt = getnum(str, &N); - if(nxt != str) parno = (int) N; - str = strchr(str, '='); - if(str){ - str = omit_spaces(++str); - getint(str, &iarg); +/*********** START of all common functions list (for `textfunctions`) ***********/ + +static errcodes cansnif(const char *str){ + uint32_t U; + if(str){ + if(*str == '=') str = omit_spaces(str + 1); + const char *nxt = getnum(str, &U); + if(nxt != str){ // setter + CAN_sniffer((uint8_t)U); } - }else str = NULL; - commands *c = cmdlist; - while(c->cmd){ - if(strcmp(c->cmd, cmd) == 0){ - if(!c->fn) return RET_CMDNOTFOUND; - return c->fn(cmd, parno, str, iarg); - } - ++c; } - return RET_CMDNOTFOUND; + usart_send("cansniff="); usart_putchar('0' + flags.can_monitor); newline(); + return ERR_OK; +} + +static errcodes canbuserr(const char *str){ + uint32_t U; + if(str){ + if(*str == '=') str = omit_spaces(str + 1); + const char *nxt = getnum(str, &U); + if(nxt != str){ // setter + flags.can_printoff = U; + } + } + usart_send("canbuserr="); usart_putchar('0' + flags.can_printoff); newline(); + return ERR_OK; +} + +static errcodes wdtest(const char _U_ *str){ + usart_send("Wait for reboot\n"); + usart_transmit(); + while(1){nop();} + return ERR_OK; +} +/* +// names of bit flags (ordered from LSE of[0]) +static const char * const bitfields[] = { + "encisSSI", + "emulatePEP", + NULL +};*/ + +static errcodes dumpconf(const char _U_ *str){ +#ifdef EBUG + uint32_t sz = FLASH_SIZE*1024; + usart_send("flashsize="); printu(sz); usart_putchar('/'); + printu(FLASH_blocksize); usart_putchar('='); printu(sz/FLASH_blocksize); + usart_send(" blocks\n"); +#endif + usart_send("userconf_addr="); printuhex((uint32_t)Flash_Data); + usart_send("\nuserconf_idx="); printi(currentconfidx); + usart_send("\nuserconf_sz="); printu(the_conf.userconf_sz); + usart_send("\ncanspeed="); printu(the_conf.CANspeed); + usart_send("\ncanid="); printu(the_conf.CANID); + /*for(int i = 0; i < ADC_TSENS; ++i){ + usart_send("\nadcmul"); usart_putchar('0'+i); usart_putchar('='); + usart_send(float2str(the_conf.adcmul[i], 3)); + }*/ + usart_send("\nusartspeed="); printu(the_conf.usartspeed); + /* + const char * const *p = bitfields; + int bit = 0; + while(*p){ + newline(); + usart_send(*p); usart_putchar('='); usart_putchar((the_conf.flags & (1< 31) break; + ++p; + }*/ + newline(); + return ERR_OK; +} + +static errcodes cansend(const char *txt){ + CAN_message canmsg; + bzero(&canmsg, sizeof(canmsg)); + int ctr = -1; + canmsg.ID = 0xffff; + do{ + txt = omit_spaces(txt); + uint32_t N; + const char *n = getnum(txt, &N); + if(txt == n) break; + txt = n; + if(ctr == -1){ + if(N > 0x7ff){ + return ERR_BADPAR; + } + canmsg.ID = (uint16_t)(N&0x7ff); + ctr = 0; + continue; + } + if(ctr > 7){ + return ERR_WRONGLEN; + } + if(N > 0xff){ + return ERR_BADVAL; + } + canmsg.data[ctr++] = (uint8_t) N; + }while(1); + if(canmsg.ID == 0xffff){ + return ERR_BADPAR; + } + canmsg.length = (uint8_t) ctr; + uint32_t Tstart = Tms; + while(Tms - Tstart < SEND_TIMEOUT_MS){ + if(CAN_OK == CAN_send(&canmsg)){ + return ERR_OK; + } + } + return ERR_CANTRUN; +} + +/************ END of all common functions list (for `textfunctions`) ************/ + +// in `textfn` arg `str` is the rest of input string (spaces-omitted) after command +typedef errcodes (*textfn)(const char *str); +static textfn textfunctions[TCMD_AMOUNT] = { + [TCMD_PROHIBITED] = NULL, + [TCMD_WDTEST] = wdtest, + [TCMD_DUMPCONF] = dumpconf, + [TCMD_CANSEND] = cansend, + [TCMD_CANSNIFFER] = cansnif, + [TCMD_CANBUSERRPRNT] = canbuserr, +}; + +static const char* const errors_txt[ERR_AMOUNT] = { + [ERR_OK] = "OK" + ,[ERR_BADPAR] = "badpar" + ,[ERR_BADVAL] = "badval" + ,[ERR_WRONGLEN] = "wronglen" + ,[ERR_BADCMD] = "badcmd" + ,[ERR_CANTRUN] = "cantrun" +}; + +static void errtext(errcodes e){ + usart_send("error="); + usart_send(errors_txt[e]); + newline(); } /** * @brief cmd_parser - command parsing * @param txt - buffer with commands & data */ -const char *cmd_parser(const char *txt){ - int ret = parsecmd(txt); - switch(ret){ - case RET_WRONGPARNO: return "Wrong parameter number\n"; break; - case RET_CMDNOTFOUND: printhelp(); return NULL; break; - case RET_WRONGARG: return "Wrong command parameters\n"; break; - case RET_GOOD: return NULL; break; - default: return "FAIL\n"; break; +void cmd_parser(const char *str){ + if(!str || !*str) goto ret; + char cmd[MAXCMDLEN + 1]; + errcodes ecode = ERR_BADCMD; + int idx = CMD_AMOUNT; + const funcdescr *c = funclist; + int l = 0; + str = omit_spaces(str); + const char *ptr = str; + while(*ptr > '@' && l < MAXCMDLEN){ cmd[l++] = *ptr++;} + if(l == 0) goto ret; + cmd[l] = 0; + while(c->help){ + if(!c->cmd) continue; + if(0 == strcmp(c->cmd, cmd)){ + idx = c->idx; + break; + } + ++c; + } + if(idx == CMD_AMOUNT){ // didn't found + // send help over USB + printhelp(); + goto ret; + } + str = omit_spaces(ptr); + if(idx < 0){ // text-only function + ecode = textfunctions[-idx](str); + goto ret; + } + // common CAN/text function: we need to form 8-byte data buffer + CAN_message msg; + bzero(&msg, sizeof(msg)); + uint8_t *data = msg.data; + uint8_t datalen = 2; // only command for start + *((uint16_t*)data) = (uint16_t)idx; + data[2] = NO_PARNO; // no parameter number by default + if(*str >= '0' && *str <= '9'){ // have parameter with number + uint32_t N; + ptr = getnum(str, &N); + if(ptr != str){ + str = ptr; + if(N <= 0x7F) data[2] = (uint8_t)N; + else{ ecode = ERR_BADPAR; goto ret; } + } + datalen = 3; + } + str = omit_spaces(str); + if(*str == '='){ // setter + ++str; + ptr = getint(str, ((int32_t*)&data[4])); + if(str == ptr){ + ecode = ERR_BADVAL; + goto ret; + } + data[2] |= SETTER_FLAG; + datalen = 8; + } + msg.length = datalen; + run_can_cmd(&msg); + // now check error code + ecode = data[3]; +ret: + if(ecode != ERR_OK) errtext(ecode); + else if(idx > -1){ // parce all back for common functions + if(msg.length != 8){ + usart_send("OK\n"); // non setters/getters will just print "OK" if all OK + }else{ + usart_send(cmd); + data[2] &= ~SETTER_FLAG; + if(data[2] != NO_PARNO) usart_send(u2str(data[2])); + usart_putchar('='); + usart_send(i2str(*(int32_t*)&data[4])); + newline(); + } } } diff --git a/F1:F103/FX3U/proto.h b/F1:F103/FX3U/proto.h index 0402f29..8ed6c12 100644 --- a/F1:F103/FX3U/proto.h +++ b/F1:F103/FX3U/proto.h @@ -21,31 +21,15 @@ #include #include "hardware.h" -#ifndef _U_ -#define _U_ __attribute__((__unused__)) -#endif - -#define CMD_MAXLEN (32) - -enum{ - RET_WRONGPARNO = -3, // wrong parameter number - RET_CMDNOTFOUND = -2, // command not found - RET_WRONGARG = -1, // wrong argument - RET_GOOD = 0, // all OK - RET_BAD = 1 // something wrong -}; +#define MAXCMDLEN (12) +// flags for some RS-232 comands typedef struct{ - uint32_t can_monitor : 1; + uint32_t can_monitor : 1; // monitor any CAN bus connections + uint32_t can_printoff : 1; // print errors to RS-232 if CAN bus is off or other bus errors } flags_t; extern flags_t flags; -#ifdef EBUG -#define DBG(str) do{usart_send(__FILE__ " (L" STR(__LINE__) "): " str); \ - usart_putchar('\n'); usart_transmit(); }while(0) -#else -#define DBG(str) -#endif -const char *cmd_parser(const char *txt); +void cmd_parser(const char *txt); diff --git a/F1:F103/FX3U/strfunc.h b/F1:F103/FX3U/strfunc.h index 3be4040..0d0b72d 100644 --- a/F1:F103/FX3U/strfunc.h +++ b/F1:F103/FX3U/strfunc.h @@ -23,6 +23,17 @@ #include "usart.h" +#ifndef _U_ +#define _U_ __attribute__((__unused__)) +#endif + +#ifdef EBUG +#define DBG(str) do{usart_send(__FILE__ " (L" STR(__LINE__) "): " str); \ +usart_putchar('\n'); usart_transmit(); }while(0) +#else +#define DBG(str) +#endif + void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len); char *u2str(uint32_t val); char *i2str(int32_t i); diff --git a/F1:F103/FX3U/version.inc b/F1:F103/FX3U/version.inc index 8c865e6..a4d3b7e 100644 --- a/F1:F103/FX3U/version.inc +++ b/F1:F103/FX3U/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "20" -#define BUILD_DATE "2024-05-30" +#define BUILD_NUMBER "36" +#define BUILD_DATE "2024-06-01"