Reputation: 27636
Based on Mika Tuupola's tutorial I am trying to use serial input from the UART as stdin
. The lowlevel UART communication code is as follows:
#ifndef BAUD
#define BAUD 9600
#endif
#include <avr/io.h>
#include <stdio.h>
#include <util/setbaud.h>
void uart_init ()
{
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
}
void uart_putchar (char c)
{
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
}
char uart_getchar ()
{
loop_until_bit_is_set(UCSR0A, RXC0);
return UDR0;
}
The next layer exposes uart_getchar
and uart_putchar
as stream handler-compatible functions:
int uart_putchar_s (char c, FILE *stream)
{
if (c == '\n')
uart_putchar('\r');
uart_putchar(c);
return 0;
}
int uart_getchar_s (FILE *stream)
{
return uart_getchar();
}
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar_s, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getchar_s, _FDEV_SETUP_READ);
void uart_init_stdio()
{
stdout = &uart_output;
stdin = &uart_input;
}
and then my main
just reads in a character and prints it back out. It deliberately uses printf
so that the output is always via the stdout
stream abstraction.
int main ()
{
uart_init();
uart_init_stdio();
for (;;)
{
char c = uart_getchar();
printf("%c", c);
}
}
If I connect to this from a UTF-8 serial terminal, and type in e.g. á
, I correctly see that I get back the two bytes representing á
in UTF-8: local echo shows that my terminal sends the bytes C3 A1
, and these are the same two bytes I get back. So far, so good.
However, if I then change main
to use getchar()
instead of uart_getchar()
(i.e. if I go through the stdin
stream abstraction for the input), then after sending the same C3 A1
bytes, all I get back is FF FF
. Why is that? Is there something more going on here then just sending and receiving individual bytes that just happen to encode single glyphs when looked at through the lens of UTF-8?
Upvotes: 0
Views: 1406
Reputation: 18420
The problem is, that uart_getchar()
returns a "char", which is signed on your platform.
Characters > 0x7f are therefore interpreted as negative return value and thus, the stdio-layer returns EOF
, which is -1 (0xFF if interpreted unsigned) on your platform.
Try declaring uart_getchar()
as returning "int":
int uart_getchar ()
{
loop_until_bit_is_set(UCSR0A, RXC0);
return (unsigned char) UDR0;
}
Upvotes: 3