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 4277f73..ae27881 100755 Binary files a/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin and b/F0:F030,F042,F072/usbcan_gpio/usbcangpio.bin differ 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"