FDEV_SETUP_STREAM - not working as docs say or my error?

Hi all,

I’m working on some code to connect standard input, output and error to various character devices.

AVR-LIBC provides two functions (note one is lower case, one is upper):

  • ```*

  • fdev_setup_stream (…)*

  • ```*

  • ```*

  • FDEV_SETUP_STREAM (…)*

  • ```*

The difference between the two is the lower case version takes FOUR parameters:

  • ```*

  • Address of file pointer*

  • ```*

  • ```*

  • Device write code (i.e. “putchar”)*

  • ```*

  • ```*

  • Device read code (i.e. “getchar”)*

  • ```*

  • ```*

  • Mode (i.e. Read, Write or Read/Write)*

  • ```*

…while the uppercase version takes THREE parameters (code, code and mode) and returns a file pointer.

The first one (lowercase) works fine, but I can’t seem to make the uppercase version work.

The example in the AVR-LIBC documentation (link - 1/3 of the page down):

#include <stdio.h>
static mystdout = FDEV_SETUP_STREAM (uart_putchar, NULL, _FDEV_SETUP_WRITE);

…doesn’t work. I get this compiler error:

error: cannot convert ‘’ to ‘__file*’ in assignment mystdout = FDEV_SETUP_STREAM (_putchar, NULL, _FDEV_SETUP_WRITE);

I know “the error message tells you where the problem is”, but I don’t understand the error message and a Google search didn’t help.

Any info you all can provide me will be greatly appreciated. Thanks!

– Roger

http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdio_1gaea2b6be92ead4673bc487b271b7227fb.html

This macro acts similar to fdev_setup_stream(), but it is to be used as the initializer of a variable of type FILE.

So, where is this FILE object going to write to/read from? The Arduino doesn't have FILEs.

The stdiodemo that comes with the AVR LIBC source (and maybe with the Ubuntu install of AVR LIBC). Shows the use of the FDEV_SETUP_STREAM() macro.

You need to use the FILE macro with it. FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

PaulS: http://www.atmel.com/webdoc/AVRLibcReferenceManual/group__avr__stdio_1gaea2b6be92ead4673bc487b271b7227fb.htmlSo, where is this FILE object going to write to/read from? The Arduino doesn't have FILEs.

Yes it does. The "inchar" and "outchar" parameters that are passed to fdev_setup are read and write functions (the "main" ones that read or write one character).

The standard input, output and error (files? paths? streams? call 'em what you want) can be "connected" to read and write functions, enabling the use of "printf()" and even "fprintf (stdout, ...);".

tf68: The stdiodemo that comes with the AVR LIBC source (and maybe with the Ubuntu install of AVR LIBC). Shows the use of the FDEV_SETUP_STREAM() macro.

You need to use the FILE macro with it. FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

As you can see in the "code" block in the first post, I do indeed use "FILE" (without the usual "*" - as per the Atmel example). And I get the error I mentioned.

I tried "[b]FILE mystdout =[/b]" and "[b]FILE *mystdout =[/b]" neither worked.

I even copied the example code verbatim and got the same error.

By the way, I compiled my own AVR toolchain. I'm using avr-gcc 4.9.2 and AVR libc 1.8.1 (shouldn't matter anyway - except for a few old depreciated functions that nobody uses anyway).

Yes it does.

No, it doesn't. It has streams. Streams and FILEs are not the same thing.

FILE != File case matters...

From: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaed4dabeb9f7c518ded42f930a04abce8

Typedef Documentation

typedef struct __file FILE FILE is the opaque structure that is passed around between the various standard IO functions.

Krupski: As you can see in the "code" block in the first post, I do indeed use "FILE" (without the usual "*" - as per the Atmel example). And I get the error I mentioned.

I tried "[b]FILE mystdout =[/b]" and "[b]FILE *mystdout =[/b]" neither worked.

I even copied the example code verbatim and got the same error.

By the way, I compiled my own AVR toolchain. I'm using avr-gcc 4.9.2 and AVR libc 1.8.1 (shouldn't matter anyway - except for a few old depreciated functions that nobody uses anyway).

From looking at the examples, do you need a static in there?

static FILE mystdout = ...

I don't really understand why or what it is supposed to do. But they have it on the example.

I use the FILE macro all the time with Atmel Studio IV and avr-gcc.

Here are the headers and start of main from a Pro Mini time/temperature data logger that is running in a greenhouse right now:

