From e17058b2de9604e9e13716fa273a69bbfc87ced2 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Wed, 11 Feb 2026 23:34:14 +0300 Subject: [PATCH] all descriptors read - OK, interfaces work - bad (only first two works - why? need to debug) --- F3:F303/InterfaceBoard/Readme.md | 96 +++++- F3:F303/InterfaceBoard/flash.c | 31 +- F3:F303/InterfaceBoard/flash.h | 3 +- F3:F303/InterfaceBoard/hardware.c | 27 +- F3:F303/InterfaceBoard/hardware.h | 23 ++ F3:F303/InterfaceBoard/main.c | 21 +- F3:F303/InterfaceBoard/multiiface.bin | Bin 10612 -> 13152 bytes .../InterfaceBoard/multiiface.creator.user | 2 +- F3:F303/InterfaceBoard/proto.c | 44 ++- F3:F303/InterfaceBoard/proto.h | 18 ++ F3:F303/InterfaceBoard/usb_descr.c | 204 ++++++++----- F3:F303/InterfaceBoard/usb_descr.h | 36 ++- F3:F303/InterfaceBoard/usb_dev.c | 278 +++++++++++------- F3:F303/InterfaceBoard/usb_dev.h | 36 ++- F3:F303/InterfaceBoard/usb_lib.c | 1 + F3:F303/InterfaceBoard/version.inc | 4 +- 16 files changed, 565 insertions(+), 259 deletions(-) diff --git a/F3:F303/InterfaceBoard/Readme.md b/F3:F303/InterfaceBoard/Readme.md index 49c6019..324814a 100644 --- a/F3:F303/InterfaceBoard/Readme.md +++ b/F3:F303/InterfaceBoard/Readme.md @@ -1,15 +1,95 @@ -7 interfaces over USB -====================== +Multiport board +==================================== + +Seven isolated interfaces: - 1 CAN - 3 RS-485 - 2 or 1 RS-232 -- 1 SSI or 1 RS-422 (in this case 1 RS-232) +- 1 SSI or 1 RS-422 (in this case only one RS-232) Inner USB interfaces (IFx): -1..3 - RS-485 (1..3) -4 - RS-232 (1) -5 - RS-232 (2) or RS-485 -6 - CAN -7 - SSI (over SPI) or configuration interface (if "Config mode" jumper shortened) + +1. RS-485 (1) +2. RS-485 (2) +3. RS-485 (3) +4. RS-232 (1) +5. RS-232 (2) or RS-422 (by jumpers) +6. CAN +7. SSI (over SPI, by jumpers) or configuration interface (if "Config mode" jumper opened) + +# Pinout + +### Sorted by pin number + +| Pin # | Pin name | function | settings | comment | +|---------|-------------|-------------|---------------|---------------------| +| 1 | (VBAT) | | | | +| 2 | PC13 | NC | | | +| 3 | PC14 | NC | | | +| 4 | PC15 | NC | | | +| 5 | (OSC IN) | | | | +| 6 | (OSC OUT) | | | | +| 7 | (NRST) | | | | +| 8 | PC0 | NC | | | +| 9 | PC1 | NC | | | +| 10 | PC2 | NC | | | +| 11 | PC3 | NC | | | +| 12 | (VREF-) | | | | +| 13 | (VREF+) | | | | +| 14 | PA0 | NC | | | +| 15 | PA1 | USART2 DE | AF7 | RS-485 (3) DE | +| 16 | PA2 | USART2 TX | AF7 | RS-485 (3) Tx | +| 17 | PA3 | USART2 RX | AF7 | RS-485 (3) Rx | +| 18 | PF4 | NC | | | +| 19 | (VDD) | | | | +| 20 | PA4 | NC | | | +| 21 | PA5 | SPI1 SCK | AF5 | SSI CLK | +| 22 | PA6 | SPI1 MISO | AF5 | SSI DAT | +| 23 | PA7 | NC | | | +| 24 | PC4 | USART1 TX | AF7 | RS-485 (2) Tx | +| 25 | PC5 | USART1 RX | AF7 | RS-485 (2) Rx | +| 26 | PB0 | (USART1 DE) | PP OUT | RS-485 (2) DE | +| 27 | PB1 | NC | | | +| 28 | PB2 | NC | | | +| 29 | PB10 | USART3 TX | AF7 | RS-485 (1) Tx | +| 30 | PB11 | USART3 RX | AF7 | RS-485 (1) Rx | +| 31 | (VSS) | | | | +| 32 | (VDD) | | | | +| 33 | PB12 | NC | | | +| 34 | PB13 | NC | | | +| 35 | PB14 | USART3 DE | AF7 | RS-485 (1) DE | +| 36 | PB15 | | | | +| 37 | PC6 | NC | | | +| 38 | PC7 | NC | | | +| 39 | PC8 | NC | | | +| 40 | PC9 | NC | | | +| 41 | PA8 | NC | | | +| 42 | PA9 | (CONF EN) | PU IN | Config jumper | +| 43 | PA10 | (USB PU) | PP OUT | USB pullup | +| 44 | PA11 | USB DM | AF14 | | +| 45 | PA12 | USB DP | AF14 | | +| 46 | PA13 | SWDIO | AF0 | | +| 47 | (VSS) | | | | +| 48 | (VDD) | | | | +| 49 | PA14 | SWCLK | AF0 | | +| 50 | PA15 | NC | | | +| 51 | PC10 | UART4 TX | AF5 | RS-232 (1) Tx | +| 52 | PC11 | UART4 RX | AF5 | RS-232 (1) Rx | +| 53 | PC12 | UART5 TX | AF5 | RS-232(2) / 485 Tx | +| 54 | PD2 | UART5 RX | AF5 | RS-232(2) / 485 Rx | +| 55 | PB3 | NC | | | +| 56 | PB4 | NC | | | +| 57 | PB5 | NC | | | +| 58 | PB6 | NC | | | +| 59 | PB7 | NC | | | +| 60 | (BOOT0) | | | | +| 61 | PB8 | CAN RX | AF9 | | +| 62 | PB9 | CAN TX | AF9 | | +| 63 | (VSS) | | | | +| 64 | (VDD) | | | | + +### Some comments. + +### Sorted by ports (with AF numbers). diff --git a/F3:F303/InterfaceBoard/flash.c b/F3:F303/InterfaceBoard/flash.c index 3088d3b..496eaf2 100644 --- a/F3:F303/InterfaceBoard/flash.c +++ b/F3:F303/InterfaceBoard/flash.c @@ -32,15 +32,15 @@ const user_conf *Flash_Data = (const user_conf *)(&__varsstart); user_conf the_conf = { .userconf_sz = sizeof(user_conf), .iInterface = { - [ISerial0] = u"usbserial0", - [ISerial1] = u"usbserial1", - [ISerial2] = u"usbserial2", - [ISerial3] = u"usbserial3", - [ISerial4] = u"usbserial4", + [ISerial0] = u"usbserial0.", + [ISerial1] = u"usbserial1.", + [ISerial2] = u"usbserial2.", + [ISerial3] = u"usbserial3.", + [ISerial4] = u"usbserial4.", [ISPI] = u"usbSPI", [ICAN] = u"usbCAN" }, - .iIlengths = {20,20,20,20,20,12,12}, + .iIlengths = {22,22,22,22,22,12,12}, }; int currentconfidx = -1; // index of current configuration @@ -117,12 +117,12 @@ static int write2flash(const void *start, const void *wrdata, uint32_t stor_size *(volatile uint16_t*)(address + i) = data[i]; while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; if(*(volatile uint16_t*)(address + i) != data[i]){ - USB_sendstr("DON'T MATCH!\n"); + CFGWR("DON'T MATCH!\n"); ret = 1; break; } if(FLASH->SR & FLASH_SR_PGERR){ - USB_sendstr("Prog err\n"); + CFGWR("Prog err\n"); ret = 1; // program error - meet not 0xffff break; } @@ -136,7 +136,7 @@ static int write2flash(const void *start, const void *wrdata, uint32_t stor_size static int erase_pageN(int N){ int ret = 0; #ifdef EBUG - //CMDWR("Erase page #"); CMDWR(u2str(N)); CMDn(); + CFGWR("Erase page #"); CFGWRn(u2str(N)); #endif FLASH->AR = (uint32_t)Flash_Data + N*FLASH_blocksize; FLASH->CR |= FLASH_CR_STRT; @@ -158,16 +158,13 @@ int erase_storage(int npage){ flsz -= (uint32_t)Flash_Data - FLASH_BASE; } end = flsz / FLASH_blocksize; -/* #ifdef EBUG - CMDWR("FLASH_SIZE="); CMDWR(u2str(FLASH_SIZE)); - CMDWR("\nflsz="); CMDWR(u2str(flsz)); - CMDWR("\nend="); CMDWR(u2str(end)); - CMDWR("\ncurrentconfidx="); CMDWR(u2str(currentconfidx)); - CMDWR("\nmaxCnum="); CMDWR(u2str(maxCnum)); - CMDn(); + CFGWR("FLASH_SIZE="); CFGWR(u2str(FLASH_SIZE)); + CFGWR("\nflsz="); CFGWR(u2str(flsz)); + CFGWR("\nend="); CFGWR(u2str(end)); + CFGWR("\ncurrentconfidx="); CFGWR(u2str(currentconfidx)); + CFGWR("\nmaxCnum="); CFGWRn(u2str(maxCnum)); #endif -*/ if(end == 0 || end >= FLASH_SIZE) return 1; if(npage > -1){ // erase only one page if((uint32_t)npage >= end) return 1; diff --git a/F3:F303/InterfaceBoard/flash.h b/F3:F303/InterfaceBoard/flash.h index 4f3f564..e8ff614 100644 --- a/F3:F303/InterfaceBoard/flash.h +++ b/F3:F303/InterfaceBoard/flash.h @@ -34,8 +34,9 @@ */ typedef struct __attribute__((packed, aligned(4))){ uint16_t userconf_sz; // "magick number" + // we store iInterface "as is" uint16_t iInterface[InterfacesAmount][MAX_IINTERFACE_SZ]; // hryunikod! - uint8_t iIlengths[InterfacesAmount]; + uint8_t iIlengths[InterfacesAmount]; } user_conf; extern user_conf the_conf; diff --git a/F3:F303/InterfaceBoard/hardware.c b/F3:F303/InterfaceBoard/hardware.c index d3c8237..c3634a9 100644 --- a/F3:F303/InterfaceBoard/hardware.c +++ b/F3:F303/InterfaceBoard/hardware.c @@ -1,11 +1,36 @@ +/* + * This file is part of the multiiface 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 "hardware.h" +uint8_t Config_mode = 0; + static inline void gpio_setup(){ RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs for(int i = 0; i < 10000; ++i) nop(); // USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14 GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12); - GPIOA->MODER = MODER_O(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14); + // PA9 - config jumper (PU in), PA10 - USB pullup (PP) + GPIOA->MODER = MODER_I(9) | MODER_O(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14); + GPIOA->OSPEEDR = OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14); + GPIOA->PUPDR = PUPD_PU(9); + for(int i = 0; i < 10000; ++i) nop(); + if(CFG_ON()) Config_mode = 1; } void hw_setup(){ diff --git a/F3:F303/InterfaceBoard/hardware.h b/F3:F303/InterfaceBoard/hardware.h index 457c6fc..8dd6707 100644 --- a/F3:F303/InterfaceBoard/hardware.h +++ b/F3:F303/InterfaceBoard/hardware.h @@ -1,3 +1,21 @@ +/* + * This file is part of the multiiface 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 @@ -7,7 +25,12 @@ #define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) #define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) +#define CFG_port GPIOA +#define CFG_pin (1<<9) +#define CFG_ON() (CFG_port->IDR & CFG_pin) + extern volatile uint32_t Tms; +extern uint8_t Config_mode; void hw_setup(); diff --git a/F3:F303/InterfaceBoard/main.c b/F3:F303/InterfaceBoard/main.c index af65cd3..5810040 100644 --- a/F3:F303/InterfaceBoard/main.c +++ b/F3:F303/InterfaceBoard/main.c @@ -43,15 +43,20 @@ int main(void){ //uint32_t ctr = Tms; USBPU_ON(); while(1){ - /*if(Tms - ctr > 499){ - ctr = Tms; - }*/ + // Put here code working WITOUT USB connected if(!usbON) continue; - int l = USB_receivestr(inbuff, MAXSTRLEN); - if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n"); - else if(l){ - const char *ans = parse_cmd(inbuff); - if(ans) USB_sendstr(ans); + for(int i = 0; i < 6; ++i){ // just echo for first time + int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN); + if(l) USB_send(i, (uint8_t*)inbuff, l); + } + // and here is code what should run when USB connected + if(Config_mode){ + int l = USB_receivestr(ICFG, inbuff, MAXSTRLEN); + if(l < 0) CFGWR("ERROR: USB buffer overflow or string was too long\n"); + else if(l){ + const char *ans = parse_cmd(inbuff); + if(ans) CFGWR(ans); + } } } } diff --git a/F3:F303/InterfaceBoard/multiiface.bin b/F3:F303/InterfaceBoard/multiiface.bin index aac465af69f907bc98bd4c81f89eeeea3febd646..80ef1e43ed625235c1451c5b223bc7709d82efd1 100755 GIT binary patch delta 6838 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 Ryc>q|=zsd*-Jl!H`)~0-5BvZC delta 4288 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 - + EnvironmentId diff --git a/F3:F303/InterfaceBoard/proto.c b/F3:F303/InterfaceBoard/proto.c index e2c6438..660eb49 100644 --- a/F3:F303/InterfaceBoard/proto.c +++ b/F3:F303/InterfaceBoard/proto.c @@ -1,3 +1,21 @@ +/* + * This file is part of the multiiface 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 @@ -6,6 +24,8 @@ #include "usb_dev.h" #include "version.inc" +// all functions of this file could be run only in configuration mode + static const char *const sOKn = "OK\n", *const sERRn = "ERR\n"; //#define LOCBUFFSZ (32) @@ -25,19 +45,18 @@ const char *helpstring = ; static void dumpflash(){ - USB_sendstr("userconf_sz="); USB_sendstr(u2str(the_conf.userconf_sz)); - USB_sendstr("\ncurrentconfidx="); USB_sendstr(i2str(currentconfidx)); - USB_putbyte('\n'); + CFGWR("userconf_sz="); CFGWR(u2str(the_conf.userconf_sz)); + CFGWR("\ncurrentconfidx="); CFGWRn(i2str(currentconfidx)); for(int i = 0; i < InterfacesAmount; ++i){ - USB_sendstr("interface"); USB_putbyte('0' + i); - USB_putbyte('='); + CFGWR("interface"); USB_putbyte(ICFG, '0' + i); + USB_putbyte(ICFG, '='); int l = the_conf.iIlengths[i] / 2; char *ptr = (char*) the_conf.iInterface[i]; for(int j = 0; j < l; ++j){ - USB_putbyte(*ptr); + USB_putbyte(ICFG, *ptr); ptr += 2; } - USB_putbyte('\n'); + CFGn(); } } @@ -58,10 +77,10 @@ static void setiface(const char *str){ *ptr++ = *nxt++; *ptr++ = 0; } - USB_sendstr(sOKn); + CFGWR(sOKn); return; err: - USB_sendstr(sERRn); + CFGWR(sERRn); } static const char* erpg(const char *str){ @@ -106,12 +125,11 @@ const char *parse_cmd(const char *buf){ if(store_userconf()) return sERRn; return sOKn; case 'T': - USB_sendstr("T="); - USB_sendstr(u2str(Tms)); - newline(); + CFGWR("T="); + CFGWRn(u2str(Tms)); break; default: // help - USB_sendstr(helpstring); + CFGWR(helpstring); break; } return NULL; diff --git a/F3:F303/InterfaceBoard/proto.h b/F3:F303/InterfaceBoard/proto.h index 5c6c029..7306aba 100644 --- a/F3:F303/InterfaceBoard/proto.h +++ b/F3:F303/InterfaceBoard/proto.h @@ -1,3 +1,21 @@ +/* + * This file is part of the multiiface 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 char *parse_cmd(char *buf); diff --git a/F3:F303/InterfaceBoard/usb_descr.c b/F3:F303/InterfaceBoard/usb_descr.c index 3e1a872..36ec5b8 100644 --- a/F3:F303/InterfaceBoard/usb_descr.c +++ b/F3:F303/InterfaceBoard/usb_descr.c @@ -15,6 +15,9 @@ * along with this program. If not, see . */ +#include // memcpy +#include "flash.h" // descriptors +#include "hardware.h" // `config` flag #include "usb_descr.h" // low/high for uint16_t @@ -55,7 +58,88 @@ static const uint8_t USB_DeviceQualifierDescriptor[] = { 0 // Reserved }; -#define wTotalLength (USB_DT_CONFIG_SIZE + (bNumInterfaces * USB_DT_INTERFACE_SIZE) + (bTotNumEndpoints * USB_DT_ENDPOINT_SIZE) + (bNumCsInterfaces * USB_DT_CS_INTERFACE_SIZE) - 1) +#define wTotalLength (USB_DT_CONFIG_SIZE + (bTotNumEndpoints * 66)) + +/* + * _1stI - number of first interface + * IDidx - 0 or index of string descriptor for given interface + * EPx - number of virtual interrupt EP + * EP - number of real EP in/out + */ +#define USB_IAD(_1stI, IDidx, EPx, EP) \ + USB_DT_IAD_SIZE, /* bLength: IAD size */ \ + USB_DT_IAD, /* bDescriptorType: IAD */ \ + _1stI, /* bFirstInterface */ \ + 2, /* bInterfaceCount */ \ + 2, /* bFunctionClass: CDC */ \ + 2, /* bFunctionSubClass */ \ + 0, /* bFunctionProtocol */ \ + 0, /* iFunction */ \ + /* Interface Descriptor */ \ + USB_DT_INTERFACE_SIZE, /* bLength: Interface Descriptor size */ \ + USB_DT_INTERFACE, /* bDescriptorType: Interface */ \ + _1stI, /* bInterfaceNumber: Number of Interface */ \ + 0, /* bAlternateSetting: Alternate setting */ \ + 1, /* bNumEndpoints: one for this */ \ + USB_CLASS_COMM, /* bInterfaceClass */ \ + 2, /* bInterfaceSubClass: ACM */ \ + 0, /* bInterfaceProtocol */ \ + IDidx, /* iInterface */ \ + /* CDC descriptor */ \ + USB_DT_CS_INTERFACE_SIZE, /* bLength */ \ + USB_DT_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */ \ + 0, /* bDescriptorSubtype: Header Func Desc */ \ + 0x10, /* bcdCDC: spec release number */ \ + 1, /* bDataInterface */ \ + USB_DT_CS_INTERFACE_SIZE, /* bLength */ \ + USB_DT_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */ \ + 1, /* bDescriptorSubtype: Call Management Func Desc */ \ + 0, /* bmCapabilities: D0+D1 */ \ + (_1stI+1), /* bDataInterface */ \ + USB_DT_CS_INTERFACE_SIZE-1, /* bLength */ \ + USB_DT_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */ \ + 2, /* bDescriptorSubtype: Abstract Control Management desc */ \ + 2, /* bmCapabilities */ \ + USB_DT_CS_INTERFACE_SIZE, /* bLength */ \ + USB_DT_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */ \ + 6, /* bDescriptorSubtype: Union func desc */ \ + _1stI, /* bMasterInterface: Communication class interface */ \ + (_1stI+1), /* bSlaveInterface0: Data Class Interface */ \ + /* Virtual endpoint 1 Descriptor */ \ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ \ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ \ + (0x80+EPx), /* bEndpointAddress IN8 - non-existant */ \ + USB_BM_ATTR_INTERRUPT, /* bmAttributes: Interrupt */ \ + L16(USB_EP1BUFSZ), /* wMaxPacketSize LO */ \ + H16(USB_EP1BUFSZ), /* wMaxPacketSize HI */ \ + 0x10, /* bInterval: 16ms */ \ + /* DATA endpoint */ \ + USB_DT_INTERFACE_SIZE, /* bLength: Interface Descriptor size */ \ + USB_DT_INTERFACE, /* bDescriptorType: Interface */ \ + (_1stI+1), /* bInterfaceNumber: Number of Interface */ \ + 0, /* bAlternateSetting: Alternate setting */ \ + 2, /* bNumEndpoints: in and out */ \ + USB_CLASS_DATA, /* bInterfaceClass */ \ + 2, /* bInterfaceSubClass: ACM */ \ + 0, /* bInterfaceProtocol */ \ + 0, /* iInterface */ \ + /*Endpoint IN1 Descriptor */ \ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ \ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ \ + (0x80+EP), /* bEndpointAddress: IN1 */ \ + USB_BM_ATTR_BULK, /* bmAttributes: Bulk */ \ + L16(USB_TXBUFSZ), /* wMaxPacketSize LO */ \ + H16(USB_TXBUFSZ), /* wMaxPacketSize HI */ \ + 0, /* bInterval: ignore for Bulk transfer */ \ + /* Endpoint OUT1 Descriptor */ \ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ \ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ \ + EP, /* bEndpointAddress: OUT1 */ \ + USB_BM_ATTR_BULK, /* bmAttributes: Bulk */ \ + L16(USB_RXBUFSZ), /* wMaxPacketSize LO */ \ + H16(USB_RXBUFSZ), /* wMaxPacketSize HI */ \ + 0 /* bInterval: ignore for Bulk transfer */ + static const uint8_t USB_ConfigDescriptor[] = { // Configuration Descriptor @@ -68,89 +152,52 @@ static const uint8_t USB_ConfigDescriptor[] = { 0, // iConfiguration: Index of string descriptor describing the configuration or 0 BusPowered, // bmAttributes - Bus powered 50, // MaxPower in 2mA units - //--------------------------------------------------------------------------- - // Virtual command Interface Descriptor - USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size - USB_DT_INTERFACE, // bDescriptorType: Interface - 0, // bInterfaceNumber: Number of Interface - 0, // bAlternateSetting: Alternate setting - 1, // bNumEndpoints: one for this - USB_CLASS_COMM, // bInterfaceClass - 2, // bInterfaceSubClass: ACM - 1, // bInterfaceProtocol: Common AT commands - iINTERFACE_DESCR1, // iInterface - // ---- CS Interfaces - USB_DT_CS_INTERFACE_SIZE, // bLength - USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE - 0, // bDescriptorSubtype: Header Func Desc - 0x10, // bcdCDC: spec release number - 1, // bDataInterface - USB_DT_CS_INTERFACE_SIZE, // bLength - USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE - 1, // bDescriptorSubtype: Call Management Func Desc - 0, // bmCapabilities: D0+D1 - 1, // bDataInterface - USB_DT_CS_INTERFACE_SIZE-1, // bLength - USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE - 2, // bDescriptorSubtype: Abstract Control Management desc - 2, // bmCapabilities - USB_DT_CS_INTERFACE_SIZE, // bLength - USB_DT_CS_INTERFACE, // bDescriptorType: CS_INTERFACE - 6, // bDescriptorSubtype: Union func desc - 0, // bMasterInterface: Communication class interface - 1, // bSlaveInterface0: Data Class Interface - // Virtual endpoint 1 Descriptor - USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size - USB_DT_ENDPOINT, // bDescriptorType: Endpoint - 0x8A, // bEndpointAddress IN10 - USB_BM_ATTR_INTERRUPT, // bmAttributes: Interrupt - L16(USB_EP1BUFSZ), // wMaxPacketSize LO - H16(USB_EP1BUFSZ), // wMaxPacketSize HI - 0x10, // bInterval: 16ms - //--------------------------------------------------------------------------- - // Data interface - USB_DT_INTERFACE_SIZE, // bLength: Interface Descriptor size - USB_DT_INTERFACE, // bDescriptorType: Interface - 1, // bInterfaceNumber: Number of Interface - 0, // bAlternateSetting: Alternate setting - 2, // bNumEndpoints: in and out - USB_CLASS_DATA, // bInterfaceClass - 2, // bInterfaceSubClass: ACM - 0, // bInterfaceProtocol - 0, // iInterface - //Endpoint IN1 Descriptor - USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size - USB_DT_ENDPOINT, // bDescriptorType: Endpoint - 0x81, // bEndpointAddress: IN1 - USB_BM_ATTR_BULK, // bmAttributes: Bulk - L16(USB_TXBUFSZ), // wMaxPacketSize LO - H16(USB_TXBUFSZ), // wMaxPacketSize HI - 0, // bInterval: ignore for Bulk transfer - // Endpoint OUT1 Descriptor - USB_DT_ENDPOINT_SIZE, // bLength: Endpoint Descriptor size - USB_DT_ENDPOINT, // bDescriptorType: Endpoint - 0x01, // bEndpointAddress: OUT1 - USB_BM_ATTR_BULK, // bmAttributes: Bulk - L16(USB_RXBUFSZ), // wMaxPacketSize LO - H16(USB_RXBUFSZ), // wMaxPacketSize HI - 0, // bInterval: ignore for Bulk transfer - + //--IADs------------------------------------------------------------------------- + USB_IAD(0, iINTERFACE_DESCR1, 8, 1), + USB_IAD(2, iINTERFACE_DESCR2, 9, 2), + USB_IAD(4, iINTERFACE_DESCR3, 10, 3), + USB_IAD(6, iINTERFACE_DESCR4, 11, 4), + USB_IAD(8, iINTERFACE_DESCR5, 12, 5), + USB_IAD(10, iINTERFACE_DESCR6, 13, 6), + USB_IAD(12, iINTERFACE_DESCR7, 14, 7), }; -//const uint8_t HID_ReportDescriptor[]; _USB_LANG_ID_(LD, LANG_US); _USB_STRING_(SD, u"0.0.1"); _USB_STRING_(MD, u"eddy@sao.ru"); _USB_STRING_(PD, u"USB-CDC"); -_USB_STRING_(ID, u"usbcdc"); + +// iInterface will change on initialisation by config +#define _USB_IIDESCR_(str) {sizeof(str), 0x03, str} +typedef struct{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bString[MAX_IINTERFACE_SZ]; +}iidescr_t; +static iidescr_t iids[InterfacesAmount] = { + _USB_IIDESCR_(u"iface0"), + _USB_IIDESCR_(u"iface1"), + _USB_IIDESCR_(u"iface2"), + _USB_IIDESCR_(u"iface3"), + _USB_IIDESCR_(u"iface4"), + _USB_IIDESCR_(u"iface5"), + _USB_IIDESCR_(u"iface6"), +}; + static const void* const StringDescriptor[iDESCR_AMOUNT] = { [iLANGUAGE_DESCR] = &LD, [iMANUFACTURER_DESCR] = &MD, [iPRODUCT_DESCR] = &PD, [iSERIAL_DESCR] = &SD, - [iINTERFACE_DESCR1] = &ID + [iINTERFACE_DESCR1] = &iids[0], + [iINTERFACE_DESCR2] = &iids[1], + [iINTERFACE_DESCR3] = &iids[2], + [iINTERFACE_DESCR4] = &iids[3], + [iINTERFACE_DESCR5] = &iids[4], + [iINTERFACE_DESCR6] = &iids[5], + [iINTERFACE_DESCR7] = &iids[6], }; static void wr0(const uint8_t *buf, uint16_t size, uint16_t askedsize){ @@ -208,3 +255,18 @@ void get_descriptor(config_pack_t *pack){ break; } } +// change values of iInterface by content of global config +void setup_interfaces(){ + for(int i = 0; i < InterfacesAmount; ++i){ + if(the_conf.iIlengths[i]){ + iids[i].bLength = the_conf.iIlengths[i] + 2; // +2 - for bLength and bDescriptorType + memcpy(iids[i].bString, the_conf.iInterface[i], the_conf.iIlengths[i]); + } + iids[i].bDescriptorType = 0x03; + } + if(Config_mode){ + // configuration interface identificator is hardware fixed + memcpy(iids[ICFG].bString, u"multiportCFG", 24); + iids[ICFG].bLength = 48; + } +} diff --git a/F3:F303/InterfaceBoard/usb_descr.h b/F3:F303/InterfaceBoard/usb_descr.h index 39eeb76..2390859 100644 --- a/F3:F303/InterfaceBoard/usb_descr.h +++ b/F3:F303/InterfaceBoard/usb_descr.h @@ -31,21 +31,24 @@ #define bcdDevice_Ver 0x0200 #define bNumConfigurations 1 -// amount of interfaces and endpoints (except 0) used -#define bNumInterfaces 2 -#define bTotNumEndpoints 3 -#define bNumCsInterfaces 4 - // amount of interfaces #define InterfacesAmount 7 +// index of interface (ep number minus one) #define ISerial0 0 -#define ICFG 0 #define ISerial1 1 #define ISerial2 2 #define ISerial3 3 #define ISerial4 4 -#define ISPI 5 -#define ICAN 6 +#define ICAN 5 +#define ISPI 6 +#define ICFG 6 +// EP number of interface +#define EPNO(i) (i + 1) + +// amount of interfaces (including virtual) except 0 +#define bNumInterfaces (2*InterfacesAmount) +// amount of endpoints used +#define bTotNumEndpoints (1+InterfacesAmount) // powered #define BusPowered (1<<7) @@ -55,10 +58,14 @@ // buffer sizes // for USB FS EP0 buffers are from 8 to 64 bytes long #define USB_EP0BUFSZ 64 +// virtual #define USB_EP1BUFSZ 10 -// Rx/Tx EPs -#define USB_RXBUFSZ 64 -#define USB_TXBUFSZ 64 +// Rx/Tx EPs (USB_BTABLE_SIZE-64-2*USB_EP0BUFSZ)/(2*InterfacesAmount) rounded to 8 +// 534 / 112 -> 4 +#define _RTBUFSZ8 (((USB_BTABLE_SIZE) - 64 - (2 * (USB_EP0BUFSZ)))/(16 * (InterfacesAmount))) +// 32 bytes; so we have free 86 bytes which can't be used +#define USB_RXBUFSZ (8 * (_RTBUFSZ8)) +#define USB_TXBUFSZ (8 * (_RTBUFSZ8)) // string descriptors enum{ @@ -67,7 +74,14 @@ enum{ iPRODUCT_DESCR, iSERIAL_DESCR, iINTERFACE_DESCR1, + iINTERFACE_DESCR2, + iINTERFACE_DESCR3, + iINTERFACE_DESCR4, + iINTERFACE_DESCR5, + iINTERFACE_DESCR6, + iINTERFACE_DESCR7, iDESCR_AMOUNT }; void get_descriptor(config_pack_t *pack); +void setup_interfaces(); diff --git a/F3:F303/InterfaceBoard/usb_dev.c b/F3:F303/InterfaceBoard/usb_dev.c index 8d61eee..81fa994 100644 --- a/F3:F303/InterfaceBoard/usb_dev.c +++ b/F3:F303/InterfaceBoard/usb_dev.c @@ -17,6 +17,7 @@ #include +#include "hardware.h" #include "ringbuffer.h" #include "usb_descr.h" #include "usb_dev.h" @@ -37,170 +38,226 @@ #define CONTROL_RTS 0x02 // inbuf overflow when receiving -static volatile uint8_t bufovrfl = 0; +static volatile uint8_t bufovrfl[InterfacesAmount] = {0}; // receive buffer: hold data until chkin() call -static uint8_t volatile rcvbuf[USB_RXBUFSZ]; -static uint8_t volatile rcvbuflen = 0; +static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ]; +static uint8_t volatile rcvbuflen[InterfacesAmount] = {0}; // line coding -usb_LineCoding WEAK lineCoding = {115200, 0, 0, 8}; +#define DEFL {115200, 0, 0, 8} +usb_LineCoding lineCoding[InterfacesAmount] = {DEFL,DEFL,DEFL,DEFL,DEFL,DEFL,DEFL}; // CDC configured and ready to use -volatile uint8_t CDCready = 0; +volatile uint8_t CDCready[InterfacesAmount] = {0}; // ring buffers for incoming and outgoing data -static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ]; -static volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; -static volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; -// last send data size -static volatile int lastdsz = 0; +static uint8_t obuf[InterfacesAmount][RBOUTSZ], ibuf[InterfacesAmount][RBINSZ]; +#define OBUF(N) {.data = obuf[N], .length = RBOUTSZ, .head = 0, .tail = 0} +static volatile ringbuffer rbout[InterfacesAmount] = {OBUF(0), OBUF(1), OBUF(2), OBUF(3), OBUF(4), OBUF(5), OBUF(6)}; +#define IBUF(N) {.data = ibuf[N], .length = RBINSZ, .head = 0, .tail = 0} +static volatile ringbuffer rbin[InterfacesAmount] = {IBUF(0), IBUF(1), IBUF(2), IBUF(3), IBUF(4), IBUF(5), IBUF(6)}; +// last send data size (<0 if USB transfer ready) +static volatile int lastdsz[InterfacesAmount] = {-1, -1, -1, -1, -1, -1, -1}; -static void chkin(){ - if(bufovrfl) return; // allow user to know that previous buffer was overflowed and cleared - if(!rcvbuflen) return; - int w = RB_write((ringbuffer*)&rbin, (uint8_t*)rcvbuf, rcvbuflen); +static void chkin(uint8_t ifno){ + if(bufovrfl[ifno]) return; // allow user to know that previous buffer was overflowed and cleared + if(!rcvbuflen[ifno]) return; + int w = RB_write((ringbuffer*)&rbin[ifno], (uint8_t*)rcvbuf[ifno], rcvbuflen[ifno]); if(w < 0){ return; } - if(w != rcvbuflen) bufovrfl = 1; - rcvbuflen = 0; - uint16_t status = KEEP_DTOG(USB->EPnR[1]); // don't change DTOG - USB->EPnR[1] = (status & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // prepare to get next data portion + if(w != rcvbuflen[ifno]) bufovrfl[ifno] = 1; + rcvbuflen[ifno] = 0; + uint16_t status = KEEP_DTOG(USB->EPnR[1+ifno]); // don't change DTOG + USB->EPnR[1+ifno] = (status & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // prepare to get next data portion } // called from transmit EP to send next data portion or by user - when new transmission starts -static void send_next(){ +static void send_next(uint8_t ifno){ uint8_t usbbuff[USB_TXBUFSZ]; - int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); - if(buflen == 0){ - if(lastdsz == 64) EP_Write(1, NULL, 0); // send ZLP after 64 bits packet when nothing more to send - lastdsz = 0; - return; - }else if(buflen < 0){ - lastdsz = 0; + int buflen = RB_read((ringbuffer*)&rbout[ifno], (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!CDCready[ifno]){ + lastdsz[ifno] = -1; return; } - EP_Write(1, (uint8_t*)usbbuff, buflen); - lastdsz = buflen; + if(buflen == 0){ + if(lastdsz[ifno] == USB_TXBUFSZ){ + EP_Write(1+ifno, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz[ifno] = 0; + }else lastdsz[ifno] = -1; // OK. User can start sending data + return; + }else if(buflen < 0){ + lastdsz[ifno] = -1; + return; + } + EP_Write(1+ifno, (uint8_t*)usbbuff, buflen); + lastdsz[ifno] = buflen; } // data IN/OUT handler static void rxtx_handler(){ - uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + uint8_t ifno = (USB->ISTR & USB_ISTR_EPID) - 1; + if(ifno > InterfacesAmount-1){ + return; + } + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1+ifno]); if(RX_FLAG(epstatus)){ // receive data - if(rcvbuflen){ - bufovrfl = 1; // lost last data - rcvbuflen = 0; + if(rcvbuflen[ifno]){ + bufovrfl[ifno] = 1; // lost last data + rcvbuflen[ifno] = 0; } - rcvbuflen = EP_Read(1, (uint8_t*)rcvbuf); - USB->EPnR[1] = epstatus & ~(USB_EPnR_CTR_RX | USB_EPnR_STAT_RX | USB_EPnR_STAT_TX); // keep RX in STALL state until read data - chkin(); // try to write current data into RXbuf if it's not busy + rcvbuflen[ifno] = EP_Read(1+ifno, (uint8_t*)rcvbuf[ifno]); + USB->EPnR[1+ifno] = epstatus & ~(USB_EPnR_CTR_RX | USB_EPnR_STAT_RX | USB_EPnR_STAT_TX); // keep RX in STALL state until read data + chkin(ifno); // try to write current data into RXbuf if it's not busy }else{ // tx successfull - USB->EPnR[1] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; - send_next(); + USB->EPnR[1+ifno] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; + send_next(ifno); } } -// weak handlers: change them somewhere else if you want to setup USART // SET_LINE_CODING -void WEAK linecoding_handler(usb_LineCoding *lc){ - lineCoding = *lc; +void linecoding_handler(uint8_t ifno, usb_LineCoding *lc){ + lineCoding[ifno] = *lc; + // TODO: set up interfaces +} + +// clear IN/OUT buffers on connection +static void clearbufs(uint8_t ifno){ + uint32_t T0 = Tms; + while(Tms - T0 < 10){ // wait no more than 10ms + if(1 == RB_clearbuf((ringbuffer*)&rbin[ifno])) break; + } + T0 = Tms; + while(Tms - T0 < 10){ + if(1 == RB_clearbuf((ringbuffer*)&rbout[ifno])) break; + } } // SET_CONTROL_LINE_STATE -void WEAK clstate_handler(uint16_t val){ - CDCready = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected +void clstate_handler(uint8_t ifno, uint16_t val){ + CDCready[ifno] = val; // CONTROL_DTR | CONTROL_RTS -> interface connected; 0 -> disconnected + lastdsz[ifno] = -1; + if(val) clearbufs(ifno); } -// SEND_BREAK -void WEAK break_handler(){ - CDCready = 0; +// SEND_BREAK - disconnect interface and clear its buffers +// this is a fake handler as classic CDC ACM never receives this +void break_handler(uint8_t ifno){ + CDCready[ifno] = 0; } - // USB is configured: setup endpoints void set_configuration(){ - EP_Init(1, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_handler); // IN1 and OUT1 + for(int i = 0; i < InterfacesAmount; ++i){ + IWDG->KR = IWDG_REFRESH; + int r = EP_Init(1+i, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_handler); + if(r){ + // OOPS, can't init EP. What to do? Cry? + break; + } + } } -// PL2303 CLASS request +// USB CDC CLASS request void usb_class_request(config_pack_t *req, uint8_t *data, uint16_t datalen){ uint8_t recipient = REQUEST_RECIPIENT(req->bmRequestType); uint8_t dev2host = (req->bmRequestType & 0x80) ? 1 : 0; + uint8_t ifno = req->wIndex >> 1; + if(ifno > InterfacesAmount-1){ // wrong interface number + EP_WriteIRQ(0, NULL, 0); + return; + } switch(recipient){ - case REQ_RECIPIENT_INTERFACE: - switch(req->bRequest){ - case SET_LINE_CODING: - if(!data || !datalen) break; // wait for data - if(datalen == sizeof(usb_LineCoding)) - linecoding_handler((usb_LineCoding*)data); - break; - case GET_LINE_CODING: - EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding)); - break; - case SET_CONTROL_LINE_STATE: - clstate_handler(req->wValue); - break; - case SEND_BREAK: - break_handler(); - break; - default: - break; - } - break; + case REQ_RECIPIENT_INTERFACE: + switch(req->bRequest){ + case SET_LINE_CODING: + if(!data || !datalen) break; // wait for data + if(datalen == sizeof(usb_LineCoding)) + linecoding_handler(ifno, (usb_LineCoding*)data); + break; + case GET_LINE_CODING: + EP_WriteIRQ(0, (uint8_t*)&lineCoding[ifno], sizeof(lineCoding)); + break; + case SET_CONTROL_LINE_STATE: + clstate_handler(ifno, req->wValue); + break; + case SEND_BREAK: + break_handler(ifno); + break; default: - if(dev2host) EP_WriteIRQ(0, NULL, 0); + // WTF? + break; + } + break; + default: + // WTF? + if(dev2host) EP_WriteIRQ(0, NULL, 0); } if(!dev2host) EP_WriteIRQ(0, NULL, 0); } // blocking send full content of ring buffer -int USB_sendall(){ - while(lastdsz > 0){ - if(!CDCready) return FALSE; +int USB_sendall(uint8_t ifno){ + uint32_t T0 = Tms; + while(lastdsz[ifno] > 0){ + if(Tms - T0 > DISCONN_TMOUT){ + break_handler(ifno); + return FALSE; + } + if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; } return TRUE; } // put `buf` into queue to send -int USB_send(const uint8_t *buf, int len){ - if(!buf || !CDCready || !len) return FALSE; +int USB_send(uint8_t ifno, const uint8_t *buf, int len){ + if(!buf || !CDCready[ifno] || !len) return FALSE; + uint32_t T0 = Tms; while(len){ - IWDG->KR = IWDG_REFRESH; - int l = RB_datalen((ringbuffer*)&rbout); - if(l < 0) continue; - int portion = rbout.length - 1 - l; - if(portion < 1){ - if(lastdsz == 0) send_next(); - continue; + if(Tms - T0 > DISCONN_TMOUT){ + break_handler(ifno); + return FALSE; } - if(portion > len) portion = len; - int a = RB_write((ringbuffer*)&rbout, buf, portion); + if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; + int a = RB_write((ringbuffer*)&rbout[ifno], buf, len); if(a > 0){ len -= a; buf += a; - } else if (a < 0) continue; // do nothing if buffer is in reading state - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN + }else if(a == 0){ // overfull + if(lastdsz[ifno] < 0) send_next(ifno); + } } + if(buf[len-1] == '\n' && lastdsz[ifno] < 0) send_next(ifno); return TRUE; } -int USB_putbyte(uint8_t byte){ - if(!CDCready) return FALSE; +int USB_putbyte(uint8_t ifno, uint8_t byte){ + if(!CDCready[ifno]) return FALSE; int l = 0; - while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){ - if(l < 0) continue; + uint32_t T0 = Tms; + while((l = RB_write((ringbuffer*)&rbout[ifno], &byte, 1)) != 1){ + if(Tms - T0 > DISCONN_TMOUT){ + break_handler(ifno); + return FALSE; + } + if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; + if(l == 0){ // overfull + if(lastdsz[ifno] < 0) send_next(ifno); + continue; + } } - if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN + // send line if got EOL + if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno); return TRUE; } -int USB_sendstr(const char *string){ - if(!string || !CDCready) return FALSE; - int len = 0; - const char *b = string; - while(*b++) ++len; +int USB_sendstr(uint8_t ifno, const char *string){ + if(!string || !CDCready[ifno]) return FALSE; + int len = strlen(string); if(!len) return FALSE; - return USB_send((const uint8_t*)string, len); + return USB_send(ifno, (const uint8_t*)string, len); } /** @@ -209,14 +266,14 @@ int USB_sendstr(const char *string){ * @param len - length of `buf` * @return amount of received bytes (negative, if overfull happened) */ -int USB_receive(uint8_t *buf, int len){ - chkin(); - if(bufovrfl){ - while(1 != RB_clearbuf((ringbuffer*)&rbin)); - bufovrfl = 0; +int USB_receive(uint8_t ifno, uint8_t *buf, int len){ + chkin(ifno); // rxtx_handler could leave last message unwritten if buffer was busy + if(bufovrfl[ifno]){ + while(1 != RB_clearbuf((ringbuffer*)&rbin[ifno])); // run watchdog in case of problems + bufovrfl[ifno] = 0; return -1; } - int sz = RB_read((ringbuffer*)&rbin, buf, len); + int sz = RB_read((ringbuffer*)&rbin[ifno], buf, len); if(sz < 0) return 0; // buffer in writting state return sz; } @@ -227,17 +284,17 @@ int USB_receive(uint8_t *buf, int len){ * @param len - its length * @return strlen or negative value indicating overflow (if so, string won't be ends with 0 and buffer should be cleared) */ -int USB_receivestr(char *buf, int len){ - chkin(); - if(bufovrfl){ - while(1 != RB_clearbuf((ringbuffer*)&rbin)); - bufovrfl = 0; +int USB_receivestr(uint8_t ifno, char *buf, int len){ + chkin(ifno); // rxtx_handler could leave last message unwritten if buffer was busy + if(bufovrfl[ifno]){ + while(1 != RB_clearbuf((ringbuffer*)&rbin[ifno])); + bufovrfl[ifno] = 0; return -1; } - int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len); + int l = RB_readto((ringbuffer*)&rbin[ifno], '\n', (uint8_t*)buf, len); if(l < 1){ - if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found - while(1 != RB_clearbuf((ringbuffer*)&rbin)); + if(rbin[ifno].length == RB_datalen((ringbuffer*)&rbin[ifno])){ // buffer is full but no '\n' found + while(1 != RB_clearbuf((ringbuffer*)&rbin[ifno])); return -1; } return 0; @@ -246,4 +303,3 @@ int USB_receivestr(char *buf, int len){ buf[l-1] = 0; // replace '\n' with strend return l; } - diff --git a/F3:F303/InterfaceBoard/usb_dev.h b/F3:F303/InterfaceBoard/usb_dev.h index 1f8003c..07b1efb 100644 --- a/F3:F303/InterfaceBoard/usb_dev.h +++ b/F3:F303/InterfaceBoard/usb_dev.h @@ -18,6 +18,7 @@ #include #include "usb_lib.h" +#include "usb_descr.h" typedef struct { uint32_t dwDTERate; @@ -34,24 +35,29 @@ typedef struct { uint8_t bDataBits; } __attribute__ ((packed)) usb_LineCoding; -extern usb_LineCoding lineCoding; -extern volatile uint8_t CDCready; +extern volatile uint8_t CDCready[InterfacesAmount]; -void break_handler(); -void clstate_handler(uint16_t val); -void linecoding_handler(usb_LineCoding *lc); +void break_handler(uint8_t ifno); +void clstate_handler(uint8_t ifno, uint16_t val); +void linecoding_handler(uint8_t ifno, usb_LineCoding *lc); +// as ugly CDC have no BREAK after disconnected client in non-canonical mode, we should use timeout - more than 2ms +#define DISCONN_TMOUT (2) // sizes of ringbuffers for outgoing and incoming data -#define RBOUTSZ (1024) -#define RBINSZ (1024) +#define RBOUTSZ (256) +#define RBINSZ (256) -#define newline() USB_putbyte('\n') -#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) +#define newline(ifno) USB_putbyte(ifno, '\n') +#define USND(ifno, s) do{USB_sendstr(ifno, s); USB_putbyte(ifno, '\n');}while(0) +// configuratin interface macros +#define CFGWR(s) USB_sendstr(ICFG, s) +#define CFGWRn(s) do{USB_sendstr(ICFG, s); USB_putbyte(ICFG, '\n');}while(0) +#define CFGn() USB_putbyte(ICFG, '\n') -int USB_sendall(); -int USB_send(const uint8_t *buf, int len); -int USB_putbyte(uint8_t byte); -int USB_sendstr(const char *string); -int USB_receive(uint8_t *buf, int len); -int USB_receivestr(char *buf, int len); +int USB_sendall(uint8_t ifno); +int USB_send(uint8_t ifno, const uint8_t *buf, int len); +int USB_putbyte(uint8_t ifno, uint8_t byte); +int USB_sendstr(uint8_t ifno, const char *string); +int USB_receive(uint8_t ifno, uint8_t *buf, int len); +int USB_receivestr(uint8_t ifno, char *buf, int len); diff --git a/F3:F303/InterfaceBoard/usb_lib.c b/F3:F303/InterfaceBoard/usb_lib.c index 9f01a8f..f5dbd5f 100644 --- a/F3:F303/InterfaceBoard/usb_lib.c +++ b/F3:F303/InterfaceBoard/usb_lib.c @@ -356,6 +356,7 @@ void USB_setup(){ USB->BCDR |= USB_BCDR_DPPU; NVIC_EnableIRQ(USB_IRQn); #endif + setup_interfaces(); // refresh interfaces names } diff --git a/F3:F303/InterfaceBoard/version.inc b/F3:F303/InterfaceBoard/version.inc index d737cd6..c0afe52 100644 --- a/F3:F303/InterfaceBoard/version.inc +++ b/F3:F303/InterfaceBoard/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "8" -#define BUILD_DATE "2025-12-28" +#define BUILD_NUMBER "20" +#define BUILD_DATE "2026-02-11"