Serial questions - redirecting stdout, line buffering

18 Jan 2018

What is the recommended way to redirect stdout to a different serial port? Can it be redirected and maintain line-buffering behavior? Without supplying a new buffer?

Currently I'm doing it like this:

char const  SerialStreamPath[] = "/serial";
char const *SerialStreamName   = &(SerialStreamPath[1]);

Serial s(P0_0 , P0_1 , SerialStreamName, SERIAL_BAUD_RATE);

int main()
{
   // https://os.mbed.com/users/simon/code/stdout/docs/tip/main_8cpp_source.html
   freopen(SerialStreamPath, "w", stdout);

   //...
}

...but this changes it from line-buffered to fully-buffered.

Can I make it line-buffered? Without calling setvbuf()? I don't want to change the location or size of the buffer that it's already using; I just want it to behave as a line buffer, not a full buffer.

22 Jan 2018

Hi,

what toolchain are you using?

If you look at Stream class there is a commit 09ae609d5612d6e7dda49063f119bd89f9932a7e (Serial class inherits from Stream). The change log is:

Quote:

Stream class should use mbed::fdopen() to attach a stream

mbed::fdopen() is provided in mbed_retarget.cpp which will attach a stream to the given FileHandle. Removing mbed_set_unbuffered_stream() from stream class as it is defined in mbed_retarget.cpp. Stream class should not decide whether it wants to detach buffers from c library or not. mbed::fdopen() will do that based upon isatty() call. So if a FileHandle is not a tty, i.e., is not a device type, c library buffering will not be turned off. For device type FileHandles, c library buffering is turned off.

22 Jan 2018

I'm using gcc-arm-none-eabi via NXP MCUXpresso.

Martin Kojtal wrote:

For device type FileHandles, c library buffering is turned off.

freopen() is causing stdout to become fully buffered, which is not what I want. I think it is the opposite of the intent stated above, too. Am I correct that this is unexpected behavior?

The following is my new experimentation that demonstrates this.


To simplify things a bit, when I print just a couple lines like this, without freopen(), I can tell stdout is line buffered.

#define SERIAL_BAUD_RATE  (115200)

Serial s(USBTX, USBRX, SerialStreamName, SERIAL_BAUD_RATE);

int main()
{
   for (size_t i = 0; i < 2; i++)
   {
      printf("%3u\r\n", i);
      wait_ms(1000);
   }

   while(true) {}
}

But when I call freopen(), it becomes fully-buffered, with a 1024 buffer, as demonstrated by the fact that the following code doesn't print. When I raise the loop bound by one (to 205), it prints everything except the last '\n'. (Five chars per line, 5 * 205 = 1025.)

#define SERIAL_BAUD_RATE  (115200)

Serial s(USBTX, USBRX, SerialStreamName, SERIAL_BAUD_RATE);

int main()
{
   freopen(SerialStreamPath, "w", stdout);

   for (size_t i = 0; i < 204; i++)
   {
      printf("%3u\r\n", i);
   }

   while(true) {}
}
22 Jan 2018

Hello Brendan,

I'm not sure whether this is the recommended way how to do it, however you can try to do the following:

#include "mbed.h"

extern serial_t   stdio_uart;
extern int        stdio_uart_inited;

int main()
{
    serial_init(&stdio_uart, p28, p27); // Tx and Rx pin of the new stdout serial port.
    stdio_uart_inited = 1;
    serial_baud(&stdio_uart, 115200);   // Set new bit rate if needed. Default is 9600 bits/s.

    for (size_t i = 0; i < 204; i++)
    {
       printf("%3u\r\n", i);
    }
}

With best regards,

Zoltan

02 May 2018

For future reference, as suggested by kjbracey-arm, the current solution is to implement mbed_override_console(), which overrides the weak function. This works since Mbed OS 5.8.0.