Andriy Makukha / Mbed 2 deprecated football_project_wo_output

Dependencies:   mbed

Fork of football_project by MZJ

io/MySerial.cpp

Committer:
AntonLS
Date:
2015-04-18
Revision:
8:d5d055be2bb8
Parent:
7:205ef63d311a
Child:
9:95dc84e9fb7f

File content as of revision 8:d5d055be2bb8:

/*
 *
 * Replacement for Serial, so UART flow control is inited properly.    ALS 20150412
 *
 * MySerialBase is a replacement for SerialBase, to prevent it from calling
 *  the faulty-for-nRF51822-uart-init serial_init()
 *  in mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c 
 *
 */

#include "MySerial.h"

extern "C"
{
    void pin_mode( PinName, PinMode );

    void UART0_IRQHandler();  // Make sure UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
                              // TODO Maybe move all serial_api.c workarounds into serial_api.c
}

extern int stdio_uart_inited;
extern serial_t stdio_uart;

// Our versions of serial_api.c's...
// (serial_free(), etc. in serial_api.c won't work when use our own copy.)  TODO Maybe make one in serial_api.c accessible.
#define UART_NUM    1
static uint32_t serial_irq_ids[UART_NUM] = {0};
static uart_irq_handler irq_handler;


using namespace moo;


MySerialBase::MySerialBase( PinName tx,  PinName rx,
                            PinName rts, PinName cts ) : _my_serial(), _my_baud( 9600 )
{
    my_serial_init( &_my_serial, tx, rx, rts, cts, _my_baud );
//    serial_irq_handler( &_my_serial, _irq_handler, (uint32_t)this );  // serial_api.c only calls handler for Tx & Rx.

    // Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
    my_serial_irq_handler( &_my_serial, _irq_handler, (uint32_t)this );

    // For uart errors -- Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
    attach( this, &MySerialBase::error_handler, (Serial::IrqType)ErrIrq );
    // For cts         -- Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
    attach( this, &MySerialBase::ncts_handler, (Serial::IrqType)NctsIrq );
    attach( this, &MySerialBase::cts_handler, (Serial::IrqType)CtsIrq );
}
void MySerialBase::baud( int baudrate )
{
    serial_baud( &_my_serial, baudrate );
    _my_baud = baudrate;
}
void MySerialBase::format( int bits, SerialBase::Parity parity, int stop_bits )
{
    serial_format( &_my_serial, bits, (SerialParity)parity, stop_bits );
}
int MySerialBase::readable()
{
    return  serial_readable( &_my_serial );
}
int MySerialBase::writeable()
{
    return  serial_writable( &_my_serial );
}
void MySerialBase::attach( void (*fptr)(void), Serial::IrqType type )
{
    if( fptr )
    {
        _my_irq[type].attach( fptr );
        my_serial_irq_set( &_my_serial, (IrqType)type, 1 );

    } else
      {
          my_serial_irq_set( &_my_serial, (IrqType)type, 0 );
      }
}
void MySerialBase::my_serial_init( serial_t *obj, PinName tx, PinName rx, PinName rts, PinName cts, int baudrate )
{
    UARTName uart = UART_0;
    obj->uart = (NRF_UART_Type *)uart;

    // pin configurations --
    NRF_GPIO->DIR |=  (1 << tx);                       // TX_PIN_NUMBER
    NRF_GPIO->DIR |=  ((NC == rts) ? 0 : (1 << rts));  // RTS_PIN_NUMBER

    NRF_GPIO->DIR &= ~(1 << rx);                       // RX_PIN_NUMBER
    NRF_GPIO->DIR &= ~((NC == cts) ? 0 : (1 << cts));  // CTS_PIN_NUMBER

    obj->uart->PSELRTS = ((NC == rts) ? 0xFFFFFFFF : rts);  // RTS_PIN_NUMBER
    obj->uart->PSELTXD = tx;                                // TX_PIN_NUMBER
    obj->uart->PSELCTS = ((NC == cts) ? 0xFFFFFFFF : cts);  // CTS_PIN_NUMBER
    obj->uart->PSELRXD = rx;                                // RX_PIN_NUMBER

    if( (NC != rts) || (NC != cts) )
    {
          obj->uart->CONFIG |=  0x01;  // Enable HWFC

    } else
      {
          obj->uart->CONFIG &= ~0x01;  // Disable HWFC;
      }

    // set default baud rate and format
    serial_baud  ( obj, baudrate );
    serial_format( obj, 8, ParityNone, 1 );

    obj->uart->ENABLE        = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos);
    obj->uart->TASKS_STARTTX = 1;
    obj->uart->TASKS_STARTRX = 1;
    obj->uart->EVENTS_RXDRDY = 0;
    // dummy write needed or TXDRDY trails write rather than leads write.
    //  pins are disconnected so nothing is physically transmitted on the wire
    obj->uart->TXD = 0;

    obj->index = 0;
    
    // set rx/tx pins in PullUp mode
    if (tx != NC) {
        pin_mode(tx, PullUp);
    }
    if (rx != NC) {
        pin_mode(rx, PullUp);
    }

    // Set CTS pin to PullDown mode if used.
    if( cts != NC )
    {
        pin_mode( cts, PullDown );
    }


    if (uart == STDIO_UART) {
        stdio_uart_inited = 1;
        memcpy(&stdio_uart, obj, sizeof(serial_t));
    }
}