/*

DS3231 time/temp logger program using simple I2C routines

ATmega328 @ 16 MHz Pro Mini Atmel Studio IV/ avr-gcc
DS18B20 temp sensor SparkFun OpenLog

Don't forget pullups on I2C!

Jim Remington sjames.remington@gmail.com  8/22/2014

build options for floating point output:
add -Wl,-u,vfprintf to the LINKER options. It appears to only cater to printf but not scanf.
add -lprintf_flt or -lscanf_flt to the linker options which is done by listing printf_flt as a library.
need to set -lm if using float in any case

*/

// sample interval now 10 minutes in 1 second units

#define SAMPLE_INTERVAL 600

#define F_CPU 16000000UL
#include <math.h>
#include <util/delay.h>
#include <avr/io.h>
#include "ds18b20.c"
#include "uart.c"
#include "ds3231.c"

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

#define BUTTON PB4
#define BUTTON_GND PB5
#define LED PB2
#define LED_GND PB3

//DS18B20 probe PD2=Q, PD3=Vcc
//DS3231  RTC   PD4=GND, PD6=Vcc, PC4 & PC5


int main( void ) {

 int t,i;
 unsigned int delay_count; //number of seconds between samples
 char z;
// port pin settings

 DDRB &= ~(1 << BUTTON);    //input
 PORTB |= (1 << BUTTON);    //input pullup
 DDRB |= (1 << BUTTON_GND)|(1 << LED_GND)|(1 << LED); // set PB pins to output
 PORTB &= ~((1 << BUTTON_GND)|(1 << LED_GND)|(1 << LED)); //set low for ground

 DDRD |= (1 << PD3)|(1 << PD4)|(1 << PD6); // set PORTD, pins 3,4,6 to output
 PORTD |= (1 << PD3)|(1 << PD6);  //5V, power DS18B20 and DS3231
 PORTD &= ~(1 << PD4); //ground for DS3231


    uart_init(9600);
    stdout = &mystdout; //Required for printf init
 
    delay_ms(100);
    
    printf("\r\n"); printf("\r\n");
    printf("TempLogger 1.0: date,time,logger,probe\r\n");

There was a recent discussion on AVRfreaks, the upshot of which was that the FDEV_SETUP_STREAM macro uses features that don't work in C++ (but work fine in C.)

http://www.avrfreaks.net/forum/stdio-setup-printf-and-pulling-my-hair-out

westfw:
There was a recent discussion on AVRfreaks, the upshot of which was that the FDEV_SETUP_STREAM macro uses features that don’t work in C++ (but work fine in C.)

http://www.avrfreaks.net/forum/stdio-setup-printf-and-pulling-my-hair-out

Well, that’s interesting. The “lowercase” version (that takes 4 parameters) works fine. In fact, I made a little library that HardwareSerial calls to automatically provide me stdin/out/err for the serial port. And, it sets up the proper one (for example, If, on a MEGA, I do “Serial1.begin()”, it correctly associates Serial1 to the stdin/out streams.

Stdinout.cpp

#include <Stdinout.h>

// connect stdio to stream
void STDINOUT::open (Stream &str)
{
	if (_std_init) {
		close ();
	}
	_stream_pointer = &str;
	fdev_setup_stream (&_fp, _putchar, _getchar, _FDEV_SETUP_RW);
	stdin = stdout = stderr = &_fp;
	_std_init = true;
}

void STDINOUT::close (void)
{
	if (_std_init) {
		_stream_pointer->flush ();
		fdev_close ();
		_stream_pointer = NULL;
		_std_init = false;
	}
}

// Function that printf and related will use to print
int STDINOUT::_putchar (char c, FILE *stream)
{
	if (_stream_pointer) {
		if (c == '\n') { // \n sends crlf
			_putchar ((char) '\r', stream);
		}
		return (_stream_pointer->write (c));
	} else {
		return 0;
	}
}

// Function that scanf and related will use to read
int STDINOUT::_getchar (FILE *stream)
{
	if (_stream_pointer) {
		while (!(_stream_pointer->available ()));
		return (_stream_pointer->read ());
	} else {
		return 0;
	}
}

// end of stdinout.cpp

Stdinout.h

#ifndef STD_IN_OUT_H
#define STD_IN_OUT_H

#include <Stream.h>

static Stream *_stream_pointer;

class STDINOUT
{
	public:
		void open (Stream &);
		void close (void);
	private:
		FILE _fp;
		static int _putchar (char, FILE *);
		static int _getchar (FILE *);
		int _std_init = false;
};

#endif

// end of Stdinout.h

Then, in HardwareSerial, at the end of both begin() functions, I have this:

    STDIO.open (*this); // connect stdin/out/err to current serial stream

…and at the end of end():

    STDIO.close (); // flush, close and disconnect std streams

Lastly, what I didn’t show is that there’s a [b]static STDINOUT STDIO;[/b] in the HardwareSerial.h file.

It works like a charm