SX1261 and sx1262 common library

Dependents:   SX126xDevKit SX1262PingPong SX126X_TXonly SX126X_PingPong_Demo ... more

Fork of SX126xLib by Gregory Cristian

Revision:
0:deaafdfde3bb
Child:
1:35d34672a089
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sx126x-hal.cpp	Tue Sep 06 06:56:46 2016 +0000
@@ -0,0 +1,506 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2016 Semtech
+
+Description: Handling of the node configuration protocol
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis, Gregory Cristian and Matthieu Verdy
+*/
+#include "sx1261-hal.h"
+
+#define V1A_WORKAROUNDS
+
+/*!
+ * \brief Used to block execution waiting for low state on radio busy pin.
+ *        Essentially used in SPI communications
+ */
+#define WaitBusy( )          while( BUSY == 1 ){ }
+
+
+
+/*!
+ * \brief Blocking routine for waiting the UART to be writeable
+ *
+ */
+#define WaitUartWritable( )  while( RadioUart->writeable( ) == false ){ }
+
+/*!
+ * \brief Blocking routine for waiting the UART to be readable
+ *
+ */
+#define WaitUartReadable( )  while( RadioUart->readable( ) == false ){ }
+
+SX1261Hal::SX1261Hal( PinName mosi, PinName miso, PinName sclk, PinName nss, PinName busy, PinName dio1, PinName dio2, PinName dio3, PinName rst,
+                            void ( *txDone )( ), void ( *rxDone )( ), void ( *rxPblSyncWordHeader )( IrqPblSyncHeaderCode_t val ),
+                            void ( *rxTxTimeout )( ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *rangingDone )( IrqRangingCode_t val ),
+                            void ( *cadDone )( bool channelActivityDetected ),
+                            void ( *onDioIrq )( ) )
+        :   SX1261( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout,  rxError, rangingDone, cadDone, onDioIrq ),
+            RadioNss( nss ),
+            RadioReset( rst ),
+            BUSY( busy ),
+            DIO1( dio1 ),
+            DIO2( dio2 ),
+            DIO3( dio3 )
+{
+    RadioSpi = new SPI( mosi, miso, sclk );
+    RadioUart = NULL;
+
+    RadioNss = 1;
+    RadioReset = 1;
+}
+
+SX1261Hal::SX1261Hal( PinName tx, PinName rx, PinName busy, PinName dio1, PinName dio2, PinName dio3, PinName rst,
+                            void ( *txDone )( ), void ( *rxDone )( ), void ( *rxPblSyncWordHeader )( IrqPblSyncHeaderCode_t val ),
+                            void ( *rxTxTimeout )( ), void ( *rxError )( IrqErrorCode_t errorCode ), void ( *rangingDone )( IrqRangingCode_t val ),
+                            void ( *cadDone )( bool channelActivityDetected ),
+                            void ( *onDioIrq )( ) )
+        :   SX1261( txDone, rxDone, rxPblSyncWordHeader, rxTxTimeout, rxError, rangingDone, cadDone, onDioIrq ),
+            RadioNss( NC ),
+            RadioReset( rst ),
+            BUSY( busy ),
+            DIO1( dio1 ),
+            DIO2( dio2 ),
+            DIO3( dio3 )
+{
+    RadioSpi = NULL;
+    RadioUart = new Serial( tx, rx );
+    RadioReset = 1;
+}
+
+void SX1261Hal::SpiInit( void )
+{
+    RadioNss = 1;
+    RadioSpi->format( 8, 0 );
+    RadioSpi->frequency( SX1261_SPI_FREQ_DEFAULT );
+
+    wait( 0.1 );
+}
+
+void SX1261Hal::UartInit( void )
+{
+    RadioUart->format( 9, SerialBase::Even, 1 ); // 8 data bits + 1 even parity bit + 1 stop bit
+    RadioUart->baud( 115200 );
+
+    // By default the SX1261 UART is setup to handle bytes MSB first.
+    // In order to setup the radio to use the UART standard way we first send
+    // the equivalent of a WriteRegister with reversed bit order in order to
+    // change the endianness.
+    //@todo 
+    /*uint8_t regVal = 0;
+    RadioUart->putc( 0x98 );            // Reversed opcode for read register (0x19)
+    RadioUart->putc( 0x10 );            // Reversed MSB register address (0x08)
+    RadioUart->putc( 0x18 );            // Reversed LSB register address (0x18)
+    RadioUart->putc( 0x80 );            // Reversed value for reading only 1 byte (0x01)
+    regVal = RadioUart->getc( )& 0xF3;  // Read reversed value and mask it
+
+    RadioUart->putc( 0x18 );            // Reversed opcode for read register (0x18)
+    RadioUart->putc( 0x10 );            // Reversed MSB register address (0x08)
+    RadioUart->putc( 0x18 );            // Reversed LSB register address (0x18)
+    RadioUart->putc( 0x80 );            // Reversed value for writing only 1 byte (0x01)
+    RadioUart->putc( regVal );          // The new value of the register*/
+
+    // After this point, the UART is running standard mode: 8 data bit, 1 even
+    // parity bit, 1 stop bit, 115200 baud, LSB first
+    wait_us( 10 );
+}
+
+void SX1261Hal::IoIrqInit( DioIrqHandler irqHandler )
+{
+    assert_param( RadioSpi != 0 || RadioUart != 0 );
+    if( RadioSpi != NULL )
+    {
+        SpiInit( );
+    }
+    if( RadioUart != NULL )
+    {
+        UartInit( );
+    }
+
+    BUSY.mode( PullDown );
+    DIO1.mode( PullDown );
+    DIO2.mode( PullDown );
+    DIO3.mode( PullDown );
+
+    DIO1.rise( this, static_cast <Trigger>( irqHandler ) );
+    DIO2.rise( this, static_cast <Trigger>( irqHandler ) );
+    DIO3.rise( this, static_cast <Trigger>( irqHandler ) );
+}
+
+void SX1261Hal::Reset( void )
+{
+    __disable_irq( );
+    wait( 0.05 );
+    RadioReset = 0;
+    wait( 0.1 );
+    RadioReset = 1;
+    wait( 0.05 );
+    __enable_irq( );
+}
+
+void SX1261Hal::ClearInstructionRam( void )
+{
+    // Clearing the instruction RAM is writing 0x00s on every bytes of the
+    // instruction RAM
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_WRITE_REGISTER );                 // Send write register opcode
+        RadioSpi->write( ( IRAM_START_ADDRESS >> 8 ) & 0x00FF ); // Send MSB of the first byte address
+        RadioSpi->write( IRAM_START_ADDRESS & 0x00FF );          // Send LSB of the first byte address
+
+        for( uint16_t address = IRAM_START_ADDRESS; address < ( IRAM_START_ADDRESS + IRAM_SIZE ); address++ )
+        {
+            RadioSpi->write( 0x00 );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        // We can't erase the whole instruction RAM in one shot with UART
+        // because we need to send the length of register to erase
+        // and this length is coded on 1 byte.
+        for( uint16_t address = IRAM_START_ADDRESS; address < ( IRAM_START_ADDRESS + IRAM_SIZE ); address++ )
+        {
+            WriteRegister( address, 0 );
+        }
+    }
+
+    WaitBusy( );
+}
+
+void SX1261Hal::Wakeup( void )
+{
+    __disable_irq( );
+
+    //Don't wait for DIO0 here
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_GET_STATUS );
+        RadioSpi->write( 0 );
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_GET_STATUS );
+        WaitUartReadable( );
+        RadioUart->getc( );
+    }
+
+    // Wait for chip to be ready.
+    WaitBusy( );
+    
+    #ifdef V1A_WORKAROUNDS
+    //V1a workaround: rc64k not enabled after warm_start, rtc_wake_up=0
+    WriteRegister(0x91e, ReadRegister(0x91e) | 0x40);
+    //rc13m enable bug
+    uint8_t txFallbackFunc[2];
+    //set to  ModeTx2Rc addr = 0fce, so rc is not enabled before ramp down
+    txFallbackFunc[0] = 0x0f;
+    txFallbackFunc[1] = 0xce;
+    WriteRegister(0x00CC, txFallbackFunc, 2);
+    #endif
+
+    __enable_irq( );
+}
+
+void SX1261Hal::WriteCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( ( uint8_t )command );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioSpi->write( buffer[i] );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( command );
+        if( size > 0 )
+        {
+            RadioUart->putc( size );
+            for( uint16_t i = 0; i < size; i++ )
+            {
+                RadioUart->putc( buffer[i] );
+            }
+        }
+    }
+
+    if( command != RADIO_SET_SLEEP )
+    {
+        WaitBusy( );
+    }
+}
+
+void SX1261Hal::ReadCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( ( uint8_t )command );
+        RadioSpi->write( 0 );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+             buffer[i] = RadioSpi->write( 0 );
+        }
+        RadioNss = 1;
+    }
+    else if( RadioUart != NULL )
+    {
+        RadioUart->putc( command );
+
+        // Behavior on the UART is different depending of the opcode command
+        if( ( command == RADIO_GET_PACKETTYPE ) ||
+            ( command == RADIO_GET_RXBUFFERSTATUS ) ||
+            ( command == RADIO_GET_RSSIINST ) ||
+            ( command == RADIO_GET_PACKETSTATUS ) ||
+            ( command == RADIO_GET_IRQSTATUS ) )
+        {
+            RadioUart->putc( size );
+        }
+
+        WaitUartReadable( );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+             buffer[i] = RadioUart->getc( );
+        }
+    }
+    else
+    {
+        buffer[0] = 0xFF;
+    }
+
+    WaitBusy( );
+}
+
+void SX1261Hal::WriteRegister( uint16_t address, uint8_t *buffer, uint16_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_WRITE_REGISTER );
+        RadioSpi->write( ( address & 0xFF00 ) >> 8 );
+        RadioSpi->write( address & 0x00FF );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioSpi->write( buffer[i] );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_WRITE_REGISTER );
+        RadioUart->putc( ( address & 0xFF00 ) >> 8 );
+        RadioUart->putc( address & 0x00FF );
+        RadioUart->putc( size );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioUart->putc( buffer[i] );
+        }
+    }
+
+    WaitBusy( );
+}
+
+void SX1261Hal::WriteRegisterNoBusy( uint16_t address, uint8_t *buffer, uint16_t size )
+{
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_WRITE_REGISTER );
+        RadioSpi->write( ( address & 0xFF00 ) >> 8 );
+        RadioSpi->write( address & 0x00FF );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioSpi->write( buffer[i] );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_WRITE_REGISTER );
+        RadioUart->putc( ( address & 0xFF00 ) >> 8 );
+        RadioUart->putc( address & 0x00FF );
+        RadioUart->putc( size );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioUart->putc( buffer[i] );
+        }
+    }
+}
+
+void SX1261Hal::WriteRegister( uint16_t address, uint8_t value )
+{
+    WriteRegister( address, &value, 1 );
+}
+
+void SX1261Hal::WriteRegisterNoBusy( uint16_t address, uint8_t value )
+{
+    WriteRegisterNoBusy( address, &value, 1 );
+}
+
+void SX1261Hal::ReadRegister( uint16_t address, uint8_t *buffer, uint16_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_READ_REGISTER );
+        RadioSpi->write( ( address & 0xFF00 ) >> 8 );
+        RadioSpi->write( address & 0x00FF );
+        RadioSpi->write( 0 );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioSpi->write( 0 );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_READ_REGISTER );
+        RadioUart->putc( ( address & 0xFF00 ) >> 8 );
+        RadioUart->putc( address & 0x00FF );
+        RadioUart->putc( size );
+        WaitUartReadable( );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioUart->getc( );
+        }
+    }
+
+    WaitBusy( );
+}
+
+void SX1261Hal::ReadRegisterNoBusy( uint16_t address, uint8_t *buffer, uint16_t size )
+{
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_READ_REGISTER );
+        RadioSpi->write( ( address & 0xFF00 ) >> 8 );
+        RadioSpi->write( address & 0x00FF );
+        RadioSpi->write( 0 );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioSpi->write( 0 );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_READ_REGISTER );
+        RadioUart->putc( ( address & 0xFF00 ) >> 8 );
+        RadioUart->putc( address & 0x00FF );
+        RadioUart->putc( size );
+        WaitUartReadable( );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioUart->getc( );
+        }
+    }
+
+}
+
+uint8_t SX1261Hal::ReadRegister( uint16_t address )
+{
+    uint8_t data;
+
+    ReadRegister( address, &data, 1 );
+    return data;
+}
+
+uint8_t SX1261Hal::ReadRegisterNoBusy( uint16_t address )
+{
+    uint8_t data;
+
+    ReadRegisterNoBusy( address, &data, 1 );
+    return data;
+}
+
+void SX1261Hal::WriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_WRITE_BUFFER );
+        RadioSpi->write( offset );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioSpi->write( buffer[i] );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_WRITE_BUFFER );
+        RadioUart->putc( offset );
+        RadioUart->putc( size );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            RadioUart->putc( buffer[i] );
+        }
+    }
+
+    WaitBusy( );
+}
+
+void SX1261Hal::ReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
+{
+    WaitBusy( );
+
+    if( RadioSpi != NULL )
+    {
+        RadioNss = 0;
+        RadioSpi->write( RADIO_READ_BUFFER );
+        RadioSpi->write( offset );
+        RadioSpi->write( 0 );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioSpi->write( 0 );
+        }
+        RadioNss = 1;
+    }
+    if( RadioUart != NULL )
+    {
+        RadioUart->putc( RADIO_READ_BUFFER );
+        RadioUart->putc( offset );
+        RadioUart->putc( size );
+        WaitUartReadable( );
+        for( uint16_t i = 0; i < size; i++ )
+        {
+            buffer[i] = RadioUart->getc( );
+        }
+    }
+
+    WaitBusy( );
+}
+
+uint8_t SX1261Hal::GetDioStatus( void )
+{
+    return ( DIO3 << 3 ) | ( DIO2 << 2 ) | ( DIO1 << 1 ) | ( BUSY << 0 );
+}
+
+