|
Open Model Railroad Network (OpenMRN)
|
Device driver for PIC32MX USB virtual serial port. More...
Public Member Functions | |
| Pic32mxCdc (const char *name) | |
| Constructor. | |
| ~Pic32mxCdc () | |
| Destructor. | |
| void | interrupt_handler () |
| Handle an interrupt. | |
| void | device_tasks () |
| Background thread for doing USB device driver tasks. | |
| void | event_hander_from_isr (USB_DEVICE_EVENT event, void *pData) |
| This function is called from the interrupt context of the USB driver to notify us about various events at the driver layer, such as USB plugged in. | |
| USB_DEVICE_CDC_EVENT_RESPONSE | cdc_event_hander_from_isr (USB_DEVICE_CDC_EVENT event, void *pData) |
| This function is called from the interrupt context of the USB driver to notify us about various events at the CDC layer, such as TX complete. | |
Public Member Functions inherited from Device | |
| Device (const char *name) | |
| Constructor. | |
| virtual | ~Device () |
| Destructor. | |
Private Member Functions | |
| void | tx_char () override |
| Unused. | |
| void | enable () override |
| Called by the serial driver when the first fd gets opened. | |
| void | disable () override |
| Called by the serial driver when the last fd gets closed. | |
| void | flush_buffers () override |
| Called by the serial driver after the last fd gets closed. | |
| ssize_t | read (File *file, void *buf, size_t count) override |
| Read from a file or device. | |
| 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. | |
| void | start_read_atomic () |
| Issues a read to the USB driver stack. | |
| void | start_write_atomic () |
| Issues a write to the USB driver stack. | |
| DeviceBuffer< uint8_t > * | current_rx_buffer () |
| DeviceBuffer< uint8_t > * | next_rx_buffer () |
| Pic32mxCdc () | |
| Default constructor. | |
| DISALLOW_COPY_AND_ASSIGN (Pic32mxCdc) | |
Private Member Functions inherited from Atomic | |
| void | lock () |
| void | unlock () |
Private Attributes | |
| SYS_MODULE_OBJ | drvUSBObject |
| Module pointer for USB core device. | |
| SYS_MODULE_OBJ | usbDevObject0 |
| Module pointer for USB middleware device. | |
| USB_DEVICE_HANDLE | deviceHandle {USB_DEVICE_HANDLE_INVALID} |
| Equivalent of an fd for the USB core driver. | |
| USB_CDC_LINE_CODING | lineCodingData |
| Holds last set line coding data that came from the host. | |
| USB_DEVICE_CDC_TRANSFER_HANDLE | readHandle |
| Handle for the current pending read. | |
| USB_DEVICE_CDC_TRANSFER_HANDLE | writeHandle |
| Handle for the current pending write. | |
| unsigned | isEnabled: 1 |
| True when we have open fds. | |
| unsigned | needAttach: 1 |
| true wehen we need to execute an attach command on the usb task. | |
| unsigned | isConfigured: 1 |
| true when we have a configured host. | |
| unsigned | currentReadBuffer: 1 |
| Index of the buffer for current (userspace) reads. | |
| unsigned | rxPending: 1 |
| true when we have an outstanding read request with the USB driver. | |
| unsigned | nextReadBufferFull: 1 |
| true if the opposite read buffer (the one after current) also has data. | |
| unsigned | txPendingBytes: 7 |
| Zero if no writes are pending, otherwise the number of bytes we sent with the pending write to the USB device driver. | |
| unsigned | driverErrors: 10 |
| Counts internal error conditions that should not occur but we are hoping we can recover from them. | |
| unsigned | irqVector: 5 |
| unused. | |
| DeviceBuffer< uint8_t > * | rxBuffers [2] |
| Receive buffers. | |
Static Private Attributes | |
| static constexpr unsigned | USB_CDC_BUFFER_SIZE = 64 |
| static constexpr unsigned | TX_BUFFER_SIZE = 3 * USB_CDC_BUFFER_SIZE |
| static constexpr unsigned | RX_DEVICEBUFFER_SIZE = 0 |
Additional Inherited Members | |
Static Public Member Functions inherited from Device | |
| static int | open (struct _reent *reent, const char *path, int flags, int mode) |
| Open a file or device. | |
| static int | close (struct _reent *reent, int fd) |
| Close a file or device. | |
| static int | stat (struct _reent *reent, const char *path, struct stat *stat) |
| Get the status information of a file or device. | |
| static int | select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, long long timeout) |
| POSIX select(). | |
| static void | select_clear () |
| Clears the current thread's select bits. | |
Static Public Member Functions inherited from FileIO | |
| static ssize_t | read (struct _reent *reent, int fd, void *buf, size_t count) |
| Read from a file or device. | |
| static ssize_t | write (struct _reent *reent, int fd, const void *buf, size_t count) |
| Write to a file or device. | |
| static _off_t | lseek (struct _reent *reent, int fd, _off_t offset, int whence) |
| Change the offset index of a file or device. | |
| static int | fstat (struct _reent *reent, int fd, struct stat *stat) |
| Get the status information of a file or device. | |
| static int | ioctl (int fd, unsigned long int key, unsigned long data) |
| Request and ioctl transaction. | |
| static int | fcntl (int fd, int cmd, unsigned long data) |
| Manipulate a file descriptor. | |
| static bool | is_device (int fd) |
| Test if the file descriptor belongs to a device. | |
Protected Member Functions inherited from Serial | |
| Serial (const char *name, size_t tx_buffer_size=config_serial_tx_buffer_size(), size_t rx_buffer_size=config_serial_rx_buffer_size()) | |
| Constructor. | |
| ~Serial () | |
| Destructor. | |
| ssize_t | read (File *file, void *buf, size_t count) OVERRIDE |
| Read from a file or device. | |
| ssize_t | write (File *file, const void *buf, size_t count) OVERRIDE |
| Write to a file or device. | |
| int | ioctl (File *file, unsigned long int key, unsigned long data) OVERRIDE |
| Request an ioctl transaction. | |
| bool | select (File *file, int mode) OVERRIDE |
| Device select method. | |
| void | flush_buffers () OVERRIDE |
| Discards all pending buffers. | |
Protected Member Functions inherited from Node | |
| Node (const char *name) | |
| Constructor. | |
| virtual | ~Node () |
| Destructor. | |
| int | open (File *, const char *, int, int) OVERRIDE |
| Open method. | |
| int | close (File *) OVERRIDE |
| Close method. | |
| virtual int | fstat (File *file, struct stat *stat) override |
| Get the status information of a file or device. | |
Protected Member Functions inherited from FileIO | |
| FileIO (const char *name) | |
| Constructor. | |
| virtual | ~FileIO () |
| Destructor. | |
| virtual off_t | lseek (File *f, off_t offset, int whence) |
| Seek method. | |
| virtual int | fcntl (File *file, int cmd, unsigned long data) |
| Manipulate a file descriptor. | |
Static Protected Member Functions inherited from Device | |
| static void | select_insert (SelectInfo *info) |
| Add client to list of clients needing woken. | |
| static void | select_wakeup (SelectInfo *info) |
| Wakeup the list of clients needing woken. | |
| static void | select_wakeup_from_isr (SelectInfo *info, int *woken) |
| Wakeup the list of clients needing woken. | |
Static Protected Member Functions inherited from FileIO | |
| static int | fd_alloc (void) |
| Allocate a free file descriptor. | |
| static void | fd_free (int fd) |
| Free up a file descriptor. | |
| static File * | file_lookup (int fd) |
| Looks up a reference to a File corresponding to a given file descriptor. | |
| static int | fd_lookup (File *file) |
| Looks up a file descriptor corresponding to a given File reference. | |
Protected Attributes inherited from Serial | |
| DeviceBuffer< uint8_t > * | txBuf |
| transmit buffer | |
| DeviceBuffer< uint8_t > * | rxBuf |
| receive buffer | |
| unsigned int | overrunCount |
| overrun count | |
Protected Attributes inherited from Node | |
| OSMutex | lock_ |
| protects internal structures. | |
| mode_t | mode_ |
| File open mode, such as O_NONBLOCK. | |
| unsigned int | references_ |
| number of open references | |
Protected Attributes inherited from FileIO | |
| const char * | name |
| device name | |
Static Protected Attributes inherited from FileIO | |
| static const unsigned int | numOpenFiles = 20 |
| static File | files [] |
| File descriptor pool. | |
| static OSMutex | mutex |
| mutual exclusion for fileio | |
Device driver for PIC32MX USB virtual serial port.
High-level decisions:
The serial port driver is compiled without RTOS support. This means all the mutexes it has internally are just bits. This can cause error values returned if we have multiple calls from different thread + interrupt context.
Major decision: whether we are calling CDC send/receive functions from the interrupt handler or not. If we don't, then we need to ensure that a user thread gets woken up when a transmit is complete and there are pending bytes in the transmit buffer. That's somewhat difficult. It's easier to call the next transmit inline in the interrupt handler, and also gives better performance (fewer context switches, less CPU usage, more throughput).
In order to achieve this, we need to ensure that all calls to the USB stack are protected by critical sections that prevent the interrupt from occuring.
A specialty of this USB driver is that write and read commands have zero-copy API, which means that the buffer pointer we give to the stack needs to remain available so long as the transfer is outstanding. We cannot use the userspace buffer pointers and have O_NONBLOCK file descriptors. So we are making one copy from user buffer into the device buffer, then give that pointer to the USB stack.
For transmit buffer we are using the standard txBuf coming from Serial. We set this transmit buffer to 3 urb length. This allows us to keep sending 64-byte packets when the application stack keeps pushing bytes at the full available throughput. For receive buffer there is a driver restriction to always give a 64-byte buffer for read. We cannot do that with a single DeviceBuffer (even if we set it to 128 byte long), thus we manage our own receive buffers. We still use DeviceBuffer class, but two of them with double buffering, as this combination allows us tracking the holes between the two buffers when a short read comes in.
Definition at line 92 of file Pic32mxUsbCdcDevice.cxx.
| Pic32mxCdc::Pic32mxCdc | ( | const char * | name | ) |
Constructor.
| name | name of this device instance in the file system |
Definition at line 267 of file Pic32mxUsbCdcDevice.cxx.
| Pic32mxCdc::~Pic32mxCdc | ( | ) |
Destructor.
Definition at line 310 of file Pic32mxUsbCdcDevice.cxx.
|
inline |
This function is called from the interrupt context of the USB driver to notify us about various events at the CDC layer, such as TX complete.
Definition at line 637 of file Pic32mxUsbCdcDevice.cxx.
|
inlineprivate |
Definition at line 177 of file Pic32mxUsbCdcDevice.cxx.
|
inline |
Background thread for doing USB device driver tasks.
Must be called a ~dozen times per second in order to initialize, register with the USB hosts, etc.
Definition at line 559 of file Pic32mxUsbCdcDevice.cxx.
|
overrideprivatevirtual |
Called by the serial driver when the last fd gets closed.
Implements Node.
Definition at line 337 of file Pic32mxUsbCdcDevice.cxx.
|
overrideprivatevirtual |
Called by the serial driver when the first fd gets opened.
Implements Node.
Definition at line 316 of file Pic32mxUsbCdcDevice.cxx.
|
inline |
This function is called from the interrupt context of the USB driver to notify us about various events at the driver layer, such as USB plugged in.
Definition at line 594 of file Pic32mxUsbCdcDevice.cxx.
|
overrideprivatevirtual |
Called by the serial driver after the last fd gets closed.
Implements Node.
Definition at line 343 of file Pic32mxUsbCdcDevice.cxx.
|
inline |
Handle an interrupt.
Definition at line 104 of file Pic32mxUsbCdcDevice.cxx.
|
inlineprivate |
Definition at line 184 of file Pic32mxUsbCdcDevice.cxx.
|
overrideprivatevirtual |
Read from a file or device.
| file | file reference for this device |
| buf | location to place read data |
| count | number of bytes to read |
Implements FileIO.
Definition at line 378 of file Pic32mxUsbCdcDevice.cxx.
Device select method.
Default impementation returns true.
| file | reference to the file |
| mode | FREAD for read active, FWRITE for write active, 0 for exceptions |
Reimplemented from FileIO.
Definition at line 510 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Issues a read to the USB driver stack.
Must be called from within a lock or critical section. Uses next_rx_buffer().
Definition at line 358 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Issues a write to the USB driver stack.
Must be called from within a lock or critical section or interrupt.
Definition at line 429 of file Pic32mxUsbCdcDevice.cxx.
|
inlineoverrideprivatevirtual |
|
privatevirtual |
Write to a file or device.
| file | file reference for this device |
| buf | location to find write data |
| count | number of bytes to write |
Implements FileIO.
Definition at line 460 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Index of the buffer for current (userspace) reads.
This buffer is considered full, even if it has zero bytes remaining. The steady state, when all input bytes are already consumed by the application layer, is that rxBuffer[currentReadBuffer] has zero bytes pending, rxPending is true, and rxBuffers[currentReadBuffer ^ 1] has its pointer submitted to the USB driver stack to receive the next urb from the host, whenever it comes.
Definition at line 217 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Equivalent of an fd for the USB core driver.
Definition at line 194 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Counts internal error conditions that should not occur but we are hoping we can recover from them.
Definition at line 229 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Module pointer for USB core device.
Definition at line 190 of file Pic32mxUsbCdcDevice.cxx.
|
private |
unused.
Do not remove – needed to force linking in the interrupt trampoline.
Definition at line 233 of file Pic32mxUsbCdcDevice.cxx.
|
private |
true when we have a configured host.
Definition at line 209 of file Pic32mxUsbCdcDevice.cxx.
|
private |
True when we have open fds.
Definition at line 205 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Holds last set line coding data that came from the host.
Definition at line 196 of file Pic32mxUsbCdcDevice.cxx.
|
private |
true wehen we need to execute an attach command on the usb task.
Definition at line 207 of file Pic32mxUsbCdcDevice.cxx.
|
private |
true if the opposite read buffer (the one after current) also has data.
If this is true, then rxPending cannot be true.
Definition at line 222 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Handle for the current pending read.
Definition at line 198 of file Pic32mxUsbCdcDevice.cxx.
|
staticconstexprprivate |
Definition at line 128 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Receive buffers.
We have these separate from Serial, because we need to use double buffering with the USB middleware; specifically we always need to provide a free 64-byte buffer for the read command.
Definition at line 238 of file Pic32mxUsbCdcDevice.cxx.
|
private |
true when we have an outstanding read request with the USB driver.
Definition at line 219 of file Pic32mxUsbCdcDevice.cxx.
|
staticconstexprprivate |
Definition at line 127 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Zero if no writes are pending, otherwise the number of bytes we sent with the pending write to the USB device driver.
Definition at line 225 of file Pic32mxUsbCdcDevice.cxx.
|
staticconstexprprivate |
Definition at line 125 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Module pointer for USB middleware device.
Definition at line 192 of file Pic32mxUsbCdcDevice.cxx.
|
private |
Handle for the current pending write.
Definition at line 200 of file Pic32mxUsbCdcDevice.cxx.