Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TivaUsbCdcDevice.cxx
Go to the documentation of this file.
1
34#ifndef gcc
36#define gcc
37#endif
38
39#include <algorithm>
40#include <cstdint>
41#include <fcntl.h>
42#include <sys/select.h>
43
44#include "inc/hw_types.h"
45#include "inc/hw_memmap.h"
46#include "inc/hw_ints.h"
47#include "driverlib/rom.h"
48#include "driverlib/rom_map.h"
49#include "usblib/usblib.h"
50#include "usblib/usbcdc.h"
51#include "usblib/usb-ids.h"
52#include "usblib/device/usbdevice.h"
53#include "usblib/device/usbdcdc.h"
54
55#include "TivaDev.hxx"
56
61#define TIVA_USB_PACKET_SIZE 64
62
66#define TIVA_USB_BUFFER_SIZE (TIVA_USB_PACKET_SIZE * 4)
67
70const uint8_t langDescriptor[] =
71{
72 4,
73 USB_DTYPE_STRING,
74 USBShort(USB_LANG_EN_US)
75};
76
79const uint8_t manufacturerString[] =
80{
81 2 + (7 * 2),
82 USB_DTYPE_STRING,
83 'O', 0, 'p', 0, 'e', 0, 'n', 0, 'M', 0, 'R', 0, 'N', 0
84};
85
88const uint8_t productString[] =
89{
90 2 + (16 * 2),
91 USB_DTYPE_STRING,
92 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, 'a', 0, 'l', 0, ' ', 0,
93 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, 'o', 0, 'r', 0, 't', 0
94
95};
96
99const uint8_t serialNumberString[] =
100{
101 2 + (8 * 2),
102 USB_DTYPE_STRING,
103 '2', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0
104};
105
108const uint8_t controlInterfaceString[] =
109{
110 2 + (21 * 2),
111 USB_DTYPE_STRING,
112 'A', 0, 'C', 0, 'M', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0, 't', 0,
113 'r', 0, 'o', 0, 'l', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0,
114 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0
115};
116
119const uint8_t configString[] =
120{
121 2 + (26 * 2),
122 USB_DTYPE_STRING,
123 'S', 0, 'e', 0, 'l', 0, 'f', 0, ' ', 0, 'P', 0, 'o', 0, 'w', 0,
124 'e', 0, 'r', 0, 'e', 0, 'd', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0,
125 'f', 0, 'i', 0, 'g', 0, 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0,
126 'o', 0, 'n', 0
127};
128
140
142#define NUM_STRING_DESCRIPTORS (sizeof(stringDescriptors) / sizeof(uint8_t *))
143
145static TivaCdc *instances[1] = {NULL};
146
151TivaCdc::TivaCdc(const char *name, uint32_t interrupt)
152 : Serial(name, 0, TIVA_USB_BUFFER_SIZE)
153 , usbdcdcDevice{USB_VID_TI_1CBE, USB_PID_SERIAL, 0, USB_CONF_ATTR_SELF_PWR,
154 control_callback, this, rx_callback, this, tx_callback,
156 , interrupt(interrupt)
157 , connected(false)
158 , enabled(false)
159 , woken(false)
160 , txPending(false)
161 , lineCoding{115200, USB_CDC_STOP_BITS_1, USB_CDC_PARITY_NONE, 8}
162 , selInfoWr()
163{
164 instances[0] = this;
165
166 /* USB interrupt low priority. We make this a low priority because
167 * USB interrupts perform a decent amount of processing and we want
168 * to maintain the overall determinism of our system.
169 */
170 MAP_IntPrioritySet(interrupt, 0xff);
171
172 USBStackModeSet(0, eUSBModeForceDevice, 0);
173 USBDCDCInit(0, &usbdcdcDevice);
174}
175
179{
180 enabled = true;
181}
182
186{
187 enabled = false;
188}
189
196ssize_t TivaCdc::write(File *file, const void *buf, size_t count)
197{
198 unsigned char *data = (unsigned char*)buf;
199 ssize_t result = 0;
200
201 while (count)
202 {
203 if (!connected)
204 {
205 if (file->flags & O_NONBLOCK)
206 {
207 return -EAGAIN;
208 }
209 fd_set fds;
210 FD_ZERO(&fds);
211 int fd = Device::fd_lookup(file);
212 FD_SET(fd, &fds);
213
214 ::select(fd + 1, NULL, &fds, NULL, NULL);
215 }
216 portENTER_CRITICAL();
217 size_t size = std::min((size_t)TIVA_USB_PACKET_SIZE, count);
218 uint32_t sent = USBDCDCPacketWrite(&usbdcdcDevice, data,
219 size, true);
220 if (sent == 0)
221 {
222 portEXIT_CRITICAL();
223 if (result > 0)
224 {
225 break;
226 }
227 if (file->flags & O_NONBLOCK)
228 {
229 return -EAGAIN;
230 }
231 else
232 {
233 fd_set fds;
234 FD_ZERO(&fds);
235 int fd = Device::fd_lookup(file);
236 FD_SET(fd, &fds);
237
238 ::select(fd + 1, NULL, &fds, NULL, NULL);
239 }
240 }
241 else
242 {
243 txPending = true;
244 portEXIT_CRITICAL();
245 count -= sent;
246 result += sent;
247 data += sent;
248 }
249 }
250
251 return result;
252}
253
260bool TivaCdc::select(File* file, int mode)
261{
262 bool retval = false;
263
264 portENTER_CRITICAL();
265 switch (mode)
266 {
267 case FREAD:
268 if (rxBuf->pending() > 0)
269 {
270 retval = true;
271 }
272 else
273 {
275 }
276 break;
277 case FWRITE:
278 if (connected)
279 {
280 if (txPending == false)
281 {
282 retval = true;
283 break;
284 }
285 }
287 break;
288 default:
289 case 0:
290 /* we don't support any exceptions */
291 break;
292 }
293 portEXIT_CRITICAL();
294
295 return retval;
296}
297
306uint32_t TivaCdc::control_callback(void *data, unsigned long event,
307 unsigned long msg_param, void *msg_data)
308{
309 TivaCdc *serial = (TivaCdc*)data;
310
311 switch(event)
312 {
313 case USB_EVENT_CONNECTED:
314 serial->connected = true;
315 // starts sending data.
316 serial->select_wakeup_from_isr(&serial->selInfoWr, &serial->woken);
317 break;
318 case USB_EVENT_DISCONNECTED:
319 serial->connected = false;
320 break;
321 case USBD_CDC_EVENT_GET_LINE_CODING:
322 {
323 tLineCoding *line_coding = (tLineCoding*)msg_data;
324 *line_coding = serial->lineCoding;
325 break;
326 }
327 case USBD_CDC_EVENT_SET_LINE_CODING:
328 {
329 tLineCoding *line_coding = (tLineCoding*)msg_data;
330 serial->lineCoding = *line_coding;
331 break;
332 }
333 case USBD_CDC_EVENT_SET_CONTROL_LINE_STATE:
334 break;
335 case USBD_CDC_EVENT_SEND_BREAK:
336 break;
337 case USBD_CDC_EVENT_CLEAR_BREAK:
338 break;
339 case USB_EVENT_SUSPEND:
340 break;
341 case USB_EVENT_RESUME:
342 break;
343 default:
344 break;
345 }
346 return 0;
347}
348
357uint32_t TivaCdc::rx_callback(void *data, unsigned long event,
358 unsigned long msg_param, void *msg_data)
359{
360 TivaCdc *serial = (TivaCdc*)data;
361
362 switch (event)
363 {
364 default:
365 break;
366 case USB_EVENT_RX_AVAILABLE:
367 {
368 HASSERT(msg_data == NULL);
369 uint8_t *data;
370 size_t space = serial->rxBuf->data_write_pointer(&data);
371 uint32_t count = USBDCDCPacketRead(&serial->usbdcdcDevice,
372 data, space, true);
373 if (serial->enabled && count)
374 {
375 /* we only commit the data if the device is open */
376 serial->rxBuf->advance(count);
378 }
379 return count;
380 }
381 case USB_EVENT_DATA_REMAINING:
382 return serial->rxBuf->pending();
383 case USB_EVENT_ERROR:
384 break;
385 }
386 return 0;
387}
388
397uint32_t TivaCdc::tx_callback(void *data, unsigned long event,
398 unsigned long msg_param, void *msg_data)
399{
400 TivaCdc *serial = (TivaCdc*)data;
401
402 switch (event)
403 {
404 default:
405 break;
406 case USB_EVENT_TX_COMPLETE:
407 serial->txPending = false;
408 serial->select_wakeup_from_isr(&serial->selInfoWr, &serial->woken);
409 break;
410 }
411 return 0;
412}
413
417{
418 woken = 0;
419 USB0DeviceIntHandler();
420 os_isr_exit_yield_test(woken);
421}
422
423extern "C" {
427{
428
429 if (instances[0])
430 {
432 }
433}
434
435} // extern "C"
static CC32xxUart * instances[2]
Instance pointers help us get context from the interrupt handler(s)
static TivaCdc * instances[1]
Instance pointers help us get context from the interrupt handler(s)
const uint8_t controlInterfaceString[]
The configuration interface description string.
#define TIVA_USB_BUFFER_SIZE
This is the size of the RX buffer in bytes.
const uint8_t *const stringDescriptors[]
The descriptor string table.
const uint8_t langDescriptor[]
The languages supported by this device.
const uint8_t manufacturerString[]
The manufacturur string.
const uint8_t productString[]
The product string.
#define TIVA_USB_PACKET_SIZE
This is fixed and equals the USB packet size that the CDC device will advertise to be able to receive...
const uint8_t configString[]
The configuration description string.
#define NUM_STRING_DESCRIPTORS
number of string descriptors
void usb0_interrupt_handler(void)
Handle interrupts for USB0.
const uint8_t serialNumberString[]
The serial number string.
size_t advance(size_t items)
Add a number of items to the buffer by advancing the writeIndex.
size_t pending()
Return the number of items in the queue.
void select_insert()
Add client to list of clients needing woken.
void signal_condition_from_isr()
Signal the wakeup condition from an ISR context.
size_t data_write_pointer(T **buf)
Get a reference to the current location in the buffer for write.
static int fd_lookup(File *file)
Looks up a file descriptor corresponding to a given File reference.
Definition Fileio.cxx:101
Private data for a serial device.
Definition Serial.hxx:46
DeviceBuffer< uint8_t > * rxBuf
receive buffer
Definition Serial.hxx:85
Private data for this implementation of serial.
Definition TivaDev.hxx:61
void interrupt_handler()
handle an interrupt.
static uint32_t control_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data)
Handles CDC driver notifications related to control and setup of the device.
int woken
task woken metadata for ISR
Definition TivaDev.hxx:141
bool txPending
true if a transmission is in progress or pending
Definition TivaDev.hxx:142
bool connected
connection status
Definition TivaDev.hxx:139
tUSBDCDCDevice usbdcdcDevice
CDC serial device instance.
Definition TivaDev.hxx:137
SelectInfo selInfoWr
Metadata for select() logic.
Definition TivaDev.hxx:144
uint32_t interrupt
interrupt number for device
Definition TivaDev.hxx:138
ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
Write to a file or device.
bool select(File *file, int mode) OVERRIDE
Device select method.
static uint32_t tx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data)
Handles CDC driver notifications related to transmission.
static uint32_t rx_callback(void *data, unsigned long event, unsigned long msg_param, void *msg_data)
Handles CDC driver notifications related to reception.
void disable() override
function to disable device
tLineCoding lineCoding
line encoding for the device
Definition TivaDev.hxx:143
void enable() override
function to enable device
TivaCdc()
Default constructor.
bool enabled
enabled status
Definition TivaDev.hxx:140
#define FWRITE
Workaround for missing header defines on some newlib versions.
Definition fcntl.h:58
#define FREAD
Workaround for missing header defines on some newlib versions.
Definition fcntl.h:53
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
static void select_wakeup_from_isr(SelectInfo *info, int *woken)
Wakeup the list of clients needing woken.
Definition Select.cxx:224
static void select_insert(SelectInfo *info)
Add client to list of clients needing woken.
Definition Select.cxx:197
File information.
Definition Devtab.hxx:52
int flags
open flags
Definition Devtab.hxx:63