0,0 → 1,177 |
|
// wi232.c: |
// |
// Call fopen_wi232() to set up the wi232 as an input output data stream. |
// If fopen_wi232() is the first fopen command called, then the wi232 |
// becomes stdin and stdout and stderr. |
// The |
// |
// Uses Interupts to handle data streaming. The wi232 uses USART0, which uses: |
// Rx = PORTE0 = pin 2 |
// Tx = PORTE1 = pin 3 |
// CTS = PORTE2 = pin 4 |
|
#include <inttypes.h> |
#include <stdio.h> |
#include <avr/io.h> |
#include <avr/interrupt.h> |
#include <avr/signal.h> |
|
#include "wi232.h" |
#include "circularqueue.h" |
#include "usart.h" |
|
const int _baud_rate_c = 38400; |
const int _tx_buffer_size_c = 256; |
const int _rx_buffer_size_c = 256; |
const uint8_t _cts_pin_c = _BV( PINE2 ); |
|
volatile char wi232_tx_buffer[ _tx_buffer_size_c ]; |
volatile char wi232_rx_buffer[ _rx_buffer_size_c ]; |
|
// circular queues used for the USART |
CircularQueue< volatile char > wi232_tx_q( wi232_tx_buffer, _tx_buffer_size_c ); |
CircularQueue< volatile char > wi232_rx_q( wi232_rx_buffer, _rx_buffer_size_c ); |
|
// prototype |
int wi232_putchar( char ); |
int wi232_getchar(); |
void initialize_baud_rate(); |
void command( bool enable ); |
void write_register( uint8_t reg, uint8_t value ); |
bool _cts(); |
|
// use BAUD_RATE baud 8N1 RX & TX on USART0 |
// to transmit to the wi232 |
FILE* fopen_wi232() |
{ |
// enable Rx, Tx & Rx interupt |
// (Tx buffer empty interupt is enabled when we actually send something) |
UCSR0B = _BV( RXEN0 ) | |
_BV( TXEN0 ) | |
_BV( RXCIE0 ); |
|
// UCSC00 = 1 & UCSC01 = 1 -> 8-bit data |
UCSR0C = _BV( UCSZ00 ) | _BV( UCSZ01 ); |
|
initialize_baud_rate(); |
wi232_tx_q.clear(); |
wi232_rx_q.clear(); |
|
// set wi232_putchar as the stdout stream character Tx-er |
// set wi232_getchar as the stdin stream chacacter Rx-er |
return fdevopen( wi232_putchar, wi232_getchar, 0 ); |
} |
|
inline void initialize_baud_rate() |
{ |
// enable command pin as output |
DDRE |= _BV( PORTE3 ); |
command( true ); |
usart0_set_baud_rate( 2400 ); |
sei(); |
write_register( 78, 3 ); // set baud rate to 38400 |
wait(100); |
cli(); |
usart0_set_baud_rate( 38400 ); |
command( false ); |
} |
|
inline void command( bool enable ) |
{ |
if ( enable ) |
PORTE &= ~_BV( PORTE3 ); |
else |
PORTE |= _BV( PORTE3 ); |
} |
|
inline void write_register( uint8_t reg, uint8_t value ) |
{ |
if ( value < 0x80 ) |
{ |
// data = [ 0xFF, 2, reg, value ] |
wi232_putchar( 0xFF ); |
wi232_putchar( 2 ); |
wi232_putchar( reg ); |
wi232_putchar( value ); |
} |
else // value >= 0x80 |
{ |
// data = [ 0xFF, 3, reg, 0xFE, (value - 0x80) ] |
wi232_putchar( 0xFF ); |
wi232_putchar( 3 ); |
wi232_putchar( reg ); |
wi232_putchar( 0xFE ); |
wi232_putchar( value - 0x80 ); |
} |
} |
|
int wi232_putchar( char x ) |
{ |
wi232_tx_q.put( x ); |
|
// enable the "data register empty" interupt |
// (it may already be enabled in which case no harm is done) |
UCSR0B |= _BV( UDRIE0 ); |
|
// return -1 if overflow is true, otherwise return 0 |
// return wi232_tx_q.overflow() ? -1 : 0; |
return 0; // for now, screw overflow - just ignore it |
} |
|
int wi232_getchar() |
{ |
// wait until the queue is no longer empty |
while ( wi232_rx_q.is_empty() ); |
|
char x = wi232_rx_q.get(); |
return x; |
} |
|
uint16_t wi232_data_available() |
{ |
return wi232_rx_q.length(); |
} |
|
bool wi232_is_empty() |
{ |
return wi232_rx_q.is_empty(); |
} |
|
// returns true when CTS is low, |
// i.e. it is true when it is okay to send data |
inline bool _cts() |
{ |
return !(PINE & _cts_pin_c); |
} |
|
// we received some data on USART0 |
// put this data into the received data queue |
SIGNAL( SIG_UART0_RECV ) |
{ |
wi232_rx_q.put( UDR0 ); |
} |
|
// the USART is ready to queue another byte to send |
SIGNAL( SIG_UART0_DATA ) |
{ |
if ( !wi232_tx_q.is_empty() ) |
{ |
if ( !_cts() ) |
{ |
sei(); |
// wait until CTS is true |
while ( !_cts() ); |
} |
|
// if the queue is not empty, put the next character in the buffer |
// this also resets the interupt flag automatically |
UDR0 = wi232_tx_q.get(); |
} |
else |
{ |
// disable the interupt |
UCSR0B &= ~_BV( UDRIE0 ); |
} |
} |
|