Redirecting output to the Nokia LCD

30 Nov 2009 . Edited: 30 Nov 2009

Hello,

I have just got the Nokia LCD driver working and have a question regarding redirecting output to it when using other libraries.

I am interested in using the ethernet and SD card libraries. When I use them by themselves, the IP address is output on the USB serial connection from the ethernet library.

If I now include the Nokia LCD library, will this text be output on the LCD instead, or do I have to modify the source of the ethernet files to change the output?

In other words, if the ethernet library is using just a printf() function to output IP details, when I include the Nokia library which has a _putc() function will this override any output directing to the USB serial?

I look forward to hearing you comments.

Regards

Phil.

30 Nov 2009 . Edited: 30 Nov 2009

Hi Phil,

Phil Green wrote:
I have just got the Nokia LCD driver working and have a question regarding redirecting output to it when using other libraries. I am interested in using the ethernet and SD card libraries. When I use them by themselves, the IP address is output on the USB serial connection from the ethernet library. If I now include the Nokia LCD library, will this text be output on the LCD instead, or do I have to modify the source of the ethernet files to change the output?

Here are some of the things that relate to this question:

1) All stream-like peripherals (terminals, UARTs, LCDs) currently inherit from "Stream"; this means they all get printf/putc file-like functionality, and are therefore compatible. For example, if you had:

output.printf("Hello World!\n");

You could have interchangeably created output as any of the following:

Serial output(USBTX, USBRX);
// Serial output(p9, p10);
// MobileLCD output(p5, p6, p7, p8, p9);
// : 

This approach is the preferable way for dealing with output that is part of a program/interface etc, as it is explicit (but interchangeable) where the output is directed.

2) We do have the concept of stdio, more familiar to those working on a unix-like PC environment. By default, this is routed to the USB serial interface, so if you do:

printf("Hello World!\n");

i.e. no device specified, then it'll go to stdout/the USB serial. This is more used for debug in general.

But we've made it so you can actually re-route this using the C "freopen" call. This could be to a file or a device. For the second, you need a filename to refer to the device, but we've put most of that logic in there already; Stream just needs to be passed a name when created. The LCD libraries don't pass this at the moment, so in the following example I included a modified version of TextLCD that allows you to pass a name too:

// example showing how to re-route stdout, sford

#include "mbed.h"
#include "TextLCD.h"

Serial pc(USBTX, USBRX, "hi");
TextLCD lcd(p10, p11, p12, p15, p16, p29, p30, "lcd"); // notice the name "lcd" is passed
LocalFileSystem local("local");

int main() {
    // printf to specific peripherals
    pc.printf("Hello World!\n");
    lcd.printf("Hello World!\n");

    // printf to stdout
    printf("Hello USB Serial World!\n");
    
    // change stdout to file
    freopen("/local/output.txt", "w", stdout);
    printf("Hello FileSystem World!\n");
    fclose(stdout);
    
    // change stdout to LCD
    freopen("/lcd", "w", stdout);
    printf("Hello LCD World!\n");
    fclose(stdout);

    wait(5);    

    pc.printf("Hello World!\n");
    lcd.printf("Hello World!\n");
}

stdout (Includes modified TextLCD library)

3) There is a little party trick left too; Stream objects can act like file handles. For example:

#include "mbed.h"
#include "TextLCD.h"

TextLCD lcd(p10, p11, p12, p15, p16, p29, p30);

void foo(FILE *fp) {
    fprintf(fp, "Hello World\n");
}

int main() {
    fprintf(lcd, "Hello There\n");
    foo(lcd);
}

Whilst 1) is the main recommended way to target output, I've also discussed the more "experimental" 2) and 3) as I think the approaches could have some potential. Feedback welcome here!

Simon

30 Nov 2009

Quick question Simon,

To use fprintf(), shouldn't *fp be initialized with fopen()? Or is that assumed in your examle?

30 Nov 2009 . Edited: 30 Nov 2009

Hi,

Igor Martinovski wrote:
To use fprintf(), shouldn't *fp be initialized with fopen()? Or is that assumed in your examle?

No need to fopen in this case; Stream objects can be interpreted as an open file handle - think of it as when the object is created, it is opened for file access, and when destructed, it is closed for file access.

It is experimental as I said, but it feels quite nice to be able to treat any stream object as a file, especially as it can be used interchangeably with a real file. Open to ideas/comments.

Simon

20 Jun 2010

I have been searching for an hr+ to learn where stdout (printf) appear. Now I know. But where should I have been looking to find answers for these basic questions?

Greg

14 Jan 2011

I am late to the party, I know. I tried alternative 2 in Simon's example but I find that all the output to the LCD is buffered until the fclose(stdout)... What am I doing wrong? I would like to redirect the Ip-stack output to my LCD, but this way it is a bit useless. I am using a SED1330 based display for which I use the TextLCD as base. lcd.printf() works as expected. Suggestions?

Louis

15 Jan 2011

Ok, I Found the issue: after a freopen stdout is set to full buffering. A

char lineBuffer[256]; setvbuf(stdout, lineBuffer, _IOLBF, sizeof(lineBuffer));

after the freopen() solves the buffering issue.

Louis

03 Jan 2013

Bump:

Quote:

But we've made it so you can actually re-route this using the C "freopen" call. This could be to a file or a device. For the second, you need a filename to refer to the device

Just wondering, how are we supposed to reroute stdout to an LCD display if we need to give the Stream a name, but that option is removed in the recent mbed libraries?

08 Jan 2013

Erik - wrote:

how are we supposed to reroute stdout to an LCD display if we need to give the Stream a name, but that option is removed in the recent mbed libraries?

Good point Erik. [Rev 54] has restored this use case.

Cheers, Emilio

25 Dec 2015

Restore buffering:

    freopen("/lcdlog", "w", stdout);
    mbed::mbed_set_unbuffered_stream(stdout);