//  Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
void MySerialBase::my_serial_irq_handler( serial_t *obj, uart_irq_handler handler, uint32_t id )
{
    irq_handler                = handler;
    serial_irq_ids[obj->index] = id;
}
//

// Replacement for serial_irq_set() in serial_api.c so we can grab uart errors.
void MySerialBase::my_serial_irq_set( serial_t *obj, IrqType irq, uint32_t enable )
{
    IRQn_Type irq_n = (IRQn_Type)0;

    switch( (int)obj->uart )
    {
      case UART_0:
        irq_n = UART0_IRQn;
        break;
    }

    if( enable )
    {
        switch( irq )
        {
          case RxIrq:
            obj->uart->INTENSET = UART_INTENSET_RXDRDY_Msk;
            break;
          case TxIrq:
            obj->uart->INTENSET = UART_INTENSET_TXDRDY_Msk;
            break;
          case ErrIrq:
            obj->uart->INTENSET = UART_INTENSET_ERROR_Msk;
            break;
          case CtsIrq:
            obj->uart->INTENSET = UART_INTENSET_CTS_Msk;
            break;
          case NctsIrq:
            obj->uart->INTENSET = UART_INTENSET_NCTS_Msk;
            break;
          case RxtoIrq:
            obj->uart->INTENSET = UART_INTENSET_RXTO_Msk;
            break;
        }
        NVIC_SetPriority( irq_n, 3 );
        NVIC_EnableIRQ( irq_n );

    } else
      { // Disable
          switch( irq )
          {
            case RxIrq:
              obj->uart->INTENCLR = UART_INTENCLR_RXDRDY_Msk;
              break;
            case TxIrq:
              obj->uart->INTENCLR = UART_INTENCLR_TXDRDY_Msk;
              break;
            case ErrIrq:
              obj->uart->INTENCLR = UART_INTENCLR_ERROR_Msk;
              break;
            case CtsIrq:
              obj->uart->INTENCLR = UART_INTENCLR_CTS_Msk;
              break;
            case NctsIrq:
              obj->uart->INTENCLR = UART_INTENCLR_NCTS_Msk;
              break;
            case RxtoIrq:
              obj->uart->INTENCLR = UART_INTENCLR_RXTO_Msk;
              break;
          }

          if( 0 == obj->uart->INTENCLR )
          {
              NVIC_DisableIRQ( irq_n );
          }
      }
}
void MySerialBase::_irq_handler( uint32_t id, SerialIrq irq_type )
{
    MySerialBase *handler = (MySerialBase*)id;
    handler->_my_irq[irq_type].call();
}

// Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
void MySerialBase::error_handler()
{
    // Apparently handler will be continuously called until [error] condition is gone even though cleared.

    if( (UART_ERRORSRC_OVERRUN_Present << UART_ERRORSRC_OVERRUN_Pos) == (UART_ERRORSRC_OVERRUN_Msk & _my_serial.uart->ERRORSRC) )
    {
        puts( "\r\n[ERR: OVERRUN]\r\n" );

        // Clear the error
        _my_serial.uart->ERRORSRC = (UART_ERRORSRC_OVERRUN_Clear << UART_ERRORSRC_OVERRUN_Pos);

    } else if( (UART_ERRORSRC_PARITY_Present << UART_ERRORSRC_PARITY_Pos) == (UART_ERRORSRC_PARITY_Msk & _my_serial.uart->ERRORSRC) )
      {
          puts( "\r\n[ERR: PARITY]\r\n" );

          // Clear the error
          _my_serial.uart->ERRORSRC = (UART_ERRORSRC_PARITY_Clear << UART_ERRORSRC_PARITY_Pos);

      } else if( (UART_ERRORSRC_FRAMING_Present << UART_ERRORSRC_FRAMING_Pos) == (UART_ERRORSRC_FRAMING_Msk & _my_serial.uart->ERRORSRC) )
        {
            puts( "\r\n[ERR: FRAMING]\r\n" );

            // Clear the error
            _my_serial.uart->ERRORSRC = (UART_ERRORSRC_FRAMING_Clear << UART_ERRORSRC_FRAMING_Pos);

        } else if( (UART_ERRORSRC_BREAK_Present << UART_ERRORSRC_BREAK_Pos) == (UART_ERRORSRC_BREAK_Msk & _my_serial.uart->ERRORSRC) )
          {
              puts( "\r\n[ERR: BREAK]\r\n" );

              // Clear the error
              _my_serial.uart->ERRORSRC = (UART_ERRORSRC_BREAK_Clear << UART_ERRORSRC_BREAK_Pos);

          } else
            {
                // Clear the error interrupt...
                _my_serial.uart->EVENTS_ERROR = 0;
            }
}

// Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
void MySerialBase::cts_handler()
{
    // Clear interrupt.
    _my_serial.uart->EVENTS_CTS = 0;

//    puts( "\r\n[CTS: Clear]\r\n" );
}

// Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
void MySerialBase::ncts_handler()
{
    // Attempt to clear interrupt.
    _my_serial.uart->EVENTS_NCTS = 0;

    puts( "\r\n[CTS: High]\r\n" );
}

int MySerialBase::_base_getc()
{
    return  serial_getc( &_my_serial );
}
int MySerialBase::_base_putc( int c )
{
    serial_putc( &_my_serial, c );
    return  c;
}

void MySerialBase::send_break()
 {
  // Wait for 1.5 frames before clearing the break condition
  // This will have different effects on our platforms, but should
  // ensure that we keep the break active for at least one frame.
  // We consider a full frame (1 start bit + 8 data bits bits +
  // 1 parity bit + 2 stop bits = 12 bits) for computation.
  // One bit time (in us) = 1000000/_my_baud
  // Twelve bits: 12000000/baud delay
  // 1.5 frames: 18000000/baud delay
  serial_break_set( &_my_serial );
  wait_us( 18000000/_my_baud );
  serial_break_clear( &_my_serial );
}


MySerial::MySerial( PinName tx,  PinName rx,  const char *name,
                    PinName rts, PinName cts  ) : MySerialBase( tx, rx, rts, cts ), Stream( name )
{
}
int MySerial::_getc()
{
    return  _base_getc();
}
int MySerial::_putc( int c )
{
    return  _base_putc( c );
}
int MySerial::puts( const char *str )
{
    while( *str )
        putc( *str ++ );

    return  0;
}

int MySerial::printf( const char *format, ... )
{
    va_list arg;
    va_start( arg, format );

    int len = MySerial::vprintf( format, arg );

    va_end( arg );

    return  len;
}
int MySerial::vprintf( const char *format, va_list arg )
{
    int len = vsnprintf( NULL, 0, format, arg );
    if( len < STRING_STACK_LIMIT )
    {
        char temp[STRING_STACK_LIMIT];
        vsprintf( temp, format, arg );
        puts( temp );

    } else
      {
        char *temp = new char[len + 1];
        vsprintf( temp, format, arg );
        puts( temp );
        delete[] temp;
      }

    return  len;
}

//  Won't work unless UART0_IRQHandler is commented-out in serial_api.c (rebuild mbed lib.)
#ifdef __cplusplus
extern "C"
{
#endif
void UART0_IRQHandler()
{
    MySerial::IrqType irq_type;

    if( (NRF_UART0->INTENSET & UART_INTENSET_TXDRDY_Msk) && NRF_UART0->EVENTS_TXDRDY )
    {
        irq_type = MySerial::TxIrq;

    } else if( (NRF_UART0->INTENSET & UART_INTENSET_RXDRDY_Msk) && NRF_UART0->EVENTS_RXDRDY )
      {
          irq_type = MySerial::RxIrq;

      } else if( (NRF_UART0->INTENSET & UART_INTENSET_ERROR_Msk) && NRF_UART0->EVENTS_ERROR )
        {
            irq_type = MySerial::ErrIrq;

        } else if( (NRF_UART0->INTENSET & UART_INTENSET_CTS_Msk) && NRF_UART0->EVENTS_CTS )
          {
              irq_type = MySerial::CtsIrq;

          } else if( (NRF_UART0->INTENSET & UART_INTENSET_NCTS_Msk) && NRF_UART0->EVENTS_NCTS )
            {
                irq_type = MySerial::NctsIrq;

            } else if( (NRF_UART0->INTENSET & UART_INTENSET_RXTO_Msk) && NRF_UART0->EVENTS_RXTO )
              {
                  irq_type = MySerial::RxtoIrq;

              } else
                {
                    return;
                }

    if( serial_irq_ids[0] != 0 )
    {
        irq_handler( serial_irq_ids[0], (SerialIrq)irq_type );
    }
}
#ifdef __cplusplus
}
#endif
//

/* EOF */