From 9713b10cd41fc4987053b7fe10c20fc732b32aba Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Mon, 9 Mar 2026 01:24:02 +0300 Subject: [PATCH] continue developing GPIO config; not tested yet --- F0:F030,F042,F072/usbcan_gpio/flash.c | 13 + F0:F030,F042,F072/usbcan_gpio/flash.h | 6 + F0:F030,F042,F072/usbcan_gpio/gpio.c | 117 ++++++++ F0:F030,F042,F072/usbcan_gpio/gpio.h | 92 ++++++ F0:F030,F042,F072/usbcan_gpio/hashparser.cpp | 267 +++++++++++++++--- F0:F030,F042,F072/usbcan_gpio/hashparser.h | 5 +- F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin | Bin 24344 -> 17892 bytes .../usbcan_gpio/usbcangpio.creator.user | 2 +- .../usbcan_gpio/usbcangpio.files | 2 + F0:F030,F042,F072/usbcan_gpio/version.inc | 4 +- 10 files changed, 470 insertions(+), 38 deletions(-) create mode 100644 F0:F030,F042,F072/usbcan_gpio/gpio.c create mode 100644 F0:F030,F042,F072/usbcan_gpio/gpio.h diff --git a/F0:F030,F042,F072/usbcan_gpio/flash.c b/F0:F030,F042,F072/usbcan_gpio/flash.c index 27c871e..793f154 100644 --- a/F0:F030,F042,F072/usbcan_gpio/flash.c +++ b/F0:F030,F042,F072/usbcan_gpio/flash.c @@ -39,6 +39,18 @@ static int write2flash(const void*, const void*, uint32_t); // 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t' const user_conf *Flash_Data = (const user_conf *)(&__varsstart); +// default pin config: all are low speed floating inputs +#define PINEN {.enable = 1} +// GPIOA, enabled: PA0-PA3, PA5-PA7, PA9, PA10 +#define PACONF \ +[0] = PINEN, [1] = PINEN, [2] = PINEN, [3] = PINEN, [5] = PINEN, \ +[6] = PINEN, [7] = PINEN, [9] = PINEN, [10] = PINEN + +// GPIOB, enabled: PB0-PB7, PB10, PB11 +#define PBCONF \ +[0] = PINEN, [1] = PINEN, [2] = PINEN, [3] = PINEN, [4] = PINEN, \ +[5] = PINEN, [6] = PINEN, [7] = PINEN, [10] = PINEN, [11] = PINEN + user_conf the_conf = { .userconf_sz = sizeof(user_conf), .CANspeed = 100, @@ -47,6 +59,7 @@ user_conf the_conf = { [IGPIO] = u"USB-GPIO", }, .iIlengths = {14, 16}, + .pinconfig = {[0] = {PACONF}, [1] = {PBCONF}}, }; int currentconfidx = -1; // index of current configuration diff --git a/F0:F030,F042,F072/usbcan_gpio/flash.h b/F0:F030,F042,F072/usbcan_gpio/flash.h index 843f4e7..6004eb6 100644 --- a/F0:F030,F042,F072/usbcan_gpio/flash.h +++ b/F0:F030,F042,F072/usbcan_gpio/flash.h @@ -23,6 +23,8 @@ #pragma once #include + +#include "gpio.h" #include "usb_descr.h" // register with flash size (in blocks) @@ -43,6 +45,10 @@ typedef struct __attribute__((packed, aligned(4))){ uint16_t CANspeed; // default CAN speed (in kBaud!!!) uint16_t iInterface[InterfacesAmount][MAX_IINTERFACE_SZ]; // we store Interface name here in UTF! uint8_t iIlengths[InterfacesAmount]; // length in BYTES (symbols amount x2)! + // gpio settings + pinconfig_t pinconfig[2][16]; // GPIOA, GPIOB + usartconfig_t usartconfig; + spiconfig_t spiconfig; } user_conf; extern user_conf the_conf; // global user config (read from FLASH to RAM) diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.c b/F0:F030,F042,F072/usbcan_gpio/gpio.c new file mode 100644 index 0000000..bbeaabd --- /dev/null +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.c @@ -0,0 +1,117 @@ +/* + * This file is part of the usbcangpio project. + * Copyright 2026 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 + +#include "flash.h" +#include "gpio.h" + +// TODO: remove AFmask, make function to get right AF number by pin's FuncValues +typedef struct{ + funcvalues_t vals; + uint8_t AFmask; +} pinprops_t; + +static const pinprops_t pin_props[2][16] = { + [0] = { // PORT A + [0] = { .vals.flags = 0b00000001, .AFmask = (1<<2) }, // PA0: ADC0, AF2 (TIM2_CH1) + [1] = { .vals.flags = 0b00000001, .AFmask = (1<<2) }, // PA1: ADC1, AF2 (TIM2_CH2) + [2] = { .vals.flags = 0b00000011, .AFmask = (1<<2) | (1<<1) }, // PA2: ADC2, AF2 (TIM2_CH3), AF1 (USART2_TX) + [3] = { .vals.flags = 0b00000011, .AFmask = (1<<2) | (1<<1) }, // PA3: ADC3, AF2 (TIM2_CH4), AF1 (USART2_RX) + [5] = { .vals.flags = 0b00000101, .AFmask = (1<<0) }, // PA5: ADC5, SPI1_SCK (AF0) + [6] = { .vals.flags = 0b00000101, .AFmask = (1<<0) }, // PA6: ADC6, SPI1_MISO (AF0) + [7] = { .vals.flags = 0b00000101, .AFmask = (1<<0) }, // PA7: ADC7, SPI1_MOSI (AF0) + [9] = { .vals.flags = 0b00000010, .AFmask = (1<<1) }, // PA9: USART1_TX (AF1) + [10] = { .vals.flags = 0b00000010, .AFmask = (1<<1) }, // PA10: USART1_RX (AF1) + }, + [1] = { // PORT B + [0] = { .vals.flags = 0b00000001, .AFmask = (1<<2) | (1<<3) }, // PB0: ADC8, TIM3_CH3 (AF1), TIM1_CH2N (AF2) + [1] = { .vals.flags = 0b00000001, .AFmask = (1<<0) | (1<<1) | (1<<2) }, // PB1: ADC9, TIM14_CH1 (AF0), TIM3_CH4 (AF1), TIM1_CH3N (AF2) + [2] = { .vals.flags = 0b00000000, .AFmask = 0 }, // PB2: nothing except GPIO + [3] = { .vals.flags = 0b00000100, .AFmask = (1<<0) | (1<<2) }, // PB3: SPI1_SCK (AF0), TIM2_CH2 (AF2) + [4] = { .vals.flags = 0b00000100, .AFmask = (1<<0) | (1<<1) }, // PB4: SPI1_MISO (AF0), TIM3_CH1 (AF1) + [5] = { .vals.flags = 0b00000100, .AFmask = (1<<0) | (1<<1) }, // PB5: SPI1_MOSI (AF0), TIM3_CH2 (AF1) + [6] = { .vals.flags = 0b00000010, .AFmask = (1<<0) | (1<<1) | (1<<2) }, // PB6: USART1_TX (AF0), I2C1_SCL (AF1), TIM16_CH1N (AF2) + [7] = { .vals.flags = 0b00000010, .AFmask = (1<<0) | (1<<1) | (1<<2) }, // PB7: USART1_RX (AF0), I2C1_SDA (AF1), TIM17_CH1N (AF2) + [10] = { .vals.flags = 0b00000000, .AFmask = (1<<1) | (1<<2) }, // PB10: I2C1_SCL (AF1), TIM2_CH3 (AF2) + [11] = { .vals.flags = 0b00000000, .AFmask = (1<<1) | (1<<2) }, // PB11: I2C1_SDA (AF1), TIM2_CH4 (AF2) + } +}; + +static int is_disabled(uint8_t port, uint8_t pin){ + if(port > 1 || pin > 15) return FALSE; + if(!the_conf.pinconfig[port][pin].enable) return FALSE; + return TRUE; +} + +/** + * @brief is_func_allowed - check if alternate function `afno` allowed on given pin + * @param port - 0 for GPIOA and 1 for GPIOB + * @param pin - 0..15 + * @param afno - number of alternate function + * @return TRUE if all OK + */ +int is_func_allowed(uint8_t port, uint8_t pin, pinconfig_t *pcfg){ + if(is_disabled(port, pin)) return FALSE; + const pinprops_t *props = &pin_props[port][pin]; + switch(pcfg->mode){ + case MODE_ANALOG: + if(!props->vals.canADC) return FALSE; + pcfg->pull = PULL_NONE; // no PullUp for analog mode + break; + case MODE_AF: + // here af is one of enum FuncValues !!! we should change `af` later + if(!((1<af) & props->vals.flags)) return FALSE; + // TODO: set right AF number here !!! + //if(!(props->AFmask & (1 << pcfg->af))) return FALSE; // no such AF or not supported + pcfg->speed = SPEED_HIGH; // many AF needs high speed + pcfg->otype = OUTPUT_PP; // no OD for AF + break; + case MODE_INPUT: // no limits + break; + case MODE_OUTPUT: // no limits + break; + default: + return FALSE; + } + return TRUE; +} + +int gpio_reinit(){ + for(int port = 0; port < 2; port++){ + GPIO_TypeDef *gpio = (port == 0) ? GPIOA : GPIOB; + for(int pin = 0; pin < 16; pin++){ + pinconfig_t *cfg = &the_conf.pinconfig[port][pin]; + int shift2 = pin << 1; + if(!cfg->enable) continue; + gpio->MODER = (gpio->MODER & ~(3 << shift2))| (cfg->mode << shift2); + gpio->OTYPER = (gpio->OTYPER & ~(1 << pin)) | (cfg->otype << pin); + gpio->OSPEEDR = (gpio->OSPEEDR & ~(3 << shift2)) | (cfg->speed << shift2); + gpio->PUPDR = (gpio->PUPDR & ~(3 << shift2)) | (cfg->pull << shift2); + if(pin < 8){ + int shift4 = pin << 4; + gpio->AFR[0] = (gpio->AFR[0] & ~(0xf << shift4)) | (cfg->af << shift4); + }else{ + int shift4 = (pin - 8) << 4; + gpio->AFR[1] = (gpio->AFR[1] & ~(0xf << shift4)) | (cfg->af << shift4); + } + } + } + // TODO: configure USART, SPI etc + return TRUE; +} diff --git a/F0:F030,F042,F072/usbcan_gpio/gpio.h b/F0:F030,F042,F072/usbcan_gpio/gpio.h new file mode 100644 index 0000000..3ff2d77 --- /dev/null +++ b/F0:F030,F042,F072/usbcan_gpio/gpio.h @@ -0,0 +1,92 @@ +/* + * This file is part of the usbcangpio project. + * Copyright 2026 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 + +// MODER +typedef enum{ + MODE_INPUT = 0, + MODE_OUTPUT = 1, + MODE_AF = 2, + MODE_ANALOG = 3 +} pinmode_t; + +// PUPDR +typedef enum{ + PULL_NONE = 0, + PULL_UP = 1, + PULL_DOWN = 2 +} pinpull_t; + +// OTYPER +typedef enum{ + OUTPUT_PP = 0, + OUTPUT_OD = 1 +} pinout_t; + +// OSPEEDR +typedef enum{ + SPEED_LOW = 0, + SPEED_MEDIUM = 1, + SPEED_HIGH = 3 +} pinspeed_t; + +enum FuncShifts{ // shift 1 by this to get "canUSART" etc; not more than 7! + FUNC_USART = 1, + FUNC_SPI = 2, +}; + +typedef union{ + struct{ + uint8_t canADC : 1; + uint8_t canUSART : 1; + uint8_t canSPI : 1; + }; + uint8_t flags; +} funcvalues_t; + +typedef struct{ + uint8_t enable : 1; // [immutable!] pin config avialable (==1 for PA0-PA3, PA5-PA7, PA9, PA10, PB0-PB7, PB10, PB11, ==0 for rest) + pinmode_t mode : 2; + pinpull_t pull : 2; + pinout_t otype : 1; + pinspeed_t speed : 2; + uint8_t af : 3; // alternate function number (only if mode == MODE_AF) + uint8_t monitor : 1; // monitor changes +} pinconfig_t; + +typedef struct{ + uint32_t baudrate; + uint8_t databits; // 8 or 9 + char parity; // 'N','E','O' + uint8_t stopbits; // 1 or 2 + uint8_t enabled; // is USART active (flag `monitor` taken from pinconfig_t also as Rx/Tx enable) +} usartconfig_t; + +typedef struct{ + uint32_t speed; + uint8_t cpol : 1; + uint8_t cpha : 1; + uint8_t lsbfirst : 1; + uint8_t enabled : 1; +} spiconfig_t; + +int is_func_allowed(uint8_t port, uint8_t pin, pinconfig_t *pcfg); +int gpio_reinit(); diff --git a/F0:F030,F042,F072/usbcan_gpio/hashparser.cpp b/F0:F030,F042,F072/usbcan_gpio/hashparser.cpp index e5a6563..6b12bf7 100644 --- a/F0:F030,F042,F072/usbcan_gpio/hashparser.cpp +++ b/F0:F030,F042,F072/usbcan_gpio/hashparser.cpp @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +// !!! Some commands could change icoming string, so don't try to use it after function call !!! + #include extern "C"{ @@ -23,20 +25,30 @@ extern "C"{ #include "can.h" #include "flash.h" #include "hashparser.h" +#include "gpio.h" #include "gpioproto.h" #define USBIF IGPIO #include "strfunc.h" } -static const char *const sOKn = "OK\n", *const sERRn = "ERR\n"; extern uint32_t Tms; // list of all commands and handlers #define COMMAND_TABLE \ COMMAND(canspeed, "CAN bus speed setter/getter (kBaud, 10..1000)") \ COMMAND(dumpflash, "flash config dump") \ - COMMAND(time, "Current time (ms)") \ - COMMAND(help, "Show this help") + COMMAND(help, "Show this help") \ + COMMAND(PA, "GPIOA setter/getter (type PAx=help for further info)") \ + COMMAND(PB, "GPIOB setter/getter") \ + COMMAND(reinit, "apply pin config") \ + COMMAND(storeconf, "save config to flash") \ + COMMAND(time, "show current time (ms)") + +// COMMAND(USART, "Read USART data or send (USART=hex)") +// COMMAND(usartconf, "set USART params (e.g. usartconf=115200 8N1)") +// COMMAND(SPI, "Read SPI data or send (SPI=hex)") +// COMMAND(spiconf, "set SPI params") + typedef struct { const char *name; @@ -54,6 +66,224 @@ static const CmdInfo cmdInfo[] = { // command name, description - for `help` #undef COMMAND }; +// pin settings parser +struct Keyword { + const char *name; + uint8_t group; + uint8_t value; +}; + +enum KeywordGroup { + GROUP_MODE, + GROUP_PULL, + GROUP_OTYPE, + GROUP_FUNC, + GROUP_MISC +}; + +enum MiscValues{ + MISC_MONITOR = 1, +}; + +static constexpr Keyword keywords[] = { + {"AIN", GROUP_MODE, MODE_ANALOG}, + {"IN", GROUP_MODE, MODE_INPUT}, + {"OUT", GROUP_MODE, MODE_OUTPUT}, + {"AF", GROUP_MODE, MODE_AF}, + {"PU", GROUP_PULL, PULL_UP}, + {"PD", GROUP_PULL, PULL_DOWN}, + {"FL", GROUP_PULL, PULL_NONE}, + {"PP", GROUP_OTYPE, OUTPUT_PP}, + {"OD", GROUP_OTYPE, OUTPUT_OD}, + {"USART", GROUP_FUNC, FUNC_USART}, + {"SPI", GROUP_FUNC, FUNC_SPI}, + {"MONITOR",GROUP_MISC, MISC_MONITOR}, // monitor flag +}; +#define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0])) + +static const char* errtxt[ERR_AMOUNT] = { + [ERR_OK] = "OK", + [ERR_BADCMD] = "BADCMD", + [ERR_BADPAR] = "BADPAR", + [ERR_BADVAL] = "BADVAL", + [ERR_WRONGLEN] = "WRONGLEN", + [ERR_CANTRUN] = "CANTRUN", +}; + +static const char *EQ = " = "; // equal sign for getters + +/** + * @brief splitargs - get command parameter and setter from `args` + * @param args (i) - rest of string after command (like `1 = PU OD OUT`) + * @param parno (o) - parameter number or -1 if none + * @return setter (part after `=` without leading spaces) or NULL if none + */ +static char *splitargs(char *args, int32_t *parno){ + if(!args) return NULL; + uint32_t U32; + char *next = getnum(args, &U32); + int p = -1; + if(next != args && U32 <= MAXPARNO) p = U32; + if(parno) *parno = p; + next = strchr(next, '='); + if(next){ + if(*(++next)) next = omit_spaces(next); + if(*(++next) == 0) next = NULL; + } + return next; +} + +#if 0 +/** + * @brief argsvals - split `args` into `parno` and setter's value + * @param args - rest of string after command + * @param parno (o) - parameter number or -1 if none + * @param parval - integer setter's value + * @return false if no setter or it's not a number, true - got setter's num + */ +static bool argsvals(char *args, int32_t *parno, int32_t *parval){ + char *setter = splitargs(args, parno); + if(!setter) return false; + int32_t I32; + char *next = getint(setter, &I32); + if(next != setter && parval){ + *parval = I32; + return true; + } + return false; +} +#endif + +// `port` and `pin` are checked in `parse_pin_command` +// `PAx = ` also printed there +static void pin_getter(uint8_t port, uint8_t pin){ + pinconfig_t *pcfg = &the_conf.pinconfig[port][pin]; + switch(pcfg->mode){ + case MODE_INPUT: + case MODE_OUTPUT: { + uint32_t idr = (port == 0) ? GPIOA->IDR : GPIOB->IDR; + uint8_t bit = (idr >> pin) & 1; + PUTCHAR(bit ? '1' : '0'); + NL(); + } + break; + case MODE_ANALOG: + SENDn("TODO"); + // TODO: read ADC channel #pin + //SENDn(u2str(get_adc_value(port, pin))); + break; + case MODE_AF: + SENDn("ERR: pin in AF mode, use USART/SPI commands"); + break; + default: + break; + } +} + +// `port` and `pin` are checked in `parse_pin_command` +// set GPIO values (if *setter is 0/1) or configure it +static errcodes_t pin_setter(uint8_t port, uint8_t pin, char *setter){ + pinconfig_t *pcfg = &the_conf.pinconfig[port][pin]; + char _1st = *setter; + if(_1st == '0' || _1st == '1'){ // just set/clear pin state; throw out all text after "1"/"0" + if(pcfg->mode != MODE_OUTPUT) return ERR_CANTRUN; + volatile GPIO_TypeDef * GPIOx = (port == 0) ? GPIOA : GPIOB; + if(_1st == '1') GPIOx->BSRR = (1 << pin); + else GPIOx->BRR = (1 << pin); + return ERR_OK; + } + // complex setter: parse properties + uint8_t mode_set = 0xFF, pull_set = 0xFF, otype_set = 0xFF, func_set = 0xFF; + bool monitor = false; + char *saveptr, *token = strtok_r(setter, " ,", &saveptr); + while(token){ + size_t i = 0; + for(; i < NUM_KEYWORDS; i++){ + if(strcmp(token, keywords[i].name) == 0){ + switch(keywords[i].group){ + case GROUP_MODE: + if(mode_set != 0xFF) return ERR_BADVAL; // repeated similar group parameter + mode_set = keywords[i].value; + break; + case GROUP_PULL: + if(pull_set != 0xFF) return ERR_BADVAL; + pull_set = keywords[i].value; + break; + case GROUP_OTYPE: + if(otype_set != 0xFF) return ERR_BADVAL; + otype_set = keywords[i].value; + break; + case GROUP_FUNC: + if(func_set != 0xFF) return ERR_BADVAL; + func_set = keywords[i].value; + break; + case GROUP_MISC: + if(keywords[i].value == MISC_MONITOR) monitor = true; + break; + } + break; + } + } + if(i == NUM_KEYWORDS) return ERR_BADVAL; // not found + token = strtok_r(NULL, " ,", &saveptr); + } + if(func_set != 0xFF) mode_set = MODE_AF; + if(mode_set == 0xFF) return ERR_BADVAL; // user forgot to set mode + // set defaults + if(pull_set == 0xFF) pull_set = PULL_NONE; + if(otype_set == 0xFF) otype_set = OUTPUT_PP; + // can also do something with `speed_set`, then remove SPEED_MEDIUM from `curconfig` + // check that current parameters combination is acceptable for current pin + pinconfig_t curconf; + curconf.mode = static_cast (mode_set); + curconf.pull = static_cast (pull_set); + curconf.otype = static_cast (otype_set); + curconf.speed = SPEED_MEDIUM; + curconf.af = func_set; + curconf.monitor = monitor; + if(!is_func_allowed(port, pin, &curconf)) return ERR_BADVAL; + *pcfg = curconf; + return ERR_OK; +} + +// PAx [= aa], PBx [= bb] +static errcodes_t parse_pin_command(const char *cmd, char *args){ + if(!args) return ERR_BADPAR; // or maybe add list for all pins? + char port_char = cmd[1]; + if(port_char != 'A' && port_char != 'B') return ERR_BADCMD; + uint8_t port = (port_char == 'A') ? 0 : 1; + int32_t pin = -1; + char *setter = splitargs(args, &pin); + if(pin < 0 || pin > 15) return ERR_BADPAR; + pinconfig_t *pcfg = &the_conf.pinconfig[port][pin]; // just to check if pin can be configured + if(!pcfg->enable) return ERR_CANTRUN; // prohibited pin + if(!setter){ // simple getter -> get value and return ERR_AMOUNT as silence + SEND(cmd); SEND(u2str((uint32_t)pin)); SEND(EQ); + pin_getter(port, pin); + return ERR_AMOUNT; + } + return pin_setter(port, pin, setter); +} + +static errcodes_t cmd_PA(const char *cmd, char *args){ + return parse_pin_command(cmd, args); +} +static errcodes_t cmd_PB(const char *cmd, char *args){ + return parse_pin_command(cmd, args); +} + +static errcodes_t cmd_reinit(const char _U_ *cmd, char _U_ *args){ + if(gpio_reinit()) return ERR_OK; + SEND("Can't reinit: check your configuration!\n"); + return ERR_AMOUNT; +} + +static errcodes_t cmd_storeconf(const char _U_ *cmd, char _U_ *args){ + if(!store_userconf()) return ERR_CANTRUN; + return ERR_OK; +} + +// canspeed = baudrate (kBaud) static errcodes_t cmd_canspeed(const char *cmd, char _U_ *args){ SEND(cmd); PUTCHAR('='); SENDn(u2str(CAN_getspeed())); if(args && *args){SEND("You entered: "); SENDn(args);} @@ -97,15 +327,6 @@ constexpr uint32_t hash(const char* str, uint32_t h = 0){ return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h; } -static const char* errtxt[ERR_AMOUNT] = { - [ERR_OK] = "OK", - [ERR_BADPAR] = "BADPAR", - [ERR_BADVAL] = "BADVAL", - [ERR_WRONGLEN] = "WRONGLEN", - [ERR_CANTRUN] = "CANTRUN", -}; - - // TODO: add checking real command length! void chk(char *str){ @@ -127,25 +348,3 @@ void chk(char *str){ if(ecode < ERR_AMOUNT) SENDn(errtxt[ecode]); ; } - - -/* -if(*args){ - const char *n = getnum(args, &N); - if(n != args){ // get parameter - if(N >= CANMESG_NOPAR){ - USB_sendstr(errtxt[ERR_BADPAR]); newline(); - return RET_GOOD; - } - par = (uint8_t) N; - } - n = strchr(n, '='); - if(n){ - ++n; - const char *nxt = getint(n, &val); - if(nxt != n){ // set setter flag - par |= SETTERFLAG; - } - } -} -*/ diff --git a/F0:F030,F042,F072/usbcan_gpio/hashparser.h b/F0:F030,F042,F072/usbcan_gpio/hashparser.h index fcad2fd..b2f2cd0 100644 --- a/F0:F030,F042,F072/usbcan_gpio/hashparser.h +++ b/F0:F030,F042,F072/usbcan_gpio/hashparser.h @@ -21,6 +21,7 @@ // error codes for answer message typedef enum{ ERR_OK, // all OK + ERR_BADCMD, // wrong command ERR_BADPAR, // wrong parameter ERR_BADVAL, // wrong value (for setter) ERR_WRONGLEN, // wrong message length @@ -29,6 +30,8 @@ typedef enum{ } errcodes_t; // maximal length of command (without trailing zero) -#define CMD_MAXLEN (15) +#define CMD_MAXLEN 15 +// maximal available parameter number +#define MAXPARNO 255 void chk(char *str); diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin index 4277f73de25393844078646a8944e085288b00c3..ae2788162054d34ff2bc3874bfd6972d11837b7e 100755 GIT binary patch literal 17892 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∈^Cq@g&6kS>1t<(Kne*d*7G@KJd@ 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 diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user index a198073..fa6f043 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user +++ b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files index 1dbb0d4..105b97b 100644 --- a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files +++ b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.files @@ -4,6 +4,8 @@ canproto.c canproto.h flash.c flash.h +gpio.c +gpio.h gpioproto.c gpioproto.h hardware.c diff --git a/F0:F030,F042,F072/usbcan_gpio/version.inc b/F0:F030,F042,F072/usbcan_gpio/version.inc index f7ff2a9..323e780 100644 --- a/F0:F030,F042,F072/usbcan_gpio/version.inc +++ b/F0:F030,F042,F072/usbcan_gpio/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "94" -#define BUILD_DATE "2026-03-08" +#define BUILD_NUMBER "105" +#define BUILD_DATE "2026-03-09"