@ -54,8 +54,7 @@ unsigned char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
volatile uint8_t SoftwareSerial : : _receive_buffer_tail = 0 ;
volatile uint8_t SoftwareSerial : : _receive_buffer_head = 0 ;
typedef struct _DELAY_TABLE
{
typedef struct _DELAY_TABLE {
long baud ;
uint16_t rx_delay_centering ;
uint16_t rx_delay_intrabit ;
@ -64,16 +63,12 @@ typedef struct _DELAY_TABLE
} DELAY_TABLE ;
// rough delay estimation
static const DELAY_TABLE table [ ] =
{
//baud |rxcenter|rxintra |rxstop |tx
{ 250000 , 2 , 4 , 4 , 4 , } , //Done but not good due to instruction cycle error
{ 115200 , 4 , 8 , 8 , 8 , } , //Done but not good due to instruction cycle error
static const DELAY_TABLE table [ ] = {
//baud |rxcenter|rxintra |rxstop |tx { 250000, 2, 4, 4, 4, }, //Done but not good due to instruction cycle error { 115200, 4, 8, 8, 8, }, //Done but not good due to instruction cycle error
//{ 74880, 69, 139, 62, 162, }, // estimation
// { 57600, 100, 185, 1, 208, }, // Done but not good due to instruction cycle error
//{ 38400, 13, 26, 26, 26, }, // Done
//{ 19200, 26, 52, 52, 52, }, // Done
{ 9600 , 52 , 104 , 104 , 104 , } , // Done
//{ 19200, 26, 52, 52, 52, }, // Done { 9600, 52, 104, 104, 104, }, // Done
//{ 4800, 104, 208, 208, 208, },
//{ 2400, 208, 417, 417, 417, },
//{ 1200, 416, 833, 833, 833,},
@ -85,7 +80,7 @@ static const DELAY_TABLE table[] =
#if 0
/* static */
inline void SoftwareSerial : : tunedDelay ( uint32_t count ) {
inline void SoftwareSerial : : tunedDelay ( const uint32_t count ) {
asm volatile (
@ -101,20 +96,18 @@ inline void SoftwareSerial::tunedDelay(uint32_t count) {
}
# else
inline void SoftwareSerial : : tunedDelay ( uint32_t count ) {
inline void SoftwareSerial : : tunedDelay ( const uint32_t count ) {
delayMicroseconds ( count ) ;
}
# endif
// This function sets the current object as the "listening"
// one and returns true if it replaces another
bool SoftwareSerial : : listen ( )
{
bool SoftwareSerial : : listen ( ) {
if ( ! _rx_delay_stopbit )
return false ;
if ( active_object ! = this )
{
if ( active_object ! = this ) {
if ( active_object )
active_object - > stopListening ( ) ;
@ -130,10 +123,8 @@ bool SoftwareSerial::listen()
}
// Stop listening. Returns true if we were actually listening.
bool SoftwareSerial : : stopListening ( )
{
if ( active_object = = this )
{
bool SoftwareSerial : : stopListening ( ) {
if ( active_object = = this ) {
setRxIntMsk ( false ) ;
active_object = NULL ;
return true ;
@ -144,14 +135,12 @@ bool SoftwareSerial::stopListening()
//
// The receive routine called by the interrupt handler
//
void SoftwareSerial : : recv ( )
{
void SoftwareSerial : : recv ( ) {
uint8_t d = 0 ;
// If RX line is high, then we don't see any start bit
// so interrupt is probably not for us
if ( _inverse_logic ? rx_pin_read ( ) : ! rx_pin_read ( ) )
{
if ( _inverse_logic ? rx_pin_read ( ) : ! rx_pin_read ( ) ) {
// Disable further interrupts during reception, this prevents
// triggering another interrupt directly after we return, which can
// cause problems at higher baudrates.
@ -160,38 +149,31 @@ void SoftwareSerial::recv()
// Wait approximately 1/2 of a bit width to "center" the sample
tunedDelay ( _rx_delay_centering ) ;
// Read each of the 8 bits
for ( uint8_t i = 8 ; i > 0 ; - - i )
{
tunedDelay ( _rx_delay_intrabit ) ;
for ( uint8_t i = 8 ; i > 0 ; - - i ) {
tunedDelay ( _rx_delay_intrabit ) ;
d > > = 1 ;
if ( rx_pin_read ( ) )
d | = 0x80 ;
if ( rx_pin_read ( ) ) d | = 0x80 ;
}
if ( _inverse_logic )
d = ~ d ;
if ( _inverse_logic ) d = ~ d ;
// if buffer full, set the overflow flag and return
uint8_t next = ( _receive_buffer_tail + 1 ) % _SS_MAX_RX_BUFF ;
if ( next ! = _receive_buffer_head )
{
if ( next ! = _receive_buffer_head ) {
// save new data in buffer: tail points to where byte goes
_receive_buffer [ _receive_buffer_tail ] = d ; // save new byte
_receive_buffer_tail = next ;
}
else
{
else {
_buffer_overflow = true ;
}
tunedDelay ( _rx_delay_stopbit ) ;
tunedDelay ( _rx_delay_stopbit ) ;
// Re-enable interrupts when we're sure to be inside the stop bit
setRxIntMsk ( true ) ; //__enable_irq();//
setRxIntMsk ( true ) ; //__enable_irq();//
}
}
uint32_t SoftwareSerial : : rx_pin_read ( )
{
uint32_t SoftwareSerial : : rx_pin_read ( ) {
return digitalRead ( _receivePin ) ;
}
@ -200,12 +182,9 @@ uint32_t SoftwareSerial::rx_pin_read()
//
/* static */
inline void SoftwareSerial : : handle_interrupt ( )
{
inline void SoftwareSerial : : handle_interrupt ( ) {
if ( active_object )
{
active_object - > recv ( ) ;
}
}
extern " C " void intWrapper ( ) {
SoftwareSerial : : handle_interrupt ( ) ;
@ -219,23 +198,19 @@ SoftwareSerial::SoftwareSerial(pin_t receivePin, pin_t transmitPin, bool inverse
_rx_delay_stopbit ( 0 ) ,
_tx_delay ( 0 ) ,
_buffer_overflow ( false ) ,
_inverse_logic ( inverse_logic )
{
_inverse_logic ( inverse_logic ) {
setTX ( transmitPin ) ;
setRX ( receivePin ) ;
}
//
// Destructor
//
SoftwareSerial : : ~ SoftwareSerial ( )
{
SoftwareSerial : : ~ SoftwareSerial ( ) {
end ( ) ;
}
void SoftwareSerial : : setTX ( pin_t tx )
{
void SoftwareSerial : : setTX ( pin_t tx ) {
// First write, then set output. If we do this the other way around,
// the pin would be output low for a short while before switching to
// output hihg. Now, it is input with pullup for a short while, which
@ -244,36 +219,30 @@ void SoftwareSerial::setTX(pin_t tx)
digitalWrite ( tx , _inverse_logic ? LOW : HIGH ) ;
pinMode ( tx , OUTPUT ) ;
_transmitPin = tx ;
}
void SoftwareSerial : : setRX ( pin_t rx )
{
void SoftwareSerial : : setRX ( pin_t rx ) {
pinMode ( rx , INPUT_PULLUP ) ; // pullup for normal logic!
//if (!_inverse_logic)
// digitalWrite(rx, HIGH);
_receivePin = rx ;
_receivePort = LPC1768_PIN_PORT ( rx ) ;
_receivePortPin = LPC1768_PIN_PIN ( rx ) ;
/* GPIO_T * rxPort = digitalPinToPort(rx);
/* GPIO_T * rxPort = digitalPinToPort(rx);
_receivePortRegister = portInputRegister ( rxPort ) ;
_receiveBitMask = digitalPinToBitMask ( rx ) ; */
}
//
// Public methods
//
void SoftwareSerial : : begin ( long speed )
{
void SoftwareSerial : : begin ( long speed ) {
_rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0 ;
for ( uint8_t i = 0 ; i < sizeof ( table ) / sizeof ( table [ 0 ] ) ; + + i )
{
for ( uint8_t i = 0 ; i < sizeof ( table ) / sizeof ( table [ 0 ] ) ; + + i ) {
long baud = table [ i ] . baud ;
if ( baud = = speed )
{
if ( baud = = speed ) {
_rx_delay_centering = table [ i ] . rx_delay_centering ;
_rx_delay_intrabit = table [ i ] . rx_delay_intrabit ;
_rx_delay_stopbit = table [ i ] . rx_delay_stopbit ;
@ -289,29 +258,24 @@ void SoftwareSerial::begin(long speed)
}
void SoftwareSerial : : setRxIntMsk ( bool enable )
{
void SoftwareSerial : : setRxIntMsk ( bool enable ) {
if ( enable )
GpioEnableInt ( _receivePort , _receivePin , CHANGE ) ;
else
GpioDisableInt ( _receivePort , _receivePin ) ;
}
void SoftwareSerial : : end ( )
{
void SoftwareSerial : : end ( ) {
stopListening ( ) ;
}
// Read data from buffer
int SoftwareSerial : : read ( )
{
if ( ! isListening ( ) )
return - 1 ;
int SoftwareSerial : : read ( ) {
if ( ! isListening ( ) ) return - 1 ;
// Empty buffer?
if ( _receive_buffer_head = = _receive_buffer_tail )
return - 1 ;
if ( _receive_buffer_head = = _receive_buffer_tail ) return - 1 ;
// Read from "head"
uint8_t d = _receive_buffer [ _receive_buffer_head ] ; // grab next byte
@ -319,16 +283,13 @@ int SoftwareSerial::read()
return d ;
}
int SoftwareSerial : : available ( )
{
if ( ! isListening ( ) )
return 0 ;
int SoftwareSerial : : available ( ) {
if ( ! isListening ( ) ) return 0 ;
return ( _receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head ) % _SS_MAX_RX_BUFF ;
}
size_t SoftwareSerial : : write ( uint8_t b )
{
size_t SoftwareSerial : : write ( uint8_t b ) {
// By declaring these as local variables, the compiler will put them
// in registers _before_ disabling interrupts and entering the
// critical timing sections below, which makes it a lot easier to
@ -337,36 +298,25 @@ size_t SoftwareSerial::write(uint8_t b)
bool inv = _inverse_logic ;
uint16_t delay = _tx_delay ;
if ( inv )
b = ~ b ;
if ( inv ) b = ~ b ;
cli ( ) ; // turn off interrupts for a clean txmit
// Write the start bit
if ( inv )
digitalWrite ( _transmitPin , 1 ) ;
else
digitalWrite ( _transmitPin , 0 ) ;
digitalWrite ( _transmitPin , ! ! inv ) ;
tunedDelay ( delay ) ;
// Write each of the 8 bits
for ( uint8_t i = 8 ; i > 0 ; - - i )
{
if ( b & 1 ) // choose bit
digitalWrite ( _transmitPin , 1 ) ; // send 1 //(GPIO_Desc[_transmitPin].P)->DOUT |= GPIO_Desc[_transmitPin].bit;
else
digitalWrite ( _transmitPin , 0 ) ; // send 0 //(GPIO_Desc[_transmitPin].P)->DOUT &= ~GPIO_Desc[_transmitPin].bit;
for ( uint8_t i = 8 ; i > 0 ; - - i ) {
digitalWrite ( _transmitPin , b & 1 ) ; // send 1 //(GPIO_Desc[_transmitPin].P)->DOUT |= GPIO_Desc[_transmitPin].bit;
// send 0 //(GPIO_Desc[_transmitPin].P)->DOUT &= ~GPIO_Desc[_transmitPin].bit;
tunedDelay ( delay ) ;
b > > = 1 ;
}
// restore pin to natural state
if ( inv )
digitalWrite ( _transmitPin , 0 ) ;
else
digitalWrite ( _transmitPin , 1 ) ;
digitalWrite ( _transmitPin , ! inv ) ;
sei ( ) ; // turn interrupts back on
tunedDelay ( delay ) ;
@ -374,18 +324,15 @@ size_t SoftwareSerial::write(uint8_t b)
return 1 ;
}
void SoftwareSerial : : flush ( )
{
if ( ! isListening ( ) )
return ;
void SoftwareSerial : : flush ( ) {
if ( ! isListening ( ) ) return ;
cli ( ) ;
_receive_buffer_head = _receive_buffer_tail = 0 ;
sei ( ) ;
}
int SoftwareSerial : : peek ( )
{
int SoftwareSerial : : peek ( ) {
if ( ! isListening ( ) )
return - 1 ;