Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
mbed_async_usbserial.cxx
Go to the documentation of this file.
1
35#include "mbed.h"
36#include "USBSerial.h"
37#include "Serial.hxx"
38#include "os/os.h"
39#include "utils/macros.h"
40#include "portmacro.h"
41#include "utils/Atomic.hxx"
43
44#ifdef TARGET_LPC2368
45#endif
46
48#define TX_DATA_SIZE 64
50#define RX_DATA_SIZE 64
51
52#include <stdlib.h>
53
55void *operator new(size_t size);
57void *operator new[](size_t size);
59void operator delete(void *ptr);
61void operator delete[](void *ptr);
62
64__extension__ typedef int __guard __attribute__((mode(__DI__)));
65
67extern "C" int __cxa_guard_acquire(__guard *);
69extern "C" void __cxa_guard_release(__guard *);
71extern "C" void __cxa_guard_abort(__guard *);
73extern "C" void __cxa_pure_virtual(void);
74
77
88class MbedAsyncUSBSerial : public USBCDC, public ::NonBlockNode
89{
90public:
97 MbedAsyncUSBSerial(const char *name, uint16_t vendor_id = 0x1f00,
98 uint16_t product_id = 0x2012, uint16_t product_release = 0x0001)
99 : USBCDC(vendor_id, product_id, product_release)
101 , overrunCount_(0)
102 , txCount_(0)
103 , rxBegin_(0)
104 , rxEnd_(0)
105 , txPending_(false)
106 , rxPending_(false)
107 {
108 }
109
111 {
112 }
113
114protected:
116 bool EP2_OUT_callback() override
117 {
118 // HASSERT(IsEpPending());
119 // and wake up the RX thread.
120 rxPending_ = 1;
121 if (readableNotify_)
122 {
123 readableNotify_->notify_from_isr();
124 readableNotify_ = nullptr;
125 }
126 return false;
127 }
128
130 bool EP2_IN_callback() override
131 {
132 configASSERT(txPending_);
133 TxHelper();
134 if (writableNotify_)
135 {
136 writableNotify_->notify_from_isr();
137 writableNotify_ = nullptr;
138 }
139 return true;
140 }
141
142private:
144 {
145 }
147 {
148 }
150 {
151 }
152
154 {
155 return (rxPending_ || rxBegin_ < rxEnd_);
156 }
157
159 {
160 return (!txPending_ || txCount_ < sizeof(txData_));
161 }
162
170 ssize_t read(File *file, void *buf, size_t count) OVERRIDE
171 {
172 uint8_t *rbuf = static_cast<uint8_t *>(buf);
173 ssize_t result = 0;
174 while (true)
175 {
176 {
177 OSMutexLock l(&lock_);
178 while (result < (int)count && rxBegin_ < rxEnd_)
179 {
180 *rbuf++ = rxData_[rxBegin_++];
181 ++result;
182 }
183 if (rxBegin_ >= rxEnd_ && rxPending_)
184 {
185 bool result = true;
186 {
188 if (!rxPending_)
189 {
190 continue;
191 }
192 uint32_t rxSize = 0;
193 // we read the packet received to our assembly buffer
194 result = readEP_NB(rxData_, &rxSize);
195 rxPending_ = 0;
196 HASSERT(rxSize >= 0 && rxSize <= 255);
197 rxEnd_ = rxSize;
198 rxBegin_ = 0;
199 }
200 if (!result)
201 {
202 diewith(0x80000CCC);
203 }
204 continue;
205 }
206 if (result > 0)
207 {
208 return result;
209 }
210 } // lock
211 // Now: we have no data to give back.
212 if (file->flags & O_NONBLOCK)
213 {
214 return result;
215 }
216 Notifiable *n = nullptr;
217 {
219 if (rxPending_ || rxBegin_ < rxEnd_)
220 {
221 continue;
222 }
223 // Will be called at the end if non-null.
224 n = readableNotify_;
225 if (n == &readSync_)
226 {
227 DIE("This serial driver does not support having multiple "
228 "threads execute blocking reads concurrently.");
229 }
231 }
236 if (n)
237 {
238 n->notify();
239 }
240 }
241 }
242
250 ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
251 {
252 const uint8_t *wbuf = static_cast<const uint8_t *>(buf);
253 ssize_t result = 0;
254 while (true)
255 {
256 {
257 OSMutexLock l(&lock_);
258 {
260 while (result < (int)count && txCount_ < sizeof(txData_))
261 {
262 txData_[txCount_++] = *wbuf++;
263 ++result;
264 }
265 if (txCount_ > 0 && !txPending_)
266 {
267 TxHelper();
268 continue;
269 }
270 } // end atomic
271 } // end mutex
272 // Now: we have either result == count or tx buffer full and still
273 // having data to write.
274 if (result > 0)
275 {
276 return result;
277 }
278 // Now: we couldn't yet write anything.
279 if (file->flags & O_NONBLOCK)
280 {
281 return result;
282 }
283 // Now: let's wait for some space in the buffer to be available.
284 Notifiable *n = nullptr;
285 {
287 if (txCount_ < sizeof(txData_) || !txPending_)
288 {
289 continue;
290 }
292 if (n == &writeSync_)
293 {
294 DIE("This serial driver does not support having multiple "
295 "threads execute blocking writes concurrently.");
296 }
298 }
303 if (n)
304 {
305 n->notify();
306 }
307 } // while trying to write
308 }
309
311 static const int MAX_TX_PACKET_LENGTH = 64;
313 static const int MAX_RX_PACKET_LENGTH = 64;
314
318 void TxHelper()
319 {
320 if (!txCount_)
321 {
322 txPending_ = false;
323 return;
324 }
325 if (!configured())
326 {
327 // An error occured, data was lost.
328 txPending_ = false;
330 return;
331 }
332 txPending_ = true;
333 sendNB(txData_, txCount_);
334 txCount_ = 0;
335 }
336
345 uint8_t txCount_;
347 uint8_t rxBegin_;
349 uint8_t rxEnd_;
350 uint8_t txPending_ : 1;
351 uint8_t rxPending_ : 1;
356};
357
358void *operator new(size_t size)
359{
360 return malloc(size);
361}
362
363void *operator new [](size_t size)
364{ return malloc(size); } void
365operator delete(void *ptr) noexcept(true)
366{
367 free(ptr);
368}
369
370void operator delete [](void *ptr) noexcept(true)
371{ free(ptr); } int __cxa_guard_acquire(__guard *g)
372{
373 return !*(char *)(g);
374};
376{
377 *(char *)g = 1;
378};
380
382{
383 configASSERT(0);
384};
385
void diewith(uint32_t pattern)
Sets a blinking pattern and never returns.
See OSMutexLock in os/OS.hxx.
Definition Atomic.hxx:153
Lightweight locking class for protecting small critical sections.
Definition Atomic.hxx:130
const char * name
device name
Definition Devtab.hxx:266
This class is an empty wrapper around MBed's USB CDC class.
void TxHelper()
Transmits txCount_ bytes from the txData_ buffer.
SyncNotifiable writeSync_
Helper object to block writer.
void disable() OVERRIDE
This will be called when reference count goes from non-zero to 0.
MbedAsyncUSBSerial(const char *name, uint16_t vendor_id=0x1f00, uint16_t product_id=0x2012, uint16_t product_release=0x0001)
Constructor.
bool has_rx_buffer_data() OVERRIDE
Called under a critical section.
SyncNotifiable readSync_
Helper object to block reader.
unsigned overrunCount_
How many times have we had to drop data to the floor due to buffer overrun.
bool EP2_OUT_callback() override
Callback when EP2_OUT is ready.
void flush_buffers() OVERRIDE
Instructs the device driver to drop all TX and RX queues.
uint8_t rxBegin_
First valid character in rxData.
uint8_t txCount_
number of valid characters in txData
static const int MAX_TX_PACKET_LENGTH
What's the maximum packet length for transmit.
uint8_t txData_[MAX_TX_PACKET_LENGTH]
packet assemby buffer from app to device
bool EP2_IN_callback() override
Callback when EP2_IN is ready.
uint8_t rxPending_
there is a packet in the USB block waiting
uint8_t txPending_
transmission currently pending
uint8_t rxEnd_
1 + Last valid character in rxData.
ssize_t write(File *file, const void *buf, size_t count) OVERRIDE
Write to a file or device.
bool has_tx_buffer_space() OVERRIDE
Called under a critical section.
ssize_t read(File *file, void *buf, size_t count) OVERRIDE
Read from a file or device.
uint8_t rxData_[MAX_RX_PACKET_LENGTH]
packet assemby buffer from device to app
void enable() OVERRIDE
This will be called once when reference-count goes from 0 to positive.
static const int MAX_RX_PACKET_LENGTH
What's the maximum packet length for receive.
OSMutex lock_
protects internal structures.
Definition Devtab.hxx:588
Node information for a device node in the filesystem that has support for nonblocking mode via Notifi...
Definition Devtab.hxx:611
Notifiable * readableNotify_
This will be notified if the device has data avilable for read.
Definition Devtab.hxx:635
Notifiable * writableNotify_
This will be notified if the device has buffer avilable for write.
Definition Devtab.hxx:637
An object that can schedule itself on an executor to run.
virtual void notify()=0
Generic callback.
Class to allow convenient locking and unlocking of mutexes in a C context.
Definition OS.hxx:494
A Notifiable for synchronously waiting for a notification.
void wait_for_notification()
Blocks the current thread until the notification is delivered.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
Definition macros.h:180
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138
#define DIE(MSG)
Unconditionally terminates the current process with a message.
Definition macros.h:143
int __cxa_guard_acquire(__guard *)
C++ operator (not sure why this is needed).
void __cxa_guard_abort(__guard *)
C++ operator (not sure why this is needed).
static Atomic critical_lock
Mutex for the USB-serial object.
void __cxa_pure_virtual(void)
C++ operator (not sure why this is needed).
MbedAsyncUSBSerial g_mbed_usb_serial("/dev/serUSB0")
Global object for the mbed usb serial.
void __cxa_guard_release(__guard *)
C++ operator (not sure why this is needed).
__extension__ typedef int __guard
not sure why this is needed.
File information.
Definition Devtab.hxx:52