File syn_usb_cdc.c¶
File List > drivers > syn_usb_cdc.c
Go to the documentation of this file
#include "syntropic/drivers/syn_usb_cdc.h"
#include <string.h>
static const uint8_t CDC_INTERFACE_DESC[67] = {
/* Interface Association Descriptor (IAD) */
0x08, 0x0B, 0x00, 0x02, 0x02, 0x02, 0x01, 0x00,
/* Interface 0: Communication Interface Class */
0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,
/* Header Functional Descriptor */
0x05, 0x24, 0x00, 0x10, 0x01,
/* Call Management Functional Descriptor */
0x05, 0x24, 0x01, 0x00, 0x01,
/* ACM Functional Descriptor */
0x04, 0x24, 0x02, 0x02,
/* Union Functional Descriptor */
0x05, 0x24, 0x06, 0x00, 0x01,
/* Endpoint 0x82: Interrupt IN */
0x07, 0x05, 0x82, 0x03, 0x08, 0x00, 0x10,
/* Interface 1: Data Interface Class */
0x09, 0x04, 0x01, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,
/* Endpoint 0x01: Bulk OUT */
0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00,
/* Endpoint 0x81: Bulk IN */
0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00};
static SYN_Status cdc_class_setup(void *ctx, const SYN_USB_SetupPacket *pkt, uint8_t *resp,
uint16_t *rlen)
{
SYN_USB_CDC *cdc = (SYN_USB_CDC *)ctx;
size_t size_rlen = 0;
SYN_Status st = syn_usb_cdc_handle_setup(cdc, pkt, resp, &size_rlen);
*rlen = (uint16_t)size_rlen;
return st;
}
static SYN_Status cdc_class_configured(void *ctx, uint8_t config)
{
SYN_USB_CDC *cdc = (SYN_USB_CDC *)ctx;
if (cdc) {
cdc->configured = (config != 0U);
}
return SYN_OK;
}
SYN_Status syn_usb_cdc_init(SYN_USB_CDC *cdc)
{
if (!cdc) {
return SYN_INVALID_PARAM;
}
memset(cdc, 0, sizeof(*cdc));
cdc->ep_in = 0x81;
cdc->ep_out = 0x01;
cdc->ep_cmd = 0x82;
cdc->configured = false;
cdc->line_coding.baudrate = 115200;
cdc->line_coding.stop_bits = 0; /* 1 Stop Bit */
cdc->line_coding.parity = 0; /* None */
cdc->line_coding.data_bits = 8;
return SYN_OK;
}
SYN_Status syn_usb_cdc_register(SYN_USB_Device *dev, SYN_USB_CDC *cdc)
{
if (!dev || !cdc) {
return SYN_INVALID_PARAM;
}
SYN_USB_ClassDriver cls;
memset(&cls, 0, sizeof(cls));
cls.iface_start = 0U;
cls.iface_count = 2U;
cls.ctx = cdc;
cls.setup = cdc_class_setup;
cls.configured = cdc_class_configured;
return syn_usb_register_class(dev, &cls, CDC_INTERFACE_DESC, sizeof(CDC_INTERFACE_DESC));
}
SYN_Status syn_usb_cdc_handle_setup(SYN_USB_CDC *cdc, const SYN_USB_SetupPacket *setup,
uint8_t *resp, size_t *rlen)
{
if (!cdc || !setup || !resp || !rlen) {
return SYN_INVALID_PARAM;
}
*rlen = 0;
switch (setup->bRequest) {
case SYN_USB_REQ_SET_ADDRESS:
cdc->dev_address = (uint8_t)(setup->wValue & 0x7F);
return SYN_OK;
case SYN_USB_REQ_SET_CONFIGURATION:
cdc->configured = (setup->wValue != 0);
return SYN_OK;
case SYN_USB_CDC_SET_LINE_CODING:
/* Line coding data stage handler can update active parameters */
return SYN_OK;
case SYN_USB_CDC_GET_LINE_CODING:
resp[0] = (uint8_t)(cdc->line_coding.baudrate & 0xFF);
resp[1] = (uint8_t)((cdc->line_coding.baudrate >> 8) & 0xFF);
resp[2] = (uint8_t)((cdc->line_coding.baudrate >> 16) & 0xFF);
resp[3] = (uint8_t)((cdc->line_coding.baudrate >> 24) & 0xFF);
resp[4] = cdc->line_coding.stop_bits;
resp[5] = cdc->line_coding.parity;
resp[6] = cdc->line_coding.data_bits;
*rlen = 7;
return SYN_OK;
case SYN_USB_CDC_SET_CONTROL_LINE_STATE:
return SYN_OK;
default:
return SYN_OK;
}
}
SYN_Status syn_usb_cdc_write(SYN_USB_CDC *cdc, const void *data, size_t len)
{
if (!cdc || !data || len == 0) {
return SYN_INVALID_PARAM;
}
if (len > sizeof(cdc->tx_buf)) {
len = sizeof(cdc->tx_buf);
}
memcpy(cdc->tx_buf, data, len);
cdc->tx_len = (uint16_t)len;
return SYN_OK;
}
SYN_Status syn_usb_cdc_read(SYN_USB_CDC *cdc, void *buf, size_t max_len, size_t *out_len)
{
if (!cdc || !buf || !out_len) {
return SYN_INVALID_PARAM;
}
uint16_t available = cdc->rx_len;
if (available == 0) {
*out_len = 0;
return SYN_OK;
}
if (max_len < available) {
available = (uint16_t)max_len;
}
memcpy(buf, cdc->rx_buf, available);
*out_len = available;
if (available < cdc->rx_len) {
memmove(cdc->rx_buf, &cdc->rx_buf[available], cdc->rx_len - available);
cdc->rx_len -= available;
} else {
cdc->rx_len = 0;
}
return SYN_OK;
}
bool syn_usb_cdc_rx_available(const SYN_USB_CDC *cdc)
{
return (cdc != NULL) && (cdc->rx_len > 0U);
}
bool syn_usb_cdc_tx_ready(const SYN_USB_CDC *cdc)
{
return (cdc != NULL) && (cdc->tx_len == 0U);
}