Bringing MBed serial ports back like it's 1999... or at least 2019.
Dependents: CC1200-MorseEncoder AccurateWaiter-Test
SerialStream adapts an MBed 6.0 serial port class into a Stream instance. This lets you do two useful things with it:
- Call printf() and scanf() on it
- Pass it to code that expects a Stream to print things on. This should help adapt code written for older versions of MBed with a minimum of pain.
Example code:
Hello world program with SerialStream
#include <mbed.h> #include "SerialStream.h" BufferedSerial serial(USBTX, USBRX, 115200); SerialStream<BufferedSerial> pc(serial); int main() { while(true) { pc.printf("Hello world!\n"); ThisThread::sleep_for(1s); } }
Why Serial was deprecated
Using a Stream does introduce some additional overhead into your code, and this was part of the reason the new serial classes did not implement Stream. However, this is unlikely to make a difference in many applications.
There is also a newer way to use printf() with BufferedSerial using fdopen():
Hello world program with mbed 6 serial
#include <mbed.h> BufferedSerial serial(USBTX, USBRX, 115200); FILE * pc; int main() { pc = fdopen(&serial, "r+"); while(true) { fprintf(pc, "Hello world!\n"); ThisThread::sleep_for(1s); } }
This takes advantage of Mbed's FileHandle API and its integration with the C library. Any class that implements FileHandle can be opened as a C FILE
.
This method (along with some other interesting info) can be found in the PR that deprecated Serial. In my opinion, this is something that ARM has done an atrocious job of documenting and it’s criminal that the only place I found this information was by digging through closed PRs! (though it’s also buried in the FileHandle docs if you look hard enough)
SerialStream.h@1:9437ea7d0799, 2020-08-25 (annotated)
- Committer:
- Jamie Smith
- Date:
- Tue Aug 25 17:53:20 2020 -0700
- Revision:
- 1:9437ea7d0799
- Parent:
- 0:889cfd2df4cd
- Child:
- 2:3736580f2dbe
Allow including as the first header file
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jamie Smith |
0:889cfd2df4cd | 1 | #ifndef SERIALSTREAM_H |
Jamie Smith |
0:889cfd2df4cd | 2 | #define SERIALSTREAM_H |
Jamie Smith |
0:889cfd2df4cd | 3 | |
Jamie Smith |
1:9437ea7d0799 | 4 | #include <mbed.h> |
Jamie Smith |
0:889cfd2df4cd | 5 | #include <platform/Stream.h> |
Jamie Smith |
0:889cfd2df4cd | 6 | |
Jamie Smith |
0:889cfd2df4cd | 7 | /** |
Jamie Smith |
0:889cfd2df4cd | 8 | * SerialStream |
Jamie Smith |
0:889cfd2df4cd | 9 | * Bringing MBed serial ports back like it's 1999... or at least 2019. |
Jamie Smith |
0:889cfd2df4cd | 10 | * |
Jamie Smith |
0:889cfd2df4cd | 11 | * This class adapts an MBed 6.0 serial port class into a Stream instance. |
Jamie Smith |
0:889cfd2df4cd | 12 | * This lets you do two useful things with it: |
Jamie Smith |
0:889cfd2df4cd | 13 | * - Call printf() and scanf() on it |
Jamie Smith |
0:889cfd2df4cd | 14 | * - Pass it to code that expects a Stream to print things on. |
Jamie Smith |
0:889cfd2df4cd | 15 | * |
Jamie Smith |
0:889cfd2df4cd | 16 | */ |
Jamie Smith |
0:889cfd2df4cd | 17 | template<class SerialClass> |
Jamie Smith |
0:889cfd2df4cd | 18 | class SerialStream : public Stream |
Jamie Smith |
0:889cfd2df4cd | 19 | { |
Jamie Smith |
0:889cfd2df4cd | 20 | SerialClass & serialClass; |
Jamie Smith |
0:889cfd2df4cd | 21 | |
Jamie Smith |
0:889cfd2df4cd | 22 | public: |
Jamie Smith |
0:889cfd2df4cd | 23 | |
Jamie Smith |
0:889cfd2df4cd | 24 | /** |
Jamie Smith |
0:889cfd2df4cd | 25 | * Create a SerialStream from a serial port. |
Jamie Smith |
0:889cfd2df4cd | 26 | * @param _serialClass BufferedSerial or UnbufferedSerial instance |
Jamie Smith |
0:889cfd2df4cd | 27 | * @param name The name of the stream associated with this serial port (optional) |
Jamie Smith |
0:889cfd2df4cd | 28 | */ |
Jamie Smith |
0:889cfd2df4cd | 29 | SerialStream(SerialClass & _serialClass, const char *name = nullptr): |
Jamie Smith |
0:889cfd2df4cd | 30 | Stream(name), |
Jamie Smith |
0:889cfd2df4cd | 31 | serialClass(_serialClass) |
Jamie Smith |
0:889cfd2df4cd | 32 | { |
Jamie Smith |
0:889cfd2df4cd | 33 | } |
Jamie Smith |
0:889cfd2df4cd | 34 | |
Jamie Smith |
0:889cfd2df4cd | 35 | |
Jamie Smith |
0:889cfd2df4cd | 36 | private: |
Jamie Smith |
0:889cfd2df4cd | 37 | |
Jamie Smith |
0:889cfd2df4cd | 38 | // override Stream::read() and write() to call serial class directly. |
Jamie Smith |
0:889cfd2df4cd | 39 | // This avoids the overhead of feeding in individual characters. |
Jamie Smith |
0:889cfd2df4cd | 40 | virtual ssize_t write(const void *buffer, size_t length) |
Jamie Smith |
0:889cfd2df4cd | 41 | { |
Jamie Smith |
0:889cfd2df4cd | 42 | return serialClass.write(buffer, length); |
Jamie Smith |
0:889cfd2df4cd | 43 | } |
Jamie Smith |
0:889cfd2df4cd | 44 | |
Jamie Smith |
0:889cfd2df4cd | 45 | virtual ssize_t read(void *buffer, size_t length) |
Jamie Smith |
0:889cfd2df4cd | 46 | { |
Jamie Smith |
0:889cfd2df4cd | 47 | return serialClass.read(buffer, length); |
Jamie Smith |
0:889cfd2df4cd | 48 | } |
Jamie Smith |
0:889cfd2df4cd | 49 | |
Jamie Smith |
0:889cfd2df4cd | 50 | // Dummy implementations -- these will never be called because we override write() and read() instead. |
Jamie Smith |
0:889cfd2df4cd | 51 | // but we have to override them since they're pure virtual. |
Jamie Smith |
0:889cfd2df4cd | 52 | virtual int _putc(int c) { return 0; } |
Jamie Smith |
0:889cfd2df4cd | 53 | virtual int _getc() { return 0; } |
Jamie Smith |
0:889cfd2df4cd | 54 | }; |
Jamie Smith |
0:889cfd2df4cd | 55 | |
Jamie Smith |
0:889cfd2df4cd | 56 | #endif //SERIALSTREAM_H |