diff options
| author | Dien-Nhung Nguyen-Phu <kein@kienlab.com> | 2024-07-11 21:34:07 +0700 |
|---|---|---|
| committer | Dien-Nhung Nguyen-Phu <kein@kienlab.com> | 2024-07-11 22:18:56 +0700 |
| commit | c3912e01a2767334103cd139d875d50c834f3f05 (patch) | |
| tree | 9db23b8e6cdfb06d8bab77e83224e604f20c4629 | |
| parent | 49fc27a23e0f5ca46337493cdac02ee116f786e3 (diff) | |
usb: add cdc-acm serial and write to flash
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | src/main.c | 1 | ||||
| -rw-r--r-- | src/usb/composite/cdc-serial.c | 202 | ||||
| -rw-r--r-- | src/usb/setup.c | 2 | ||||
| -rw-r--r-- | src/usb/usb.h | 4 |
5 files changed, 210 insertions, 0 deletions
@@ -63,6 +63,7 @@ src/usb/ctrl.c \ src/usb/debug.c \ src/usb/dev.c \ src/usb/composite/hiddev.c \ +src/usb/composite/cdc-serial.c \ # ASM sources ASM_SOURCES = \ @@ -175,6 +175,7 @@ int main() debug_init();
PRINT("\nDebug console is on UART%d\n", DEBUG);
+ cdc_onWrite(usb_receive);
hiddev_onWrite(usb_receive);
usb_start();
diff --git a/src/usb/composite/cdc-serial.c b/src/usb/composite/cdc-serial.c new file mode 100644 index 0000000..99f0c40 --- /dev/null +++ b/src/usb/composite/cdc-serial.c @@ -0,0 +1,202 @@ +#include <stdint.h> +#include <memory.h> + +#include "CH58x_common.h" + +#include "../utils.h" +#include "../debug.h" + +#define NOTI_EP_NUM (2) +#define DATA_EP_NUM (3) +#define ACM_IF_NUM (1) + +#define USB_DESCTYPE_CS_INTERFACE 0x24 + +static __attribute__((aligned(4))) uint8_t noti_ep_buf[64 + 64]; +static uint8_t *const noti_ep_out = noti_ep_buf; +static uint8_t *const noti_ep_in = noti_ep_buf + 64; + +static __attribute__((aligned(4))) uint8_t data_ep_buf[64 + 64]; +static uint8_t *const data_ep_out = data_ep_buf; +static uint8_t *const data_ep_in = data_ep_buf + 64; + +static void (*on_write)(uint8_t *buf, uint16_t len); + +/* CDC Communication interface */ +static USB_ITF_DESCR acm_if_desc = { + .bLength = sizeof(USB_ITF_DESCR), + .bDescriptorType = USB_DESCR_TYP_INTERF, + .bInterfaceNumber = ACM_IF_NUM, + .bAlternateSetting = 0, + .bNumEndpoints = 3, // A Notification and RX/TX Endpoint + + .bInterfaceClass = 0x02, /* Communications and CDC Control */ + .bInterfaceSubClass = 2, /* ACM subclass */ + .bInterfaceProtocol = 1, /* AT Command V.250 protocol */ + + .iInterface = 0 /* No string descriptor */ +}; + +/* Header Functional descriptor */ +static uint8_t header_func_desc[] = { + 5, /* bLength */ + USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */ + 0x00, /* bDescriptorsubtype, HEADER */ + 0x10, 0x01, /* bcdCDC */ +}; + +/* ACM Functional descriptor */ +static uint8_t acm_func_desc[] = { + 4, /* bLength */ + USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */ + 0x02, /* bDescriptorsubtype, ABSTRACT CONTROL MANAGEMENT */ + 0x02, /* bmCapabilities: Supports subset of ACM commands */ +}; + +/* Call Management Functional descriptor */ +static uint8_t callmgr_func_desc[] = { + 4, /* bLength */ + USB_DESCTYPE_CS_INTERFACE, /* bDescriptortype */ + 0x01, /* bDescriptorsubtype, CALL MANAGEMENT */ + 0x03, /* bmCapabilities, DIY */ +}; + +/* Notification Endpoint descriptor */ +static USB_ENDP_DESCR noti_ep_desc = { + .bLength = sizeof(USB_ENDP_DESCR), + .bDescriptorType = USB_DESCR_TYP_ENDP, + .bEndpointAddress = 0x80 | NOTI_EP_NUM, /* IN endpoint */ + .bmAttributes = 0x03, /* Interrupt transfer */ + .wMaxPacketSize = 64, /* bytes */ + .bInterval = 0xff +}; + +/* Data TX Endpoint descriptor */ +static USB_ENDP_DESCR tx_ep_desc = { + .bLength = sizeof(USB_ENDP_DESCR), + .bDescriptorType = USB_DESCR_TYP_ENDP, + .bEndpointAddress = 0x80 | DATA_EP_NUM, /* IN endpoint */ + .bmAttributes = 0x02, /* Bulk */ + .wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */ + .bInterval = 0xff +}; + +/* Data RX Endpoint descriptor */ +static USB_ENDP_DESCR rx_ep_desc = { + .bLength = sizeof(USB_ENDP_DESCR), + .bDescriptorType = USB_DESCR_TYP_ENDP, + .bEndpointAddress = DATA_EP_NUM, /* OUT endpoint */ + .bmAttributes = 0x02, /* Bulk */ + .wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */ + .bInterval = 0xff +}; + +static void cdc_request_handler(USB_SETUP_REQ * request) +{ + _TRACE(); + // Handle CDC Class Request here +} + +static void noti_ep_handler() +{ + _TRACE(); + // Handle Subclass Request here +} + +static volatile uint16_t transferred; + +static void data_ep_handler() +{ + _TRACE(); + static int tog; + + uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN; + switch(token) { + case UIS_TOKEN_OUT: + if (on_write) + on_write(data_ep_out, R8_USB_RX_LEN); + tog = !tog; + set_handshake(DATA_EP_NUM, USB_ACK, tog, 0); + break; + + case UIS_TOKEN_IN: + if (transferred == 0) { + transferred = 1; + } else { + set_handshake(DATA_EP_NUM, USB_NAK, 1, 0); + } + break; + + default: + break; + } +} + +// In case we want to send something to the host, +// or want to see the log over ttyACMx +void cdc_fill_IN(uint8_t *buf, uint8_t len) +{ + if (len > tx_ep_desc.wMaxPacketSize) + return; + + static int tog; + + memcpy(data_ep_in, buf, len); + set_handshake(DATA_EP_NUM, USB_ACK, tog, len); + + tog = !tog; + transferred = 0; +} + +static int wait_until_sent(uint16_t timeout_ms) +{ + while(timeout_ms--) { + if (transferred) { + return 0; + } + DelayMs(1); + } + return -1; +} + +int cdc_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms) +{ + int i = 0; + while (len > tx_ep_desc.wMaxPacketSize) { + cdc_fill_IN(buf + i, tx_ep_desc.wMaxPacketSize); + if (wait_until_sent(timeout_ms)) + return -1; + + i += tx_ep_desc.wMaxPacketSize; + len -= tx_ep_desc.wMaxPacketSize; + } + cdc_fill_IN(buf + i, len); + if (wait_until_sent(timeout_ms)) + return -1; + + return 0; +} + +void cdc_onWrite(void (*cb)(uint8_t *buf, uint16_t len)) +{ + on_write = cb; +} + +void cdc_acm_init() +{ + cfg_desc_append(&acm_if_desc); + cfg_desc_append(header_func_desc); + cfg_desc_append(acm_func_desc); + cfg_desc_append(callmgr_func_desc); + + cfg_desc_append(¬i_ep_desc); + cfg_desc_append(&rx_ep_desc); + cfg_desc_append(&tx_ep_desc); + + if_cb_register(ACM_IF_NUM, cdc_request_handler); + ep_cb_register(NOTI_EP_NUM, noti_ep_handler); + ep_cb_register(DATA_EP_NUM, data_ep_handler); + + dma_register(NOTI_EP_NUM, noti_ep_buf); + dma_register(DATA_EP_NUM, data_ep_buf); +}
\ No newline at end of file diff --git a/src/usb/setup.c b/src/usb/setup.c index 609267a..d53c318 100644 --- a/src/usb/setup.c +++ b/src/usb/setup.c @@ -125,6 +125,8 @@ void usb_start() { for the first interface (not the interface number) */ hiddev_init(); + cdc_acm_init(); + init(); PFIC_EnableIRQ(USB_IRQn); }
\ No newline at end of file diff --git a/src/usb/usb.h b/src/usb/usb.h index a542e68..f1d41f9 100644 --- a/src/usb/usb.h +++ b/src/usb/usb.h @@ -3,6 +3,10 @@ #include <stdint.h> +void cdc_fill_IN(uint8_t *buf, uint8_t len); +int cdc_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms); +void cdc_onWrite(void (*cb)(uint8_t *buf, uint16_t len)); + void hiddev_fill_IN(uint8_t *buf, uint8_t len); int hiddev_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms); void hiddev_onWrite(void (*cb)(uint8_t *buf, uint16_t len)); |