summaryrefslogtreecommitdiff
path: root/class/tmc/usbd_tmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'class/tmc/usbd_tmc.c')
-rw-r--r--class/tmc/usbd_tmc.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/class/tmc/usbd_tmc.c b/class/tmc/usbd_tmc.c
new file mode 100644
index 00000000..7f351e99
--- /dev/null
+++ b/class/tmc/usbd_tmc.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "usbd_core.h"
+#include "usbd_tmc.h"
+
+#define TMC_OUT_EP_IDX 0
+#define TMC_IN_EP_IDX 1
+
+/* Describe EndPoints configuration */
+static struct usbd_endpoint tmc_ep_data[2];
+
+#ifndef CONFIG_USBDEV_TMC_MAX_BUFSIZE
+#define CONFIG_USBDEV_TMC_MAX_BUFSIZE 1024
+#endif
+
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t tmc_read_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t tmc_write_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+
+static volatile uint32_t g_tmc_read_offset = 0;
+static volatile uint32_t g_tmc_read_total = 0;
+
+static scpi_t scpi_context;
+
+static char scpi_input_buffer[CONFIG_USBDEV_TMC_MAX_BUFSIZE];
+
+#define SCPI_ERROR_QUEUE_SIZE 4
+static scpi_error_t scpi_error_queue_data[SCPI_ERROR_QUEUE_SIZE];
+
+static size_t SCPI_Write(scpi_t *context, const char *data, size_t len)
+{
+ (void)context;
+
+ struct tmc_bulk_header *header = (struct tmc_bulk_header *)tmc_write_buffer;
+
+ USB_ASSERT_MSG((header->msg_specific.dev_dep_msg_in.transferSize + len) <= (CONFIG_USBDEV_TMC_MAX_BUFSIZE - sizeof(struct tmc_bulk_header)), "SCPI_Write: buffer overflow\r\n");
+
+ memcpy(tmc_write_buffer + sizeof(struct tmc_bulk_header) + header->msg_specific.dev_dep_msg_in.transferSize, data, len);
+ header->msg_specific.dev_dep_msg_in.transferSize += len;
+
+ return len;
+}
+
+static scpi_result_t SCPI_Flush(scpi_t *context)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static int SCPI_Error(scpi_t *context, int_fast16_t err)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_result_t SCPI_Control(scpi_t *context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_result_t SCPI_Reset(scpi_t *context)
+{
+ (void)context;
+
+ return SCPI_RES_OK;
+}
+
+static scpi_interface_t scpi_interface = {
+ .error = SCPI_Error,
+ .write = SCPI_Write,
+ .control = SCPI_Control,
+ .flush = SCPI_Flush,
+ .reset = SCPI_Reset,
+};
+
+static int tmc_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
+{
+ USB_LOG_DBG("TMC Class request: "
+ "bRequest 0x%02x\r\n",
+ setup->bRequest);
+
+ struct tmc_capabilities_response s_tmc_capabilities = {
+ .USBTMC_status = TMC_STATUS_SUCCESS,
+ .bcdUSBTMC = 0x0100,
+ .reserved0 = 0,
+ .reserved1 = { 0 },
+ .reserved_subclass = { 0 },
+ .InterfaceCapabilities = 0,
+ .DeviceCapabilities = 0
+ };
+
+ switch (setup->bRequest) {
+ case TMC_REQUEST_INITIATE_ABORT_BULK_OUT:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 2;
+ break;
+ case TMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0; // bmAbortBulkIn
+ (*data)[2] = 0; // reserved
+ (*data)[3] = 0; // reserved
+ *len = 4;
+ break;
+ case TMC_REQUEST_INITIATE_ABORT_BULK_IN:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 2;
+ break;
+ case TMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0; // bmAbortBulkIn
+ (*data)[2] = 0; // reserved
+ (*data)[3] = 0; // reserved
+ *len = 4;
+ break;
+ case TMC_REQUEST_INITIATE_CLEAR:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 1;
+ break;
+ case TMC_REQUEST_CHECK_CLEAR_STATUS:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ (*data)[1] = 0;
+ *len = 2;
+ break;
+ case TMC_REQUEST_GET_CAPABILITIES:
+ memcpy(*data, &s_tmc_capabilities, sizeof(s_tmc_capabilities));
+ *len = sizeof(s_tmc_capabilities);
+ break;
+ case TMC_REQUEST_INDICATOR_PULSE:
+ (*data)[0] = TMC_STATUS_SUCCESS;
+ *len = 1;
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC Class bRequest 0x%02x\r\n", setup->bRequest);
+ return -1;
+ }
+
+ return 0;
+}
+
+void tmc_notify_handler(uint8_t busid, uint8_t event, void *arg)
+{
+ (void)arg;
+
+ switch (event) {
+ case USBD_EVENT_RESET:
+ break;
+ case USBD_EVENT_CONFIGURED:
+ g_tmc_read_offset = 0;
+ g_tmc_read_total = 0;
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+ break;
+
+ default:
+ break;
+ }
+}
+
+void tmc_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ struct tmc_bulk_header *out_header = (struct tmc_bulk_header *)tmc_read_buffer;
+ struct tmc_bulk_header *in_header = (struct tmc_bulk_header *)tmc_write_buffer;
+
+ g_tmc_read_offset += nbytes;
+
+ if (g_tmc_read_total == 0) {
+ USB_ASSERT_MSG(nbytes >= sizeof(struct tmc_bulk_header), "tmc header size error\r\n");
+
+ switch (out_header->MsgID) {
+ case TMC_MSGID_OUT_DEV_DEP_MSG_OUT:
+ g_tmc_read_total = ((out_header->msg_specific.dev_dep_msg_out.transferSize + 3u) & ~3u) + sizeof(struct tmc_bulk_header);
+ break;
+ case TMC_MSGID_OUT_REQUEST_DEV_DEP_MSG_IN:
+ g_tmc_read_total = sizeof(struct tmc_bulk_header);
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC MsgID 0x%02x\r\n", out_header->MsgID);
+ break;
+ }
+ USB_ASSERT_MSG(g_tmc_read_total <= CONFIG_USBDEV_TMC_MAX_BUFSIZE, "tmc read buffer overflow\r\n");
+ }
+
+ if (g_tmc_read_offset < g_tmc_read_total) {
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+ return;
+ }
+
+ switch (out_header->MsgID) {
+ case TMC_MSGID_OUT_DEV_DEP_MSG_OUT:
+ SCPI_Input(&scpi_context,
+ (const char *)(tmc_read_buffer + sizeof(struct tmc_bulk_header)),
+ g_tmc_read_total);
+ break;
+ case TMC_MSGID_OUT_REQUEST_DEV_DEP_MSG_IN:
+
+ in_header->MsgID = TMC_MSGID_IN_DEV_DEP_MSG_IN;
+ in_header->bTag = out_header->bTag;
+ in_header->bTagInverse = out_header->bTagInverse;
+ in_header->reserved = 0;
+ in_header->msg_specific.dev_dep_msg_in.bmTransferAttributes = TMC_BULK_HEADER_TRANSFER_ATTR_TERMCHAR;
+
+ usbd_ep_start_write(busid, tmc_ep_data[TMC_IN_EP_IDX].ep_addr, tmc_write_buffer, sizeof(struct tmc_bulk_header) + in_header->msg_specific.dev_dep_msg_in.transferSize);
+ break;
+ default:
+ USB_LOG_WRN("Unhandled TMC MsgID 0x%02x\r\n", out_header->MsgID);
+ break;
+ }
+
+ g_tmc_read_offset = 0;
+ g_tmc_read_total = 0;
+ usbd_ep_start_read(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr, tmc_read_buffer + g_tmc_read_offset, usbd_get_ep_mps(busid, tmc_ep_data[TMC_OUT_EP_IDX].ep_addr));
+}
+
+void tmc_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
+{
+ if ((nbytes % usbd_get_ep_mps(busid, ep)) == 0 && nbytes) {
+ /* send zlp */
+ usbd_ep_start_write(busid, ep, NULL, 0);
+ } else {
+ }
+}
+
+struct usbd_interface *usbd_tmc_init_intf(uint8_t busid,
+ struct usbd_interface *intf,
+ const uint8_t out_ep, const uint8_t in_ep,
+ const scpi_command_t *scpi_commands,
+ const char **idn)
+{
+ (void)busid;
+
+ intf->class_interface_handler = tmc_class_interface_request_handler;
+ intf->class_endpoint_handler = NULL;
+ intf->vendor_handler = NULL;
+ intf->notify_handler = tmc_notify_handler;
+
+ tmc_ep_data[TMC_OUT_EP_IDX].ep_addr = out_ep;
+ tmc_ep_data[TMC_OUT_EP_IDX].ep_cb = tmc_bulk_out;
+ tmc_ep_data[TMC_IN_EP_IDX].ep_addr = in_ep;
+ tmc_ep_data[TMC_IN_EP_IDX].ep_cb = tmc_bulk_in;
+
+ usbd_add_endpoint(busid, &tmc_ep_data[TMC_OUT_EP_IDX]);
+ usbd_add_endpoint(busid, &tmc_ep_data[TMC_IN_EP_IDX]);
+
+ SCPI_Init(&scpi_context,
+ scpi_commands,
+ &scpi_interface,
+ scpi_units_def,
+ idn[0], idn[1], idn[2], idn[3],
+ scpi_input_buffer, CONFIG_USBDEV_TMC_MAX_BUFSIZE,
+ scpi_error_queue_data, SCPI_ERROR_QUEUE_SIZE);
+
+ return intf;
+} \ No newline at end of file