try to make PL2303 @ new concept

This commit is contained in:
Edward Emelianov 2024-12-12 22:55:24 +03:00
parent d8284ea725
commit f9d9735a5e
11 changed files with 662 additions and 156 deletions

View File

@ -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;
}

View File

@ -0,0 +1,167 @@
/*
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 len<data in buffer or buffer is busy)
*/
int RB_readto(ringbuffer *b, uint8_t byte, uint8_t *s, int len){
if(b->busy) 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;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2023 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#if defined STM32F0
#include <stm32f0.h>
#elif defined STM32F1
#include <stm32f1.h>
#elif defined STM32F3
#include <stm32f3.h>
#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);

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 14.0.2, 2024-11-30T23:28:05. -->
<!-- Written by QtCreator 14.0.2, 2024-12-12T22:54:34. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@ -1,6 +1,8 @@
hardware.c
hardware.h
main.c
ringbuffer.c
ringbuffer.h
usb_descr.c
usb_descr.h
usb_lib.c

View File

@ -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
@ -87,20 +74,47 @@ const uint8_t USB_ConfigDescriptor[] = {
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;
}
}

View File

@ -18,6 +18,8 @@
#include <stdint.h>
#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);

View File

@ -18,65 +18,261 @@
#include <stm32f1.h>
#include <string.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 = 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);
EP_Write(3, (uint8_t*)usbbuff, buflen);
lastdsz = buflen;
}
// 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 CMD_GET_STATUS:
memcpy(buf, &status, sizeof(status));
len = sizeof(status);
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;
}
EP_WriteIRQ(0, buf, len); // write ZLP if nothing received
break;
default:
if(dev2host) EP_WriteIRQ(0, NULL, 0);
}
}
void usb_vendor_request(config_pack_t *req, uint8_t *data, unsigned int datalen) __attribute__ ((alias ("usb_class_request")));
// 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;
}

View File

@ -18,3 +18,47 @@
#include <stm32f1.h>
#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);

View File

@ -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);
}
/*

View File

@ -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();