1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
|
/*
* 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;
if (g_tmc_read_offset > sizeof(tmc_read_buffer) ||
nbytes > sizeof(tmc_read_buffer) - g_tmc_read_offset) {
goto reset_read;
}
g_tmc_read_offset += nbytes;
if (g_tmc_read_total == 0) {
if (nbytes < sizeof(struct tmc_bulk_header)) {
goto reset_read;
}
switch (out_header->MsgID) {
case TMC_MSGID_OUT_DEV_DEP_MSG_OUT:
if (out_header->msg_specific.dev_dep_msg_out.transferSize >
((sizeof(tmc_read_buffer) - sizeof(struct tmc_bulk_header)) & ~3u)) {
goto reset_read;
}
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;
}
if (g_tmc_read_total == 0 || g_tmc_read_total > sizeof(tmc_read_buffer)) {
goto reset_read;
}
}
if (g_tmc_read_offset > g_tmc_read_total) {
goto reset_read;
}
if (g_tmc_read_offset < g_tmc_read_total) {
if ((g_tmc_read_offset + usbd_get_ep_mps(busid, ep)) > sizeof(tmc_read_buffer)) {
goto reset_read;
}
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)),
out_header->msg_specific.dev_dep_msg_out.transferSize);
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;
}
reset_read:
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;
}
|