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 aac465a..80ef1e4 100755 Binary files a/F3:F303/InterfaceBoard/multiiface.bin and b/F3:F303/InterfaceBoard/multiiface.bin differ diff --git a/F3:F303/InterfaceBoard/multiiface.creator.user b/F3:F303/InterfaceBoard/multiiface.creator.user index bd2b309..393c9cc 100644 --- a/F3:F303/InterfaceBoard/multiiface.creator.user +++ b/F3:F303/InterfaceBoard/multiiface.creator.user @@ -1,6 +1,6 @@ - + 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"