diff --git a/F1:F103/USB_NEW_concept/main.c b/F1:F103/USB_NEW_concept/main.c index f94ba27..cc3afe1 100644 --- a/F1:F103/USB_NEW_concept/main.c +++ b/F1:F103/USB_NEW_concept/main.c @@ -17,7 +17,6 @@ */ #include "hardware.h" -#include "usb_lib.h" #include "usb_dev.h" volatile uint32_t Tms = 0; @@ -30,24 +29,28 @@ void sys_tick_handler(void){ #define STRLEN (256) int main(void){ + char inbuff[RBINSZ+1]; uint32_t lastT = 0; StartHSE(); hw_setup(); USBPU_OFF(); SysTick_Config(72000); USB_setup(); - i2c_setup(); #ifndef EBUG iwdg_setup(); #endif USBPU_ON(); - while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(lastT > Tms || Tms - lastT > 499){ LED_blink(LED0); lastT = Tms; } + int l = USB_receivestr(inbuff, RBINSZ); + if(l < 0) USB_sendstr("ERROR: USB buffer overflow or string was too long\n"); + else if(l){ + USB_sendstr("RECEIVED: _"); USB_sendstr(inbuff); USB_sendstr("_\n"); + } } return 0; } diff --git a/F1:F103/USB_NEW_concept/ringbuffer.c b/F1:F103/USB_NEW_concept/ringbuffer.c new file mode 100644 index 0000000..8d8d6ca --- /dev/null +++ b/F1:F103/USB_NEW_concept/ringbuffer.c @@ -0,0 +1,167 @@ +/* + * 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 "ringbuffer.h" + +static int datalen(ringbuffer *b){ + if(b->tail >= b->head) return (b->tail - b->head); + else return (b->length - b->head + b->tail); +} + +// 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){ // + 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; +} + +/** + * @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++; +} + +// increment head or tail +TRUE_INLINE void incr(ringbuffer *b, volatile int *what, int n){ + *what += n; + if(*what >= b->length) *what -= b->length; +} + +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; + 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_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 lenbusy) return -1; + b->busy = 1; + int n = readto(b, byte, s, len); + b->busy = 0; + return n; +} + +static int write(ringbuffer *b, const uint8_t *str, int l){ + int r = b->length - 1 - 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; +} + +/** + * @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` +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/F1:F103/USB_NEW_concept/ringbuffer.h b/F1:F103/USB_NEW_concept/ringbuffer.h new file mode 100644 index 0000000..ed2cf95 --- /dev/null +++ b/F1:F103/USB_NEW_concept/ringbuffer.h @@ -0,0 +1,41 @@ +/* + * 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 + +#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); +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); +int RB_clearbuf(ringbuffer *b); diff --git a/F1:F103/USB_NEW_concept/someusb.creator.user b/F1:F103/USB_NEW_concept/someusb.creator.user index 8d6c72e..8f45bb0 100644 --- a/F1:F103/USB_NEW_concept/someusb.creator.user +++ b/F1:F103/USB_NEW_concept/someusb.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F1:F103/USB_NEW_concept/someusb.files b/F1:F103/USB_NEW_concept/someusb.files index 66e8365..c1b4596 100644 --- a/F1:F103/USB_NEW_concept/someusb.files +++ b/F1:F103/USB_NEW_concept/someusb.files @@ -1,6 +1,8 @@ hardware.c hardware.h main.c +ringbuffer.c +ringbuffer.h usb_descr.c usb_descr.h usb_lib.c diff --git a/F1:F103/USB_NEW_concept/usb_descr.c b/F1:F103/USB_NEW_concept/usb_descr.c index 4993ff2..a21a3a7 100644 --- a/F1:F103/USB_NEW_concept/usb_descr.c +++ b/F1:F103/USB_NEW_concept/usb_descr.c @@ -16,23 +16,10 @@ */ #include "usb_descr.h" -#include "usb_lib.h" -// 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 -}; +// low/high for uint16_t +#define L16(x) (x & 0xff) +#define H16(x) (x >> 8) const uint8_t USB_DeviceDescriptor[] = { USB_DT_DEVICE_SIZE, // bLength @@ -43,12 +30,12 @@ const uint8_t USB_DeviceDescriptor[] = { bDeviceSubClass, // bDeviceSubClass bDeviceProtocol, // bDeviceProtocol USB_EP0BUFSZ, // bMaxPacketSize - L(idVendor), // idVendor_L - H(idVendor), // idVendor_H - L(idProduct), // idProduct_L - H(idProduct), // idProduct_H - L(bcdDevice_Ver), // bcdDevice_Ver_L - H(bcdDevice_Ver), // bcdDevice_Ver_H + 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 @@ -71,7 +58,7 @@ const uint8_t USB_DeviceQualifierDescriptor[] = { #define wTotalLength (USB_DT_CONFIG_SIZE + (bNumInterfaces * USB_DT_INTERFACE_SIZE) + (bTotNumEndpoints * USB_DT_ENDPOINT_SIZE)) const uint8_t USB_ConfigDescriptor[] = { - /*Configuration Descriptor*/ + /* Configuration Descriptor*/ USB_DT_CONFIG_SIZE, /* bLength: Configuration Descriptor size */ USB_DT_CONFIG, /* bDescriptorType: Configuration */ L16(wTotalLength), /* wTotalLength.L :no of returned bytes */ @@ -82,25 +69,52 @@ const uint8_t USB_ConfigDescriptor[] = { BusPowered, /* bmAttributes - Bus powered */ 100, /* MaxPower in 2mA units */ /*---------------------------------------------------------------------------*/ - /*Interface Descriptor */ + /* Interface Descriptor */ USB_DT_INTERFACE_SIZE, /* bLength: Interface Descriptor size */ USB_DT_INTERFACE, /* bDescriptorType: Interface */ 0, /* bInterfaceNumber: Number of Interface */ 0, /* bAlternateSetting: Alternate setting */ - 1, /* bNumEndpoints: only 1 used */ - 0, /* bInterfaceClass */ + 3, /* bNumEndpoints */ + USB_CLASS_VENDOR_SPEC, /* bInterfaceClass */ 0, /* bInterfaceSubClass */ 0, /* bInterfaceProtocol */ iINTERFACE_DESCR1, /* iInterface: */ + /*---------------------------------------------------------------------------*/ + /* Endpoint 1 Descriptor */ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ + 0x81, /* bEndpointAddress IN1 */ + EP_TYPE_INTERRUPT, /* bmAttributes: Interrupt */ + L16(USB_EP1BUFSZ), /* wMaxPacketSize LO */ + H16(USB_EP1BUFSZ), /* wMaxPacketSize HI */ + 0x01, /* bInterval: 1ms */ + /* Endpoint OUT2 Descriptor */ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ + 0x02, /* bEndpointAddress: OUT2 */ + EP_TYPE_BULK, /* bmAttributes: Bulk */ + L16(USB_RXBUFSZ), /* wMaxPacketSize LO */ + H16(USB_RXBUFSZ), /* wMaxPacketSize HI */ + 0, /* bInterval: ignore for Bulk transfer */ + /*Endpoint IN3 Descriptor*/ + USB_DT_ENDPOINT_SIZE, /* bLength: Endpoint Descriptor size */ + USB_DT_ENDPOINT, /* bDescriptorType: Endpoint */ + 0x83, /* bEndpointAddress: IN3 */ + EP_TYPE_BULK, /* bmAttributes: Bulk */ + L16(USB_TXBUFSZ), /* wMaxPacketSize LO */ + H16(USB_TXBUFSZ), /* wMaxPacketSize HI */ + 0, /* bInterval: ignore for Bulk transfer */ }; +//const uint8_t HID_ReportDescriptor[]; + _USB_LANG_ID_(LD, LANG_US); _USB_STRING_(SD, u"0.0.1"); -_USB_STRING_(MD, u"eddy@sao"); -_USB_STRING_(PD, u"Some USB device"); -_USB_STRING_(ID, u"first interface"); +_USB_STRING_(MD, u"eddy@sao.ru"); +_USB_STRING_(PD, u"USB-Serial Controller"); +_USB_STRING_(ID, u"USB-STM32"); -const uint8_t* const StringDescriptor[iDESCR_AMOUNT] = { +const void* const StringDescriptor[iDESCR_AMOUNT] = { [iLANGUAGE_DESCR] = &LD, [iMANUFACTURER_DESCR] = &MD, [iPRODUCT_DESCR] = &PD, @@ -108,3 +122,55 @@ const uint8_t* const StringDescriptor[iDESCR_AMOUNT] = { [iINTERFACE_DESCR1] = &ID }; +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; + } +} diff --git a/F1:F103/USB_NEW_concept/usb_descr.h b/F1:F103/USB_NEW_concept/usb_descr.h index 97f065d..c842e9c 100644 --- a/F1:F103/USB_NEW_concept/usb_descr.h +++ b/F1:F103/USB_NEW_concept/usb_descr.h @@ -18,6 +18,8 @@ #include +#include "usb_lib.h" + // definition of parts common for USB_DeviceDescriptor & USB_DeviceQualifierDescriptor // bcdUSB: 1.10 #define bcdUSB 0x0110 @@ -28,10 +30,6 @@ #define bcdDevice_Ver 0x0205 #define bNumConfigurations 1 -// low/high for uint16_t -#define L16(x) (x & 0xff) -#define H16(x) (x >> 8) - // amount of interfaces and endpoints (except 0) used #define bNumInterfaces 1 #define bTotNumEndpoints 1 @@ -41,6 +39,27 @@ #define SelfPowered (1<<6) #define RemoteWakeup (1<<5) -extern const uint8_t USB_DeviceDescriptor[]; -extern const uint8_t USB_DeviceQualifierDescriptor[]; -extern const uint8_t USB_ConfigDescriptor[]; +// buffer sizes +// for USB FS EP0 buffers are from 8 to 64 bytes long +#define USB_EP0BUFSZ 64 +#define USB_EP1BUFSZ 10 +#define USB_RXBUFSZ 64 +#define USB_TXBUFSZ 64 + +// 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); diff --git a/F1:F103/USB_NEW_concept/usb_dev.c b/F1:F103/USB_NEW_concept/usb_dev.c index 695feb1..e0fd5c5 100644 --- a/F1:F103/USB_NEW_concept/usb_dev.c +++ b/F1:F103/USB_NEW_concept/usb_dev.c @@ -18,65 +18,261 @@ #include #include +#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 = 0; + +// receive buffer: hold data until chkin() call +static uint8_t volatile rcvbuf[USB_RXBUFSZ]; +static uint8_t volatile rcvbuflen = 0; +// line coding +usb_LineCoding WEAK lineCoding = {115200, 0, 0, 8}; +// CDC configured and ready to use +static volatile uint8_t CDCready = 0; + +// ring buffers for incoming and outgoing data +static uint8_t obuf[RBOUTSZ], ibuf[RBINSZ]; +static volatile ringbuffer rbout = {.data = obuf, .length = RBOUTSZ, .head = 0, .tail = 0}; +static volatile ringbuffer rbin = {.data = ibuf, .length = RBINSZ, .head = 0, .tail = 0}; +// last send data size +static volatile int lastdsz = 0; + static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; } -void set_configuration(uint16_t _U_ configuration){ +static void chkin(){ + if(bufovrfl) return; // allow user to know that previous buffer was overflowed and cleared + if(!rcvbuflen) return; + int w = RB_write((ringbuffer*)&rbin, (uint8_t*)rcvbuf, rcvbuflen); + if(w < 0) return; + if(w != rcvbuflen) bufovrfl = 1; + rcvbuflen = 0; + uint16_t status = KEEP_DTOG(USB->EPnR[2]); // don't change DTOG + USB->EPnR[2] = status ^ USB_EPnR_STAT_RX; } - -void usb_class_request(config_pack_t *req, uint8_t *data, unsigned int datalen){ - uint8_t buf[USB_EP0BUFSZ]; - size_t len = 0; - //uint8_t recipient = REQUEST_RECIPIENT(req->bmRequestType); - if((req->bmRequestType & 0x80) == 0){ // OUT - setters - switch(req->bRequest){ - case CMD_I2C_IO: - case CMD_I2C_IO | CMD_I2C_BEGIN: - case CMD_I2C_IO | CMD_I2C_END: - case CMD_I2C_IO | CMD_I2C_BEGIN | CMD_I2C_END: // write - if(req->wValue & I2C_M_RD) break; // OUT - only write - if(!data) break; // wait for data - len = datalen; - usb_i2c_io(req, data, &len); - break; - default: - break; - } - EP_WriteIRQ(0, 0, 0); +// called from transmit EP to send next data portion or by user - when new transmission starts +static void send_next(){ + uint8_t usbbuff[USB_TXBUFSZ]; + int buflen = RB_read((ringbuffer*)&rbout, (uint8_t*)usbbuff, USB_TXBUFSZ); + if(buflen == 0){ + if(lastdsz == 64) EP_Write(3, NULL, 0); // send ZLP after 64 bits packet when nothing more to send + lastdsz = 0; + return; + }else if(buflen < 0){ + lastdsz = 0; + // Uncomment next line if you want 4Mbit/s instead of 6Mbit/s + //EP_Write(3, NULL, 0); // send ZLP if buffer is in writting state now return; } - switch(req->bRequest){ - case CMD_ECHO: - memcpy(buf, &req->wValue, sizeof(req->wValue)); - len = sizeof(req->wValue); - break; - case CMD_GET_FUNC: - /* Report our capabilities */ - bzero(buf, req->wLength); - memcpy(buf, &func, sizeof(func)); - len = req->wLength; - break; - case CMD_I2C_IO: - case CMD_I2C_IO | CMD_I2C_BEGIN: - case CMD_I2C_IO | CMD_I2C_END: - case CMD_I2C_IO | CMD_I2C_BEGIN | CMD_I2C_END: // read - if(req->wValue & I2C_M_RD){ // IN - only read - len = req->wLength; - usb_i2c_io(req, buf, &len); - } - break; - case CMD_GET_STATUS: - memcpy(buf, &status, sizeof(status)); - len = sizeof(status); - break; - default: - break; - } - EP_WriteIRQ(0, buf, len); // write ZLP if nothing received + EP_Write(3, (uint8_t*)usbbuff, buflen); + lastdsz = buflen; } -void usb_vendor_request(config_pack_t *req, uint8_t *data, unsigned int datalen) __attribute__ ((alias ("usb_class_request"))); +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); + // clear CTR keep DTOGs & STATs + USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr + send_next(); +} + +// receiver reads data from local buffer and only then ACK'ed +static void receive_Handler(){ // EP2OUT + uint16_t status = KEEP_DTOG_STAT(USB->EPnR[2]); // don't change DTOG and NACK + if(rcvbuflen){ + bufovrfl = 1; // lost last data + rcvbuflen = 0; + } + rcvbuflen = EP_Read(2, (uint8_t*)rcvbuf); + USB->EPnR[2] = status & ~USB_EPnR_CTR_RX; +} + +// weak handlers: change them somewhere else if you want to setup USART +// SET_LINE_CODING +void WEAK linecoding_handler(usb_LineCoding *lc){ + lineCoding = *lc; +} + +// SET_CONTROL_LINE_STATE +void WEAK clstate_handler(uint16_t _U_ val){ +} + +// SEND_BREAK +void WEAK break_handler(){ +} + + +// USB is configured: setup endpoints +void set_configuration(){ + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data +} + +// PL2303 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; + switch(recipient){ + case REQ_RECIPIENT_INTERFACE: + switch(req->bRequest){ + case SET_LINE_CODING: + if(!data || !datalen) break; // wait for data + if(datalen == sizeof(usb_LineCoding)) + linecoding_handler((usb_LineCoding*)data); + break; + case GET_LINE_CODING: + EP_WriteIRQ(0, (uint8_t*)&lineCoding, sizeof(lineCoding)); + break; + case SET_CONTROL_LINE_STATE: + CDCready = 1; + clstate_handler(req->wValue); + break; + case SEND_BREAK: + CDCready = 0; + break_handler(); + break; + default: + break; + } + break; + default: + if(dev2host) EP_WriteIRQ(0, NULL, 0); + } +} + +// Vendor request for PL2303 +void usb_vendor_request(config_pack_t *req, uint8_t _U_ *data, uint16_t _U_ datalen){ + uint8_t c; + if(req->bmRequestType & 0x80){ // read + switch(req->wValue){ + case 0x8484: + c = 2; + break; + case 0x0080: + c = 1; + break; + case 0x8686: + c = 0xaa; + break; + default: + c = 0; + } + EP_WriteIRQ(0, &c, 1); + }else{ // write ZLP + EP_WriteIRQ(0, NULL, 0); + } +} + + + +// blocking send full content of ring buffer +int USB_sendall(){ + while(lastdsz > 0){ + if(!CDCready) return FALSE; + } + return TRUE; +} + +// put `buf` into queue to send +int USB_send(const uint8_t *buf, int len){ + if(!buf || !CDCready || !len) return FALSE; + while(len){ + int a = RB_write((ringbuffer*)&rbout, buf, len); + if(a > 0){ + len -= a; + buf += a; + } else if (a < 0) continue; // do nothing if buffer is in reading state + if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN + } + return TRUE; +} + +int USB_putbyte(uint8_t byte){ + if(!CDCready) return FALSE; + int l = 0; + while((l = RB_write((ringbuffer*)&rbout, &byte, 1)) != 1){ + if(l < 0) continue; + } + if(lastdsz == 0) send_next(); // need to run manually - all data sent, so no IRQ on IN + return TRUE; +} + +int USB_sendstr(const char *string){ + if(!string || !CDCready) return FALSE; + int len = 0; + const char *b = string; + while(*b++) ++len; + if(!len) return FALSE; + return USB_send((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 *buf, int len){ + chkin(); + if(bufovrfl){ + while(1 != RB_clearbuf((ringbuffer*)&rbin)); + bufovrfl = 0; + return -1; + } + int sz = RB_read((ringbuffer*)&rbin, 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(char *buf, int len){ + chkin(); + if(bufovrfl){ + while(1 != RB_clearbuf((ringbuffer*)&rbin)); + bufovrfl = 0; + return -1; + } + int l = RB_readto((ringbuffer*)&rbin, '\n', (uint8_t*)buf, len); + if(l < 1){ + if(rbin.length == RB_datalen((ringbuffer*)&rbin)){ // buffer is full but no '\n' found + while(1 != RB_clearbuf((ringbuffer*)&rbin)); + return -1; + } + return 0; + } + if(l == 0) return 0; + buf[l-1] = 0; // replace '\n' with strend + return l; +} diff --git a/F1:F103/USB_NEW_concept/usb_dev.h b/F1:F103/USB_NEW_concept/usb_dev.h index 3e55209..163dc6d 100644 --- a/F1:F103/USB_NEW_concept/usb_dev.h +++ b/F1:F103/USB_NEW_concept/usb_dev.h @@ -18,3 +18,47 @@ #include #include "usb_lib.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 usb_LineCoding lineCoding; + +void break_handler(); +void clstate_handler(uint16_t val); +void linecoding_handler(usb_LineCoding *lc); + + +// sizes of ringbuffers for outgoing and incoming data +#define RBOUTSZ (256) +#define RBINSZ (256) + +#define newline() USB_putbyte('\n') +#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) + +#define STR_HELPER(s) #s +#define STR(s) STR_HELPER(s) + +#ifdef EBUG +#define DBG(str) do{USB_sendstr(__FILE__ " (L" STR(__LINE__) "): " str); newline();}while(0) +#else +#define DBG(str) +#endif + +int USB_sendall(); +int USB_send(const uint8_t *buf, int len); +int USB_putbyte(uint8_t byte); +int USB_sendstr(const char *string); +int USB_receive(uint8_t *buf, int len); +int USB_receivestr(char *buf, int len); diff --git a/F1:F103/USB_NEW_concept/usb_lib.c b/F1:F103/USB_NEW_concept/usb_lib.c index 4676535..a4cf454 100644 --- a/F1:F103/USB_NEW_concept/usb_lib.c +++ b/F1:F103/USB_NEW_concept/usb_lib.c @@ -28,62 +28,14 @@ static uint8_t ep0dbuflen = 0; static config_pack_t *setup_packet = (config_pack_t*) setupdatabuf; volatile uint8_t usbON = 0; // device is configured and active -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 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, (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; - } -} +const uint8_t HID_ReportDescriptor[] WEAK = {0}; static uint16_t configuration = 0; // reply for GET_CONFIGURATION (==1 if configured) static inline void std_d2h_req(){ 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 *)&st, 2); // send status: Bus Powered @@ -105,7 +57,7 @@ static inline void std_h2d_req(){ case SET_CONFIGURATION: // Now device configured configuration = setup_packet->wValue; - set_configuration(configuration); + set_configuration(); usbON = 1; break; default: @@ -116,6 +68,7 @@ static inline void std_h2d_req(){ void WEAK usb_standard_request(){ uint8_t recipient = REQUEST_RECIPIENT(setup_packet->bmRequestType); uint8_t dev2host = (setup_packet->bmRequestType & 0x80) ? 1 : 0; + uint8_t reqtype = REQUEST_TYPE(setup_packet->bmRequestType); switch(recipient){ case REQ_RECIPIENT_DEVICE: if(dev2host){ @@ -123,15 +76,31 @@ void WEAK usb_standard_request(){ return; }else{ std_h2d_req(); - EP_WriteIRQ(0, (uint8_t *)0, 0); + EP_WriteIRQ(0, NULL, 0); } break; case REQ_RECIPIENT_INTERFACE: - //EP_WriteIRQ(0, (const uint8_t*)"epi", 4); + switch(reqtype){ + case REQ_TYPE_STANDARD: + if(dev2host && setup_packet->bRequest == GET_DESCRIPTOR){ + get_descriptor(setup_packet); + }else EP_WriteIRQ(0, NULL, 0); + break; + case REQ_TYPE_CLASS: + if(setup_packet->bRequest == GET_INTERFACE){ + EP_WriteIRQ(0, NULL, 0); + }/*else if (setup_packet->bRequest == SET_FEAUTRE){ + //set_featuring = 1; + }*/ + break; + default: + if(dev2host) EP_WriteIRQ(0, NULL, 0); + break; + } break; case REQ_RECIPIENT_ENDPOINT: if(setup_packet->bRequest == CLEAR_FEATURE){ - EP_WriteIRQ(0, (uint8_t *)0, 0); + EP_WriteIRQ(0, NULL, 0); }else{ //EP_WriteIRQ(0, (const uint8_t*)"epr", 4); } @@ -142,12 +111,12 @@ void WEAK usb_standard_request(){ } } -void WEAK usb_class_request(config_pack_t _U_ *req, uint8_t _U_ *data, unsigned int _U_ datalen){ - EP_WriteIRQ(0, (const uint8_t*)"cls", 4); +void WEAK usb_class_request(config_pack_t _U_ *req, uint8_t _U_ *data, uint16_t _U_ datalen){ + EP_WriteIRQ(0, NULL, 0); } -void WEAK usb_vendor_request(config_pack_t _U_ *packet, uint8_t _U_ *data, unsigned int _U_ datalen){ - EP_WriteIRQ(0, (const uint8_t*)"vnd", 4); +void WEAK usb_vendor_request(config_pack_t _U_ *packet, uint8_t _U_ *data, uint16_t datalen){ + EP_WriteIRQ(0, NULL, 0); } /* diff --git a/F1:F103/USB_NEW_concept/usb_lib.h b/F1:F103/USB_NEW_concept/usb_lib.h index db19778..2c947c9 100644 --- a/F1:F103/USB_NEW_concept/usb_lib.h +++ b/F1:F103/USB_NEW_concept/usb_lib.h @@ -76,10 +76,6 @@ #endif // NOCAN // first 64 bytes of USB_BTABLE are registers! -// for USB FS EP0 buffers are from 8 to 64 bytes long -#define USB_EP0BUFSZ 64 -// EP1 - interrupt - buffer size -#define USB_EP1BUFSZ 8 #define USB_BTABLE_BASE 0x40006000 #define USB ((USB_TypeDef *) USB_BASE) @@ -218,6 +214,7 @@ typedef struct{ #define REQ_TYPE_VENDOR 2 #define REQ_TYPE_RESERVED 3 +/* // deprecated defines: #define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_INTERFACE_REQUEST_TYPE 1 @@ -225,6 +222,7 @@ typedef struct{ #define STANDARD_OTHER_REQUEST_TYPE 3 #define VENDOR_REQUEST_TYPE 0x40 #define CONTROL_REQUEST_TYPE 0x21 +*/ // bRequest, standard; for bmRequestType == 0x80 #define GET_STATUS 0x00 @@ -247,6 +245,7 @@ typedef struct{ #define CONFIGURATION_DESCRIPTOR 0x02 #define STRING_DESCRIPTOR 0x03 #define DEVICE_QUALIFIER_DESCRIPTOR 0x06 +#define HID_REPORT_DESCRIPTOR 0x2200 // EP types #define EP_TYPE_BULK 0x00 @@ -315,6 +314,6 @@ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); int EP_Read(uint8_t number, uint8_t *buf); // could be [re]defined in usb_dev.c -extern void usb_class_request(config_pack_t *packet, uint8_t *data, unsigned int datalen); -extern void usb_vendor_request(config_pack_t *packet, uint8_t *data, unsigned int datalen); -extern void set_configuration(uint16_t configuration); +extern void usb_class_request(config_pack_t *packet, uint8_t *data, uint16_t datalen); +extern void usb_vendor_request(config_pack_t *packet, uint8_t *data, uint16_t datalen); +extern void set_configuration();