aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-07-11 21:34:07 +0700
committerDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-07-11 22:18:56 +0700
commitc3912e01a2767334103cd139d875d50c834f3f05 (patch)
tree9db23b8e6cdfb06d8bab77e83224e604f20c4629
parent49fc27a23e0f5ca46337493cdac02ee116f786e3 (diff)
usb: add cdc-acm serial and write to flash
-rw-r--r--Makefile1
-rw-r--r--src/main.c1
-rw-r--r--src/usb/composite/cdc-serial.c202
-rw-r--r--src/usb/setup.c2
-rw-r--r--src/usb/usb.h4
5 files changed, 210 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 448c201..f0d8a0e 100644
--- a/Makefile
+++ b/Makefile
@@ -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 = \
diff --git a/src/main.c b/src/main.c
index f2e788c..cec43be 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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(&noti_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));