From 148c25b555900709ba1185c1e78330f1b9d78281 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 13 Feb 2026 22:35:10 +0300 Subject: [PATCH] copy InterfaceBoard as 7CDCs template --- .../7CDCs.cflags | 0 .../7CDCs.config | 0 .../7CDCs.creator | 0 .../7CDCs.creator.user | 0 .../7CDCs.creator.user.7bd84e3 | 0 .../7CDCs.cxxflags | 0 .../7CDCs.files | 0 .../7CDCs.includes | 0 F3:F303/Seven_CDCs.deprecated/Makefile | 9 + .../can.c | 0 .../can.h | 0 .../canproto.c | 0 .../canproto.h | 0 .../cmdproto.c | 0 .../cmdproto.h | 0 .../debug.h | 0 F3:F303/Seven_CDCs.deprecated/hardware.c | 62 + F3:F303/Seven_CDCs.deprecated/hardware.h | 34 + F3:F303/Seven_CDCs.deprecated/main.c | 109 ++ F3:F303/Seven_CDCs.deprecated/openocd.cfg | 4 + F3:F303/Seven_CDCs.deprecated/ringbuffer.c | 124 ++ F3:F303/Seven_CDCs.deprecated/ringbuffer.h | 39 + .../sevenCDCs.bin | Bin F3:F303/Seven_CDCs.deprecated/strfunc.c | 351 ++++++ F3:F303/Seven_CDCs.deprecated/strfunc.h | 33 + .../usart.c | 0 .../usart.h | 0 .../usb.c | 0 .../usb.h | 0 F3:F303/Seven_CDCs.deprecated/usb_lib.c | 962 +++++++++++++++ F3:F303/Seven_CDCs.deprecated/usb_lib.h | 167 +++ .../usbhw.c | 0 .../usbhw.h | 0 F3:F303/Seven_CDCs.deprecated/version.inc | 2 + F3:F303/Seven_CDCs/7DCD_template.bin | Bin 0 -> 8304 bytes F3:F303/Seven_CDCs/Makefile | 4 +- F3:F303/Seven_CDCs/Readme.md | 4 + F3:F303/Seven_CDCs/flash.c | 191 +++ F3:F303/Seven_CDCs/flash.h | 47 + F3:F303/Seven_CDCs/hardware.c | 47 +- F3:F303/Seven_CDCs/hardware.h | 14 +- F3:F303/Seven_CDCs/main.c | 93 +- F3:F303/Seven_CDCs/multiiface.cflags | 1 + F3:F303/Seven_CDCs/multiiface.config | 8 + F3:F303/Seven_CDCs/multiiface.creator | 1 + F3:F303/Seven_CDCs/multiiface.creator.user | 214 ++++ F3:F303/Seven_CDCs/multiiface.cxxflags | 1 + F3:F303/Seven_CDCs/multiiface.files | 20 + F3:F303/Seven_CDCs/multiiface.includes | 6 + F3:F303/Seven_CDCs/openocd.cfg | 2 +- F3:F303/Seven_CDCs/proto.c | 136 +++ F3:F303/Seven_CDCs/proto.h | 22 + F3:F303/Seven_CDCs/ringbuffer.c | 122 +- F3:F303/Seven_CDCs/ringbuffer.h | 16 +- F3:F303/Seven_CDCs/strfunc.c | 98 +- F3:F303/Seven_CDCs/strfunc.h | 9 +- F3:F303/Seven_CDCs/usb_descr.c | 272 +++++ F3:F303/Seven_CDCs/usb_descr.h | 89 ++ F3:F303/Seven_CDCs/usb_dev.c | 321 +++++ F3:F303/Seven_CDCs/usb_dev.h | 63 + F3:F303/Seven_CDCs/usb_lib.c | 1057 ++++------------- F3:F303/Seven_CDCs/usb_lib.h | 324 +++-- F3:F303/Seven_CDCs/version.inc | 4 +- 63 files changed, 3919 insertions(+), 1163 deletions(-) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.cflags (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.config (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.creator (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.creator.user (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.creator.user.7bd84e3 (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.cxxflags (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.files (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/7CDCs.includes (100%) create mode 100644 F3:F303/Seven_CDCs.deprecated/Makefile rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/can.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/can.h (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/canproto.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/canproto.h (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/cmdproto.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/cmdproto.h (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/debug.h (100%) create mode 100644 F3:F303/Seven_CDCs.deprecated/hardware.c create mode 100644 F3:F303/Seven_CDCs.deprecated/hardware.h create mode 100644 F3:F303/Seven_CDCs.deprecated/main.c create mode 100644 F3:F303/Seven_CDCs.deprecated/openocd.cfg create mode 100644 F3:F303/Seven_CDCs.deprecated/ringbuffer.c create mode 100644 F3:F303/Seven_CDCs.deprecated/ringbuffer.h rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/sevenCDCs.bin (100%) create mode 100644 F3:F303/Seven_CDCs.deprecated/strfunc.c create mode 100644 F3:F303/Seven_CDCs.deprecated/strfunc.h rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usart.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usart.h (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usb.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usb.h (100%) create mode 100644 F3:F303/Seven_CDCs.deprecated/usb_lib.c create mode 100644 F3:F303/Seven_CDCs.deprecated/usb_lib.h rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usbhw.c (100%) rename F3:F303/{Seven_CDCs => Seven_CDCs.deprecated}/usbhw.h (100%) create mode 100644 F3:F303/Seven_CDCs.deprecated/version.inc create mode 100755 F3:F303/Seven_CDCs/7DCD_template.bin create mode 100644 F3:F303/Seven_CDCs/Readme.md create mode 100644 F3:F303/Seven_CDCs/flash.c create mode 100644 F3:F303/Seven_CDCs/flash.h create mode 100644 F3:F303/Seven_CDCs/multiiface.cflags create mode 100644 F3:F303/Seven_CDCs/multiiface.config create mode 100644 F3:F303/Seven_CDCs/multiiface.creator create mode 100644 F3:F303/Seven_CDCs/multiiface.creator.user create mode 100644 F3:F303/Seven_CDCs/multiiface.cxxflags create mode 100644 F3:F303/Seven_CDCs/multiiface.files create mode 100644 F3:F303/Seven_CDCs/multiiface.includes create mode 100644 F3:F303/Seven_CDCs/proto.c create mode 100644 F3:F303/Seven_CDCs/proto.h create mode 100644 F3:F303/Seven_CDCs/usb_descr.c create mode 100644 F3:F303/Seven_CDCs/usb_descr.h create mode 100644 F3:F303/Seven_CDCs/usb_dev.c create mode 100644 F3:F303/Seven_CDCs/usb_dev.h diff --git a/F3:F303/Seven_CDCs/7CDCs.cflags b/F3:F303/Seven_CDCs.deprecated/7CDCs.cflags similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.cflags rename to F3:F303/Seven_CDCs.deprecated/7CDCs.cflags diff --git a/F3:F303/Seven_CDCs/7CDCs.config b/F3:F303/Seven_CDCs.deprecated/7CDCs.config similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.config rename to F3:F303/Seven_CDCs.deprecated/7CDCs.config diff --git a/F3:F303/Seven_CDCs/7CDCs.creator b/F3:F303/Seven_CDCs.deprecated/7CDCs.creator similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.creator rename to F3:F303/Seven_CDCs.deprecated/7CDCs.creator diff --git a/F3:F303/Seven_CDCs/7CDCs.creator.user b/F3:F303/Seven_CDCs.deprecated/7CDCs.creator.user similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.creator.user rename to F3:F303/Seven_CDCs.deprecated/7CDCs.creator.user diff --git a/F3:F303/Seven_CDCs/7CDCs.creator.user.7bd84e3 b/F3:F303/Seven_CDCs.deprecated/7CDCs.creator.user.7bd84e3 similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.creator.user.7bd84e3 rename to F3:F303/Seven_CDCs.deprecated/7CDCs.creator.user.7bd84e3 diff --git a/F3:F303/Seven_CDCs/7CDCs.cxxflags b/F3:F303/Seven_CDCs.deprecated/7CDCs.cxxflags similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.cxxflags rename to F3:F303/Seven_CDCs.deprecated/7CDCs.cxxflags diff --git a/F3:F303/Seven_CDCs/7CDCs.files b/F3:F303/Seven_CDCs.deprecated/7CDCs.files similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.files rename to F3:F303/Seven_CDCs.deprecated/7CDCs.files diff --git a/F3:F303/Seven_CDCs/7CDCs.includes b/F3:F303/Seven_CDCs.deprecated/7CDCs.includes similarity index 100% rename from F3:F303/Seven_CDCs/7CDCs.includes rename to F3:F303/Seven_CDCs.deprecated/7CDCs.includes diff --git a/F3:F303/Seven_CDCs.deprecated/Makefile b/F3:F303/Seven_CDCs.deprecated/Makefile new file mode 100644 index 0000000..a597ea5 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/Makefile @@ -0,0 +1,9 @@ +BINARY := sevenCDCs +# MCU code +MCU := F303xb +# change this linking script depending on particular MCU model, +LDSCRIPT := stm32f303xB.ld +DEFINES := -DUSB1_16 + +include ../makefile.f3 +include ../../makefile.stm32 diff --git a/F3:F303/Seven_CDCs/can.c b/F3:F303/Seven_CDCs.deprecated/can.c similarity index 100% rename from F3:F303/Seven_CDCs/can.c rename to F3:F303/Seven_CDCs.deprecated/can.c diff --git a/F3:F303/Seven_CDCs/can.h b/F3:F303/Seven_CDCs.deprecated/can.h similarity index 100% rename from F3:F303/Seven_CDCs/can.h rename to F3:F303/Seven_CDCs.deprecated/can.h diff --git a/F3:F303/Seven_CDCs/canproto.c b/F3:F303/Seven_CDCs.deprecated/canproto.c similarity index 100% rename from F3:F303/Seven_CDCs/canproto.c rename to F3:F303/Seven_CDCs.deprecated/canproto.c diff --git a/F3:F303/Seven_CDCs/canproto.h b/F3:F303/Seven_CDCs.deprecated/canproto.h similarity index 100% rename from F3:F303/Seven_CDCs/canproto.h rename to F3:F303/Seven_CDCs.deprecated/canproto.h diff --git a/F3:F303/Seven_CDCs/cmdproto.c b/F3:F303/Seven_CDCs.deprecated/cmdproto.c similarity index 100% rename from F3:F303/Seven_CDCs/cmdproto.c rename to F3:F303/Seven_CDCs.deprecated/cmdproto.c diff --git a/F3:F303/Seven_CDCs/cmdproto.h b/F3:F303/Seven_CDCs.deprecated/cmdproto.h similarity index 100% rename from F3:F303/Seven_CDCs/cmdproto.h rename to F3:F303/Seven_CDCs.deprecated/cmdproto.h diff --git a/F3:F303/Seven_CDCs/debug.h b/F3:F303/Seven_CDCs.deprecated/debug.h similarity index 100% rename from F3:F303/Seven_CDCs/debug.h rename to F3:F303/Seven_CDCs.deprecated/debug.h diff --git a/F3:F303/Seven_CDCs.deprecated/hardware.c b/F3:F303/Seven_CDCs.deprecated/hardware.c new file mode 100644 index 0000000..44dc333 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/hardware.c @@ -0,0 +1,62 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2023 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" +#include "usart.h" + +TRUE_INLINE void iwdg_setup(){ + uint32_t tmout = 16000000; + /* Enable the peripheral clock RTC */ + /* (1) Enable the LSI (40kHz) */ + /* (2) Wait while it is not ready */ + RCC->CSR |= RCC_CSR_LSION; /* (1) */ + while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */ + /* Configure IWDG */ + /* (1) Activate IWDG (not needed if done in option bytes) */ + /* (2) Enable write access to IWDG registers */ + /* (3) Set prescaler by 64 (1.6ms for each tick) */ + /* (4) Set reload value to have a rollover each 2s */ + /* (5) Check if flags are reset */ + /* (6) Refresh counter */ + IWDG->KR = IWDG_START; /* (1) */ + IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */ + IWDG->PR = IWDG_PR_PR_1; /* (3) */ + IWDG->RLR = 1250; /* (4) */ + tmout = 16000000; + while(IWDG->SR){if(--tmout == 0) break;} /* (5) */ + IWDG->KR = IWDG_REFRESH; /* (6) */ +} + + +static inline void gpio_setup(){ + RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; + // USB - alternate function 14 @ pins PA11/PA12; USART1 = AF7 @PA9/10; SWD - AF0 @PA13/14 + GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10) | AFRf(14, 11) | AFRf(14, 12); + // USART1: PA10(Rx), PA9(Tx); USB - PA11, PA12; SWDIO - PA13, PA14; Pullup - PA15 + GPIOA->MODER = MODER_AF(9) | MODER_AF(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15); + GPIOA->OSPEEDR = OSPEED_HI(11) | OSPEED_HI(12) | OSPEED_HI(13) | OSPEED_HI(14); + // LEDs on PB0 and PB1 + GPIOB->MODER = GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O; + GPIOB->ODR = 1; +} + +void hw_setup(){ + gpio_setup(); + iwdg_setup(); +} + diff --git a/F3:F303/Seven_CDCs.deprecated/hardware.h b/F3:F303/Seven_CDCs.deprecated/hardware.h new file mode 100644 index 0000000..82cd0ce --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/hardware.h @@ -0,0 +1,34 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2023 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 +#ifndef __HARDWARE_H__ +#define __HARDWARE_H__ + +#include + +#define USBPU_port GPIOA +#define USBPU_pin (1<<15) +#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin) +#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin) + +extern volatile uint32_t Tms; + +void hw_setup(); + +#endif // __HARDWARE_H__ diff --git a/F3:F303/Seven_CDCs.deprecated/main.c b/F3:F303/Seven_CDCs.deprecated/main.c new file mode 100644 index 0000000..a286234 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/main.c @@ -0,0 +1,109 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2023 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 "can.h" +#include "canproto.h" +#include "cmdproto.h" +#include "debug.h" +#include "hardware.h" +#include "strfunc.h" +#include "usart.h" +#include "usb.h" + +#define MAXSTRLEN RBINSZ + +volatile uint32_t Tms = 0; + +void sys_tick_handler(void){ + ++Tms; +} + +static const char *ebufovr = "ERROR: USB buffer overflow or string was too long\n"; +static const char *idxnames[MAX_IDX] = {"CMD", "DBG", "USART1", "USART2", "USART3", "NOFUNCT", "CAN"}; + +int main(void){ + char inbuff[MAXSTRLEN+1]; + USBPU_OFF(); + if(StartHSE()){ + SysTick_Config((uint32_t)72000); // 1ms + }else{ + StartHSI(); + SysTick_Config((uint32_t)48000); // 1ms + } + hw_setup(); + usarts_setup(); + USB_setup(); + CAN_setup(100); + USBPU_ON(); + + CAN_message *can_mesg; + uint32_t ctr = Tms; + while(1){ + IWDG->KR = IWDG_REFRESH; + if(Tms - ctr > 499){ + ctr = Tms; + pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 + //USB_sendstr(CMD_IDX, "1"); + //DBGmesg(u2str(Tms)); + //DBGnl(); + } + can_proc(); + if(CAN_get_status() == CAN_FIFO_OVERRUN){ + USB_sendstr(CAN_IDX, "CAN bus fifo overrun occured!\n"); + } + while((can_mesg = CAN_messagebuf_pop())){ + if(isgood(can_mesg->ID)){ + if(ShowMsgs){ // display message content + IWDG->KR = IWDG_REFRESH; + uint8_t len = can_mesg->length; + USB_sendstr(CAN_IDX, u2str(Tms)); + USB_sendstr(CAN_IDX, " #"); + USB_sendstr(CAN_IDX, uhex2str(can_mesg->ID)); + for(uint8_t i = 0; i < len; ++i){ + USB_putbyte(CAN_IDX, ' '); + USB_sendstr(CAN_IDX, uhex2str(can_mesg->data[i])); + } + USB_putbyte(CAN_IDX, '\n'); + } + } + } + for(int i = 0; i < MAX_IDX; ++i){ + int l = USB_receivestr(i, inbuff, MAXSTRLEN); + if(l < 0){ + USB_sendstr(DBG_IDX, ebufovr); + if(i == CMD_IDX) USB_sendstr(CMD_IDX, ebufovr); + continue; + } + if(l == 0) continue; + USB_sendstr(DBG_IDX, idxnames[i]); + USB_sendstr(DBG_IDX, "> "); + USB_sendstr(DBG_IDX, inbuff); + USB_putbyte(DBG_IDX, '\n'); + switch(i){ + case CMD_IDX: + parse_cmd(inbuff); + break; + case CAN_IDX: + cmd_parser(inbuff); + break; + default: + break; + } + } + } +} diff --git a/F3:F303/Seven_CDCs.deprecated/openocd.cfg b/F3:F303/Seven_CDCs.deprecated/openocd.cfg new file mode 100644 index 0000000..0210594 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/openocd.cfg @@ -0,0 +1,4 @@ +set FLASH_SIZE 0x20000 + +source [find interface/stlink-v2-1.cfg] +source [find target/stm32f3x.cfg] diff --git a/F3:F303/Seven_CDCs.deprecated/ringbuffer.c b/F3:F303/Seven_CDCs.deprecated/ringbuffer.c new file mode 100644 index 0000000..d7b4ced --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/ringbuffer.c @@ -0,0 +1,124 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2022 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 "ringbuffer.h" + +// stored data length +int RB_datalen(ringbuffer *b){ + if(b->tail >= b->head) return (b->tail - b->head); + else return (b->length - b->head + b->tail); +} + +/** + * @brief RB_hasbyte - check if buffer has given byte stored + * @param b - buffer + * @param byte - byte to find + * @return index if found, -1 if none + */ +int RB_hasbyte(ringbuffer *b, uint8_t byte){ + if(b->head == b->tail) return -1; // no data in buffer + int startidx = b->head; + if(b->head > b->tail){ // + for(int found = b->head; found < b->length; ++found) + if(b->data[found] == byte) return found; + startidx = 0; + } + for(int found = startidx; found < b->tail; ++found) + if(b->data[found] == byte) return found; + return -1; +} + +// poor memcpy +static void mcpy(uint8_t *targ, const uint8_t *src, int l){ + while(l--) *targ++ = *src++; +} + +// increment head or tail +TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ + *what += n; + if(*what >= b->length) *what -= b->length; +} + +/** + * @brief RB_read - read data from ringbuffer + * @param b - buffer + * @param s - array to write data + * @param len - max len of `s` + * @return bytes read + */ +int RB_read(ringbuffer *b, uint8_t *s, int len){ + int l = RB_datalen(b); + if(!l) return 0; + if(l > len) l = len; + int _1st = b->length - b->head; + if(_1st > l) _1st = l; + if(_1st > len) _1st = len; + mcpy(s, b->data + b->head, _1st); + if(_1st < len && l > _1st){ + mcpy(s+_1st, b->data, l - _1st); + incr(b, &b->head, l); + return l; + } + incr(b, &b->head, _1st); + return _1st; +} + +/** + * @brief RB_readto fill array `s` with data until byte `byte` (with it) + * @param b - ringbuffer + * @param byte - check byte + * @param s - buffer to write data + * @param len - length of `s` + * @return amount of bytes written (negative, if lenhead; + // now calculate length of new data portion + if(idx < b->head) partlen += b->length; + if(partlen > len) return -RB_read(b, s, len); + return RB_read(b, s, partlen); +} + +/** + * @brief RB_write - write some data to ringbuffer + * @param b - buffer + * @param str - data + * @param l - length + * @return amount of bytes written + */ +int RB_write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - RB_datalen(b); // rest length + if(l > r) l = r; + if(!l) return 0; + int _1st = b->length - b->tail; + if(_1st > l) _1st = l; + mcpy(b->data + b->tail, str, _1st); + if(_1st < l){ // add another piece from start + mcpy(b->data, str+_1st, l-_1st); + } + incr(b, &b->tail, l); + return l; +} + +// just delete all information in buffer `b` +void RB_clearbuf(ringbuffer *b){ + b->head = 0; + b->tail = 0; +} diff --git a/F3:F303/Seven_CDCs.deprecated/ringbuffer.h b/F3:F303/Seven_CDCs.deprecated/ringbuffer.h new file mode 100644 index 0000000..b5e08b8 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/ringbuffer.h @@ -0,0 +1,39 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2022 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 +#ifndef RINGBUFFER_H__ +#define RINGBUFFER_H__ + +#include + +typedef struct{ + uint8_t *data; // data buffer + const int length; // its length + int head; // head index + int tail; // tail index +} ringbuffer; + +int RB_read(ringbuffer *b, uint8_t *s, int len); +int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len); +int RB_hasbyte(ringbuffer *b, uint8_t byte); +int RB_write(ringbuffer *b, const uint8_t *str, int l); +int RB_datalen(ringbuffer *b); +void RB_clearbuf(ringbuffer *b); + +#endif // RINGBUFFER_H__ diff --git a/F3:F303/Seven_CDCs/sevenCDCs.bin b/F3:F303/Seven_CDCs.deprecated/sevenCDCs.bin similarity index 100% rename from F3:F303/Seven_CDCs/sevenCDCs.bin rename to F3:F303/Seven_CDCs.deprecated/sevenCDCs.bin diff --git a/F3:F303/Seven_CDCs.deprecated/strfunc.c b/F3:F303/Seven_CDCs.deprecated/strfunc.c new file mode 100644 index 0000000..614b263 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/strfunc.c @@ -0,0 +1,351 @@ +/* + * This file is part of the 7CDCs project. + * Copyright 2023 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 +#include +#include "usb.h" +/** + * @brief hexdump - dump hex array by 16 bytes in string + * @param ifno - USB interface number + * @param arr - array to dump + * @param len - length of `arr` + */ +void hexdump(int ifno, uint8_t *arr, uint16_t len){ + char buf[52], *bptr = buf; + for(uint16_t l = 0; l < len; ++l, ++arr){ + for(int16_t j = 1; j > -1; --j){ + register uint8_t half = (*arr >> (4*j)) & 0x0f; + if(half < 10) *bptr++ = half + '0'; + else *bptr++ = half - 10 + 'a'; + } + if(l % 16 == 15){ + *bptr++ = '\n'; + *bptr = 0; + USB_sendstr(ifno, buf); + bptr = buf; + }else *bptr++ = ' '; + } + if(bptr != buf){ + *bptr++ = '\n'; + *bptr = 0; + USB_sendstr(ifno, buf); + } +} + +/** + * @brief _2str - convert value into string buffer + * @param val - |value| + * @param minus - ==0 if value > 0 + * @return buffer with number + */ +static char *_2str(uint32_t val, uint8_t minus){ + static char strbuf[12]; + char *bufptr = &strbuf[11]; + *bufptr = 0; + if(!val){ + *(--bufptr) = '0'; + }else{ + while(val){ + uint32_t x = val / 10; + *(--bufptr) = (val - 10*x) + '0'; + val = x; + //*(--bufptr) = val % 10 + '0'; + //val /= 10; + } + } + if(minus) *(--bufptr) = '-'; + return bufptr; +} + +// return string with number `val` +char *u2str(uint32_t val){ + return _2str(val, 0); +} +char *i2str(int32_t i){ + uint8_t minus = 0; + uint32_t val; + if(i < 0){ + minus = 1; + val = -i; + }else val = i; + return _2str(val, minus); +} + +/** + * @brief uhex2str - print 32bit unsigned int as hex + * @param val - value + * @return string with number + */ +char *uhex2str(uint32_t val){ + static char buf[12] = "0x"; + int npos = 2; + uint8_t *ptr = (uint8_t*)&val + 3; + int8_t i, j, z=1; + for(i = 0; i < 4; ++i, --ptr){ + if(*ptr == 0){ // omit leading zeros + if(i == 3) z = 0; + if(z) continue; + } + else z = 0; + for(j = 1; j > -1; --j){ + uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) buf[npos++] = half + '0'; + else buf[npos++] = half - 10 + 'a'; + } + } + buf[npos] = 0; + return buf; +} + +/** + * @brief omit_spaces - eliminate leading spaces and other trash in string + * @param buf - string + * @return - pointer to first character in `buf` > ' ' + */ +const char *omit_spaces(const char *buf){ + while(*buf){ + if(*buf > ' ') break; + ++buf; + } + return buf; +} + +/** + * @brief getdec - read decimal number & return pointer to next non-number symbol + * @param buf - string + * @param N - number read + * @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff + */ +static const char *getdec(const char *buf, uint32_t *N){ + char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '9'){ + break; + } + if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow + *N = 0xffffff; + return start; + } + num *= 10; + num += c - '0'; + ++buf; + } + *N = num; + return buf; +} +// read hexadecimal number (without 0x prefix!) +static const char *gethex(const char *buf, uint32_t *N){ + const char *start = buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + uint8_t M = 0; + if(c >= '0' && c <= '9'){ + M = '0'; + }else if(c >= 'A' && c <= 'F'){ + M = 'A' - 10; + }else if(c >= 'a' && c <= 'f'){ + M = 'a' - 10; + } + if(M){ + if(num & 0xf0000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 4; + num += c - M; + }else{ + break; + } + ++buf; + } + *N = num; + return buf; +} +// read octal number (without 0 prefix!) +static const char *getoct(const char *buf, uint32_t *N){ + const char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '7'){ + break; + } + if(num & 0xe0000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 3; + num += c - '0'; + ++buf; + } + *N = num; + return buf; +} +// read binary number (without b prefix!) +static const char *getbin(const char *buf, uint32_t *N){ + const char *start = (char*)buf; + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '1'){ + break; + } + if(num & 0x80000000){ // overflow + *N = 0xffffff; + return start; + } + num <<= 1; + if(c == '1') num |= 1; + ++buf; + } + *N = num; + return buf; +} + +/** + * @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111) + * @param buf - buffer with number and so on + * @param N - the number read + * @return pointer to first non-number symbol in buf + * (if it is == buf, there's no number or if *N==0xffffffff there was overflow) + */ +const char *getnum(const char *txt, uint32_t *N){ + const char *nxt = NULL; + const char *s = omit_spaces(txt); + if(*s == '0'){ // hex, oct or 0 + if(s[1] == 'x' || s[1] == 'X'){ // hex + nxt = gethex(s+2, N); + if(nxt == s+2) nxt = (char*)txt; + }else if(s[1] > '0'-1 && s[1] < '8'){ // oct + nxt = getoct(s+1, N); + if(nxt == s+1) nxt = (char*)txt; + }else{ // 0 + nxt = s+1; + *N = 0; + } + }else if(*s == 'b' || *s == 'B'){ + nxt = getbin(s+1, N); + if(nxt == s+1) nxt = (char*)txt; + }else{ + nxt = getdec(s, N); + if(nxt == s) nxt = (char*)txt; + } + return nxt; +} + +// get signed integer +const char *getint(const char *txt, int32_t *I){ + const char *s = omit_spaces(txt); + int32_t sign = 1; + uint32_t U; + if(*s == '-'){ + sign = -1; + ++s; + } + const char *nxt = getnum(s, &U); + if(nxt == s) return txt; + if(U & 0x80000000) return txt; // overfull + *I = sign * (int32_t)U; + return nxt; +} + +int mystrlen(const char *txt){ + if(!txt) return 0; + int r = 0; + while(*txt++) ++r; + return r; +} + +/* +void mymemcpy(char *dest, const char *src, int len){ + if(len < 1) return; + while(len--) *dest++ = *src++; +} +*/ + +// be careful: if pow10 would be bigger you should change str[] size! +static const float pwr10[] = {1.f, 10.f, 100.f, 1000.f, 10000.f}; +static const float rounds[] = {0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f}; +#define P10L (sizeof(pwr10)/sizeof(uint32_t) - 1) +char * float2str(float x, uint8_t prec){ + static char str[16] = {0}; // -117.5494E-36\0 - 14 symbols max! + if(prec > P10L) prec = P10L; + if(isnan(x)){ memcpy(str, "NAN", 4); return str;} + else{ + int i = isinf(x); + if(i){memcpy(str, "-INF", 5); if(i == 1) return str+1; else return str;} + } + char *s = str + 14; // go to end of buffer + uint8_t minus = 0; + if(x < 0){ + x = -x; + minus = 1; + } + int pow = 0; // xxxEpow + // now convert float to 1.xxxE3y + while(x > 1000.f){ + x /= 1000.f; + pow += 3; + } + if(x > 0.) while(x < 1.){ + x *= 1000.f; + pow -= 3; + } + // print Eyy + if(pow){ + uint8_t m = 0; + if(pow < 0){pow = -pow; m = 1;} + while(pow){ + register int p10 = pow/10; + *s-- = '0' + (pow - 10*p10); + pow = p10; + } + if(m) *s-- = '-'; + *s-- = 'E'; + } + // now our number is in [1, 1000] + uint32_t units; + if(prec){ + units = (uint32_t) x; + uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]); + // print decimals + while(prec){ + register int d10 = decimals / 10; + *s-- = '0' + (decimals - 10*d10); + decimals = d10; + --prec; + } + // decimal point + *s-- = '.'; + }else{ // without decimal part + units = (uint32_t) (x + 0.5); + } + // print main units + if(units == 0) *s-- = '0'; + else while(units){ + register uint32_t u10 = units / 10; + *s-- = '0' + (units - 10*u10); + units = u10; + } + if(minus) *s-- = '-'; + return s+1; +} diff --git a/F3:F303/Seven_CDCs.deprecated/strfunc.h b/F3:F303/Seven_CDCs.deprecated/strfunc.h new file mode 100644 index 0000000..e1dd59e --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/strfunc.h @@ -0,0 +1,33 @@ +/* + * This file is part of the 7CDCs project. + * Copyright 2023 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 +#include + +void hexdump(int ifno, uint8_t *arr, uint16_t len); +const char *u2str(uint32_t val); +const char *i2str(int32_t i); +const char *uhex2str(uint32_t val); +const char *getnum(const char *txt, uint32_t *N); +const char *omit_spaces(const char *buf); +const char *getint(const char *txt, int32_t *I); +int mystrlen(const char *txt); +//void mymemcpy(char *dest, const char *src, int len); +char * float2str(float x, uint8_t prec); diff --git a/F3:F303/Seven_CDCs/usart.c b/F3:F303/Seven_CDCs.deprecated/usart.c similarity index 100% rename from F3:F303/Seven_CDCs/usart.c rename to F3:F303/Seven_CDCs.deprecated/usart.c diff --git a/F3:F303/Seven_CDCs/usart.h b/F3:F303/Seven_CDCs.deprecated/usart.h similarity index 100% rename from F3:F303/Seven_CDCs/usart.h rename to F3:F303/Seven_CDCs.deprecated/usart.h diff --git a/F3:F303/Seven_CDCs/usb.c b/F3:F303/Seven_CDCs.deprecated/usb.c similarity index 100% rename from F3:F303/Seven_CDCs/usb.c rename to F3:F303/Seven_CDCs.deprecated/usb.c diff --git a/F3:F303/Seven_CDCs/usb.h b/F3:F303/Seven_CDCs.deprecated/usb.h similarity index 100% rename from F3:F303/Seven_CDCs/usb.h rename to F3:F303/Seven_CDCs.deprecated/usb.h diff --git a/F3:F303/Seven_CDCs.deprecated/usb_lib.c b/F3:F303/Seven_CDCs.deprecated/usb_lib.c new file mode 100644 index 0000000..ac0f04e --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/usb_lib.c @@ -0,0 +1,962 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2023 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 "debug.h" +#include "strfunc.h" +#include "usart.h" +#include "usb.h" +#include "usb_lib.h" +#include "usbhw.h" + +ep_t endpoints[STM32ENDPOINTS]; + +static uint16_t USB_Addr = 0; +uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; +config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; + +volatile uint8_t usbON = 0; + +// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor +#define bcdUSB_L 0x00 +#define bcdUSB_H 0x02 +// Class - Misc (EF), subclass - common (2), protocol - interface association descr (1) +#define bDeviceClass 0xEF +#define bDeviceSubClass 0x02 +#define bDeviceProtocol 0x01 +#define bNumConfigurations 1 + +static const uint8_t USB_DeviceDescriptor[] = { + 18, // bLength + 0x01, // bDescriptorType - Device descriptor + bcdUSB_L, // bcdUSB_L - 1.10 + bcdUSB_H, // bcdUSB_H + bDeviceClass, // bDeviceClass - USB_COMM + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0_BUFSZ, // bMaxPacketSize + // 0483:5740 (VID:PID) - stm32 VCP + 0x83, 0x04, 0x40, 0x57, + 0x00, // bcdDevice_Ver_L + 0x02, // bcdDevice_Ver_H + iMANUFACTURER_DESCR, // iManufacturer + iPRODUCT_DESCR, // iProduct + iSERIAL_DESCR, // iSerialNumber + bNumConfigurations // bNumConfigurations +}; + +static const uint8_t USB_DeviceQualifierDescriptor[] = { + 10, //bLength + 0x06, // bDescriptorType - Device qualifier + bcdUSB_L, // bcdUSB_L + bcdUSB_H, // bcdUSB_H + bDeviceClass, // bDeviceClass + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0_BUFSZ, // bMaxPacketSize0 + bNumConfigurations, // bNumConfigurations + 0x00 // Reserved +}; + +static const uint8_t USB_ConfigDescriptor[] = { + /* Configuration Descriptor*/ + 0x09, /* bLength: Configuration Descriptor size */ + 0x02, /* bDescriptorType: Configuration */ + 0xD7, /* wTotalLength:no of returned bytes (9+7*66=471, 0x1D7 */ + 0x01, + 14, /* bNumInterfaces: 14 interfaces (7*2) */ + 0x01, /* bConfigurationValue: Configuration value */ + 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ + 0x80, /* bmAttributes - Bus powered */ + 0x32, /* MaxPower 100 mA */ + + /*---------------------------------------------------------------------------*/ + // IAD0 (66 bytes) + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD + 0, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /* Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ + 0x00, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_CMD, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ + 0x01, /* bDataInterface: 1 */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ + 0x00, /* bMasterInterface: Communication class interface */ + 0x01, /* bSlaveInterface0: Data Class Interface */ + /*Endpoint 10 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x88, /* bEndpointAddress IN8 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ + 0x01, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ + 0x81, /* bEndpointAddress IN1 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ + 0x01, /* bEndpointAddress OUT1 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD1: interfaces 2&3, EP2 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 2, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 2, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_DBG, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 3, /* bDataInterface: 3 */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 2, /* bMasterInterface: Communication class interface */ +/**/ 3, /* bSlaveInterface0: Data Class Interface */ + /*Endpoint 11 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x89, /* bEndpointAddress IN9 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 3, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x82, /* bEndpointAddress IN2 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x02, /* bEndpointAddress OUT2 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD2: interfaces 4&5, EP3 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 4, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 4, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_USART1, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 5, /* bDataInterface */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 4, /* bMasterInterface: Communication class interface */ +/**/ 5, /* bSlaveInterface0: Data Class Interface */ + /*Endpoint 11 Descriptor*/ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x8a, /* bEndpointAddress IN10 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 5, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x83, /* bEndpointAddress IN3 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x03, /* bEndpointAddress OUT3 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD3: interfaces 6&7, EP4 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 6, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 6, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_USART2, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 7, /* bDataInterface */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 6, /* bMasterInterface: Communication class interface */ +/**/ 7, /* bSlaveInterface0: Data Class Interface */ + /* Interrupt Endpoint Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x8b, /* bEndpointAddress IN11 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 7, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x84, /* bEndpointAddress IN4 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x04, /* bEndpointAddress OUT4 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD4: interfaces 8&9, EP5 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 8, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 8, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_USART3, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 9, /* bDataInterface */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 8, /* bMasterInterface: Communication class interface */ +/**/ 9, /* bSlaveInterface0: Data Class Interface */ + /* Interrupt Endpoint Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x8c, /* bEndpointAddress IN12 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 9, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x85, /* bEndpointAddress IN5 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x05, /* bEndpointAddress OUT5 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD5: interfaces 10&11, EP6 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 10, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 10, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_USART4, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 11, /* bDataInterface */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 10, /* bMasterInterface: Communication class interface */ +/**/ 11, /* bSlaveInterface0: Data Class Interface */ + /* Interrupt Endpoint Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x8d, /* bEndpointAddress IN13 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 11, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x86, /* bEndpointAddress IN6 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x06, /* bEndpointAddress OUT6 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ + + /*---------------------------------------------------------------------------*/ + // IAD6: interfaces 12&13, EP7 + 0x08, // bLength: Interface Descriptor size + 0x0B, // bDescriptorType: IAD +/**/ 12, // bFirstInterface + 0x02, // bInterfaceCount + 0x02, // bFunctionClass: CDC + 0x02, // bFunctionSubClass + 0x00, // bFunctionProtocol + 0x00, // iFunction + /*---------------------------------------------------------------------------*/ + /*Interface Descriptor */ + 0x09, /* bLength: Interface Descriptor size */ + 0x04, /* bDescriptorType: Interface */ +/**/ 12, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x01, /* bNumEndpoints: One endpoints used */ + 0x02, /* bInterfaceClass: Communication Interface Class */ + 0x02, /* bInterfaceSubClass: Abstract Control Model */ + 0x00, /* bInterfaceProtocol */ + iINTERFACE_DESCR_CAN, /* iInterface: */ + /*Header Functional Descriptor*/ + 0x05, /* bLength: Endpoint Descriptor size */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x00, /* bDescriptorSubtype: Header Func Desc */ + 0x10, /* bcdCDC: spec release number */ + 0x01, + /*Call Management Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x01, /* bDescriptorSubtype: Call Management Func Desc */ + 0x00, /* bmCapabilities: D0+D1 */ +/**/ 13, /* bDataInterface */ + /*ACM Functional Descriptor*/ + 0x04, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ + 0x02, /* bmCapabilities */ + /*Union Functional Descriptor*/ + 0x05, /* bFunctionLength */ + 0x24, /* bDescriptorType: CS_INTERFACE */ + 0x06, /* bDescriptorSubtype: Union func desc */ +/**/ 12, /* bMasterInterface: Communication class interface */ +/**/ 13, /* bSlaveInterface0: Data Class Interface */ + /* Interrupt Endpoint Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x8e, /* bEndpointAddress IN14 - non-existant! */ + 0x03, /* bmAttributes: Interrupt */ + (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ + (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ + 0x10, /* bInterval: */ + /*---------------------------------------------------------------------------*/ + /*Data class interface descriptor*/ + 0x09, /* bLength: Endpoint Descriptor size */ + 0x04, /* bDescriptorType: */ +/**/ 13, /* bInterfaceNumber: Number of Interface */ + 0x00, /* bAlternateSetting: Alternate setting */ + 0x02, /* bNumEndpoints: Two endpoints used */ + 0x0A, /* bInterfaceClass: CDC */ + 0x02, /* bInterfaceSubClass: */ + 0x00, /* bInterfaceProtocol: */ + 0x00, /* iInterface: */ + /*Endpoint IN Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x87, /* bEndpointAddress IN7 */ + 0x02, /* bmAttributes: Bulk */ + (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_TXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*Endpoint OUT Descriptor */ + 0x07, /* bLength: Endpoint Descriptor size */ + 0x05, /* bDescriptorType: Endpoint */ +/**/0x07, /* bEndpointAddress OUT7 */ + 0x02, /* bmAttributes: Bulk */ + (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ + (USB_RXBUFSZ >> 8), + 0x00, /* bInterval: ignore for Bulk transfer */ + /*---------------------------------------------------------------------------*/ +}; + +_USB_LANG_ID_(LD, LANG_US); +_USB_STRING_(SD, u"0.0.1"); +_USB_STRING_(MD, u"Emelianov E.V."); +_USB_STRING_(PD, u"USB multiserial controller"); +_USB_STRING_(ID0, u"serial-cmd"); +_USB_STRING_(ID1, u"serial-usart1_"); +_USB_STRING_(ID2, u"serial-usart2_"); +_USB_STRING_(ID3, u"serial-usart3_"); +_USB_STRING_(ID4, u"serial-usart4_"); +_USB_STRING_(ID5, u"serial-can"); +_USB_STRING_(ID6, u"serial-debug"); + +static void const *StringDescriptor[iDESCR_AMOUNT] = { + [iLANGUAGE_DESCR] = &LD, + [iMANUFACTURER_DESCR] = &MD, + [iPRODUCT_DESCR] = &PD, + [iSERIAL_DESCR] = &SD, + [iINTERFACE_DESCR_CMD] = &ID0, + [iINTERFACE_DESCR_DBG] = &ID6, + [iINTERFACE_DESCR_USART1] = &ID1, + [iINTERFACE_DESCR_USART2] = &ID2, + [iINTERFACE_DESCR_USART3] = &ID3, + [iINTERFACE_DESCR_USART4] = &ID4, + [iINTERFACE_DESCR_CAN] = &ID5 +}; + +static void wr0(const uint8_t *buf, uint16_t size){ + if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request + if(size < endpoints[0].txbufsz){ + EP_WriteIRQ(0, buf, size); + return; + } + while(size){ + uint16_t l = size; + if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz; + EP_WriteIRQ(0, buf, l); + buf += l; + size -= l; + uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0; + if(size || needzlp){ // send last data buffer + uint16_t status = KEEP_DTOG(USB->EPnR[0]); + // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx + USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX)) + ^ USB_EPnR_STAT_TX; + uint32_t ctr = 1000000; + while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; + if((USB->ISTR & USB_ISTR_CTR) == 0){ + return; + } + if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0); + } + } +} + +static inline void get_descriptor(){ + uint8_t descrtype = setup_packet->wValue >> 8, + descridx = setup_packet->wValue & 0xff; + switch(descrtype){ + case DEVICE_DESCRIPTOR: + wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); + break; + case CONFIGURATION_DESCRIPTOR: + wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); + break; + case STRING_DESCRIPTOR: + if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx])); + else EP_WriteIRQ(0, (uint8_t*)0, 0); + break; + case DEVICE_QUALIFIER_DESCRIPTOR: + wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); + break; + default: + break; + } +} + +static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) +static inline void std_d2h_req(){ + uint16_t status = 0; // bus powered + switch(setup_packet->bRequest){ + case GET_DESCRIPTOR: + get_descriptor(); + break; + case GET_STATUS: + EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered + break; + case GET_CONFIGURATION: + EP_WriteIRQ(0, (uint8_t*)&configuration, 1); + break; + default: + break; + } +} + +// Rx and Tx handlers for EP1..EP7 +static void rxtx_Handler(uint8_t epno){ + uint8_t buf[USB_RXBUFSZ]; + int idx = epno - 1; + uint16_t epstatus = KEEP_DTOG(USB->EPnR[epno]); + if(RX_FLAG(epstatus)){ + epstatus = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // keep stat Tx & set valid RX, clear CTR Rx + USB->EPnR[epno] = epstatus; + uint8_t sz = EP_Read(epno, (uint8_t*)buf); + /* + DBG("epno"); + DBGmesg(u2str(epno)); DBGmesg(" ("); DBGmesg(u2str(sz)); + DBGmesg(") > "); hexdump(DBG_IDX, buf, sz); DBGnl(); + */ + if(sz){ + switch(epno){ + case USART1_EPNO: + usart_sendn(1, buf, sz); + break; + case USART2_EPNO: + usart_sendn(2, buf, sz); + break; + case USART3_EPNO: + usart_sendn(3, buf, sz); + break; + case USART4_EPNO: + ; // we have no USART4 in STM32F303CBT6 + break; + } + if(RB_write((ringbuffer*)&rbin[idx], buf, sz) != sz) bufovrfl[idx] = 1; + } + // set ACK Rx + USB->EPnR[epno] = (KEEP_DTOG(USB->EPnR[epno]) & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; + }else{ + USB->EPnR[epno] = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; // clear TX ctr + send_next(idx); + } +} + +static inline void std_h2d_req(){ + switch(setup_packet->bRequest){ + case SET_ADDRESS: + // new address will be assigned later - after acknowlegement or request to host + USB_Addr = setup_packet->wValue; + break; + case SET_CONFIGURATION: + // Now device configured + configuration = setup_packet->wValue; + for(uint8_t i = 1; i <= MAX_EPNO; ++i){ + EP_Init(i, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_Handler); + } + break; + default: + break; + } +} + +/* +bmRequestType: 76543210 +7 direction: 0 - host->device, 1 - device->host +65 type: 0 - standard, 1 - class, 2 - vendor +4..0 getter: 0 - device, 1 - interface, 2 - endpoint, 3 - other +*/ +/** + * Endpoint0 (control) handler + */ +void EP0_Handler(uint8_t __attribute__((unused)) epno){ + uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications + uint8_t reqtype = setup_packet->bmRequestType & 0x7f; + uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; + int rxflag = RX_FLAG(epstatus); + usb_LineCoding *lc; + // calculate iFno (EP number minus 1) by setup_packet->wIndex (bInterfaceNumber): iFno = wIndex >> 1 + int iFno = setup_packet->wIndex >> 1; + if(iFno != DBG_IDX){ + DBGmesg(uhex2str(epstatus)); + DBGmesg(" ("); DBGmesg(u2str(iFno)); + DBGmesg(") - "); hexdump(DBG_IDX, (uint8_t*)setup_packet, sizeof(config_pack_t)); + } + if(rxflag && SETUP_FLAG(epstatus)){ + if(iFno != DBG_IDX){DBGmesg("setup\n");} + switch(reqtype){ + case STANDARD_DEVICE_REQUEST_TYPE: // standard device request + if(dev2host){ + std_d2h_req(); + }else{ + std_h2d_req(); + EP_WriteIRQ(0, (uint8_t *)0, 0); + } + break; + case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request + if(setup_packet->bRequest == CLEAR_FEATURE){ + EP_WriteIRQ(0, (uint8_t *)0, 0); + } + break; + case CONTROL_REQUEST_TYPE: + switch(setup_packet->bRequest){ + case GET_LINE_CODING: + if(iFno != DBG_IDX){ DBG("GLC");} + lc = getLineCoding(iFno); + if(!lc) EP_WriteIRQ(0, (uint8_t *)0, 0); + else EP_WriteIRQ(0, (uint8_t*)&lc, sizeof(usb_LineCoding)); + break; + case SET_LINE_CODING: // omit this for next stage, when data will come + if(iFno != DBG_IDX){ DBG("SLC");} + break; + case SET_CONTROL_LINE_STATE: + if(iFno != DBG_IDX){ DBG("SCLS");} + usbON |= 1 << iFno; // now this interface is connected + break; + case SEND_BREAK: + if(iFno != DBG_IDX){ DBG("B");} + usbON &= ~(1<bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement + break; + default: + EP_WriteIRQ(0, (uint8_t *)0, 0); + } + }else if(rxflag){ // got data over EP0 or host acknowlegement + if(iFno != DBG_IDX){ DBGmesg("rxflag\n");} + //if(endpoints[0].rx_cnt){ + // if(setup_packet->bRequest == SET_LINE_CODING){ + if(iFno != DBG_IDX){ + DBGmesg("USART"); DBGmesg(u2str(iFno + 2 - USART1_EPNO)); + DBGmesg(" speed = "); DBGmesg(u2str(((usb_LineCoding*)ep0databuf)->dwDTERate)); DBGnl(); + } + usart_config(iFno, (usb_LineCoding*)ep0databuf); + // } + //} + } else if(TX_FLAG(epstatus)){ // package transmitted + // now we can change address after enumeration + if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ + USB->DADDR = USB_DADDR_EF | USB_Addr; + } + } + epstatus = KEEP_DTOG(USB->EPnR[0]); + if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission + else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged + // keep DTOGs, clear CTR_RX,TX, set RX VALID + USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; +} + +/** + * Write data to EP buffer (called from IRQ handler) + * @param number - EP number + * @param *buf - array with data + * @param size - its size + */ +void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ + if(size > endpoints[number].txbufsz) size = endpoints[number].txbufsz; + uint16_t N2 = (size + 1) >> 1; + // the buffer is 16-bit, so we should copy data as it would be uint16_t + uint16_t *buf16 = (uint16_t *)buf; +#if defined USB1_16 + // very bad: what if `size` is odd? + uint32_t *out = (uint32_t *)endpoints[number].tx_buf; + for(int i = 0; i < N2; ++i, ++out){ + *out = buf16[i]; + } +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < N2; i++){ + endpoints[number].tx_buf[i] = buf16[i]; + } +#else +#error "Define USB1_16 or USB2_16" +#endif + USB_BTABLE->EP[number].USB_COUNT_TX = size; +} + +/** + * Write data to EP buffer (called outside IRQ handler) + * @param number - EP number + * @param *buf - array with data + * @param size - its size + */ +void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ + EP_WriteIRQ(number, buf, size); + uint16_t status = KEEP_DTOG(USB->EPnR[number]); + // keep DTOGs, clear CTR_TX & set TX VALID to start transmission + USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; +} + +/* + * Copy data from EP buffer into user buffer area + * @param *buf - user array for data + * @return amount of data read + */ +int EP_Read(uint8_t number, uint8_t *buf){ + int sz = endpoints[number].rx_cnt; + if(!sz) return 0; + endpoints[number].rx_cnt = 0; +#if defined USB1_16 + int n = (sz + 1) >> 1; + uint32_t *in = (uint32_t*)endpoints[number].rx_buf; + uint16_t *out = (uint16_t*)buf; + for(int i = 0; i < n; ++i, ++in) + out[i] = *(uint16_t*)in; +#elif defined USB2_16 + // use memcpy instead? + for(int i = 0; i < sz; ++i) + buf[i] = endpoints[number].rx_buf[i]; +#else +#error "Define USB1_16 or USB2_16" +#endif + return sz; +} + diff --git a/F3:F303/Seven_CDCs.deprecated/usb_lib.h b/F3:F303/Seven_CDCs.deprecated/usb_lib.h new file mode 100644 index 0000000..13e45a5 --- /dev/null +++ b/F3:F303/Seven_CDCs.deprecated/usb_lib.h @@ -0,0 +1,167 @@ +/* + * This file is part of the SevenCDCs project. + * Copyright 2023 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 +#include "usbhw.h" + +#define EP0DATABUF_SIZE (64) +#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) + +// bmRequestType & 0x7f +#define STANDARD_DEVICE_REQUEST_TYPE 0 +#define STANDARD_ENDPOINT_REQUEST_TYPE 2 +#define VENDOR_REQUEST_TYPE 0x40 +#define CONTROL_REQUEST_TYPE 0x21 +// bRequest, standard; for bmRequestType == 0x80 +#define GET_STATUS 0x00 +#define GET_DESCRIPTOR 0x06 +#define GET_CONFIGURATION 0x08 +// for bmRequestType == 0 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 // unused +#define SET_ADDRESS 0x05 +#define SET_DESCRIPTOR 0x07 // unused +#define SET_CONFIGURATION 0x09 +// for bmRequestType == 0x81, 1 or 0xB2 +#define GET_INTERFACE 0x0A // unused +#define SET_INTERFACE 0x0B // unused +#define SYNC_FRAME 0x0C // unused +#define VENDOR_REQUEST 0x01 // unused + +// Class-Specific Control Requests +#define SEND_ENCAPSULATED_COMMAND 0x00 // unused +#define GET_ENCAPSULATED_RESPONSE 0x01 // unused +#define SET_COMM_FEATURE 0x02 // unused +#define GET_COMM_FEATURE 0x03 // unused +#define CLEAR_COMM_FEATURE 0x04 // unused +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// control line states +#define CONTROL_DTR 0x01 +#define CONTROL_RTS 0x02 + +// string descriptors +enum{ + iLANGUAGE_DESCR, + iMANUFACTURER_DESCR, + iPRODUCT_DESCR, + iSERIAL_DESCR, + iINTERFACE_DESCR_CMD, + iINTERFACE_DESCR_DBG, + iINTERFACE_DESCR_USART1, + iINTERFACE_DESCR_USART2, + iINTERFACE_DESCR_USART3, + iINTERFACE_DESCR_USART4, + iINTERFACE_DESCR_CAN, + iDESCR_AMOUNT +}; + +// Types of descriptors +#define DEVICE_DESCRIPTOR 0x01 +#define CONFIGURATION_DESCRIPTOR 0x02 +#define STRING_DESCRIPTOR 0x03 +#define DEVICE_QUALIFIER_DESCRIPTOR 0x06 + +#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) +#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) +#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP) + +// EPnR bits manipulation +#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) +#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) + +// EP types +#define EP_TYPE_BULK 0x00 +#define EP_TYPE_CONTROL 0x01 +#define EP_TYPE_ISO 0x02 +#define EP_TYPE_INTERRUPT 0x03 + +#define LANG_US (uint16_t)0x0409 + +#define _USB_STRING_(name, str) \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString[(sizeof(str) - 2) / 2]; \ + \ +} \ +name = {sizeof(name), 0x03, str} + +#define _USB_LANG_ID_(name, lng_id) \ + \ +static const struct name \ +{ \ + uint8_t bLength; \ + uint8_t bDescriptorType; \ + uint16_t bString; \ + \ +} \ +name = {0x04, 0x03, lng_id} + +// EP0 configuration packet +typedef struct { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} config_pack_t; + +// endpoints state +typedef struct{ + uint16_t *tx_buf; // transmission buffer address + uint16_t txbufsz; // transmission buffer size + uint8_t *rx_buf; // reception buffer address + void (*func)(uint8_t epno); // endpoint action function + unsigned rx_cnt : 10; // received data counter +} ep_t; + +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; + #define USB_CDC_1_STOP_BITS 0 + #define USB_CDC_1_5_STOP_BITS 1 + #define USB_CDC_2_STOP_BITS 2 + uint8_t bParityType; + #define USB_CDC_NO_PARITY 0 + #define USB_CDC_ODD_PARITY 1 + #define USB_CDC_EVEN_PARITY 2 + #define USB_CDC_MARK_PARITY 3 + #define USB_CDC_SPACE_PARITY 4 + uint8_t bDataBits; +} __attribute__ ((packed)) usb_LineCoding; + +extern ep_t endpoints[]; +// device disconnected from terminal (BIT flags!!!) +#define USBON(ifno) (usbON & (1<LAk{cN+KQd&34(?x3I&|nx$|8U z&?%$sh|-R)+Of4WwVhT4bXv#yh1!=>owZB+I> z`;N3txOq=QoNYUw;*1hBM<0zZ)u>$5Y}&ht(aY3~JekqG!hh$c%|DhI^9r%5U@?t2 zBqGBV`K7juYf|0^GBOLSg!1AD_D!dd}u|koU}Ns&#(e}>*;wS@W__yg<*)} zW@@Hd{OCs;#C`V9WR?9RS=IOs%>12rQ9OB7s;4;ee^57sxVs+YtSUgx*~e1Nh>Nd? zDJ`y8&OUTus=2sA!;EiVS&>{sOObRe#y)#44RcY@a9>-lcFSp7r%mh)qqKFnxuGBy zB;1UmJ=t$xR_V7dNtPm*;?iiKj$)y$vn_z879!K?k2DIiJEtt1VsQvYL6e^1)Fi*rViFRBK!5MugI53TU zYCDmkJ5bucT#bUugA!B%-Vx|OeHZWXd!mFOR$f~Va+0+pJu)odBN5*at;Ta%U3|xt ztF-jMIAvTMeX3!MNu6-ObG}8bi|Pn3Jk>yA4W52^}EbQeJzoQ-tzT!4|R?nddB>qh2ASC)?GpmG`|%)}8bSe!xTj}V8viKTjJVhMv28@nqo}* z&cgTPo7|ZSTG~kO;aL|i*(sFtdFk`=e*Gp%Ptn~vMcRcOMQMh-;Lh1vRPQ$|jTSW| z@}Hm1oN2!zC!hL2)`&zel=89blC07f#Fv0>OwLBlJ1|0fpI81=7}oB$pj}(bVb2EB z&kH}QXomU8>`nZcq1jKBLWa

`7tYZ9gA2PMSg?X@?!BA*s%ebO+qO^+YN5UwFmy zo_tjEVQ&Feq*Brp+H(EeMBIUOjEh8jpg;c3uRS~EW<58T)+vL#XGwvYdf14P9I{`J zGB^4+9=_&z()6C(!u>}K@;V}(8mPNlFZ;W}6FFz)*?N@bbz!eVy-bh1TU1}jw;L_j zx2WmvKtC72DGC=*^as3QbePT{_&d#Jc(?B{l5x$5aTSa&hVjtMD2vR@AAZMUFn#F# z5UY$?koi8nO{fnYe$AsyX?8zkM!WXO3XY728&ArN<_R&@v8S5wOg+5KgLDi0lMj=% zDRdkC@rRYZBPh^+{mw*BYjcR&=Thlrf~Pn7)rU_sJZz(MDNZV>IDUx+r!h{Hs21ak zmWp?K2sf+Ky2607?+{o*e?_ip)E2!dLn507c`QY0`Lm4dC;>kh=-+l*bzGI%=f+7S zIxh7P{x{{D`Y(FO99X9nQk*z3y7@hj4i_17vG|uBlFOXVKp>dQ;f&k{eJEMDZfFd& zsS!}aK(3=FNk?~`d6WO6Gd^x!+?TPe@Wf;$?j=68E3LIFu8BYBj21F&=4QNLzA-}h zubA;N4p+!H@&m~AO?=qJ6kE6v&yF%i%h-${%WMU@*H&(eHhM*`Z7WZ8d2K7S*F=pF z%ngY{PiMw8IWKi#X3TG7RaW%z-^eH{{P@YMay=tVHNjf~{b@i!x@ zaZVHe3G~li*2UrklvppTqToH@1S02Ex{>aCKMy5t0?8G&yj$C<)rLC1VM#HZ=<@xu zTsrEyM&&7l1N;eRl?}zk#I?ofTmNsv@OBhn`3*&ix@mR-l!sW z)q!1S8~{1OziNn|3G$0Vi};mC6#nIb{FOUx5#&Es0Vgsew9As6)H@1aH`;WB*zHa9 zK3FUsEcOY+Nx7g&4D|mdpf$srJ;}%lO|Uz+Hlvh@uCZNsW_L@u@ODd}KQK7ocx)9z zvW_Ft9B+IHxaJ$lPHi2c&NsF`tS0mf^&a-%0yKHO5iDP_9JX<&cIzQq#1UN9;IJ)>((M&=S2k<=&ug6dr&eLI_J0T zla+e4u0J^L4~~}vq~Q1#dB6~?1-8LTX8v`A&VXo0Gq0#P(-I}AaDkiDYtqqI5aY8O znZEapPfSj3(Y41G zQwXPsa!Or<4=b5$>_t%9jn42(8AT;Q zgor&;r6cTSzhU`Qc*9U<;OTX;>X|wi|BUE8RKtl3)W@kvYO)inFItonQ-6ebnSuJF z#PxuH(w=e^7X1w@36X+c_jRi%ubonU)0n36ZldrG%k@oRdxR4L;W*$`2W`EoBPW(% zAYHC&t~t!hAh3R-3goq-OO_U+3=c$D8$_5(zQMWVtFR08UFWqxSq$8)3Zk=J{*uFU z&S_Cv`elgIs^a{E&SC-0_#7l3_@+@!;uCET^f%u@DQGvmRXuR|gcpTl<8gPCjOVF! zIv3_bzCuG!m;7ZFnPX79H|F#9-+A6})bW7%eH!_vun zTa33RTetGK6LVDsnT68P4}EA=#-p^iF6kA%b%x%~L)W^MTc z3c7vTqUl9H5sSs7qVu-DE1|--kVcJez z$5_9aPcUAFn&n#$;z*r!wm&chtgZ^)a5>75gxBQ%;aA`Og{e>&Nb7Ys%QujiKi>63{C@u1%OtmaCRb(2CnFY)F{>?~ z_)sb1txG;I$jmGa`wVc;!RbsmzV1?(kW_M8J~^}&;x|~2bKV~lYcb*?%@%(Z^^x4b zA*Zv~vd!6Bxh>orQMi>?oC`04YCN2Vwi~i-m^rMdiD%BC1fal4IOs-Fgp9sM5DKAO z#!W&hveu4qB(K>`e?GF^j1t)G#kNF=riw+<8z)6XhPz%UWV(?v^v1Z@Jve&{&+h0u zzuBy{p@c-qUabXgt?gy3Zg&*Yz^k=2Vy68b=dJTU4|4K;dv=KPC0c#qXG5GjXy(E& zXLVtvS#5j9lqfww@zQuoEj}TVS)jrknq@myUsy9FyAzL;wVFe^lSnHTwNDc%4W(U0 zRzgV;lqxO4wW5#>t|jz7yc+-c<>tpsj};Y*C_$MhCEMjB!){S42Kv9dYc5(^p672% zT59EQYHE-Z&%N!oNR7P3zb@fNB}L|F(IRbJZ1LL@8b!k47Vq=q87*<;ud+rbseU$P zfmE&md}tTp4qnn=C7!(JN6KgCsXi+EVbk{Vhaa6|&Xq9UZpF4-iNjcQmt!v1kFeXy zm4?u>P5Pqjg&Bp>rTe{x@zG^~y83+S8-4#=wzL$`Mb;NVPb{50?|_e0HHh>ywmUx` zVxfZeCDPHZ3FKr>>vK^)Dk4UpW$G;B&5uG-@*ph?^LgDnL2KNEbOx!t4z$m+NcNH| z@{>pQSS^xL9c8|eLpSY&x(?|EU7AHGd0IEpPzL)q4?>ht2E-K2Z=*$Ai3TEbQ0T-QHWbc;vE{E`Fg&>H(rtMdL;JcV7~5iJvFdNHb7R(9ef$8 zE~3#*2h>+=crYiIHj;|!pOAyW4%N!H^up7t1O1x^smY%}UG=xi20{5&p#O{8_mIy) zhDEy9Tst8nAl*I}Icvuc?v%%7(NcgR=&#$m#53|Gu1mhKxJ&Lpn|UNn zsWbH29bK|ZJjUB^{sMYuH9ws^)~N6W=BbSz`tVq)`=xv&RXWCcDGWQaQk{9rjZ)ig zzUz3AKkWobJ@#ShbuUYucAkrA>9cP{y{8?=OhnJrL6o$MhdK3z-d&C{zBnp+**-ZQ zv{~Rc9abKsnvnF<0h~hZE$+;R+xVXx<)CM?W1l<;c#w3+p?GVIZxYn^(`3jW((eId z64eNLzvfWvQ)Hl<`y7uXAZhLZ8Qtl~+d!n69L9L28){^@(IV*u2d9%e;rx+i4QNu( z%}tJQFN=BfGc3C$uh8mIM~3-1Q~{WpJ168? z9O!>k4)m+<*npzE(*+q7=`0eW+HS6JJTD*S4AKgRKB>g?ynG0%?pwFjoVbYi9qLS# ze(Fy^>c;I9h_Ud&M<5ni=RH9C$5XcH>!U?rW$r z{R0nWD14ma@9yV%76HcRx8Y6)wpV~IAHy7h{(lWr^aT1Z++F~qCxVoV1FL%ATmUT= z+(sz|>8gFUN%D~KKiqz-r|a6vBx=qc-q0)Aan22hzN#z=&X?JR;pLMQO#4G-vq<|I za?IjPbC>OsQq>OUX+n-UR;2snoGx33QofK;s5jBC&P+ZlhL=;uJPFfNOyO3-2j3%C zPBTxicfkp*XrFptstcr|8}_#B;|)@aeG(wAR3hI#dz|@~{3Q`G1@#ZNR){MfYf1vN zXzMPIPT0j8FGK8$c&^@<19z!UeOQ6JckvIqeB{wC_^o+f+zY7A1{fX2ll zl^)t%$OS(Gx)J&n(5j%3yg|-wa%PjW&uWHUj%lw0tAxA#{|R^G0r%Wk@G2&^Ah2O} zXm4K|(Da}rvS(m#X+nF~1oX~lt_kiwFpBE5d!f=o!Ck$Z-{^n!-9ppd{>6a3 zz<=nF0R1B9``vH$KN_4>lx-r_3$fW<;`N-5Jw&UwJu^(-z*iy?2gJjH{)Y!Cfk=lR zo@Tn%vyvwhkT>$FuvAun+f|0tfzlWFcOJ?}g131G zCvWeGfAos{izAU|&&Zkd896(eJ`1_qct(CONk5fj@H6t9oHO!#7~`Y2%IQljl0yBu z^?|R*Sv0mV()_uN@^_a+=baG=1v&3PZAEf3@nbjmPaN{oVt59?hveJTLHIsM@;rkE zSdzol#_c@v1#*zPsz7rLDqk~X2g`P-O*AL}+(HZR(+43T5Gu4%1W-Ha@`t`TwhaGy{dBE>ZfXc{s_TQuUcPSUAC^4(8^0U1Zm~#Y5~T& zstm@BmPON-aSL;o<(U%5#EYvd*KlRk)ug`+xNWtyRW);F%ve)iYg=EExvFyQjIz?w z=gQX3sHt6>lU-w7TUAk3Go!Y;tZc?wYYhO;5OU@SIr^L#h4-f6E3MU~u!Qo8(xjPL zoPo>MXFr&s&(6roR+n-aT8Q&d)4*OYN7&z9F#uCL`bq!I&FuB&*Ct0MFbY9R<)zOKBM z3tD2$`f6)!dF8qqZgq9#+M&sp08>rn>RM2srmR-Il)M6R8Mm(NSpcdArC@zEM6t>t zk!8SB1%3e7ke#_@Yio$@)}r;O0@b2&RD~*0HT3e3fWX1<8;3RcTMBFH8N=gJ2!Uah?3NG$dk>*L zgg}Q76hjE0E-0hCkDwevP$-q`))0d79>S&&0uw?|4I!w42&(%CVM7S2FeUp!2qEkq z!sZYH8$wVIA*h20VfPWjhY-}^O7_JN0$4p{$zO&L6d{C&A%ut^g8Dwfm?4CSF-rE= zA%rpa5S|YqD9HoG!@UE_LX{u>u5cBa2z6f_v^SuA3hgR1HRP0ZXljK9916h!auGCq zeuYCJ6F!D&=;dfB;!y^~kP%u8U4}~G-*a$e)F3OwS0+T*dc@FSi~(fPDT1K-KRgf$ z{4c)_@@;}Zj`(%3qtFzi(3GRl;MDs89{jcL2Q>94wD3`A5u?z?j6xeb3N3OJnr0MQ z)DLOo56i@CH^BBas03OW_@Nv;QW5mru(^IX4xhM(hewgm{x{<}|7LvVDC2o37cCkw z>u@)u-%_*~6%G?e^d^#DLaCam})-ZWQZzMNh$BuCCL cc|>m{$IKD*;qFL|S;OQJy^$PngB$ht-ze}QfdBvi literal 0 HcmV?d00001 diff --git a/F3:F303/Seven_CDCs/Makefile b/F3:F303/Seven_CDCs/Makefile index a597ea5..05943dd 100644 --- a/F3:F303/Seven_CDCs/Makefile +++ b/F3:F303/Seven_CDCs/Makefile @@ -1,6 +1,6 @@ -BINARY := sevenCDCs +BINARY := 7DCD_template # MCU code -MCU := F303xb +MCU := F303xc # change this linking script depending on particular MCU model, LDSCRIPT := stm32f303xB.ld DEFINES := -DUSB1_16 diff --git a/F3:F303/Seven_CDCs/Readme.md b/F3:F303/Seven_CDCs/Readme.md new file mode 100644 index 0000000..3c26f1d --- /dev/null +++ b/F3:F303/Seven_CDCs/Readme.md @@ -0,0 +1,4 @@ +Template for 7 CDCs +==================================== + +Just simple template for empty CDCs based on InterfaceBoard. diff --git a/F3:F303/Seven_CDCs/flash.c b/F3:F303/Seven_CDCs/flash.c new file mode 100644 index 0000000..7f62333 --- /dev/null +++ b/F3:F303/Seven_CDCs/flash.c @@ -0,0 +1,191 @@ +/* + * This file is part of the multiiface project. + * Copyright 2025 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 "strfunc.h" +#include "usb_dev.h" // printout +#include "usb_descr.h" // descriptors +#include // memcpy + +extern const uint32_t _BLOCKSIZE; +extern const user_conf __varsstart; +static const uint32_t FLASH_blocksize = (uint32_t)&_BLOCKSIZE; +static uint32_t maxCnum = 2048 / sizeof(user_conf); // can't use blocksize here + +static int write2flash(const void*, const void*, uint32_t); +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.", + [ISPI] = u"usbSPI", + [ICAN] = u"usbCAN" + }, + .iIlengths = {22,22,22,22,22,12,12}, +}; + +int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * any struct searched should have its sizeof() @ the first field!!! + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @param start - starting address + * @param stor_size - size of structure to search + * @return index of non-empty cell or -1 + */ +static int binarySearch(int r, const uint8_t *start, int stor_size){ + int l = 0; + while(r >= l){ + int mid = l + (r - l) / 2; + const uint8_t *s = start + mid * stor_size; + if(*((const uint16_t*)s) == stor_size){ + if(*((const uint16_t*)(s + stor_size)) == 0xffff){ // next is free + return mid; + }else{ // element is to the right + l = mid + 1; + } + }else{ // element is to the left + r = mid - 1; + } + } + return -1; // not found +} + +/** + * @brief flashstorage_init - initialization of user conf storage + * run in once @ start + */ +void flashstorage_init(){ + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; + maxCnum = flsz / sizeof(user_conf); + } + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } +} + +// store new configuration +// @return 0 if all OK +int store_userconf(){ + // maxnum - 3 means that there always should be at least one empty record after last data + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > (int)maxCnum - 3){ // there's no more place + currentconfidx = 0; + if(erase_storage(-1)) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) + return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){ + int ret = 0; + if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while (FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; // clear all flags + FLASH->CR |= FLASH_CR_PG; + const uint16_t *data = (const uint16_t*) wrdata; + volatile uint16_t *address = (volatile uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; + for(i = 0; i < count; ++i){ + *(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]){ + CFGWR("DON'T MATCH!\n"); + ret = 1; + break; + } + if(FLASH->SR & FLASH_SR_PGERR){ + CFGWR("Prog err\n"); + ret = 1; // program error - meet not 0xffff + break; + } + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; + } + FLASH->CR &= ~(FLASH_CR_PG); + return ret; +} + +// erase Nth page of flash storage (flash should be prepared!) +static int erase_pageN(int N){ + int ret = 0; +#ifdef EBUG + CFGWR("Erase page #"); CFGWRn(u2str(N)); +#endif + FLASH->AR = (uint32_t)Flash_Data + N*FLASH_blocksize; + FLASH->CR |= FLASH_CR_STRT; + while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP; + if(FLASH->SR & FLASH_SR_WRPERR){ /* Check Write protection error */ + ret = 1; + FLASH->SR = FLASH_SR_WRPERR; /* Clear the flag by software by writing it at 1*/ + } + return ret; +} + +// erase full storage (npage < 0) or its nth page; @return 0 if all OK +int erase_storage(int npage){ + int ret = 0; + uint32_t end = 1, start = 0, flsz = 0; + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)Flash_Data - FLASH_BASE; + } + end = flsz / FLASH_blocksize; +#ifdef EBUG + 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; + start = npage; + end = start + 1; + } + if((FLASH->CR & FLASH_CR_LOCK) != 0){ + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while(FLASH->SR & FLASH_SR_BSY) IWDG->KR = IWDG_REFRESH; + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; + FLASH->CR |= FLASH_CR_PER; + for(uint32_t i = start; i < end; ++i){ + if(erase_pageN(i)){ + ret = 1; + break; + } + } + FLASH->CR &= ~FLASH_CR_PER; + return ret; +} + diff --git a/F3:F303/Seven_CDCs/flash.h b/F3:F303/Seven_CDCs/flash.h new file mode 100644 index 0000000..e8ff614 --- /dev/null +++ b/F3:F303/Seven_CDCs/flash.h @@ -0,0 +1,47 @@ +/* + * This file is part of the multiiface project. + * Copyright 2025 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 +#include "usb_descr.h" + +// register with flash size (in blocks) +#ifndef FLASH_SIZE_REG +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7CC) +#endif +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +// maximal size (in letters) of iInterface for settings +#define MAX_IINTERFACE_SZ (16) + +/* + * struct to save user configurations + */ +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]; +} user_conf; + +extern user_conf the_conf; +extern int currentconfidx; + +void flashstorage_init(); +int store_userconf(); +int erase_storage(int npage); diff --git a/F3:F303/Seven_CDCs/hardware.c b/F3:F303/Seven_CDCs/hardware.c index 44dc333..c3634a9 100644 --- a/F3:F303/Seven_CDCs/hardware.c +++ b/F3:F303/Seven_CDCs/hardware.c @@ -1,6 +1,6 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2023 Edward V. Emelianov . + * 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 @@ -17,46 +17,23 @@ */ #include "hardware.h" -#include "usart.h" - -TRUE_INLINE void iwdg_setup(){ - uint32_t tmout = 16000000; - /* Enable the peripheral clock RTC */ - /* (1) Enable the LSI (40kHz) */ - /* (2) Wait while it is not ready */ - RCC->CSR |= RCC_CSR_LSION; /* (1) */ - while((RCC->CSR & RCC_CSR_LSIRDY) != RCC_CSR_LSIRDY){if(--tmout == 0) break;} /* (2) */ - /* Configure IWDG */ - /* (1) Activate IWDG (not needed if done in option bytes) */ - /* (2) Enable write access to IWDG registers */ - /* (3) Set prescaler by 64 (1.6ms for each tick) */ - /* (4) Set reload value to have a rollover each 2s */ - /* (5) Check if flags are reset */ - /* (6) Refresh counter */ - IWDG->KR = IWDG_START; /* (1) */ - IWDG->KR = IWDG_WRITE_ACCESS; /* (2) */ - IWDG->PR = IWDG_PR_PR_1; /* (3) */ - IWDG->RLR = 1250; /* (4) */ - tmout = 16000000; - while(IWDG->SR){if(--tmout == 0) break;} /* (5) */ - IWDG->KR = IWDG_REFRESH; /* (6) */ -} +uint8_t Config_mode = 0; static inline void gpio_setup(){ - RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; - // USB - alternate function 14 @ pins PA11/PA12; USART1 = AF7 @PA9/10; SWD - AF0 @PA13/14 - GPIOA->AFR[1] = AFRf(7, 9) | AFRf(7, 10) | AFRf(14, 11) | AFRf(14, 12); - // USART1: PA10(Rx), PA9(Tx); USB - PA11, PA12; SWDIO - PA13, PA14; Pullup - PA15 - GPIOA->MODER = MODER_AF(9) | MODER_AF(10) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15); + 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); + // 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); - // LEDs on PB0 and PB1 - GPIOB->MODER = GPIO_MODER_MODER0_O | GPIO_MODER_MODER1_O; - GPIOB->ODR = 1; + GPIOA->PUPDR = PUPD_PU(9); + for(int i = 0; i < 10000; ++i) nop(); + if(CFG_ON()) Config_mode = 1; } void hw_setup(){ gpio_setup(); - iwdg_setup(); } diff --git a/F3:F303/Seven_CDCs/hardware.h b/F3:F303/Seven_CDCs/hardware.h index 82cd0ce..8dd6707 100644 --- a/F3:F303/Seven_CDCs/hardware.h +++ b/F3:F303/Seven_CDCs/hardware.h @@ -1,6 +1,6 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2023 Edward V. Emelianov . + * 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 @@ -17,18 +17,20 @@ */ #pragma once -#ifndef __HARDWARE_H__ -#define __HARDWARE_H__ #include #define USBPU_port GPIOA -#define USBPU_pin (1<<15) +#define USBPU_pin (1<<10) #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(); -#endif // __HARDWARE_H__ diff --git a/F3:F303/Seven_CDCs/main.c b/F3:F303/Seven_CDCs/main.c index a286234..7f1ed6b 100644 --- a/F3:F303/Seven_CDCs/main.c +++ b/F3:F303/Seven_CDCs/main.c @@ -1,6 +1,6 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2023 Edward V. Emelianov . + * This file is part of the multiiface project. + * Copyright 2025 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 @@ -15,15 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -#include "can.h" -#include "canproto.h" -#include "cmdproto.h" -#include "debug.h" +#include "flash.h" #include "hardware.h" -#include "strfunc.h" -#include "usart.h" -#include "usb.h" +#include "proto.h" +#include "usb_dev.h" #define MAXSTRLEN RBINSZ @@ -33,76 +28,40 @@ void sys_tick_handler(void){ ++Tms; } -static const char *ebufovr = "ERROR: USB buffer overflow or string was too long\n"; -static const char *idxnames[MAX_IDX] = {"CMD", "DBG", "USART1", "USART2", "USART3", "NOFUNCT", "CAN"}; - int main(void){ char inbuff[MAXSTRLEN+1]; - USBPU_OFF(); if(StartHSE()){ SysTick_Config((uint32_t)72000); // 1ms }else{ StartHSI(); SysTick_Config((uint32_t)48000); // 1ms } + flashstorage_init(); hw_setup(); - usarts_setup(); + USBPU_OFF(); USB_setup(); - CAN_setup(100); + //uint32_t ctr = Tms; USBPU_ON(); - - CAN_message *can_mesg; - uint32_t ctr = Tms; + int maxno = (Config_mode) ? ICFG : InterfacesAmount; while(1){ - IWDG->KR = IWDG_REFRESH; - if(Tms - ctr > 499){ - ctr = Tms; - pin_toggle(GPIOB, 1 << 1 | 1 << 0); // toggle LED @ PB0 - //USB_sendstr(CMD_IDX, "1"); - //DBGmesg(u2str(Tms)); - //DBGnl(); + // Put here code working WITOUT USB connected + if(!usbON) continue; + for(int i = 0; i < maxno; ++i){ // just echo for first time + if(!CDCready[i]) continue; + int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN); + if(l) USB_send(i, (uint8_t*)inbuff, l); } - can_proc(); - if(CAN_get_status() == CAN_FIFO_OVERRUN){ - USB_sendstr(CAN_IDX, "CAN bus fifo overrun occured!\n"); - } - while((can_mesg = CAN_messagebuf_pop())){ - if(isgood(can_mesg->ID)){ - if(ShowMsgs){ // display message content - IWDG->KR = IWDG_REFRESH; - uint8_t len = can_mesg->length; - USB_sendstr(CAN_IDX, u2str(Tms)); - USB_sendstr(CAN_IDX, " #"); - USB_sendstr(CAN_IDX, uhex2str(can_mesg->ID)); - for(uint8_t i = 0; i < len; ++i){ - USB_putbyte(CAN_IDX, ' '); - USB_sendstr(CAN_IDX, uhex2str(can_mesg->data[i])); - } - USB_putbyte(CAN_IDX, '\n'); - } - } - } - for(int i = 0; i < MAX_IDX; ++i){ - int l = USB_receivestr(i, inbuff, MAXSTRLEN); - if(l < 0){ - USB_sendstr(DBG_IDX, ebufovr); - if(i == CMD_IDX) USB_sendstr(CMD_IDX, ebufovr); - continue; - } - if(l == 0) continue; - USB_sendstr(DBG_IDX, idxnames[i]); - USB_sendstr(DBG_IDX, "> "); - USB_sendstr(DBG_IDX, inbuff); - USB_putbyte(DBG_IDX, '\n'); - switch(i){ - case CMD_IDX: - parse_cmd(inbuff); - break; - case CAN_IDX: - cmd_parser(inbuff); - break; - default: - break; + // and here is code what should run when USB connected + if(Config_mode && CDCready[ICFG]){ + /*if(Tms - ctr > 999){ + ctr = Tms; + CFGWR("I'm alive\n"); + }*/ + 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) CFGWRn(ans); } } } diff --git a/F3:F303/Seven_CDCs/multiiface.cflags b/F3:F303/Seven_CDCs/multiiface.cflags new file mode 100644 index 0000000..68d5165 --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.cflags @@ -0,0 +1 @@ +-std=c17 \ No newline at end of file diff --git a/F3:F303/Seven_CDCs/multiiface.config b/F3:F303/Seven_CDCs/multiiface.config new file mode 100644 index 0000000..1aff3d9 --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.config @@ -0,0 +1,8 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 +#define EBUG +#define STM32F3 +#define STM32F303xb +#define __thumb2__ 1 +#define __ARM_ARCH_7M__ +#define USB1_16 diff --git a/F3:F303/Seven_CDCs/multiiface.creator b/F3:F303/Seven_CDCs/multiiface.creator new file mode 100644 index 0000000..e94cbbd --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.creator @@ -0,0 +1 @@ +[General] diff --git a/F3:F303/Seven_CDCs/multiiface.creator.user b/F3:F303/Seven_CDCs/multiiface.creator.user new file mode 100644 index 0000000..f8feebc --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.creator.user @@ -0,0 +1,214 @@ + + + + + + EnvironmentId + {7bd84e39-ca37-46d3-be9d-99ebea85bc0d} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + true + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + KOI8-R + false + 4 + false + 0 + 80 + true + true + 1 + 0 + false + true + false + 0 + true + true + 0 + 8 + true + false + 1 + true + false + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + false + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 2 + false + + + + true + + 0 + + + + ProjectExplorer.Project.Target.0 + + Desktop + true + Desktop + Desktop + {65a14f9e-e008-4c1b-89df-4eaa4774b6e3} + 0 + 0 + 0 + + /Big/Data/00__Electronics/STM32/F303-nolib/blink + + + + all + + true + GenericProjectManager.GenericMakeStep + + 1 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + + clean + + true + GenericProjectManager.GenericMakeStep + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Default + GenericProjectManager.GenericBuildConfiguration + 0 + 0 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + false + -e cpu-cycles --call-graph dwarf,4096 -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + + true + true + + 1 + + 1 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + true + + 2 + + false + -e cpu-cycles --call-graph dwarf,4096 -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + + true + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + Version + 22 + + diff --git a/F3:F303/Seven_CDCs/multiiface.cxxflags b/F3:F303/Seven_CDCs/multiiface.cxxflags new file mode 100644 index 0000000..6435dfc --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.cxxflags @@ -0,0 +1 @@ +-std=c++17 \ No newline at end of file diff --git a/F3:F303/Seven_CDCs/multiiface.files b/F3:F303/Seven_CDCs/multiiface.files new file mode 100644 index 0000000..6203f9c --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.files @@ -0,0 +1,20 @@ +flash.c +flash.h +hardware.c +hardware.h +main.c +proto.c +proto.h +ringbuffer.c +ringbuffer.h +strfunc.c +strfunc.h +usb.c +usb.h +usb_descr.c +usb_descr.h +usb_dev.c +usb_dev.h +usb_lib.c +usb_lib.h +usbhw.h diff --git a/F3:F303/Seven_CDCs/multiiface.includes b/F3:F303/Seven_CDCs/multiiface.includes new file mode 100644 index 0000000..06d1130 --- /dev/null +++ b/F3:F303/Seven_CDCs/multiiface.includes @@ -0,0 +1,6 @@ +. +../inc +../inc/Fx +../inc/cm +../inc/ld +../inc/startup diff --git a/F3:F303/Seven_CDCs/openocd.cfg b/F3:F303/Seven_CDCs/openocd.cfg index 0210594..7ee51bf 100644 --- a/F3:F303/Seven_CDCs/openocd.cfg +++ b/F3:F303/Seven_CDCs/openocd.cfg @@ -1,4 +1,4 @@ -set FLASH_SIZE 0x20000 +set FLASH_SIZE 0x40000 source [find interface/stlink-v2-1.cfg] source [find target/stm32f3x.cfg] diff --git a/F3:F303/Seven_CDCs/proto.c b/F3:F303/Seven_CDCs/proto.c new file mode 100644 index 0000000..660eb49 --- /dev/null +++ b/F3:F303/Seven_CDCs/proto.c @@ -0,0 +1,136 @@ +/* + * 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 + +#include "flash.h" +#include "strfunc.h" +#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) +// local buffer for I2C data to send +//static uint8_t locBuffer[LOCBUFFSZ]; +extern volatile uint32_t Tms; + +const char *helpstring = + "https://github.com/eddyem/stm32samples/tree/master/F3:F303/InterfaceBoard build#" BUILD_NUMBER " @ " BUILD_DATE "\n" + "d - dump flash\n" + "ix - rename interface number x (0..6)\n" + "Ex - erase full storage (witout x) or only page x\n" + "F - reinit configurations from flash\n" + "R - soft reset\n" + "S - store new parameters into flash\n" + "T - print current Tms\n" +; + +static void dumpflash(){ + CFGWR("userconf_sz="); CFGWR(u2str(the_conf.userconf_sz)); + CFGWR("\ncurrentconfidx="); CFGWRn(i2str(currentconfidx)); + for(int i = 0; i < InterfacesAmount; ++i){ + 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(ICFG, *ptr); + ptr += 2; + } + CFGn(); + } +} + +static void setiface(const char *str){ + if(!str || !*str) goto err; + uint32_t N; + const char *nxt = getnum(str, &N); + if(!nxt || nxt == str || N >= InterfacesAmount) goto err; + nxt = strchr(nxt, '='); + if(!nxt || !*(++nxt)) goto err; + nxt = omit_spaces(nxt); + if(!nxt || !*nxt) goto err; + int l = strlen(nxt); + if(l > MAX_IINTERFACE_SZ) goto err; + the_conf.iIlengths[N] = (uint8_t) l * 2; + char *ptr = (char*)the_conf.iInterface[N]; + for(int i = 0; i < l; ++i){ + *ptr++ = *nxt++; + *ptr++ = 0; + } + CFGWR(sOKn); + return; +err: + CFGWR(sERRn); +} + +static const char* erpg(const char *str){ + uint32_t N; + if(str == getnum(str, &N)) return sERRn; + if(erase_storage(N)) return sERRn; + return sOKn; +} + +const char *parse_cmd(const char *buf){ + if(!buf || !*buf) return NULL; + if(strlen(buf) > 1){ + // "long" commands + char c = *buf++; + switch(c){ + case 'E': + return erpg(buf); + case 'i': + setiface(buf); + return NULL; + break; + default: + return buf-1; // echo wrong data + } + } + // "short" commands + switch(*buf){ + case 'd': + dumpflash(); + break; + case 'E': + if(erase_storage(-1)) return sERRn; + return sOKn; + break; + case 'F': + flashstorage_init(); + return sOKn; + case 'R': + NVIC_SystemReset(); + return NULL; + case 'S': + if(store_userconf()) return sERRn; + return sOKn; + case 'T': + CFGWR("T="); + CFGWRn(u2str(Tms)); + break; + default: // help + CFGWR(helpstring); + break; + } + return NULL; +} diff --git a/F3:F303/Seven_CDCs/proto.h b/F3:F303/Seven_CDCs/proto.h new file mode 100644 index 0000000..7306aba --- /dev/null +++ b/F3:F303/Seven_CDCs/proto.h @@ -0,0 +1,22 @@ +/* + * 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/Seven_CDCs/ringbuffer.c b/F3:F303/Seven_CDCs/ringbuffer.c index d7b4ced..b0ffe8e 100644 --- a/F3:F303/Seven_CDCs/ringbuffer.c +++ b/F3:F303/Seven_CDCs/ringbuffer.c @@ -1,6 +1,5 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 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 @@ -18,19 +17,21 @@ #include "ringbuffer.h" -// stored data length -int RB_datalen(ringbuffer *b){ +static int datalen(ringbuffer *b){ if(b->tail >= b->head) return (b->tail - b->head); else return (b->length - b->head + b->tail); } -/** - * @brief RB_hasbyte - check if buffer has given byte stored - * @param b - buffer - * @param byte - byte to find - * @return index if found, -1 if none - */ -int RB_hasbyte(ringbuffer *b, uint8_t byte){ +// stored data length +int RB_datalen(ringbuffer *b){ + if(b->busy) return -1; + b->busy = 1; + int l = datalen(b); + b->busy = 0; + return l; +} + +static int hasbyte(ringbuffer *b, uint8_t byte){ if(b->head == b->tail) return -1; // no data in buffer int startidx = b->head; if(b->head > b->tail){ // @@ -43,6 +44,20 @@ int RB_hasbyte(ringbuffer *b, uint8_t byte){ return -1; } +/** + * @brief RB_hasbyte - check if buffer has given byte stored + * @param b - buffer + * @param byte - byte to find + * @return index if found, -1 if none or busy + */ +int RB_hasbyte(ringbuffer *b, uint8_t byte){ + if(b->busy) return -1; + b->busy = 1; + int ret = hasbyte(b, byte); + b->busy = 0; + return ret; +} + // poor memcpy static void mcpy(uint8_t *targ, const uint8_t *src, int l){ while(l--) *targ++ = *src++; @@ -54,15 +69,8 @@ TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ if(*what >= b->length) *what -= b->length; } -/** - * @brief RB_read - read data from ringbuffer - * @param b - buffer - * @param s - array to write data - * @param len - max len of `s` - * @return bytes read - */ -int RB_read(ringbuffer *b, uint8_t *s, int len){ - int l = RB_datalen(b); +static int read(ringbuffer *b, uint8_t *s, int len){ + int l = datalen(b); if(!l) return 0; if(l > len) l = len; int _1st = b->length - b->head; @@ -78,35 +86,50 @@ int RB_read(ringbuffer *b, uint8_t *s, int len){ return _1st; } +/** + * @brief RB_read - read data from ringbuffer + * @param b - buffer + * @param s - array to write data + * @param len - max len of `s` + * @return bytes read or -1 if busy + */ +int RB_read(ringbuffer *b, uint8_t *s, int len){ + if(b->busy) return -1; + b->busy = 1; + int r = read(b, s, len); + b->busy = 0; + return r; +} + +static int readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){ + int idx = hasbyte(b, byte); + if(idx < 0) return 0; + int partlen = idx + 1 - b->head; + // now calculate length of new data portion + if(idx < b->head) partlen += b->length; + if(partlen > len) return -read(b, s, len); + return read(b, s, partlen); +} + /** * @brief RB_readto fill array `s` with data until byte `byte` (with it) * @param b - ringbuffer * @param byte - check byte * @param s - buffer to write data * @param len - length of `s` - * @return amount of bytes written (negative, if lenhead; - // now calculate length of new data portion - if(idx < b->head) partlen += b->length; - if(partlen > len) return -RB_read(b, s, len); - return RB_read(b, s, partlen); + if(b->busy) return -1; + b->busy = 1; + int n = readto(b, byte, s, len); + b->busy = 0; + return n; } -/** - * @brief RB_write - write some data to ringbuffer - * @param b - buffer - * @param str - data - * @param l - length - * @return amount of bytes written - */ -int RB_write(ringbuffer *b, const uint8_t *str, int l){ - int r = b->length - 1 - RB_datalen(b); // rest length - if(l > r) l = r; - if(!l) return 0; +static int write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - datalen(b); // rest length + if(l > r || !l) return 0; int _1st = b->length - b->tail; if(_1st > l) _1st = l; mcpy(b->data + b->tail, str, _1st); @@ -117,8 +140,27 @@ int RB_write(ringbuffer *b, const uint8_t *str, int l){ return l; } +/** + * @brief RB_write - write some data to ringbuffer + * @param b - buffer + * @param str - data + * @param l - length + * @return amount of bytes written or -1 if busy + */ +int RB_write(ringbuffer *b, const uint8_t *str, int l){ + if(b->busy) return -1; + b->busy = 1; + int w = write(b, str, l); + b->busy = 0; + return w; +} + // just delete all information in buffer `b` -void RB_clearbuf(ringbuffer *b){ +int RB_clearbuf(ringbuffer *b){ + if(b->busy) return -1; + b->busy = 1; b->head = 0; b->tail = 0; + b->busy = 0; + return 1; } diff --git a/F3:F303/Seven_CDCs/ringbuffer.h b/F3:F303/Seven_CDCs/ringbuffer.h index b5e08b8..ed2cf95 100644 --- a/F3:F303/Seven_CDCs/ringbuffer.h +++ b/F3:F303/Seven_CDCs/ringbuffer.h @@ -1,6 +1,5 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2022 Edward V. Emelianov . + * Copyright 2023 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 @@ -17,16 +16,21 @@ */ #pragma once -#ifndef RINGBUFFER_H__ -#define RINGBUFFER_H__ +#if defined STM32F0 +#include +#elif defined STM32F1 +#include +#elif defined STM32F3 #include +#endif typedef struct{ uint8_t *data; // data buffer const int length; // its length int head; // head index int tail; // tail index + volatile int busy; // == TRUE if buffer is busy now } ringbuffer; int RB_read(ringbuffer *b, uint8_t *s, int len); @@ -34,6 +38,4 @@ int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len); int RB_hasbyte(ringbuffer *b, uint8_t byte); int RB_write(ringbuffer *b, const uint8_t *str, int l); int RB_datalen(ringbuffer *b); -void RB_clearbuf(ringbuffer *b); - -#endif // RINGBUFFER_H__ +int RB_clearbuf(ringbuffer *b); diff --git a/F3:F303/Seven_CDCs/strfunc.c b/F3:F303/Seven_CDCs/strfunc.c index 614b263..004e62f 100644 --- a/F3:F303/Seven_CDCs/strfunc.c +++ b/F3:F303/Seven_CDCs/strfunc.c @@ -1,6 +1,6 @@ /* - * This file is part of the 7CDCs project. - * Copyright 2023 Edward V. Emelianov . + * This file is part of the multiiface project. + * Copyright 2025 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 @@ -16,17 +16,15 @@ * along with this program. If not, see . */ -#include #include -#include -#include "usb.h" + /** * @brief hexdump - dump hex array by 16 bytes in string - * @param ifno - USB interface number + * @param sendfun - function to send data * @param arr - array to dump * @param len - length of `arr` */ -void hexdump(int ifno, uint8_t *arr, uint16_t len){ +void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len){ char buf[52], *bptr = buf; for(uint16_t l = 0; l < len; ++l, ++arr){ for(int16_t j = 1; j > -1; --j){ @@ -37,14 +35,14 @@ void hexdump(int ifno, uint8_t *arr, uint16_t len){ if(l % 16 == 15){ *bptr++ = '\n'; *bptr = 0; - USB_sendstr(ifno, buf); + sendfun(buf); bptr = buf; }else *bptr++ = ' '; } if(bptr != buf){ *bptr++ = '\n'; *bptr = 0; - USB_sendstr(ifno, buf); + sendfun(buf); } } @@ -267,85 +265,3 @@ const char *getint(const char *txt, int32_t *I){ *I = sign * (int32_t)U; return nxt; } - -int mystrlen(const char *txt){ - if(!txt) return 0; - int r = 0; - while(*txt++) ++r; - return r; -} - -/* -void mymemcpy(char *dest, const char *src, int len){ - if(len < 1) return; - while(len--) *dest++ = *src++; -} -*/ - -// be careful: if pow10 would be bigger you should change str[] size! -static const float pwr10[] = {1.f, 10.f, 100.f, 1000.f, 10000.f}; -static const float rounds[] = {0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f}; -#define P10L (sizeof(pwr10)/sizeof(uint32_t) - 1) -char * float2str(float x, uint8_t prec){ - static char str[16] = {0}; // -117.5494E-36\0 - 14 symbols max! - if(prec > P10L) prec = P10L; - if(isnan(x)){ memcpy(str, "NAN", 4); return str;} - else{ - int i = isinf(x); - if(i){memcpy(str, "-INF", 5); if(i == 1) return str+1; else return str;} - } - char *s = str + 14; // go to end of buffer - uint8_t minus = 0; - if(x < 0){ - x = -x; - minus = 1; - } - int pow = 0; // xxxEpow - // now convert float to 1.xxxE3y - while(x > 1000.f){ - x /= 1000.f; - pow += 3; - } - if(x > 0.) while(x < 1.){ - x *= 1000.f; - pow -= 3; - } - // print Eyy - if(pow){ - uint8_t m = 0; - if(pow < 0){pow = -pow; m = 1;} - while(pow){ - register int p10 = pow/10; - *s-- = '0' + (pow - 10*p10); - pow = p10; - } - if(m) *s-- = '-'; - *s-- = 'E'; - } - // now our number is in [1, 1000] - uint32_t units; - if(prec){ - units = (uint32_t) x; - uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]); - // print decimals - while(prec){ - register int d10 = decimals / 10; - *s-- = '0' + (decimals - 10*d10); - decimals = d10; - --prec; - } - // decimal point - *s-- = '.'; - }else{ // without decimal part - units = (uint32_t) (x + 0.5); - } - // print main units - if(units == 0) *s-- = '0'; - else while(units){ - register uint32_t u10 = units / 10; - *s-- = '0' + (units - 10*u10); - units = u10; - } - if(minus) *s-- = '-'; - return s+1; -} diff --git a/F3:F303/Seven_CDCs/strfunc.h b/F3:F303/Seven_CDCs/strfunc.h index e1dd59e..63da760 100644 --- a/F3:F303/Seven_CDCs/strfunc.h +++ b/F3:F303/Seven_CDCs/strfunc.h @@ -1,6 +1,6 @@ /* - * This file is part of the 7CDCs project. - * Copyright 2023 Edward V. Emelianov . + * This file is part of the multiiface project. + * Copyright 2025 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 @@ -21,13 +21,10 @@ #include #include -void hexdump(int ifno, uint8_t *arr, uint16_t len); +void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len); const char *u2str(uint32_t val); const char *i2str(int32_t i); const char *uhex2str(uint32_t val); const char *getnum(const char *txt, uint32_t *N); const char *omit_spaces(const char *buf); const char *getint(const char *txt, int32_t *I); -int mystrlen(const char *txt); -//void mymemcpy(char *dest, const char *src, int len); -char * float2str(float x, uint8_t prec); diff --git a/F3:F303/Seven_CDCs/usb_descr.c b/F3:F303/Seven_CDCs/usb_descr.c new file mode 100644 index 0000000..36ec5b8 --- /dev/null +++ b/F3:F303/Seven_CDCs/usb_descr.c @@ -0,0 +1,272 @@ +/* + * Copyright 2024 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include // memcpy +#include "flash.h" // descriptors +#include "hardware.h" // `config` flag +#include "usb_descr.h" + +// low/high for uint16_t +#define L16(x) (x & 0xff) +#define H16(x) (x >> 8) + +static const uint8_t USB_DeviceDescriptor[] = { + USB_DT_DEVICE_SIZE, // bLength + USB_DT_DEVICE, // bDescriptorType + L16(bcdUSB), // bcdUSB_L + H16(bcdUSB), // bcdUSB_H + USB_CLASS_MISC, // bDeviceClass + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0BUFSZ, // bMaxPacketSize + L16(idVendor), // idVendor_L + H16(idVendor), // idVendor_H + L16(idProduct), // idProduct_L + H16(idProduct), // idProduct_H + L16(bcdDevice_Ver), // bcdDevice_Ver_L + H16(bcdDevice_Ver), // bcdDevice_Ver_H + iMANUFACTURER_DESCR, // iManufacturer - indexes of string descriptors in array + iPRODUCT_DESCR, // iProduct + iSERIAL_DESCR, // iSerial + bNumConfigurations // bNumConfigurations +}; + +static const uint8_t USB_DeviceQualifierDescriptor[] = { + USB_DT_QUALIFIER_SIZE, //bLength + USB_DT_QUALIFIER, // bDescriptorType + L16(bcdUSB), // bcdUSB_L + H16(bcdUSB), // bcdUSB_H + USB_CLASS_PER_INTERFACE, // bDeviceClass + bDeviceSubClass, // bDeviceSubClass + bDeviceProtocol, // bDeviceProtocol + USB_EP0BUFSZ, // bMaxPacketSize0 + bNumConfigurations, // bNumConfigurations + 0 // Reserved +}; + +#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 + USB_DT_CONFIG_SIZE, // bLength: Configuration Descriptor size + USB_DT_CONFIG, // bDescriptorType: Configuration + L16(wTotalLength), // wTotalLength.L :no of returned bytes + H16(wTotalLength), // wTotalLength.H + bNumInterfaces, // bNumInterfaces + 1, // bConfigurationValue: Current configuration value + 0, // iConfiguration: Index of string descriptor describing the configuration or 0 + BusPowered, // bmAttributes - Bus powered + 50, // MaxPower in 2mA units + //--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), +}; + + +_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"); + +// 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] = &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){ + if(askedsize < size) size = askedsize; // shortened request + if(size < USB_EP0BUFSZ){ + EP_WriteIRQ(0, buf, size); + return; + } + while(size){ + uint16_t l = size; + if(l > USB_EP0BUFSZ) l = USB_EP0BUFSZ; + EP_WriteIRQ(0, buf, l); + buf += l; + size -= l; + uint8_t needzlp = (l == USB_EP0BUFSZ) ? 1 : 0; + if(size || needzlp){ // send last data buffer + uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]); + // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx + USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX)) + ^ USB_EPnR_STAT_TX; + uint32_t ctr = 1000000; + while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; + if((USB->ISTR & USB_ISTR_CTR) == 0){ + return; + } + if(needzlp) EP_WriteIRQ(0, NULL, 0); + } + } +} + +void get_descriptor(config_pack_t *pack){ + uint8_t descrtype = pack->wValue >> 8, + descridx = pack->wValue & 0xff; + switch(descrtype){ + case DEVICE_DESCRIPTOR: + wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor), pack->wLength); + break; + case CONFIGURATION_DESCRIPTOR: + wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor), pack->wLength); + break; + case STRING_DESCRIPTOR: + if(descridx < iDESCR_AMOUNT){ + wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx]), pack->wLength); + }else{ + EP_WriteIRQ(0, NULL, 0); + } + break; + case DEVICE_QUALIFIER_DESCRIPTOR: + wr0(USB_DeviceQualifierDescriptor, sizeof(USB_DeviceQualifierDescriptor), pack->wLength); + break; + /* case HID_REPORT_DESCRIPTOR: + wr0(HID_ReportDescriptor, sizeof(HID_ReportDescriptor), pack->wLength); + break;*/ + default: + 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/Seven_CDCs/usb_descr.h b/F3:F303/Seven_CDCs/usb_descr.h new file mode 100644 index 0000000..90bc928 --- /dev/null +++ b/F3:F303/Seven_CDCs/usb_descr.h @@ -0,0 +1,89 @@ +/* + * Copyright 2024 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include + +#include "usb_lib.h" + +// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor +// bcdUSB: 1.10 +#define bcdUSB 0x0110 +// Class - Misc (EF), subclass - common (2), protocol - interface association descr (1) +#define bDeviceSubClass 0x02 +#define bDeviceProtocol 0x01 +#define idVendor 0x0483 +#define idProduct 0x5740 +#define bcdDevice_Ver 0x0200 +#define bNumConfigurations 1 + +// amount of interfaces +#define InterfacesAmount 7 +// index of interface (ep number minus one) +#define ISerial0 0 +#define ISerial1 1 +#define ISerial2 2 +#define ISerial3 3 +#define ISerial4 4 +#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) +#define SelfPowered (1<<6) +#define RemoteWakeup (1<<5) + +// buffer sizes +// for USB FS EP0 buffers are from 8 to 64 bytes long +#define USB_EP0BUFSZ 16 +// virtual +#define USB_EP1BUFSZ 10 +// Rx/Tx EPs (USB_BTABLE_SIZE-64-2*USB_EP0BUFSZ)/(2*InterfacesAmount) rounded to 8 +// ([btable size] - [registers] - [EP0 buffers])/([interfaces buffers (Rx/Tx)])/8 (for rounding by 8 later) +#define _RTBUFSZ8 (((USB_BTABLE_SIZE)/(ACCESSZ) - (LASTADDR_DEFAULT) - (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)) +//#define USB_RXBUFSZ 8 +//#define USB_TXBUFSZ 8 + +// string descriptors +enum{ + iLANGUAGE_DESCR, + iMANUFACTURER_DESCR, + 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/Seven_CDCs/usb_dev.c b/F3:F303/Seven_CDCs/usb_dev.c new file mode 100644 index 0000000..7256b33 --- /dev/null +++ b/F3:F303/Seven_CDCs/usb_dev.c @@ -0,0 +1,321 @@ +/* + * Copyright 2024 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "hardware.h" +#include "ringbuffer.h" +#include "usb_descr.h" +#include "usb_dev.h" + +// Class-Specific Control Requests +#define SEND_ENCAPSULATED_COMMAND 0x00 // unused +#define GET_ENCAPSULATED_RESPONSE 0x01 // unused +#define SET_COMM_FEATURE 0x02 // unused +#define GET_COMM_FEATURE 0x03 // unused +#define CLEAR_COMM_FEATURE 0x04 // unused +#define SET_LINE_CODING 0x20 +#define GET_LINE_CODING 0x21 +#define SET_CONTROL_LINE_STATE 0x22 +#define SEND_BREAK 0x23 + +// control line states +#define CONTROL_DTR 0x01 +#define CONTROL_RTS 0x02 + +// inbuf overflow when receiving +static volatile uint8_t bufovrfl[InterfacesAmount] = {0}; + +// receive buffer: hold data until chkin() call +static uint8_t volatile rcvbuf[InterfacesAmount][USB_RXBUFSZ]; +static uint8_t volatile rcvbuflen[InterfacesAmount] = {0}; +// line coding +#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[InterfacesAmount] = {0}; + +// ring buffers for incoming and outgoing data +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(uint8_t ifno){ + static int ovrflctr = 0; // "antistall" counter + 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){ // buffer busy + return; + }else if(w == 0){ // no enough space or (WTF) incoming string larger than buffer size + if(rcvbuflen[ifno] > rbin[ifno].length || ++ovrflctr > 9999){ + bufovrfl[ifno] = 1; // real overflow in case if ringbuffer's size less than USB buffer + ovrflctr = 0; + }else{ + return; // not enough space + } + } + 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(uint8_t ifno){ + uint8_t usbbuff[USB_TXBUFSZ]; + int buflen = RB_read((ringbuffer*)&rbout[ifno], (uint8_t*)usbbuff, USB_TXBUFSZ); + if(!CDCready[ifno]){ + lastdsz[ifno] = -1; + return; + } + 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(){ + uint8_t epno = (USB->ISTR & USB_ISTR_EPID), ifno = epno - 1; + if(epno > InterfacesAmount){ + return; + } + uint16_t epstatus = KEEP_DTOG(USB->EPnR[epno]); + if(RX_FLAG(epstatus)){ // receive data + if(rcvbuflen[ifno]){ + bufovrfl[ifno] = 1; // lost last data + rcvbuflen[ifno] = 0; + } + rcvbuflen[ifno] = EP_Read(epno, (uint8_t*)rcvbuf[ifno]); + USB->EPnR[epno] = 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[epno] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; + send_next(ifno); + } +} + +// SET_LINE_CODING +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; + } + rcvbuflen[ifno] = 0; +} + +// SET_CONTROL_LINE_STATE +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 - 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(){ + 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; + } + } +} + +// 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(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: + // 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(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(uint8_t ifno, const uint8_t *buf, int len){ + if(!buf || !CDCready[ifno] || !len) return FALSE; + uint32_t T0 = Tms; + while(len){ + if(Tms - T0 > DISCONN_TMOUT){ + break_handler(ifno); + return FALSE; + } + if(!CDCready[ifno]) return FALSE; + IWDG->KR = IWDG_REFRESH; + int l = RB_datalen((ringbuffer*)&rbout[ifno]); + if(l < 0) continue; + int portion = rbout[ifno].length - 1 - l; + if(portion < 1){ + if(lastdsz[ifno] < 0) send_next(ifno); + continue; + } + if(portion > len) portion = len; + int a = RB_write((ringbuffer*)&rbout[ifno], buf, portion); + if(a > 0){ + len -= a; + buf += a; + }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 ifno, uint8_t byte){ + if(!CDCready[ifno]) return FALSE; + int l = 0; + 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; + } + } + // send line if got EOL + if(byte == '\n' && lastdsz[ifno] < 0) send_next(ifno); + return TRUE; +} + +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(ifno, (const uint8_t*)string, len); +} + +/** + * @brief USB_receive - get binary data from receiving ring-buffer + * @param buf (i) - buffer for received data + * @param len - length of `buf` + * @return amount of received bytes (negative, if overfull happened) + */ +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[ifno], buf, len); + if(sz < 0) return 0; // buffer in writting state + return sz; +} + +/** + * @brief USB_receivestr - get string up to '\n' and replace '\n' with 0 + * @param buf - receiving buffer + * @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(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[ifno], '\n', (uint8_t*)buf, len); + if(l < 1){ + 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; + } + if(l == 0) return 0; + buf[l-1] = 0; // replace '\n' with strend + return l; +} diff --git a/F3:F303/Seven_CDCs/usb_dev.h b/F3:F303/Seven_CDCs/usb_dev.h new file mode 100644 index 0000000..0f9c458 --- /dev/null +++ b/F3:F303/Seven_CDCs/usb_dev.h @@ -0,0 +1,63 @@ +/* + * Copyright 2024 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include "usb_lib.h" +#include "usb_descr.h" + +typedef struct { + uint32_t dwDTERate; + uint8_t bCharFormat; +#define USB_CDC_1_STOP_BITS 0 +#define USB_CDC_1_5_STOP_BITS 1 +#define USB_CDC_2_STOP_BITS 2 + uint8_t bParityType; +#define USB_CDC_NO_PARITY 0 +#define USB_CDC_ODD_PARITY 1 +#define USB_CDC_EVEN_PARITY 2 +#define USB_CDC_MARK_PARITY 3 +#define USB_CDC_SPACE_PARITY 4 + uint8_t bDataBits; +} __attribute__ ((packed)) usb_LineCoding; + +extern volatile uint8_t CDCready[InterfacesAmount]; + +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 - near 2s +#define DISCONN_TMOUT (2000) + +// sizes of ringbuffers for outgoing and incoming data +#define RBOUTSZ (256) +#define RBINSZ (256) + +#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(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/Seven_CDCs/usb_lib.c b/F3:F303/Seven_CDCs/usb_lib.c index ac0f04e..3fb650b 100644 --- a/F3:F303/Seven_CDCs/usb_lib.c +++ b/F3:F303/Seven_CDCs/usb_lib.c @@ -1,6 +1,5 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,777 +14,38 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #include -#include "debug.h" -#include "strfunc.h" -#include "usart.h" -#include "usb.h" -#include "usb_lib.h" -#include "usbhw.h" -ep_t endpoints[STM32ENDPOINTS]; +#include "usb_lib.h" +#include "usb_descr.h" +#include "usb_dev.h" + +static ep_t endpoints[STM32ENDPOINTS]; static uint16_t USB_Addr = 0; -uint8_t ep0databuf[EP0DATABUF_SIZE], setupdatabuf[EP0DATABUF_SIZE]; -config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; - -volatile uint8_t usbON = 0; - -// definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor -#define bcdUSB_L 0x00 -#define bcdUSB_H 0x02 -// Class - Misc (EF), subclass - common (2), protocol - interface association descr (1) -#define bDeviceClass 0xEF -#define bDeviceSubClass 0x02 -#define bDeviceProtocol 0x01 -#define bNumConfigurations 1 - -static const uint8_t USB_DeviceDescriptor[] = { - 18, // bLength - 0x01, // bDescriptorType - Device descriptor - bcdUSB_L, // bcdUSB_L - 1.10 - bcdUSB_H, // bcdUSB_H - bDeviceClass, // bDeviceClass - USB_COMM - bDeviceSubClass, // bDeviceSubClass - bDeviceProtocol, // bDeviceProtocol - USB_EP0_BUFSZ, // bMaxPacketSize - // 0483:5740 (VID:PID) - stm32 VCP - 0x83, 0x04, 0x40, 0x57, - 0x00, // bcdDevice_Ver_L - 0x02, // bcdDevice_Ver_H - iMANUFACTURER_DESCR, // iManufacturer - iPRODUCT_DESCR, // iProduct - iSERIAL_DESCR, // iSerialNumber - bNumConfigurations // bNumConfigurations -}; - -static const uint8_t USB_DeviceQualifierDescriptor[] = { - 10, //bLength - 0x06, // bDescriptorType - Device qualifier - bcdUSB_L, // bcdUSB_L - bcdUSB_H, // bcdUSB_H - bDeviceClass, // bDeviceClass - bDeviceSubClass, // bDeviceSubClass - bDeviceProtocol, // bDeviceProtocol - USB_EP0_BUFSZ, // bMaxPacketSize0 - bNumConfigurations, // bNumConfigurations - 0x00 // Reserved -}; - -static const uint8_t USB_ConfigDescriptor[] = { - /* Configuration Descriptor*/ - 0x09, /* bLength: Configuration Descriptor size */ - 0x02, /* bDescriptorType: Configuration */ - 0xD7, /* wTotalLength:no of returned bytes (9+7*66=471, 0x1D7 */ - 0x01, - 14, /* bNumInterfaces: 14 interfaces (7*2) */ - 0x01, /* bConfigurationValue: Configuration value */ - 0x00, /* iConfiguration: Index of string descriptor describing the configuration */ - 0x80, /* bmAttributes - Bus powered */ - 0x32, /* MaxPower 100 mA */ - - /*---------------------------------------------------------------------------*/ - // IAD0 (66 bytes) - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD - 0, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /* Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ - 0x00, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_CMD, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ - 0x01, /* bDataInterface: 1 */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ - 0x00, /* bMasterInterface: Communication class interface */ - 0x01, /* bSlaveInterface0: Data Class Interface */ - /*Endpoint 10 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x88, /* bEndpointAddress IN8 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ - 0x01, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ - 0x81, /* bEndpointAddress IN1 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ - 0x01, /* bEndpointAddress OUT1 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD1: interfaces 2&3, EP2 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 2, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 2, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_DBG, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 3, /* bDataInterface: 3 */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 2, /* bMasterInterface: Communication class interface */ -/**/ 3, /* bSlaveInterface0: Data Class Interface */ - /*Endpoint 11 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x89, /* bEndpointAddress IN9 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 3, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x82, /* bEndpointAddress IN2 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x02, /* bEndpointAddress OUT2 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD2: interfaces 4&5, EP3 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 4, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 4, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_USART1, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 5, /* bDataInterface */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 4, /* bMasterInterface: Communication class interface */ -/**/ 5, /* bSlaveInterface0: Data Class Interface */ - /*Endpoint 11 Descriptor*/ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x8a, /* bEndpointAddress IN10 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 5, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x83, /* bEndpointAddress IN3 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x03, /* bEndpointAddress OUT3 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD3: interfaces 6&7, EP4 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 6, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 6, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_USART2, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 7, /* bDataInterface */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 6, /* bMasterInterface: Communication class interface */ -/**/ 7, /* bSlaveInterface0: Data Class Interface */ - /* Interrupt Endpoint Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x8b, /* bEndpointAddress IN11 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 7, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x84, /* bEndpointAddress IN4 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x04, /* bEndpointAddress OUT4 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD4: interfaces 8&9, EP5 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 8, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 8, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_USART3, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 9, /* bDataInterface */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 8, /* bMasterInterface: Communication class interface */ -/**/ 9, /* bSlaveInterface0: Data Class Interface */ - /* Interrupt Endpoint Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x8c, /* bEndpointAddress IN12 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 9, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x85, /* bEndpointAddress IN5 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x05, /* bEndpointAddress OUT5 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD5: interfaces 10&11, EP6 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 10, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 10, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_USART4, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 11, /* bDataInterface */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 10, /* bMasterInterface: Communication class interface */ -/**/ 11, /* bSlaveInterface0: Data Class Interface */ - /* Interrupt Endpoint Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x8d, /* bEndpointAddress IN13 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 11, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x86, /* bEndpointAddress IN6 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x06, /* bEndpointAddress OUT6 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ - - /*---------------------------------------------------------------------------*/ - // IAD6: interfaces 12&13, EP7 - 0x08, // bLength: Interface Descriptor size - 0x0B, // bDescriptorType: IAD -/**/ 12, // bFirstInterface - 0x02, // bInterfaceCount - 0x02, // bFunctionClass: CDC - 0x02, // bFunctionSubClass - 0x00, // bFunctionProtocol - 0x00, // iFunction - /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ - 0x09, /* bLength: Interface Descriptor size */ - 0x04, /* bDescriptorType: Interface */ -/**/ 12, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x01, /* bNumEndpoints: One endpoints used */ - 0x02, /* bInterfaceClass: Communication Interface Class */ - 0x02, /* bInterfaceSubClass: Abstract Control Model */ - 0x00, /* bInterfaceProtocol */ - iINTERFACE_DESCR_CAN, /* iInterface: */ - /*Header Functional Descriptor*/ - 0x05, /* bLength: Endpoint Descriptor size */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x00, /* bDescriptorSubtype: Header Func Desc */ - 0x10, /* bcdCDC: spec release number */ - 0x01, - /*Call Management Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x01, /* bDescriptorSubtype: Call Management Func Desc */ - 0x00, /* bmCapabilities: D0+D1 */ -/**/ 13, /* bDataInterface */ - /*ACM Functional Descriptor*/ - 0x04, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x02, /* bDescriptorSubtype: Abstract Control Management desc */ - 0x02, /* bmCapabilities */ - /*Union Functional Descriptor*/ - 0x05, /* bFunctionLength */ - 0x24, /* bDescriptorType: CS_INTERFACE */ - 0x06, /* bDescriptorSubtype: Union func desc */ -/**/ 12, /* bMasterInterface: Communication class interface */ -/**/ 13, /* bSlaveInterface0: Data Class Interface */ - /* Interrupt Endpoint Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x8e, /* bEndpointAddress IN14 - non-existant! */ - 0x03, /* bmAttributes: Interrupt */ - (USB_EP1BUFSZ & 0xff), /* wMaxPacketSize LO: */ - (USB_EP1BUFSZ >> 8), /* wMaxPacketSize HI: */ - 0x10, /* bInterval: */ - /*---------------------------------------------------------------------------*/ - /*Data class interface descriptor*/ - 0x09, /* bLength: Endpoint Descriptor size */ - 0x04, /* bDescriptorType: */ -/**/ 13, /* bInterfaceNumber: Number of Interface */ - 0x00, /* bAlternateSetting: Alternate setting */ - 0x02, /* bNumEndpoints: Two endpoints used */ - 0x0A, /* bInterfaceClass: CDC */ - 0x02, /* bInterfaceSubClass: */ - 0x00, /* bInterfaceProtocol: */ - 0x00, /* iInterface: */ - /*Endpoint IN Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x87, /* bEndpointAddress IN7 */ - 0x02, /* bmAttributes: Bulk */ - (USB_TXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_TXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*Endpoint OUT Descriptor */ - 0x07, /* bLength: Endpoint Descriptor size */ - 0x05, /* bDescriptorType: Endpoint */ -/**/0x07, /* bEndpointAddress OUT7 */ - 0x02, /* bmAttributes: Bulk */ - (USB_RXBUFSZ & 0xff), /* wMaxPacketSize: 64 */ - (USB_RXBUFSZ >> 8), - 0x00, /* bInterval: ignore for Bulk transfer */ - /*---------------------------------------------------------------------------*/ -}; - -_USB_LANG_ID_(LD, LANG_US); -_USB_STRING_(SD, u"0.0.1"); -_USB_STRING_(MD, u"Emelianov E.V."); -_USB_STRING_(PD, u"USB multiserial controller"); -_USB_STRING_(ID0, u"serial-cmd"); -_USB_STRING_(ID1, u"serial-usart1_"); -_USB_STRING_(ID2, u"serial-usart2_"); -_USB_STRING_(ID3, u"serial-usart3_"); -_USB_STRING_(ID4, u"serial-usart4_"); -_USB_STRING_(ID5, u"serial-can"); -_USB_STRING_(ID6, u"serial-debug"); - -static void const *StringDescriptor[iDESCR_AMOUNT] = { - [iLANGUAGE_DESCR] = &LD, - [iMANUFACTURER_DESCR] = &MD, - [iPRODUCT_DESCR] = &PD, - [iSERIAL_DESCR] = &SD, - [iINTERFACE_DESCR_CMD] = &ID0, - [iINTERFACE_DESCR_DBG] = &ID6, - [iINTERFACE_DESCR_USART1] = &ID1, - [iINTERFACE_DESCR_USART2] = &ID2, - [iINTERFACE_DESCR_USART3] = &ID3, - [iINTERFACE_DESCR_USART4] = &ID4, - [iINTERFACE_DESCR_CAN] = &ID5 -}; - -static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet->wLength < size) size = setup_packet->wLength; // shortened request - if(size < endpoints[0].txbufsz){ - EP_WriteIRQ(0, buf, size); - return; - } - while(size){ - uint16_t l = size; - if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz; - EP_WriteIRQ(0, buf, l); - buf += l; - size -= l; - uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0; - if(size || needzlp){ // send last data buffer - uint16_t status = KEEP_DTOG(USB->EPnR[0]); - // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx - USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX)) - ^ USB_EPnR_STAT_TX; - uint32_t ctr = 1000000; - while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; - if((USB->ISTR & USB_ISTR_CTR) == 0){ - return; - } - if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0); - } - } -} - -static inline void get_descriptor(){ - uint8_t descrtype = setup_packet->wValue >> 8, - descridx = setup_packet->wValue & 0xff; - switch(descrtype){ - case DEVICE_DESCRIPTOR: - wr0(USB_DeviceDescriptor, sizeof(USB_DeviceDescriptor)); - break; - case CONFIGURATION_DESCRIPTOR: - wr0(USB_ConfigDescriptor, sizeof(USB_ConfigDescriptor)); - break; - case STRING_DESCRIPTOR: - if(descridx < iDESCR_AMOUNT) wr0((const uint8_t *)StringDescriptor[descridx], *((uint8_t*)StringDescriptor[descridx])); - else EP_WriteIRQ(0, (uint8_t*)0, 0); - break; - case DEVICE_QUALIFIER_DESCRIPTOR: - wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); - break; - default: - break; - } -} +static uint8_t setupdatabuf[EP0DATABUF_SIZE]; +static config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; +volatile uint8_t usbON = 0; // device is configured and active static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) static inline void std_d2h_req(){ - uint16_t status = 0; // bus powered + uint16_t st = 0; switch(setup_packet->bRequest){ case GET_DESCRIPTOR: - get_descriptor(); + get_descriptor(setup_packet); break; case GET_STATUS: - EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered + EP_WriteIRQ(0, (uint8_t *)&st, 2); // send status: Bus Powered break; case GET_CONFIGURATION: EP_WriteIRQ(0, (uint8_t*)&configuration, 1); break; default: + EP_WriteIRQ(0, NULL, 0); break; } } -// Rx and Tx handlers for EP1..EP7 -static void rxtx_Handler(uint8_t epno){ - uint8_t buf[USB_RXBUFSZ]; - int idx = epno - 1; - uint16_t epstatus = KEEP_DTOG(USB->EPnR[epno]); - if(RX_FLAG(epstatus)){ - epstatus = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_RX)) ^ USB_EPnR_STAT_RX; // keep stat Tx & set valid RX, clear CTR Rx - USB->EPnR[epno] = epstatus; - uint8_t sz = EP_Read(epno, (uint8_t*)buf); - /* - DBG("epno"); - DBGmesg(u2str(epno)); DBGmesg(" ("); DBGmesg(u2str(sz)); - DBGmesg(") > "); hexdump(DBG_IDX, buf, sz); DBGnl(); - */ - if(sz){ - switch(epno){ - case USART1_EPNO: - usart_sendn(1, buf, sz); - break; - case USART2_EPNO: - usart_sendn(2, buf, sz); - break; - case USART3_EPNO: - usart_sendn(3, buf, sz); - break; - case USART4_EPNO: - ; // we have no USART4 in STM32F303CBT6 - break; - } - if(RB_write((ringbuffer*)&rbin[idx], buf, sz) != sz) bufovrfl[idx] = 1; - } - // set ACK Rx - USB->EPnR[epno] = (KEEP_DTOG(USB->EPnR[epno]) & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; - }else{ - USB->EPnR[epno] = (epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; // clear TX ctr - send_next(idx); - } -} - static inline void std_h2d_req(){ switch(setup_packet->bRequest){ case SET_ADDRESS: @@ -795,15 +55,58 @@ static inline void std_h2d_req(){ case SET_CONFIGURATION: // Now device configured configuration = setup_packet->wValue; - for(uint8_t i = 1; i <= MAX_EPNO; ++i){ - EP_Init(i, EP_TYPE_BULK, USB_TXBUFSZ, USB_RXBUFSZ, rxtx_Handler); - } + set_configuration(); + usbON = 1; break; default: break; } } +void WEAK usb_standard_request(){ + uint8_t recipient = REQUEST_RECIPIENT(setup_packet->bmRequestType); + uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; + switch(recipient){ + case REQ_RECIPIENT_DEVICE: + if(dev2host){ + std_d2h_req(); + }else{ + std_h2d_req(); + } + break; + case REQ_RECIPIENT_INTERFACE: + if(dev2host && setup_packet->bRequest == GET_DESCRIPTOR){ + get_descriptor(setup_packet); + } + break; + case REQ_RECIPIENT_ENDPOINT: + if(setup_packet->bRequest == CLEAR_FEATURE){ /* what to do here? */ + }else{ /* wrong */ } + break; + default: + break; + } + if(!dev2host) EP_WriteIRQ(0, NULL, 0); +} + +void WEAK usb_class_request(config_pack_t *req, uint8_t _U_ *data, uint16_t _U_ datalen){ + switch(req->bRequest){ + case GET_INTERFACE: + break; + case SET_CONFIGURATION: // set featuring by req->wValue + break; + default: + break; + } + if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev + EP_WriteIRQ(0, NULL, 0); +} + +void WEAK usb_vendor_request(config_pack_t _U_ *packet, uint8_t _U_ *data, uint16_t _U_ datalen){ + if(0 == (setup_packet->bmRequestType & 0x80)) // host2dev + EP_WriteIRQ(0, NULL, 0); +} + /* bmRequestType: 76543210 7 direction: 0 - host->device, 1 - device->host @@ -813,82 +116,50 @@ bmRequestType: 76543210 /** * Endpoint0 (control) handler */ -void EP0_Handler(uint8_t __attribute__((unused)) epno){ - uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications - uint8_t reqtype = setup_packet->bmRequestType & 0x7f; - uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; +static void EP0_Handler(){ + uint8_t ep0dbuflen = 0; + uint8_t ep0databuf[EP0DATABUF_SIZE]; + uint16_t epstatus = KEEP_DTOG(USB->EPnR[0]); // EP0R on input -> return this value after modifications int rxflag = RX_FLAG(epstatus); - usb_LineCoding *lc; - // calculate iFno (EP number minus 1) by setup_packet->wIndex (bInterfaceNumber): iFno = wIndex >> 1 - int iFno = setup_packet->wIndex >> 1; - if(iFno != DBG_IDX){ - DBGmesg(uhex2str(epstatus)); - DBGmesg(" ("); DBGmesg(u2str(iFno)); - DBGmesg(") - "); hexdump(DBG_IDX, (uint8_t*)setup_packet, sizeof(config_pack_t)); + //if(rxflag){ } + // check direction + if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) + if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack + EP_Read(0, setupdatabuf); + // interrupt handler will be called later + }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf + //if(endpoints[0].rx_cnt){ } + ep0dbuflen = EP_Read(0, ep0databuf); + } } - if(rxflag && SETUP_FLAG(epstatus)){ - if(iFno != DBG_IDX){DBGmesg("setup\n");} + if(rxflag){ + uint8_t reqtype = REQUEST_TYPE(setup_packet->bmRequestType); switch(reqtype){ - case STANDARD_DEVICE_REQUEST_TYPE: // standard device request - if(dev2host){ - std_d2h_req(); - }else{ - std_h2d_req(); - EP_WriteIRQ(0, (uint8_t *)0, 0); - } - break; - case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request - if(setup_packet->bRequest == CLEAR_FEATURE){ - EP_WriteIRQ(0, (uint8_t *)0, 0); - } - break; - case CONTROL_REQUEST_TYPE: - switch(setup_packet->bRequest){ - case GET_LINE_CODING: - if(iFno != DBG_IDX){ DBG("GLC");} - lc = getLineCoding(iFno); - if(!lc) EP_WriteIRQ(0, (uint8_t *)0, 0); - else EP_WriteIRQ(0, (uint8_t*)&lc, sizeof(usb_LineCoding)); - break; - case SET_LINE_CODING: // omit this for next stage, when data will come - if(iFno != DBG_IDX){ DBG("SLC");} - break; - case SET_CONTROL_LINE_STATE: - if(iFno != DBG_IDX){ DBG("SCLS");} - usbON |= 1 << iFno; // now this interface is connected - break; - case SEND_BREAK: - if(iFno != DBG_IDX){ DBG("B");} - usbON &= ~(1<bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement - break; + case REQ_TYPE_STANDARD: + if(SETUP_FLAG(epstatus)){ + usb_standard_request(); + }else{ /* ??? */ } + break; + case REQ_TYPE_CLASS: + usb_class_request(setup_packet, ep0databuf, ep0dbuflen); + break; + case REQ_TYPE_VENDOR: + usb_vendor_request(setup_packet, ep0databuf, ep0dbuflen); + break; default: - EP_WriteIRQ(0, (uint8_t *)0, 0); + EP_WriteIRQ(0, NULL, 0); + break; } - }else if(rxflag){ // got data over EP0 or host acknowlegement - if(iFno != DBG_IDX){ DBGmesg("rxflag\n");} - //if(endpoints[0].rx_cnt){ - // if(setup_packet->bRequest == SET_LINE_CODING){ - if(iFno != DBG_IDX){ - DBGmesg("USART"); DBGmesg(u2str(iFno + 2 - USART1_EPNO)); - DBGmesg(" speed = "); DBGmesg(u2str(((usb_LineCoding*)ep0databuf)->dwDTERate)); DBGnl(); - } - usart_config(iFno, (usb_LineCoding*)ep0databuf); - // } - //} - } else if(TX_FLAG(epstatus)){ // package transmitted + } + if(TX_FLAG(epstatus)){ // now we can change address after enumeration if ((USB->DADDR & USB_DADDR_ADD) != USB_Addr){ USB->DADDR = USB_DADDR_EF | USB_Addr; + usbON = 0; } } - epstatus = KEEP_DTOG(USB->EPnR[0]); - if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission + //epstatus = KEEP_DTOG(USB->EPnR[0]); + if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP or data transmission else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged // keep DTOGs, clear CTR_RX,TX, set RX VALID USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; @@ -930,9 +201,9 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ */ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ EP_WriteIRQ(number, buf, size); - uint16_t status = KEEP_DTOG(USB->EPnR[number]); - // keep DTOGs, clear CTR_TX & set TX VALID to start transmission - USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; + uint16_t epstatus = KEEP_DTOG(USB->EPnR[number]); + // keep DTOGs and RX stat, clear CTR_TX & set TX VALID to start transmission + USB->EPnR[number] = (epstatus & ~(USB_EPnR_CTR_TX | USB_EPnR_STAT_RX)) ^ USB_EPnR_STAT_TX; } /* @@ -960,3 +231,139 @@ int EP_Read(uint8_t number, uint8_t *buf){ return sz; } + +static uint16_t lastaddr = LASTADDR_DEFAULT; +/** + * Endpoint initialisation + * @param number - EP num (0...7) + * @param type - EP type (EP_TYPE_BULK, EP_TYPE_CONTROL, EP_TYPE_ISO, EP_TYPE_INTERRUPT) + * @param txsz - transmission buffer size @ USB/CAN buffer + * @param rxsz - reception buffer size @ USB/CAN buffer + * @param uint16_t (*func)(ep_t *ep) - EP handler function + * @return 0 if all OK + */ +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)(ep_t ep)){ + if(number >= STM32ENDPOINTS) return 4; // out of configured amount + if(txsz > USB_BTABLE_SIZE/ACCESSZ || rxsz > USB_BTABLE_SIZE/ACCESSZ) return 1; // buffer too large + if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE/ACCESSZ) return 2; // out of btable + USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); + USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; + if(rxsz & 1) return 3; // wrong rx buffer size + uint16_t countrx = 0; + if(rxsz < 64) countrx = rxsz / 2; + else{ + if(rxsz & 0x1f) return 3; // should be multiple of 32 + countrx = 31 + rxsz / 32; + } + USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; + endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); + endpoints[number].txbufsz = txsz; + lastaddr += txsz; + USB_BTABLE->EP[number].USB_COUNT_TX = 0; + USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; + endpoints[number].rx_buf = (uint8_t *)(USB_BTABLE_BASE + lastaddr * ACCESSZ); + lastaddr += rxsz; + USB_BTABLE->EP[number].USB_COUNT_RX = countrx << 10; + endpoints[number].func = func; + return 0; +} + +// standard IRQ handler +void USB_IRQ(){ + uint32_t CNTR = USB->CNTR; + USB->CNTR = 0; + if(USB->ISTR & USB_ISTR_RESET){ + usbON = 0; + // Reinit registers + CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM; + // Endpoint 0 - CONTROL + // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! + lastaddr = LASTADDR_DEFAULT; + // clear address, leave only enable bit + USB->DADDR = USB_DADDR_EF; + USB->ISTR = ~USB_ISTR_RESET; + if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0BUFSZ, USB_EP0BUFSZ, EP0_Handler)){ + return; + }; + } + if(USB->ISTR & USB_ISTR_CTR){ + // EP number + uint8_t n = USB->ISTR & USB_ISTR_EPID; + // copy received bytes amount + endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter + // call EP handler + if(endpoints[n].func) endpoints[n].func(); + } + if(USB->ISTR & USB_ISTR_WKUP){ // wakeup +#ifndef STM32F0 + CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM); // clear suspend flags +#else + CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM); +#endif + USB->ISTR = ~USB_ISTR_WKUP; + } + if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep + usbON = 0; +#ifndef STM32F0 + CNTR |= USB_CNTR_FSUSP | USB_CNTR_LP_MODE | USB_CNTR_WKUPM; +#else + CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE | USB_CNTR_WKUPM; +#endif + CNTR &= ~(USB_CNTR_SUSPM); + USB->ISTR = ~USB_ISTR_SUSP; + } + USB->CNTR = CNTR; // rewoke interrupts +} + +// here we suppose that all PIN settings done in hw_setup earlier +void USB_setup(){ +#if defined STM32F3 + NVIC_DisableIRQ(USB_LP_IRQn); + // remap USB LP & Wakeup interrupts to 75 and 76 - works only on pure F303 + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // enable tacting of SYSCFG + SYSCFG->CFGR1 |= SYSCFG_CFGR1_USB_IT_RMP; +#elif defined STM32F1 + NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); + NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn); +#elif defined STM32F0 + NVIC_DisableIRQ(USB_IRQn); + RCC->APB1ENR |= RCC_APB1ENR_CRSEN; + RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB + RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48 + uint32_t tmout = 16000000; + while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;} + FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY; + CRS->CFGR &= ~CRS_CFGR_SYNCSRC; + CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source + CRS->CR |= CRS_CR_AUTOTRIMEN; // enable auto trim + CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only + RCC->CFGR |= RCC_CFGR_SW; +#endif + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + //?? + USB->CNTR = USB_CNTR_FRES; // Force USB Reset + for(uint32_t ctr = 0; ctr < 72000; ++ctr) nop(); // wait >1ms + USB->CNTR = 0; + USB->BTABLE = 0; + USB->DADDR = 0; + USB->ISTR = 0; + USB->CNTR = USB_CNTR_RESETM; // allow only reset interrupts +#if defined STM32F3 + NVIC_EnableIRQ(USB_LP_IRQn); +#elif defined STM32F1 + NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); +#elif defined STM32F0 + USB->BCDR |= USB_BCDR_DPPU; + NVIC_EnableIRQ(USB_IRQn); +#endif + setup_interfaces(); // refresh interfaces names +} + + +#if defined STM32F3 +void usb_lp_isr() __attribute__ ((alias ("USB_IRQ"))); +#elif defined STM32F1 +void usb_lp_can_rx0_isr() __attribute__ ((alias ("USB_IRQ"))); +#elif defined STM32F0 +void usb_isr() __attribute__ ((alias ("USB_IRQ"))); +#endif diff --git a/F3:F303/Seven_CDCs/usb_lib.h b/F3:F303/Seven_CDCs/usb_lib.h index 13e45a5..9b1004f 100644 --- a/F3:F303/Seven_CDCs/usb_lib.h +++ b/F3:F303/Seven_CDCs/usb_lib.h @@ -1,6 +1,5 @@ /* - * This file is part of the SevenCDCs project. - * Copyright 2023 Edward V. Emelianov . + * Copyright 2024 Edward V. Emelianov . * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,72 +14,258 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #pragma once +#include #include -#include "usbhw.h" + +#ifndef _U_ +#define _U_ __attribute__((unused)) +#endif + +/****************************************************************** + * Hardware registers etc * + *****************************************************************/ +#if defined STM32F0 +#include +#elif defined STM32F1 +#include +// there's no this define in standard header +#define USB_BASE ((uint32_t)0x40005C00) +#elif defined STM32F3 +#include +#endif + +// max endpoints number +#define STM32ENDPOINTS 8 +/** + * Buffers size definition + **/ + +// F0 - USB2_16; F1 - USB1_16; F3 - 1/2 depending on series +#if !defined USB1_16 && !defined USB2_16 +#if defined STM32F0 +#define USB2_16 +#elif defined STM32F1 +#define USB1_16 +#else +#error "Can't determine USB1_16 or USB2_16, define by hands" +#endif +#endif + +// BTABLE_SIZE FOR STM32F3: +// In STM32F303/302xB/C, 512 bytes SRAM is not shared with CAN. +// In STM32F302x6/x8 and STM32F30xxD/E, 726 bytes dedicated SRAM and 256 bytes shared SRAM with CAN i.e. +// 1Kbytes dedicated SRAM in case CAN is disabled. +// remember, that USB_BTABLE_SIZE will be divided by ACCESSZ, so don't divide it twice for 32-bit addressing + +#ifdef NOCAN +#if defined STM32F0 +#define USB_BTABLE_SIZE 1024 +#elif defined STM32F3 +#define USB_BTABLE_SIZE 1024 +//#warning "Please, check real buffer size due to docs" +#else +#error "define STM32F0 or STM32F3" +#endif +#else // !NOCAN: F0/F3 with CAN or F1 (can't simultaneously run CAN and USB) +#if defined STM32F0 +#define USB_BTABLE_SIZE 768 +#elif defined STM32F3 +// 1024 bytes for USB and 256 from them are for CAN (on lower F303 with half-addr ACCESSZ=2 !!!) +#define USB_BTABLE_SIZE 768 +//#warning "Please, check real buffer size due to docs" +#else // STM32F103: 1024 bytes but with 32-bit addressing +#define USB_BTABLE_SIZE 1024 +#endif +#endif // NOCAN + +// first 64 bytes of USB_BTABLE are registers! + +#define USB_BTABLE_BASE 0x40006000 +#define USB ((USB_TypeDef *) USB_BASE) + +#ifdef USB_BTABLE +#undef USB_BTABLE +#endif +#define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE)) +#define USB_ISTR_EPID 0x0000000F +#define USB_FNR_LSOF_0 0x00000800 +#define USB_FNR_lSOF_1 0x00001000 +#define USB_LPMCSR_BESL_0 0x00000010 +#define USB_LPMCSR_BESL_1 0x00000020 +#define USB_LPMCSR_BESL_2 0x00000040 +#define USB_LPMCSR_BESL_3 0x00000080 +#define USB_EPnR_CTR_RX 0x00008000 +#define USB_EPnR_DTOG_RX 0x00004000 +#define USB_EPnR_STAT_RX 0x00003000 +#define USB_EPnR_STAT_RX_0 0x00001000 +#define USB_EPnR_STAT_RX_1 0x00002000 +#define USB_EPnR_SETUP 0x00000800 +#define USB_EPnR_EP_TYPE 0x00000600 +#define USB_EPnR_EP_TYPE_0 0x00000200 +#define USB_EPnR_EP_TYPE_1 0x00000400 +#define USB_EPnR_EP_KIND 0x00000100 +#define USB_EPnR_CTR_TX 0x00000080 +#define USB_EPnR_DTOG_TX 0x00000040 +#define USB_EPnR_STAT_TX 0x00000030 +#define USB_EPnR_STAT_TX_0 0x00000010 +#define USB_EPnR_STAT_TX_1 0x00000020 +#define USB_EPnR_EA 0x0000000F +#define USB_COUNTn_RX_BLSIZE 0x00008000 +#define USB_COUNTn_NUM_BLOCK 0x00007C00 +#define USB_COUNTn_RX 0x0000003F + +#define USB_TypeDef USB_TypeDef_custom + +typedef struct { + __IO uint32_t EPnR[STM32ENDPOINTS]; + __IO uint32_t RESERVED[STM32ENDPOINTS]; + __IO uint32_t CNTR; + __IO uint32_t ISTR; + __IO uint32_t FNR; + __IO uint32_t DADDR; + __IO uint32_t BTABLE; +#ifdef STM32F0 + __IO uint32_t LPMCSR; + __IO uint32_t BCDR; +#endif +} USB_TypeDef; + +// F303 D/E have 2x16 access scheme +typedef struct{ +#if defined USB2_16 + __IO uint16_t USB_ADDR_TX; + __IO uint16_t USB_COUNT_TX; + __IO uint16_t USB_ADDR_RX; + __IO uint16_t USB_COUNT_RX; +#define ACCESSZ (1) +#define BUFTYPE uint8_t +#elif defined USB1_16 + __IO uint32_t USB_ADDR_TX; + __IO uint32_t USB_COUNT_TX; + __IO uint32_t USB_ADDR_RX; + __IO uint32_t USB_COUNT_RX; +#define ACCESSZ (2) +#define BUFTYPE uint16_t +#else +#error "Define USB1_16 or USB2_16" +#endif +} USB_EPDATA_TypeDef; + + +typedef struct{ + __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS]; +} USB_BtableDef; #define EP0DATABUF_SIZE (64) #define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) -// bmRequestType & 0x7f -#define STANDARD_DEVICE_REQUEST_TYPE 0 -#define STANDARD_ENDPOINT_REQUEST_TYPE 2 -#define VENDOR_REQUEST_TYPE 0x40 -#define CONTROL_REQUEST_TYPE 0x21 -// bRequest, standard; for bmRequestType == 0x80 +/****************************************************************** + * Defines from usb.h * + *****************************************************************/ + +/* + * Device and/or Interface Class codes + */ +#define USB_CLASS_PER_INTERFACE 0 +#define USB_CLASS_AUDIO 1 +#define USB_CLASS_COMM 2 +#define USB_CLASS_HID 3 +#define USB_CLASS_PRINTER 7 +#define USB_CLASS_PTP 6 +#define USB_CLASS_MASS_STORAGE 8 +#define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 +#define USB_CLASS_MISC 0xef +#define USB_CLASS_VENDOR_SPEC 0xff + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 +#define USB_DT_QUALIFIER 0x06 +#define USB_DT_IAD 0x0B + +#define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 +#define USB_DT_CS_INTERFACE 0x24 +#define USB_DT_HUB 0x29 + +/* + * Descriptor sizes per descriptor type + */ +#define USB_DT_DEVICE_SIZE 18 +#define USB_DT_CONFIG_SIZE 9 +#define USB_DT_INTERFACE_SIZE 9 +#define USB_DT_HID_SIZE 9 +#define USB_DT_ENDPOINT_SIZE 7 +#define USB_DT_QUALIFIER_SIZE 10 +#define USB_DT_CS_INTERFACE_SIZE 5 +#define USB_DT_IAD_SIZE 8 + + +// bmRequestType & 0x80 == dev2host (1) or host2dev (0) +// recipient: bmRequestType & 0x1f +#define REQUEST_RECIPIENT(b) (b & 0x1f) +#define REQ_RECIPIENT_DEVICE 0 +#define REQ_RECIPIENT_INTERFACE 1 +#define REQ_RECIPIENT_ENDPOINT 2 +#define REQ_RECIPIENT_OTHER 3 +// type: [bmRequestType & 0x60 >> 5] +#define REQUEST_TYPE(b) ((b&0x60)>>5) +#define REQ_TYPE_STANDARD 0 +#define REQ_TYPE_CLASS 1 +#define REQ_TYPE_VENDOR 2 +#define REQ_TYPE_RESERVED 3 + + +//#define VENDOR_REQUEST 0x01 + +// standard device requests #define GET_STATUS 0x00 -#define GET_DESCRIPTOR 0x06 -#define GET_CONFIGURATION 0x08 -// for bmRequestType == 0 #define CLEAR_FEATURE 0x01 -#define SET_FEATURE 0x03 // unused +#define SET_FEATURE 0x03 #define SET_ADDRESS 0x05 -#define SET_DESCRIPTOR 0x07 // unused +#define GET_DESCRIPTOR 0x06 +#define SET_DESCRIPTOR 0x07 +#define GET_CONFIGURATION 0x08 #define SET_CONFIGURATION 0x09 -// for bmRequestType == 0x81, 1 or 0xB2 -#define GET_INTERFACE 0x0A // unused -#define SET_INTERFACE 0x0B // unused -#define SYNC_FRAME 0x0C // unused -#define VENDOR_REQUEST 0x01 // unused - -// Class-Specific Control Requests -#define SEND_ENCAPSULATED_COMMAND 0x00 // unused -#define GET_ENCAPSULATED_RESPONSE 0x01 // unused -#define SET_COMM_FEATURE 0x02 // unused -#define GET_COMM_FEATURE 0x03 // unused -#define CLEAR_COMM_FEATURE 0x04 // unused -#define SET_LINE_CODING 0x20 -#define GET_LINE_CODING 0x21 -#define SET_CONTROL_LINE_STATE 0x22 -#define SEND_BREAK 0x23 - -// control line states -#define CONTROL_DTR 0x01 -#define CONTROL_RTS 0x02 - -// string descriptors -enum{ - iLANGUAGE_DESCR, - iMANUFACTURER_DESCR, - iPRODUCT_DESCR, - iSERIAL_DESCR, - iINTERFACE_DESCR_CMD, - iINTERFACE_DESCR_DBG, - iINTERFACE_DESCR_USART1, - iINTERFACE_DESCR_USART2, - iINTERFACE_DESCR_USART3, - iINTERFACE_DESCR_USART4, - iINTERFACE_DESCR_CAN, - iDESCR_AMOUNT -}; +// and some standard interface requests +#define GET_INTERFACE 0x0A +#define SET_INTERFACE 0x0B +// and some standard endpoint requests +#define SYNC_FRAME 0x0C // Types of descriptors #define DEVICE_DESCRIPTOR 0x01 #define CONFIGURATION_DESCRIPTOR 0x02 #define STRING_DESCRIPTOR 0x03 #define DEVICE_QUALIFIER_DESCRIPTOR 0x06 +#define DEBUG_DESCRIPTOR 0x0a +#define HID_REPORT_DESCRIPTOR 0x22 + +// EP types for EP_init +#define EP_TYPE_BULK 0x00 +#define EP_TYPE_CONTROL 0x01 +#define EP_TYPE_ISO 0x02 +#define EP_TYPE_INTERRUPT 0x03 + +// EP types for descriptors +#define USB_BM_ATTR_CONTROL 0x00 +#define USB_BM_ATTR_ISO 0x01 +#define USB_BM_ATTR_BULK 0x02 +#define USB_BM_ATTR_INTERRUPT 0x03 + + +/****************************************************************** + * Other stuff * + *****************************************************************/ #define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) #define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) @@ -90,12 +275,6 @@ enum{ #define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) #define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) -// EP types -#define EP_TYPE_BULK 0x00 -#define EP_TYPE_CONTROL 0x01 -#define EP_TYPE_ISO 0x02 -#define EP_TYPE_INTERRUPT 0x03 - #define LANG_US (uint16_t)0x0409 #define _USB_STRING_(name, str) \ @@ -109,7 +288,6 @@ static const struct name \ name = {sizeof(name), 0x03, str} #define _USB_LANG_ID_(name, lng_id) \ - \ static const struct name \ { \ uint8_t bLength; \ @@ -133,35 +311,19 @@ typedef struct{ uint16_t *tx_buf; // transmission buffer address uint16_t txbufsz; // transmission buffer size uint8_t *rx_buf; // reception buffer address - void (*func)(uint8_t epno); // endpoint action function + void (*func)(); // endpoint action function unsigned rx_cnt : 10; // received data counter } ep_t; -typedef struct { - uint32_t dwDTERate; - uint8_t bCharFormat; - #define USB_CDC_1_STOP_BITS 0 - #define USB_CDC_1_5_STOP_BITS 1 - #define USB_CDC_2_STOP_BITS 2 - uint8_t bParityType; - #define USB_CDC_NO_PARITY 0 - #define USB_CDC_ODD_PARITY 1 - #define USB_CDC_EVEN_PARITY 2 - #define USB_CDC_MARK_PARITY 3 - #define USB_CDC_SPACE_PARITY 4 - uint8_t bDataBits; -} __attribute__ ((packed)) usb_LineCoding; - -extern ep_t endpoints[]; -// device disconnected from terminal (BIT flags!!!) -#define USBON(ifno) (usbON & (1<