/* * 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 "modbusrtu.h" #include "strfunc.h" #include "usart.h" #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 return ERR_OK; // send same message } // 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 = MSGP_GET_U32(msg); } FIXDL(msg); MSGP_SET_U32(msg, Tms); return ERR_OK; } // get MCU T static errcodes mcut(CAN_message *msg){ FIXDL(msg); MSGP_SET_U32(msg, getMCUtemp()); return ERR_OK; } // get ADC raw values static errcodes adcraw(CAN_message *msg){ FIXDL(msg); uint8_t no = PARVAL(msg->data); if(no >= ADC_CHANNELS) return ERR_BADPAR; MSGP_SET_U32(msg, getADCval(no)); return ERR_OK; } // set common CAN ID / get CAN IN in static errcodes canid(CAN_message *msg){ if(ISSETTER(msg->data)){ the_conf.CANIDin = the_conf.CANIDout = (uint16_t)MSGP_GET_U32(msg); CAN_reinit(0); // setup with new ID } FIXDL(msg); MSGP_SET_U32(msg, the_conf.CANIDin); return ERR_OK; } // get/set input CAN ID static errcodes canidin(CAN_message *msg){ if(ISSETTER(msg->data)){ the_conf.CANIDin = (uint16_t)MSGP_GET_U32(msg); CAN_reinit(0); // setup with new ID } FIXDL(msg); MSGP_SET_U32(msg, the_conf.CANIDin); return ERR_OK; } // get/set output CAN ID static errcodes canidout(CAN_message *msg){ if(ISSETTER(msg->data)){ the_conf.CANIDout = (uint16_t)MSGP_GET_U32(msg); } FIXDL(msg); MSGP_SET_U32(msg, the_conf.CANIDout); 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){ uint8_t no = OUTMAX+1; if(msg->length > 2){ uint8_t chnl = PARVAL(msg->data); if(chnl != NO_PARNO) no = chnl; } if(ISSETTER(msg->data)){ if(set_relay(no, MSGP_GET_U32(msg)) < 0) return ERR_BADPAR; } FIXDL(msg); int rval = get_relay(no); if(rval < 0) return ERR_BADPAR; MSGP_SET_U32(msg, (uint32_t)rval); return ERR_OK; } // get current ESW status static errcodes esw(CAN_message *msg){ uint8_t no = INMAX+1; if(msg->length > 2){ uint8_t chnl = PARVAL(msg->data); if(chnl != NO_PARNO) no = chnl; } int val = get_esw(no); if(val < 0) return ERR_BADPAR; MSGP_SET_U32(msg, (uint32_t)val); FIXDL(msg); return ERR_OK; } // bounce-free ESW get status static errcodes eswg(CAN_message *msg){ uint8_t no = INMAX+1; if(msg->length > 2){ uint8_t chnl = PARVAL(msg->data); if(chnl != NO_PARNO) no = chnl; } uint32_t curval = get_ab_esw(); if(no > INMAX) MSGP_SET_U32(msg, curval); else MSGP_SET_U32(msg, (curval & (1<length > 4 && ISSETTER(m->data)) LED(m->data[4]); m->data[4] = LED(-1); FIXDL(m); return ERR_OK; } // common uint32_t setter/getter static errcodes u32setget(CAN_message *msg){ uint16_t cmd = *(uint16_t*)msg->data; uint32_t *ptr = NULL, val; switch(cmd){ case CMD_CANSPEED: ptr = &the_conf.CANspeed; CAN_reinit(MSGP_GET_U32(msg)); break; case CMD_BOUNCE: ptr = &the_conf.bouncetime; break; case CMD_USARTSPEED: ptr = &the_conf.usartspeed; break; 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_MODBUSSPEED: ptr = &the_conf.modbusspeed; break; default: break; } if(!ptr) return ERR_CANTRUN; // unknown error if(ISSETTER(msg->data)){ if(cmd == CMD_INCHNLS || cmd == CMD_OUTCHNLS) return ERR_CANTRUN; // can't set getter-only *ptr = MSGP_GET_U32(msg); } FIXDL(msg); MSGP_SET_U32(msg, *ptr); return ERR_OK; } // common bitflag setter/getter // without parno - all flags, with - flag with number N static errcodes flagsetget(CAN_message *msg){ uint8_t idx = NO_PARNO; if(msg->length > 2){ idx = PARVAL(msg->data); if(idx != NO_PARNO && idx > MAX_FLAG_BITNO) return ERR_BADPAR; } if(ISSETTER(msg->data)){ uint32_t val = MSGP_GET_U32(msg); if(idx == NO_PARNO) the_conf.flags.u32 = val; // all bits else{ // only selected if(val) the_conf.flags.u32 |= 1 << idx; else the_conf.flags.u32 &= ~(1 << idx); } } FIXDL(msg); if(idx == NO_PARNO) MSGP_SET_U32(msg, the_conf.flags.u32); else MSGP_SET_U32(msg, (the_conf.flags.u32 & (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(' '); } 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 }