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)

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?

UserRevisionLine numberNew 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