diff --git a/F1:F103/FX3U/adc.c b/F1:F103/FX3U/adc.c index e8a7ddf..cb2952a 100644 --- a/F1:F103/FX3U/adc.c +++ b/F1:F103/FX3U/adc.c @@ -47,12 +47,13 @@ void adc_setup(){ ADC1->CR2 |= ADC_CR2_ADON; __DSB(); // wait for Tstab - at least 1us + IWDG->KR = IWDG_REFRESH; while(++ctr < 0xff) nop(); // calibration ADC1->CR2 |= ADC_CR2_RSTCAL; - ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff); + ctr = 0; while((ADC1->CR2 & ADC_CR2_RSTCAL) && ++ctr < 0xfffff) IWDG->KR = IWDG_REFRESH; ADC1->CR2 |= ADC_CR2_CAL; - ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff); + ctr = 0; while((ADC1->CR2 & ADC_CR2_CAL) && ++ctr < 0xfffff) IWDG->KR = IWDG_REFRESH; // clear possible errors and start ADC1->SR = 0; ADC1->CR2 |= ADC_CR2_SWSTART; diff --git a/F1:F103/FX3U/can.c b/F1:F103/FX3U/can.c index b4374a6..5161d68 100644 --- a/F1:F103/FX3U/can.c +++ b/F1:F103/FX3U/can.c @@ -48,9 +48,7 @@ static CAN_status can_status = CAN_STOP; static void can_process_fifo(uint8_t fifo_num); CAN_status CAN_get_status(){ - int st = can_status; - can_status = CAN_OK; - return st; + return can_status; } // push next message into buffer; return 1 if buffer overfull @@ -141,8 +139,10 @@ void CAN_setup(uint32_t speed){ /* (12) Leave filter init */ /* (13) Set error interrupts enable (& bus off) */ CAN1->MCR |= CAN_MCR_INRQ; /* (1) */ - while((CAN1->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) /* (2) */ + while((CAN1->MSR & CAN_MSR_INAK) != CAN_MSR_INAK){ /* (2) */ + IWDG->KR = IWDG_REFRESH; if(--tmout == 0) break; + } CAN1->MCR &=~ CAN_MCR_SLEEP; /* (3) */ CAN1->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */ CAN1->BTR = (CAN_TBS2-1) << 20 | (CAN_TBS1-1) << 16 | (CAN_BIT_OSC/speed - 1); //| CAN_BTR_SILM | CAN_BTR_LBKM; /* (4) */ @@ -152,8 +152,10 @@ void CAN_setup(uint32_t speed){ #endif CAN1->MCR &= ~CAN_MCR_INRQ; /* (5) */ tmout = 16000000; - while((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) /* (6) */ + while((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK){ /* (6) */ + IWDG->KR = IWDG_REFRESH; if(--tmout == 0) break; + } // accept depending of monitor flag CAN1->FMR = CAN_FMR_FINIT; /* (7) */ CAN1->FA1R = CAN_FA1R_FACT0; /* (8) */ @@ -218,6 +220,22 @@ void CAN_printerr(){ } void CAN_proc(){ + IWDG->KR = IWDG_REFRESH; + if((CAN1->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)) + || can_status != CAN_READY){ // much errors - restart CAN BUS + if(flags.can_printoff){ + const char *e; + switch(can_status){ + case CAN_ERR: e = "ERRI"; break; + case CAN_FIFO_OVERRUN: e = "FIFO_OVERRUN"; break; + default: e = "UNKNOWN"; + } + usart_send("canerror="); + usart_send(e); newline(); + CAN_printerr(); + } + CAN_reinit(0); + } // check for messages in FIFO0 & FIFO1 if(CAN1->RF0R & CAN_RF0R_FMP0){ can_process_fifo(0); @@ -225,14 +243,6 @@ void CAN_proc(){ if(CAN1->RF1R & CAN_RF1R_FMP1){ can_process_fifo(1); } - IWDG->KR = IWDG_REFRESH; - if(CAN1->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS - if(flags.can_printoff){ - usart_send("error=canerr\n"); - CAN_printerr(); - } - CAN_reinit(0); - } } CAN_status CAN_send(CAN_message *message){ @@ -290,28 +300,6 @@ CAN_status CAN_send(CAN_message *message){ 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.CANIDout; // set output ID for all output 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]; @@ -355,9 +343,8 @@ static void can_process_fifo(uint8_t fifo_num){ dat[0] = lb & 0xff; } } - // run command for my or broadcast ID - if(msg.ID == the_conf.CANIDin || msg.ID == 0) parseCANcommand(&msg); - if(flags.can_monitor && CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later + IWDG->KR = IWDG_REFRESH; + if(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; @@ -368,6 +355,7 @@ void usb_lp_can_rx0_isr(){ // Rx FIFO0 (overrun) if(CAN1->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun CAN1->RF0R &= ~CAN_RF0R_FOVR0; can_status = CAN_FIFO_OVERRUN; + RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN; } } @@ -375,6 +363,7 @@ void can_rx1_isr(){ // Rx FIFO1 (overrun) if(CAN1->RF1R & CAN_RF1R_FOVR1){ CAN1->RF1R &= ~CAN_RF1R_FOVR1; can_status = CAN_FIFO_OVERRUN; + RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN; } } @@ -386,5 +375,6 @@ void can_sce_isr(){ // status changed if(CAN1->TSR & CAN_TSR_TERR1) CAN1->TSR |= CAN_TSR_ABRQ1; if(CAN1->TSR & CAN_TSR_TERR2) CAN1->TSR |= CAN_TSR_ABRQ2; can_status = CAN_ERR; + RCC->APB1ENR &= ~RCC_APB1ENR_CAN1EN; } } diff --git a/F1:F103/FX3U/canproto.c b/F1:F103/FX3U/canproto.c index 4b7b37c..466d6f9 100644 --- a/F1:F103/FX3U/canproto.c +++ b/F1:F103/FX3U/canproto.c @@ -27,8 +27,7 @@ #define FIXDL(m) do{m->length = 8;}while(0) /*********** START of all common functions list (for `funclist`) ***********/ -static errcodes ping(CAN_message *m){ - m->ID = the_conf.CANIDout; // change ID +static errcodes ping(CAN_message _U_ *m){ return ERR_OK; // send same message } // reset MCU @@ -163,6 +162,7 @@ static errcodes u32setget(CAN_message *msg){ case CMD_INCHNLS: val = inchannels(); ptr = &val; break; case CMD_OUTCHNLS: val = outchannels(); ptr = &val; break; case CMD_MODBUSID: ptr = &the_conf.modbusID; break; + case CMD_MODBUSIDOUT: ptr = &the_conf.modbusIDout; break; case CMD_MODBUSSPEED: ptr = &the_conf.modbusspeed; break; default: break; } @@ -230,6 +230,7 @@ static const commonfunction funclist[CMD_AMOUNT] = { [CMD_INCHNLS] = {u32setget, 0, 0, 0}, [CMD_OUTCHNLS] = {u32setget, 0, 0, 0}, [CMD_MODBUSID] = {u32setget, 0, MODBUS_MAX_ID, 0}, // 0 - master! + [CMD_MODBUSIDOUT] = {u32setget, 0, MODBUS_MAX_ID, 0}, [CMD_MODBUSSPEED] = {u32setget, 1200, 115200, 0}, }; @@ -288,3 +289,25 @@ void run_can_cmd(CAN_message *msg){ newline(); #endif } + +/** + * @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 + */ +void parseCANcommand(CAN_message *msg){ + // check PING + if(msg->length != 0) run_can_cmd(msg); + uint32_t Tstart = Tms; + // send answer + while(Tms - Tstart < SEND_TIMEOUT_MS){ + if(CAN_OK == CAN_send(msg)) return; + IWDG->KR = IWDG_REFRESH; + } + usart_send("error=canbusy\n"); +} diff --git a/F1:F103/FX3U/canproto.h b/F1:F103/FX3U/canproto.h index 07278cc..d6b731e 100644 --- a/F1:F103/FX3U/canproto.h +++ b/F1:F103/FX3U/canproto.h @@ -48,6 +48,9 @@ typedef enum{ // set command bytes in CAN message #define MSG_SET_CMD(msg, cmd) do{*((uint16_t*)msg.data) = (cmd);}while(0) #define MSGP_SET_CMD(msg, cmd) do{*((uint16_t*)msg->data) = (cmd);}while(0) +// set command parameter number +#define MSG_SET_PARNO(msg, n) do{msg.data[2] = (n);}while(0) +#define MSGP_SET_PARNO(msg, n) do{msg->data[2] = (n);}while(0) // set error #define MSG_SET_ERR(msg, err) do{msg.data[3] = (err);}while(0) #define MSGP_SET_ERR(msg, err) do{msg->data[3] = (err);}while(0) @@ -75,15 +78,17 @@ enum{ CMD_GETESW, // current ESW state, bounce-free CMD_GETESWNOW, // current ESW state, absolute CMD_BOUNCE, // get/set bounce constant (ms) - CMD_USARTSPEED, // get/set USART1 speed (if encoder on RS-422) + CMD_USARTSPEED, // get/set USART1 speed CMD_LED, // onboard LED CMD_FLAGS, // flags setter/getter CMD_INCHNLS, // all bits set are active supported IN channels CMD_OUTCHNLS, // all bits set are active supported OUT channels CMD_MODBUSID, // set/get modbus slave ID (or 0 if master) + CMD_MODBUSIDOUT,// slave ID to send modbus relay command if IN changes CMD_MODBUSSPEED,// speed of modbus interface // should be the last: CMD_AMOUNT // amount of CAN commands }; void run_can_cmd(CAN_message *msg); +void parseCANcommand(CAN_message *msg); diff --git a/F1:F103/FX3U/flash.c b/F1:F103/FX3U/flash.c index 25765d4..263efba 100644 --- a/F1:F103/FX3U/flash.c +++ b/F1:F103/FX3U/flash.c @@ -35,8 +35,10 @@ static uint32_t maxCnum = 1024 / sizeof(user_conf); // can't use blocksize here ,.CANIDout = 2 \ ,.usartspeed = 115200 \ ,.bouncetime = 50 \ - ,.modbusID = MODBUS_MASTER_ID \ + ,.modbusID = 1 \ + ,.modbusIDout = 2 \ ,.modbusspeed = 9600 \ + ,.flags.sw_send_relay_inv = 1 \ } static int write2flash(const void*, const void*, uint32_t); @@ -57,6 +59,7 @@ int currentconfidx = -1; // index of current configuration static int binarySearch(int r, const uint8_t *start, int stor_size){ int l = 0; while(r >= l){ + IWDG->KR = IWDG_REFRESH; int mid = l + (r - l) / 2; const uint8_t *s = start + mid * stor_size; if(*((const uint16_t*)s) == stor_size){ diff --git a/F1:F103/FX3U/flash.h b/F1:F103/FX3U/flash.h index c9a7f8d..51d1588 100644 --- a/F1:F103/FX3U/flash.h +++ b/F1:F103/FX3U/flash.h @@ -23,15 +23,21 @@ #define FLASH_SIZE_REG ((uint32_t)0x1FFFF7E0) #define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) -// maximal bit number of flags -#define MAX_FLAG_BITNO (0) +// maximal bit NUMBER (0 etc) of flags +#define MAX_FLAG_BITNO (3) typedef union{ uint32_t u32; struct{ - uint32_t sw_send_relay_cmd; // switching ESW state will send also CMD_RELAY command with CANID_OUT + uint32_t sw_send_esw_can : 1; // 0 - if ESW state changes, send message over CAN with CANID_IN + uint32_t sw_send_relay_can : 1; // 1 - switching ESW state will send CMD_RELAY command with CANID_OUT + uint32_t sw_send_relay_inv : 1; // 2 - sw_send should be inverted related to current inputs value + uint32_t sw_send_relay_modbus : 1; // 3 - 1 for modbus }; } confflags_t; +// ALL sw_send flags mask (without relay_inv) +#define SW_SEND_MASK (0x0B) + /* * struct to save user configurations */ @@ -45,6 +51,7 @@ typedef struct __attribute__((aligned(4))){ uint32_t CANspeed; // CAN bus speed confflags_t flags; // different flags uint32_t modbusID; // MODBUS-RTU ID (0 for master) + uint32_t modbusIDout; // MODBUS-RTU slave ID to send relay command when IN changes uint32_t modbusspeed; // Speed of modbus interface } user_conf; diff --git a/F1:F103/FX3U/fx3u.bin b/F1:F103/FX3U/fx3u.bin index ef7b7ea..655429d 100755 Binary files a/F1:F103/FX3U/fx3u.bin and b/F1:F103/FX3U/fx3u.bin differ diff --git a/F1:F103/FX3U/hardware.c b/F1:F103/FX3U/hardware.c index cec837c..395e48c 100644 --- a/F1:F103/FX3U/hardware.c +++ b/F1:F103/FX3U/hardware.c @@ -20,6 +20,7 @@ #include "canproto.h" #include "flash.h" #include "hardware.h" +#include "modbusrtu.h" /* #ifdef EBUG #include "strfunc.h" @@ -116,14 +117,16 @@ void gpio_setup(void){ void iwdg_setup(){ uint32_t tmout = 16000000; RCC->CSR |= RCC_CSR_LSION; - while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} + while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY) if(--tmout == 0) break; IWDG->KR = IWDG_START; IWDG->KR = IWDG_WRITE_ACCESS; IWDG->PR = IWDG_PR_PR_1; IWDG->RLR = 1250; tmout = 16000000; - while(IWDG->SR){if(--tmout == 0) break;} - IWDG->KR = IWDG_REFRESH; + while(IWDG->SR){ + IWDG->KR = IWDG_REFRESH; + if(--tmout == 0) break; + } } typedef struct{ @@ -263,22 +266,46 @@ void proc_esw(){ else ESW_ab_values &= ~mask; lastET[i] = Tms; } - if(oldesw != ESW_ab_values){ + if(oldesw != ESW_ab_values && (the_conf.flags.u32 & SW_SEND_MASK)){ // State changes and need to send info //usart_send("esw="); usart_send(u2str(ESW_ab_values)); newline(); - CAN_message msg = {.ID = the_conf.CANIDout, .length = 8}; - MSG_SET_CMD(msg, CMD_GETESW); - MSG_SET_U32(msg, ESW_ab_values); - uint32_t Tstart = Tms; - while(Tms - Tstart < SEND_TIMEOUT_MS){ - if(CAN_OK == CAN_send(&msg)) break; - } - if(the_conf.flags.sw_send_relay_cmd){ // send also CMD_RELAY - MSG_SET_CMD(msg, CMD_RELAY); - Tstart = Tms; + if(the_conf.flags.sw_send_esw_can){ + CAN_message msg = {.ID = the_conf.CANIDin, .length = 8, .data = {0}}; + MSG_SET_CMD(msg, CMD_GETESW); + MSG_SET_U32(msg, ESW_ab_values); + uint32_t Tstart = Tms; while(Tms - Tstart < SEND_TIMEOUT_MS){ + IWDG->KR = IWDG_REFRESH; if(CAN_OK == CAN_send(&msg)) break; } } + uint32_t v = ESW_ab_values; + if(the_conf.flags.sw_send_relay_inv) v = ~v; + if(the_conf.flags.sw_send_relay_can){ // send also CMD_RELAY + CAN_message msg = {.ID = the_conf.CANIDout, .length = 8, .data = {0}}; + MSG_SET_U32(msg, v); + MSG_SET_CMD(msg, CMD_RELAY); + MSG_SET_PARNO(msg, SETTER_FLAG | NO_PARNO); + uint32_t Tstart = Tms; + while(Tms - Tstart < SEND_TIMEOUT_MS){ + IWDG->KR = IWDG_REFRESH; + if(CAN_OK == CAN_send(&msg)) break; + } + } + if(the_conf.flags.sw_send_relay_modbus && the_conf.modbusID == MODBUS_MASTER_ID){ + modbus_request r = {.ID = the_conf.modbusIDout, + .Fcode = MC_WRITE_MUL_COILS, + .startreg = 0, + .regno = OUTMAX+1, + .datalen = OUTMAXBYTES + }; + uint8_t data[OUTMAXBYTES]; + r.data = data; + for(int i = OUTMAXBYTES - 1; i > -1; --i){ + data[i] = (uint8_t) v; + v >>= 8; + } + modbus_send_request(&r); + } } } diff --git a/F1:F103/FX3U/main.c b/F1:F103/FX3U/main.c index a3d79d2..4a17183 100644 --- a/F1:F103/FX3U/main.c +++ b/F1:F103/FX3U/main.c @@ -18,6 +18,7 @@ #include "adc.h" #include "can.h" +#include "canproto.h" #include "flash.h" #include "hardware.h" #include "modbusproto.h" @@ -48,7 +49,6 @@ int main(void){ uint32_t lastT = 0; CAN_message *can_mesg; StartHSE(); - RCC->CSR |= RCC_CSR_RMVF; // remove reset flags SysTick_Config(72000); flashstorage_init(); gpio_setup(); // should be run before other peripherial setup @@ -61,6 +61,19 @@ int main(void){ iwdg_setup(); #endif usart_send("START\n"); + if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured + usart_send("IWDGRSTF=1\n"); + } + if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured + usart_send("SFTRSTF=1\n"); + } + if(RCC->CSR & RCC_CSR_PORRSTF){ // POR/RDR + usart_send("PORRSTF=1\n"); + } + if(RCC->CSR & RCC_CSR_PINRSTF){ // reset by pin NRST + usart_send("PINRSTF=1\n"); + } + RCC->CSR |= RCC_CSR_RMVF; // remove reset flags while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(Tms - lastT > 499){ // throw out short messages twice per second @@ -69,15 +82,12 @@ int main(void){ } proc_esw(); CAN_proc(); - CAN_status st = CAN_get_status(); - if(st == CAN_FIFO_OVERRUN){ - usart_send("CAN bus fifo overrun occured!\n"); - }else if(st == CAN_ERR){ - usart_send("Some CAN error occured\n"); - } while((can_mesg = CAN_messagebuf_pop())){ DBG("got CAN message\n"); IWDG->KR = IWDG_REFRESH; + // run command for my or broadcast ID + if(can_mesg->ID == the_conf.CANIDin || can_mesg->ID == 0) + parseCANcommand(can_mesg); if(flags.can_monitor){ lastT = Tms; if(!lastT) lastT = 1; diff --git a/F1:F103/FX3U/modbusproto.c b/F1:F103/FX3U/modbusproto.c index 322ed69..213a9e2 100644 --- a/F1:F103/FX3U/modbusproto.c +++ b/F1:F103/FX3U/modbusproto.c @@ -68,13 +68,12 @@ TRUE_INLINE void readdiscr(modbus_request *r){ return; } uint8_t bytes[INMAXBYTES] = {0}; - int curidx = INMAXBYTES - 1; int vals = get_esw(INMAX+1); - for(int i = 0; i < amount; ++i){ - bytes[--curidx] = vals & 0xff; + for(int i = amount - 1; i > -1; --i){ + bytes[i] = vals & 0xff; vals >>= 8; } - modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = bytes+curidx, .datalen = amount}; + modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = bytes, .datalen = amount}; modbus_send_response(&resp); } @@ -122,7 +121,7 @@ TRUE_INLINE void readadc(modbus_request *r){ uint16_t vals[ADC_CHANNELS]; for(int i = r->startreg; i < nlast; ++i){ uint16_t v = getADCval(i); - vals[i] = __builtin_bswap16(v); + vals[i - r->startreg] = __builtin_bswap16(v); } modbus_response resp = {.Fcode = r->Fcode, .ID = the_conf.modbusID, .data = (uint8_t*) vals, .datalen = r->regno * 2}; modbus_send_response(&resp); @@ -155,20 +154,21 @@ TRUE_INLINE void writereg(modbus_request *r){ // support ONLY write to ALL! // data - by bits, like in readcoil +// N registers is N bits TRUE_INLINE void writecoils(modbus_request *r){ if(r->startreg){ senderr(r, ME_ILLEGAL_ADDRESS); return; } - int amount = r->regno; - if(amount == 0 || amount > OUTMAX || r->datalen > 4){ + int amount = (r->regno + 7) >> 3; + if(amount == 0 || amount > OUTMAXBYTES || r->datalen < amount){ senderr(r, ME_ILLEGAL_VALUE); return; } uint32_t v = 0; for(int i = 0; i < amount; ++i){ - v |= r->data[i]; v <<= 8; + v |= r->data[i]; } if(set_relay(OUTMAX+1, v) < 0){ senderr(r, ME_NACK); diff --git a/F1:F103/FX3U/modbusrtu.c b/F1:F103/FX3U/modbusrtu.c index b3fef10..40fb6b8 100644 --- a/F1:F103/FX3U/modbusrtu.c +++ b/F1:F103/FX3U/modbusrtu.c @@ -39,11 +39,12 @@ static void us(){ }*/ // switch to Rx/Tx: -#define _485_Rx() do{LED(1); RS485_RX(); /*UART4->CR1 = (UART4->CR1 & ~USART_CR1_TE) | USART_CR1_RE;*/}while(0) -#define _485_Tx() do{LED(0); RS485_TX(); /*UART4->CR1 = (UART4->CR1 & ~USART_CR1_RE) | USART_CR1_TE;*/}while(0) +#define _485_Rx() do{ DMA2_Channel5->CCR &= ~DMA_CCR_EN; RS485_RX(); \ + DMA2_Channel3->CMAR = (uint32_t) rbuf[rbufno]; DMA2_Channel3->CNDTR = MODBUSBUFSZI; \ + DMA2_Channel3->CCR |= DMA_CCR_EN;}while(0) +#define _485_Tx() do{ RS485_TX(); }while(0) static volatile int modbus_txrdy = 1; -static volatile int idatalen[2] = {0,0}; // received data line length (including '\n') static volatile int modbus_rdy = 0 // received data ready ,dlen = 0 // length of data (including '\n') in current buffer @@ -68,9 +69,11 @@ static uint16_t getCRC(uint8_t *data, int l){ }else crc >>= 1; } } + /* #ifdef EBUG DBG("Calc CRC: "); printuhex(crc); newline(); #endif + */ // CRC have swapped bytes, so we can just send it as *((uint16_t*)&data[x]) = CRC return crc; } @@ -105,13 +108,13 @@ static int senddata(int l){ IWDG->KR = IWDG_REFRESH; if(--tmout == 0) return 0; }; // wait for previos buffer transmission - _485_Tx(); modbus_txrdy = 0; DMA2_Channel5->CCR &= ~DMA_CCR_EN; DMA2_Channel5->CMAR = (uint32_t) tbuf[tbufno]; // mem DMA2_Channel5->CNDTR = l + 2; // + CRC DMA2_Channel5->CCR |= DMA_CCR_EN; tbufno = !tbufno; + _485_Tx(); return l; } @@ -133,12 +136,13 @@ int modbus_send_request(modbus_request *r){ *curbuf++ = r->startreg >> 8; // H *curbuf++ = (uint8_t) r->startreg; // L *curbuf++ = r->regno >> 8; // H - *curbuf = (uint8_t) r->regno; // L + *curbuf++ = (uint8_t) r->regno; // L // if r->datalen == 0 - this is responce for request with fcode > 4 if((r->Fcode == MC_WRITE_MUL_COILS || r->Fcode == MC_WRITE_MUL_REGS) && r->datalen){ // request with data - *(++curbuf) = r->datalen; + if(r->datalen > MODBUSBUFSZO - 7) return -1; + *curbuf++ = r->datalen; memcpy(curbuf, r->data, r->datalen); - n += r->datalen; + n += r->datalen + 1; // + data length byte } packCRC(tbuf[tbufno], n) = getCRC(tbuf[tbufno], n); return senddata(n); @@ -207,62 +211,57 @@ int modbus_get_response(modbus_response* r){ // USART4: PC10 - Tx, PC11 - Rx void modbus_setup(uint32_t speed){ - uint32_t tmout = 16000000; // PC10 - Tx, PC11 - Rx RCC->APB1ENR |= RCC_APB1ENR_UART4EN; RCC->AHBENR |= RCC_AHBENR_DMA2EN; GPIOC->CRH = (GPIOC->CRH & ~(CRH(10,0xf)|CRH(11,0xf))) | CRH(10, CNF_AFPP|MODE_NORMAL) | CRH(11, CNF_FLINPUT|MODE_INPUT); - // UART4 Tx DMA - Channel5 (Rx - channel 3) + // UART4 Tx DMA - Channel5, Rx - channel 3 DMA2_Channel5->CPAR = (uint32_t) &UART4->DR; // periph DMA2_Channel5->CCR |= DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE; // 8bit, mem++, mem->per, transcompl irq + DMA2_Channel3->CPAR = (uint32_t) &UART4->DR; + DMA2_Channel3->CCR = DMA_CCR_MINC | DMA_CCR_TCIE; // Tx CNDTR set @ each transmission due to data size NVIC_SetPriority(DMA2_Channel4_5_IRQn, 2); NVIC_EnableIRQ(DMA2_Channel4_5_IRQn); - NVIC_SetPriority(UART4_IRQn, 2); + NVIC_SetPriority(DMA2_Channel3_IRQn, 2); + NVIC_EnableIRQ(DMA2_Channel3_IRQn); // setup uart4 UART4->BRR = 36000000 / speed; // APB1 is 36MHz UART4->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART + uint32_t tmout = 16000000; while(!(UART4->SR & USART_SR_TC)){ // polling idle frame Transmission IWDG->KR = IWDG_REFRESH; if(--tmout == 0) break; } + (void) UART4->DR; // clear IDLE etc UART4->SR = 0; // clear flags - UART4->CR1 |= USART_CR1_RXNEIE | USART_CR1_IDLEIE | USART_CR1_TCIE; // allow Rx and IDLE IRQ; TC IRQ for switching to Rx - UART4->CR3 = USART_CR3_DMAT; // enable DMA Tx + UART4->CR1 |= USART_CR1_IDLEIE | USART_CR1_TCIE; // allow IDLE IRQ; TC IRQ for switching to Rx + UART4->CR3 = USART_CR3_DMAT | USART_CR3_DMAR; // enable DMA Tx & Rx + NVIC_SetPriority(UART4_IRQn, 2); NVIC_EnableIRQ(UART4_IRQn); _485_Rx(); } void uart4_isr(){ if(UART4->SR & USART_SR_IDLE){ // idle - end of frame -usart_send("485: IDLE\n"); + DMA2_Channel3->CCR &= ~DMA_CCR_EN; modbus_rdy = 1; - dlen = idatalen[rbufno]; + dlen = MODBUSBUFSZI - DMA2_Channel3->CNDTR; recvdata = rbuf[rbufno]; // prepare other buffer rbufno = !rbufno; - idatalen[rbufno] = 0; (void) UART4->DR; // clear IDLE flag by reading DR - }else if(UART4->SR & USART_SR_RXNE){ // RX not emty - receive next char - uint8_t rb = UART4->DR; // clear RXNE flag - if(idatalen[rbufno] < MODBUSBUFSZI){ // put next char into buf - rbuf[rbufno][idatalen[rbufno]++] = rb; -usart_send("485: "); usart_putchar(rb); newline(); - }else{ // buffer overrun - bufovr = 1; - idatalen[rbufno] = 0; - } - }else if(UART4->SR & USART_SR_TC){ + _485_Rx(); // receive next + }else if(UART4->SR & USART_SR_TC){ // TC - switch to Rx if(modbus_txrdy){ -usart_send("->Rx\n"); _485_Rx(); } -usart_send("485: TC\n"); UART4->SR &= ~USART_SR_TC; } } +// Tx rdy void dma2_channel4_5_isr(){ if(DMA2->ISR & DMA_ISR_TCIF5){ // Tx DMA2->IFCR = DMA_IFCR_CTCIF5; // clear TC flag @@ -270,3 +269,13 @@ void dma2_channel4_5_isr(){ } } +// Rx full +void dma2_channel3_isr(){ + if(DMA2->ISR & DMA_ISR_TCIF3){ + DMA2_Channel3->CCR &= ~DMA_CCR_EN; + DMA2->IFCR = DMA_IFCR_CTCIF3; + bufovr = 1; + _485_Rx(); + } +} + diff --git a/F1:F103/FX3U/modbusrtu.h b/F1:F103/FX3U/modbusrtu.h index 85b5a5f..40e0a1b 100644 --- a/F1:F103/FX3U/modbusrtu.h +++ b/F1:F103/FX3U/modbusrtu.h @@ -19,8 +19,8 @@ #pragma once #include -// input and output buffers size -#define MODBUSBUFSZI (64) +// input and output buffers size: input buffer is greater as last symbol would be lost on Rx DMA IRQ +#define MODBUSBUFSZI (68) #define MODBUSBUFSZO (64) #define MODBUS_MASTER_ID (0) diff --git a/F1:F103/FX3U/proto.c b/F1:F103/FX3U/proto.c index 0703c8f..a2b2461 100644 --- a/F1:F103/FX3U/proto.c +++ b/F1:F103/FX3U/proto.c @@ -27,6 +27,54 @@ #include "usart.h" #include "version.inc" +// constants with commands and flags +static const char* S_adc = "adc"; +static const char* S_bounce = "bounce"; +static const char* S_canbuserr = "canbuserr"; +static const char* S_canid = "canid"; +static const char* S_canidin = "canidin"; +static const char* S_canidout = "canidout"; +static const char* S_cansniff = "cansniff"; +static const char* S_canspeed = "canspeed"; +static const char* S_dumpconf = "dumpconf"; +static const char* S_eraseflash = "eraseflash"; +static const char* S_esw = "esw"; +static const char* S_eswnow = "eswnow"; +static const char* S_flags = "flags"; +static const char* S_inchannels = "inchannels"; +static const char* S_led = "led"; +static const char* S_mcutemp = "mcutemp"; +static const char* S_modbusid = "modbusid"; +static const char* S_modbusidout = "modbusidout"; +static const char* S_modbus = "modbus"; +static const char* S_modbusraw = "modbusraw"; +static const char* S_modbusspeed = "modbusspeed"; +static const char* S_outchannels = "outchannels"; +static const char* S_relay = "relay"; +static const char* S_reset = "reset"; +static const char* S_saveconf = "saveconf"; +static const char* S_s = "s"; +static const char* S_time = "time"; +static const char* S_usartspeed = "usartspeed"; +static const char* S_wdtest = "wdtest"; + +// names of bit flags (ordered from LSE of[0]) +static const char* S_f_relay_inverted = "f_relay_inverted"; +static const char* S_f_send_esw_can = "f_send_esw_can"; +static const char* S_f_send_relay_can = "f_send_relay_can"; +static const char* S_f_send_relay_modbus = "f_send_relay_modbus"; + +// bitfield names should be in order of bit fields in confflags_t! +static const char ** const bitfields[] = { + &S_f_send_esw_can, + &S_f_send_relay_can, + &S_f_relay_inverted, + &S_f_send_relay_modbus, + NULL +}; + + +// runtime flags flags_t flags = { 0 }; @@ -39,15 +87,20 @@ typedef enum{ TCMD_CANSEND, // send CAN message TCMD_CANSNIFFER, // sniff all CAN messages TCMD_CANBUSERRPRNT, // pring all errors of bus - TCMD_SW_SEND_RELAY, // change of IN will send also command to change OUT - TCMD_MODBUS_SEND, // send raw modbus data (CRC added auto) + TCMD_MODBUS_SEND, // send modbus request + TCMD_MODBUS_SEND_RAW,// send raw modbus data (CRC added auto) + // change bit flags + TCMD_SW_SEND_CAN, // change of IN will send its current state over CAN + TCMD_SW_SEND_RCAN, // change of IN will send command to change OUT by CAN + TCMD_RELAY_INV, // inverted state between relay and inputs when send over CAN/MODBUS + TCMD_SW_SEND_RMODBUS,// modbus analog (if master) TCMD_AMOUNT } text_cmd; typedef struct{ - 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 + const char** const cmd; // command, if NULL - only display help message + int idx; // index in CAN cmd or text cmd list (if negative) + const char* const help; // help message } funcdescr; // list of all text functions; should be sorted and can be grouped (`help` is header when cmd == NULL) @@ -57,37 +110,42 @@ static const funcdescr funclist[] = { // {"adcv", CMD_ADCV, "get ADC voltage of channel 0..3 (*100V)"}, // {"bounce", CMD_BOUNCE, "get/set bounce constant (ms)"}, {NULL, 0, "CAN bus commands"}, - {"canbuserr", -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"}, - {"cansniff", -TCMD_CANSNIFFER, "switch CAN sniffer mode"}, - {"s", -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"}, + {&S_canbuserr, -TCMD_CANBUSERRPRNT, "print all CAN bus errors (a lot of if not connected)"}, + {&S_cansniff, -TCMD_CANSNIFFER, "switch CAN sniffer mode"}, + {&S_s, -TCMD_CANSEND, "send CAN message: ID 0..8 data bytes"}, {NULL, 0, "Configuration"}, - {"bounce", CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"}, - {"canid", CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"}, - {"canidin", CMD_CANIDin, "get/set input CAN ID"}, - {"canidout", CMD_CANIDout, "get/set output CAN ID"}, - {"canspeed", CMD_CANSPEED, "get/set CAN speed (bps)"}, - {"dumpconf", -TCMD_DUMPCONF, "dump current configuration"}, - {"eraseflash", CMD_ERASESTOR, "erase all flash storage"}, - {"flags", CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"}, - {"modbusid", CMD_MODBUSID, "set/get modbus slave ID (1..247) or set it master (0)"}, - {"modbusspeed", CMD_MODBUSSPEED, "set/get modbus speed (1200..115200)"}, - {"saveconf", CMD_SAVECONF, "save configuration"}, - {"sw_send_relay", -TCMD_SW_SEND_RELAY, "change of IN will send also command to change OUT with `canidout`"}, - {"usartspeed", CMD_USARTSPEED, "get/set USART1 speed"}, + {&S_bounce, CMD_BOUNCE, "set/get anti-bounce timeout (ms, max: 1000)"}, + {&S_canid, CMD_CANID, "set both (in/out) CAN ID / get in CAN ID"}, + {&S_canidin, CMD_CANIDin, "get/set input CAN ID"}, + {&S_canidout, CMD_CANIDout, "get/set output CAN ID"}, + {&S_canspeed, CMD_CANSPEED, "get/set CAN speed (bps)"}, + {&S_dumpconf, -TCMD_DUMPCONF, "dump current configuration"}, + {&S_eraseflash, CMD_ERASESTOR, "erase all flash storage"}, + {&S_f_relay_inverted, -TCMD_RELAY_INV, "inverted state between relay and inputs"}, + {&S_f_send_esw_can, -TCMD_SW_SEND_CAN, "change of IN will send status over CAN with `canidin`"}, + {&S_f_send_relay_can, -TCMD_SW_SEND_RCAN, "change of IN will send also CAN command to change OUT with `canidout`"}, + {&S_f_send_relay_modbus, -TCMD_SW_SEND_RMODBUS, "change of IN will send also MODBUS command to change OUT with `modbusidout` (only for master!)"}, + {&S_flags, CMD_FLAGS, "set/get configuration flags (as one U32 without parameter or Nth bit with)"}, + {&S_modbusid, CMD_MODBUSID, "set/get modbus slave ID (1..247) or set it master (0)"}, + {&S_modbusidout, CMD_MODBUSIDOUT, "set/get modbus slave ID (0..247) to send relay commands"}, + {&S_modbusspeed, CMD_MODBUSSPEED, "set/get modbus speed (1200..115200)"}, + {&S_saveconf, CMD_SAVECONF, "save configuration"}, + {&S_usartspeed, CMD_USARTSPEED, "get/set USART1 speed"}, {NULL, 0, "IN/OUT"}, - {"adc", CMD_ADCRAW, "get raw ADC values for given channel"}, - {"esw", CMD_GETESW, "anti-bounce read inputs"}, - {"eswnow", CMD_GETESWNOW, "read current inputs' state"}, - {"led", CMD_LED, "work with onboard LED"}, - {"relay", CMD_RELAY, "get/set relay state (0 - off, 1 - on)"}, + {&S_adc, CMD_ADCRAW, "get raw ADC values for given channel"}, + {&S_esw, CMD_GETESW, "anti-bounce read inputs"}, + {&S_eswnow, CMD_GETESWNOW, "read current inputs' state"}, + {&S_led, CMD_LED, "work with onboard LED"}, + {&S_relay, CMD_RELAY, "get/set relay state (0 - off, 1 - on)"}, {NULL, 0, "Other commands"}, - {"inchannels", CMD_INCHNLS, "get u32 with bits set on supported IN channels"}, - {"mcutemp", CMD_MCUTEMP, "get MCU temperature (*10degrC)"}, - {"modbus", -TCMD_MODBUS_SEND, "send modbus request, format: slaveID Fcode startReg numRegs"}, - {"outchannels", CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"}, - {"reset", CMD_RESET, "reset MCU"}, - {"time", CMD_TIME, "get/set time (1ms, 32bit)"}, - {"wdtest", -TCMD_WDTEST, "test watchdog"}, + {&S_inchannels, CMD_INCHNLS, "get u32 with bits set on supported IN channels"}, + {&S_mcutemp, CMD_MCUTEMP, "get MCU temperature (*10degrC)"}, + {&S_modbus, -TCMD_MODBUS_SEND, "send modbus request with format \"slaveID fcode regaddr nregs [N data]\", to send zeros you can omit rest of 'data'"}, + {&S_modbusraw, -TCMD_MODBUS_SEND_RAW, "send RAW modbus request (will send up to 62 bytes + calculated CRC)"}, + {&S_outchannels, CMD_OUTCHNLS, "get u32 with bits set on supported OUT channels"}, + {&S_reset, CMD_RESET, "reset MCU"}, + {&S_time, CMD_TIME, "get/set time (1ms, 32bit)"}, + {&S_wdtest, -TCMD_WDTEST, "test watchdog"}, {NULL, 0, NULL} // last record }; @@ -98,12 +156,13 @@ static void printhelp(){ usart_send("parameter [CAN idx] - help\n"); usart_send("--------------------------\n"); while(c->help){ + IWDG->KR = IWDG_REFRESH; if(!c->cmd){ // header usart_send("\n "); usart_send(c->help); usart_putchar(':'); }else{ - usart_send(c->cmd); + usart_send(*c->cmd); if(c->idx > -1){ usart_send(" ["); usart_send(u2str(c->idx)); @@ -128,7 +187,7 @@ static errcodes cansnif(const char *str, text_cmd _U_ cmd){ CAN_sniffer((uint8_t)U); } } - usart_send("cansniff="); usart_putchar('0' + flags.can_monitor); newline(); + usart_send(S_cansniff); EQ(); usart_putchar('0' + flags.can_monitor); newline(); return ERR_OK; } @@ -141,7 +200,7 @@ static errcodes canbuserr(const char *str, text_cmd _U_ cmd){ flags.can_printoff = U; } } - usart_send("canbuserr="); usart_putchar('0' + flags.can_printoff); newline(); + usart_send(S_canbuserr); EQ(); usart_putchar('0' + flags.can_printoff); newline(); return ERR_OK; } @@ -152,11 +211,7 @@ static errcodes wdtest(const char _U_ *str, text_cmd _U_ cmd){ return ERR_OK; } -// names of bit flags (ordered from LSE of[0]) -static const char * const bitfields[] = { - "sw_send_relay_cmd", - NULL -}; + static errcodes dumpconf(const char _U_ *str, text_cmd _U_ cmd){ #ifdef EBUG @@ -168,23 +223,21 @@ static errcodes dumpconf(const char _U_ *str, text_cmd _U_ cmd){ 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_in="); printu(the_conf.CANIDin); - usart_send("\ncanid_out="); printu(the_conf.CANIDout); - /*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); - usart_send("\nmodbus_id="); printu(the_conf.modbusID); - usart_send("\nmodbusspeed="); printu(the_conf.modbusspeed); - usart_send("\nbouncetime="); printu(the_conf.bouncetime); - const char * const *p = bitfields; + newline(); usart_send(S_canspeed); EQ(); printu(the_conf.CANspeed); + newline(); usart_send(S_canidin); EQ(); printu(the_conf.CANIDin); + newline(); usart_send(S_canidout); EQ(); printu(the_conf.CANIDout); + newline(); usart_send(S_usartspeed); EQ(); printu(the_conf.usartspeed); + newline(); usart_send(S_modbusid); EQ(); printu(the_conf.modbusID); + newline(); usart_send(S_modbusidout); EQ(); printu(the_conf.modbusIDout); + newline(); usart_send(S_modbusspeed); EQ(); printu(the_conf.modbusspeed); + newline(); usart_send(S_bounce); EQ(); printu(the_conf.bouncetime); + const char ** const *p = bitfields; int bit = 0; - usart_send("\nflags="); usart_putchar('='); printuhex(the_conf.flags.u32); + newline(); usart_send(S_flags); printuhex(the_conf.flags.u32); while(*p){ + IWDG->KR = IWDG_REFRESH; newline(); usart_putchar(' '); - usart_send(*p); usart_putchar('='); usart_putchar((the_conf.flags.u32 & (1< MAX_FLAG_BITNO) break; ++p; } @@ -198,6 +251,7 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){ int ctr = -1; canmsg.ID = 0xffff; do{ + IWDG->KR = IWDG_REFRESH; txt = omit_spaces(txt); uint32_t N; const char *n = getnum(txt, &N); @@ -225,6 +279,7 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){ canmsg.length = (uint8_t) ctr; uint32_t Tstart = Tms; while(Tms - Tstart < SEND_TIMEOUT_MS){ + IWDG->KR = IWDG_REFRESH; if(CAN_OK == CAN_send(&canmsg)){ return ERR_OK; } @@ -234,13 +289,22 @@ static errcodes cansend(const char *txt, text_cmd _U_ cmd){ // change configuration flags by one static errcodes confflags(const char _U_ *str, text_cmd cmd){ - if(str){ + if(str && *str){ if(*str == '=') str = omit_spaces(str + 1); if(*str != '0' && *str != '1') return ERR_BADVAL; uint8_t val = *str - '0'; switch(cmd){ - case TCMD_SW_SEND_RELAY: - the_conf.flags.sw_send_relay_cmd = val; + case TCMD_SW_SEND_CAN: + the_conf.flags.sw_send_esw_can = val; + break; + case TCMD_SW_SEND_RCAN: + the_conf.flags.sw_send_relay_can = val; + break; + case TCMD_RELAY_INV: + the_conf.flags.sw_send_relay_inv = val; + break; + case TCMD_SW_SEND_RMODBUS: + the_conf.flags.sw_send_relay_modbus = val; break; default: return ERR_BADCMD; @@ -248,21 +312,35 @@ static errcodes confflags(const char _U_ *str, text_cmd cmd){ } uint8_t val = 0, idx = 0; switch(cmd){ - case TCMD_SW_SEND_RELAY: - val = the_conf.flags.sw_send_relay_cmd; + case TCMD_SW_SEND_CAN: + val = the_conf.flags.sw_send_esw_can; idx = 0; break; + case TCMD_SW_SEND_RCAN: + val = the_conf.flags.sw_send_relay_can; + idx = 1; + break; + case TCMD_RELAY_INV: + val = the_conf.flags.sw_send_relay_inv; + idx = 2; + break; + case TCMD_SW_SEND_RMODBUS: + val = the_conf.flags.sw_send_relay_modbus; + idx = 3; + break; default: return ERR_BADCMD; } - usart_send(bitfields[idx]); usart_putchar('='); usart_putchar('0' + val); + usart_send(*bitfields[idx]); EQ(); usart_putchar('0' + val); newline(); return ERR_OK; } -// format: slaveID Fcode startReg numRegs +// format: slaveID Fcode startReg numRegs [N data]; +// to send zeros you can omit rest of 'data' static errcodes modbussend(const char *txt, text_cmd _U_ cmd){ modbus_request req = {0}; + uint8_t reqdata[MODBUSBUFSZO - 7] = {0}; uint32_t N = 0; const char *n = getnum(txt, &N); if(n == txt || N > MODBUS_MAX_ID){ @@ -283,15 +361,53 @@ static errcodes modbussend(const char *txt, text_cmd _U_ cmd){ } req.startreg = N; txt = n; n = getnum(txt, &N); - if(n == txt || N == 0){ - usart_send("Need registers amount\n"); + if(n == txt){ + usart_send("Need registers amount or data bytes\n"); return ERR_WRONGLEN; } req.regno = N; + txt = n; n = getnum(txt, &N); + if((req.Fcode == MC_WRITE_MUL_COILS || req.Fcode == MC_WRITE_MUL_REGS)){ // request with data + if(txt == n){ + usart_send("Need amount of data for given fcode\n"); + return ERR_WRONGLEN; + } + if(N == 0 || N > MODBUSBUFSZO - 7){ + usart_send("Data length too big\n"); + return ERR_BADVAL; + } + req.datalen = N; + for(int i = 0; i < req.datalen; ++i){ + txt = n; n = getnum(txt, &N); + if(txt == n) break; + reqdata[i] = N; + } + req.data = reqdata; + }else if(n != txt){ + usart_send("multiple data allows only for fcode 0x0f and 0x10; ignore other data\n"); + } if(modbus_send_request(&req) < 1) return ERR_CANTRUN; return ERR_OK; } +// raw data format +static errcodes modbussendraw(const char *txt, text_cmd _U_ cmd){ + uint32_t N = 0; + uint8_t reqdata[MODBUSBUFSZO], datalen = 0; + for(; datalen < MODBUSBUFSZO; ++datalen){ + const char *n = getnum(txt, &N); + if(n == txt) break; + reqdata[datalen] = N; + txt = n; + } + if(datalen == 0){ + usart_send("Need data bytes\n"); + return ERR_WRONGLEN; + } + if(modbus_send(reqdata, datalen) != datalen) return ERR_CANTRUN; + return ERR_OK; +} + /************ END of all text functions list ************/ // in `textfn` arg `str` is the rest of input string (spaces-omitted) after command @@ -303,12 +419,16 @@ static textfn textfunctions[TCMD_AMOUNT] = { [TCMD_CANSEND] = cansend, [TCMD_CANSNIFFER] = cansnif, [TCMD_CANBUSERRPRNT] = canbuserr, - [TCMD_SW_SEND_RELAY] = confflags, [TCMD_MODBUS_SEND] = modbussend, + [TCMD_MODBUS_SEND_RAW] = modbussendraw, + [TCMD_SW_SEND_CAN] = confflags, + [TCMD_SW_SEND_RCAN] = confflags, + [TCMD_RELAY_INV] = confflags, + [TCMD_SW_SEND_RMODBUS] = confflags, }; static const char* const errors_txt[ERR_AMOUNT] = { - [ERR_OK] = "OK" + [ERR_OK] = "OK" ,[ERR_BADPAR] = "badpar" ,[ERR_BADVAL] = "badval" ,[ERR_WRONGLEN] = "wronglen" @@ -339,7 +459,8 @@ void cmd_parser(const char *str){ if(l == 0) goto ret; cmd[l] = 0; while(c->help){ - if(c->cmd && 0 == strcmp(c->cmd, cmd)){ + IWDG->KR = IWDG_REFRESH; + if(c->cmd && 0 == strcmp(*c->cmd, cmd)){ idx = c->idx; break; } diff --git a/F1:F103/FX3U/proto.h b/F1:F103/FX3U/proto.h index 8ed6c12..52d0052 100644 --- a/F1:F103/FX3U/proto.h +++ b/F1:F103/FX3U/proto.h @@ -21,7 +21,7 @@ #include #include "hardware.h" -#define MAXCMDLEN (12) +#define MAXCMDLEN (32) // flags for some RS-232 comands typedef struct{ @@ -33,3 +33,4 @@ extern flags_t flags; void cmd_parser(const char *txt); + diff --git a/F1:F103/FX3U/strfunc.c b/F1:F103/FX3U/strfunc.c index 7c42a70..93ad3c2 100644 --- a/F1:F103/FX3U/strfunc.c +++ b/F1:F103/FX3U/strfunc.c @@ -64,8 +64,6 @@ static char *_2str(uint32_t val, uint8_t minus){ uint32_t x = val / 10; *(--bufptr) = (val - 10*x) + '0'; val = x; - //*(--bufptr) = val % 10 + '0'; - //val /= 10; } } if(minus) *(--bufptr) = '-'; @@ -257,8 +255,8 @@ const char *getint(const char *txt, int32_t *I){ int32_t sign = 1; uint32_t U; if(*s == '-'){ - sign = -1; - ++s; + sign = -1; + ++s; } const char *nxt = getnum(s, &U); if(nxt == s) return txt; diff --git a/F1:F103/FX3U/strfunc.h b/F1:F103/FX3U/strfunc.h index d7ceeb1..ff5607c 100644 --- a/F1:F103/FX3U/strfunc.h +++ b/F1:F103/FX3U/strfunc.h @@ -43,7 +43,8 @@ const char *getnum(const char *txt, uint32_t *N); const char *omit_spaces(const char *buf); const char *getint(const char *txt, int32_t *I); -#define newline() do{usart_putchar('\n');}while(0) -#define printu(a) do{usart_send(u2str(a));}while(0) -#define printi(a) do{usart_send(i2str(a));}while(0) +#define EQ() do{usart_putchar('=');}while(0) +#define newline() do{usart_putchar('\n');}while(0) +#define printu(a) do{usart_send(u2str(a));}while(0) +#define printi(a) do{usart_send(i2str(a));}while(0) #define printuhex(a) do{usart_send(uhex2str(a));}while(0) diff --git a/F1:F103/FX3U/usart.c b/F1:F103/FX3U/usart.c index ac724e2..df891ab 100644 --- a/F1:F103/FX3U/usart.c +++ b/F1:F103/FX3U/usart.c @@ -56,18 +56,18 @@ int usart_getline(char **line){ int usart_transmit(){ register int l = odatalen[tbufno]; if(!l) return 0; - uint32_t tmout = 1600000; + uint32_t tmout = 18000000; while(!usart_txrdy){ IWDG->KR = IWDG_REFRESH; if(--tmout == 0) return 0; }; // wait for previos buffer transmission usart_txrdy = 0; - odatalen[tbufno] = 0; DMA1_Channel4->CCR &= ~DMA_CCR_EN; DMA1_Channel4->CMAR = (uint32_t) tbuf[tbufno]; // mem DMA1_Channel4->CNDTR = l; DMA1_Channel4->CCR |= DMA_CCR_EN; tbufno = !tbufno; + odatalen[tbufno] = 0; return l; } @@ -82,6 +82,7 @@ int usart_putchar(const char ch){ int usart_send(const char *str){ int l = 0; while(*str){ + IWDG->KR = IWDG_REFRESH; if(odatalen[tbufno] == UARTBUFSZO){ if(!usart_transmit()) return 0; } @@ -100,7 +101,6 @@ int usart_send(const char *str){ */ void usart_setup(uint32_t speed){ - uint32_t tmout = 16000000; // PA9 - Tx, PA10 - Rx RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN; @@ -116,7 +116,11 @@ void usart_setup(uint32_t speed){ // setup usart1 USART1->BRR = 72000000 / speed; USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART - while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission + uint32_t tmout = 16000000; + while(!(USART1->SR & USART_SR_TC)){ + IWDG->KR = IWDG_REFRESH; + if(--tmout == 0) break; + } // polling idle frame Transmission USART1->SR = 0; // clear flags USART1->CR1 |= USART_CR1_RXNEIE; // allow Rx IRQ USART1->CR3 = USART_CR3_DMAT; // enable DMA Tx diff --git a/F1:F103/FX3U/usart.h b/F1:F103/FX3U/usart.h index 3b296e7..5800e9b 100644 --- a/F1:F103/FX3U/usart.h +++ b/F1:F103/FX3U/usart.h @@ -21,8 +21,8 @@ #include // input and output buffers size -#define UARTBUFSZI (64) -#define UARTBUFSZO (128) +#define UARTBUFSZI (196) +#define UARTBUFSZO (256) #define usartrx() (usart_linerdy) #define usartovr() (usart_bufovr) diff --git a/F1:F103/FX3U/version.inc b/F1:F103/FX3U/version.inc index 06d0e3f..60acc86 100644 --- a/F1:F103/FX3U/version.inc +++ b/F1:F103/FX3U/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "85" -#define BUILD_DATE "2024-09-24" +#define BUILD_NUMBER "105" +#define BUILD_DATE "2024-09-26"