SX1261 and sx1262 common library
Dependents: SX126xDevKit SX1262PingPong SX126X_TXonly SX126X_PingPong_Demo ... more
Fork of SX126xLib by
Diff: sx126x.cpp
- Revision:
- 4:c6ef863d0b07
- Parent:
- 3:7e3595a9ebe0
- Child:
- 5:e488e6f185f3
--- a/sx126x.cpp Wed Oct 12 08:49:58 2016 +0000 +++ b/sx126x.cpp Mon Sep 04 15:16:44 2017 +0000 @@ -1,26 +1,24 @@ /* + ______ _ / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2016 Semtech + (C)2017 Semtech -Description: Handling of the node configuration protocol +Description: Generic SX126x driver implementation License: Revised BSD License, see LICENSE.TXT file include in the project -Maintainer: Miguel Luis, Gregory Cristian and Matthieu Verdy +Authors: Miguel Luis, Gregory Cristian */ #include "mbed.h" #include "sx126x.h" #include "sx126x-hal.h" -#include "pram_c005.h" - /*! - * Radio registers definition - * + * \brief Radio registers definition */ typedef struct { @@ -28,424 +26,77 @@ uint8_t Value; //!< The value of the register }RadioRegisters_t; -// [TODO] Is this also applicable for the V2 version of the chip /*! - * \brief Radio hardware registers initialization definition + * \brief Stores the last frequency error measured on LoRa received packet */ -// { Address, RegValue } - -#define RADIO_INIT_REGISTERS_VALUE \ -{ \ - { 0x0722, 0x53 }, \ - { 0x0889, 0x01 }, \ -} - -/*! - * \brief Radio hardware registers initialization - */ -const RadioRegisters_t RadioRegsInit[] = RADIO_INIT_REGISTERS_VALUE; +volatile uint32_t FrequencyError = 0; void SX126x::Init( void ) { + /*! + * \brief pin OPT is used to detect if the board has a TCXO or a XTAL + * + * OPT = 0 >> TCXO; OPT = 1 >> XTAL + */ + DigitalIn OPT( A3 ); + Reset( ); + IoIrqInit( dioIrq ); + Wakeup( ); -/****************************************************/ SetStandby( STDBY_RC ); - WriteRegister( 0x610, 0x10 ); - for( uint16_t i = 0; i < PRAM_COUNT; i++ ) + + if( OPT == 0 ) { - uint32_t val = pram[i]; - WriteRegister( 0x8000 + 4 * i, 0 ); - WriteRegister( 0x8001 + 4 * i, ( val >> 16 ) & 0xff ); - WriteRegister( 0x8002 + 4 * i, ( val >> 8 ) & 0xff ); - WriteRegister( 0x8003 + 4 * i, val & 0xff ); + SetDio3AsTcxoCtrl( TCXO_CTRL_1_7V, 6400 ); //100 ms + WriteReg( REG_XTA_TRIM, 0x2F ); } - WriteRegister( 0x610, 0x00 ); - WriteCommand( RADIO_SET_PRAMSWAPCMD, ( uint8_t[] ) { 2 } , 1 ); // RADIO_SET_PRAMSWAPCMD = 0x8D, -/****************************************************/ - SetRegistersDefault( ); -} + + SetPollingMode( ); + + AntSwOn( ); + SetDio2AsRfSwitchCtrl( true ); + + SetPacketType( PACKET_TYPE_LORA ); -void SX126x::SetRegistersDefault( void ) -{ - for( uint8_t i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ ) - { - WriteRegister( RadioRegsInit[i].Addr, RadioRegsInit[i].Value ); - } +#ifdef USE_CONFIG_PUBLIC_NETOWRK + // Change LoRa modem Sync Word for Public Networks + WriteReg( REG_LR_SYNCWORD, ( LORA_MAC_PUBLIC_SYNCWORD >> 8 ) & 0xFF ); + WriteReg( REG_LR_SYNCWORD + 1, LORA_MAC_PUBLIC_SYNCWORD & 0xFF ); +#else + // Change LoRa modem SyncWord for Private Networks + WriteReg( REG_LR_SYNCWORD, ( LORA_MAC_PRIVATE_SYNCWORD >> 8 ) & 0xFF ); + WriteReg( REG_LR_SYNCWORD + 1, LORA_MAC_PRIVATE_SYNCWORD & 0xFF ); +#endif } -uint16_t SX126x::GetFirmwareVersion( void ) -{ - return( ( ( ReadRegister( 0xA8 ) ) << 8 ) | ( ReadRegister( 0xA9 ) ) ); -} - -RadioStatus_t SX126x::GetStatus( void ) +RadioOperatingModes_t SX126x::GetOperatingMode( void ) { - uint8_t stat = 0; - RadioStatus_t status; - - ReadCommand( RADIO_GET_STATUS, ( uint8_t * )&stat, 1 ); - status.Value = stat; - - - return( status ); + return OperatingMode; } -void SX126x::SetSleep( SleepParams_t sleepConfig ) -{ - - WriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 ); - OperatingMode = MODE_SLEEP; -} - -void SX126x::SetStandby( RadioStandbyModes_t standbyConfig ) +void SX126x::CheckDeviceReady( void ) { - WriteCommand( RADIO_SET_STANDBY, ( uint8_t* )&standbyConfig, 1 ); - if( standbyConfig == STDBY_RC ) + if( ( GetOperatingMode( ) == MODE_SLEEP ) || ( GetOperatingMode( ) == MODE_RX_DC ) ) { - OperatingMode = MODE_STDBY_RC; - } - else - { - OperatingMode = MODE_STDBY_XOSC; + Wakeup( ); + // Switch is turned off when device is in sleep mode and turned on is all other modes + AntSwOn( ); } } -void SX126x::SetFs( void ) -{ - WriteCommand( RADIO_SET_FS, 0, 0 ); - OperatingMode = MODE_FS; -} - -void SX126x::SetTx( uint32_t timeout ) -{ - uint8_t buf[3]; - buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); - buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); - buf[2] = ( uint8_t )( timeout & 0xFF ); - WriteCommand( RADIO_SET_TX, buf, 3 ); - OperatingMode = MODE_TX; -} - -void SX126x::SetRx( uint32_t timeout ) -{ - uint8_t buf[3]; - buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); - buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); - buf[2] = ( uint8_t )( timeout & 0xFF ); - WriteCommand( RADIO_SET_RX, buf, 3 ); - OperatingMode = MODE_RX; -} - -void SX126x::SetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ) -{ - uint8_t buf[6]; - - buf[0] = ( uint8_t )( ( rxTime >> 16 ) & 0xFF ); - buf[1] = ( uint8_t )( ( rxTime >> 8 ) & 0xFF ); - buf[2] = ( uint8_t )( rxTime & 0xFF ); - buf[0] = ( uint8_t )( ( sleepTime >> 16 ) & 0xFF ); - buf[1] = ( uint8_t )( ( sleepTime >> 8 ) & 0xFF ); - buf[2] = ( uint8_t )( sleepTime & 0xFF ); - WriteCommand( RADIO_SET_RXDUTYCYCLE, buf, 6 ); - OperatingMode = MODE_RX; -} - -void SX126x::SetCad( void ) -{ - WriteCommand( RADIO_SET_CAD, 0, 0 ); - OperatingMode = MODE_CAD; -} - -void SX126x::SetAutoTxRx( uint32_t time, uint8_t intMode, uint32_t timeout ) -{ - uint32_t compensatedTime = time - ( uint16_t )AUTO_RX_TX_OFFSET; - uint8_t buf[7]; - - buf[0] = ( uint8_t )( ( compensatedTime >> 16 ) & 0xFF ); - buf[1] = ( uint8_t )( ( compensatedTime >> 8 ) & 0xFF ); - buf[2] = ( uint8_t )( compensatedTime & 0xFF ); - buf[3] = intMode; - buf[4] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); - buf[5] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); - buf[6] = ( uint8_t )( timeout & 0xFF ); - WriteCommand( RADIO_SET_AUTOTXRX, buf, 7 ); -} - - -void SX126x::SetTxContinuousWave( void ) -{ - WriteCommand( RADIO_SET_TXCONTINUOUSWAVE, 0, 0 ); -} - -void SX126x::SetTxContinuousPreamble( void ) -{ - WriteCommand( RADIO_SET_TXCONTINUOUSPREAMBLE, 0, 0 ); -} - -void SX126x::SetPacketType( RadioPacketType_t packetType ) -{ - // Save packet type internally to avoid questioning the radio - this->PacketType = packetType; - - WriteCommand( RADIO_SET_PACKETTYPE, ( uint8_t* )&packetType, 1 ); -} - -RadioPacketType_t SX126x::GetPacketType( void ) -{ - return this->PacketType; -} - -void SX126x::SetRfFrequency( uint32_t frequency ) -{ - uint8_t buf[4]; - uint32_t freq = 0; - - freq = ( uint32_t )( ( double )frequency / ( double )FREQ_STEP ); - buf[0] = ( uint8_t )( ( freq >> 24 ) & 0xFF ); - buf[1] = ( uint8_t )( ( freq >> 16 ) & 0xFF ); - buf[2] = ( uint8_t )( ( freq >> 8 ) & 0xFF ); - buf[3] = ( uint8_t )( freq & 0xFF ); - WriteCommand( RADIO_SET_RFFREQUENCY, buf, 3 ); -} - -void SX126x::SetTxParams( int8_t power, RadioRampTimes_t rampTime ) -{ - uint8_t buf[2]; - - buf[0] = power ; - buf[1] = ( uint8_t )rampTime; - WriteCommand( RADIO_SET_TXPARAMS, buf, 2 ); -} - -void SX126x::SetCadConfig( RadioLoRaCadSymbols_t cadSymbolNum , uint8_t cadExitMode, uint32_t cadRxTxTimeout) -{ - uint8_t buf[5]; - buf[0] = ( uint8_t )cadSymbolNum; - buf[1] = cadExitMode; - buf[2] = ( uint8_t )( ( cadRxTxTimeout >> 16 ) & 0xFF ); - buf[3] = ( uint8_t )( ( cadRxTxTimeout >> 8 ) & 0xFF ); - buf[4] = ( uint8_t )( cadRxTxTimeout & 0xFF ); - WriteCommand( RADIO_SET_CADPARAMS, buf, 5 ); - OperatingMode = MODE_CAD; -} - -void SX126x::SetBufferBaseAddresses( uint8_t txBaseAddress, uint8_t rxBaseAddress ) -{ - uint8_t buf[2]; - - buf[0] = txBaseAddress; - buf[1] = rxBaseAddress; - WriteCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 ); -} - -void SX126x::SetModulationParams( ModulationParams_t *modulationParams ) +void SX126x::SetPayload( uint8_t *payload, uint8_t size ) { - uint8_t n; - uint32_t tempVal = 0; - uint8_t buf[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - // Check if required configuration corresponds to the stored packet type - // If not, silently update radio packet type - if( this->PacketType != modulationParams->PacketType ) - { - this->SetPacketType( modulationParams->PacketType ); - } - - switch( modulationParams->PacketType ) - { - case PACKET_TYPE_GFSK: - tempVal = ( uint32_t )( ( double )XTAL_FREQ / ( double )modulationParams->Params.Gfsk.BitRate ); - tempVal = tempVal * 32; - buf[0] = ( tempVal >> 16 ) & 0xFF; - buf[1] = ( tempVal >> 8 ) & 0xFF; - buf[2] = tempVal & 0xFF; - - buf[3] = modulationParams->Params.Gfsk.PulseShape; - buf[4] = modulationParams->Params.Gfsk.BW; - - tempVal = ( uint32_t )( ( double )FREQ_STEP * ( double )modulationParams->Params.Gfsk.Fdev ); - buf[5] = ( tempVal >> 16 ) & 0xFF; - buf[6] = ( tempVal >> 8 ) & 0xFF; - buf[7] = ( tempVal& 0xFF ); - n = 8; - break; - - case PACKET_TYPE_LORA: - n = 3; - buf[0] = modulationParams->Params.LoRa.SpreadingFactor; - buf[1] = modulationParams->Params.LoRa.Bandwidth; - buf[2] = modulationParams->Params.LoRa.CodingRate; - break; - - case PACKET_TYPE_RESERVED: - return; - } - WriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n ); -} - -void SX126x::SetPacketParams( PacketParams_t *packetParams ) -{ - uint8_t n; - - // Check if required configuration corresponds to the stored packet type - // If not, silently update radio packet type - if( this->PacketType != packetParams->PacketType ) - { - this->SetPacketType( packetParams->PacketType ); - } - - switch( packetParams->PacketType ) - { - case PACKET_TYPE_GFSK: - n = 8; - break; - case PACKET_TYPE_LORA: - n = 5; - break; - case PACKET_TYPE_RESERVED: - return; - } - WriteCommand( RADIO_SET_PACKETPARAMS, packetParams->Params.Buffer, n ); -} - -void SX126x::GetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPointer ) -{ - uint8_t status[2]; - - ReadCommand( RADIO_GET_RXBUFFERSTATUS, status, 2 ); - - *payloadLength = status[0]; - *rxStartBufferPointer = status[1]; -} - -void SX126x::GetPacketStatus( PacketStatus_t *pktStatus ) -{ - uint8_t status[3]; - - - ReadCommand( RADIO_GET_PACKETSTATUS, status, 3 ); - - pktStatus->packetType = this -> GetPacketType( ); - switch( pktStatus->packetType ) - { - case PACKET_TYPE_GFSK: - pktStatus->Gfsk.RxStatus = status[0]; - pktStatus->Gfsk.RssiSync = -status[1] / 2; - pktStatus->Gfsk.RssiAvg = -status[2] / 2; - break; - - case PACKET_TYPE_LORA: - pktStatus->LoRa.RssiPkt = -status[0] / 2; - ( status[1] < 128 ) ? ( pktStatus->LoRa.SnrPkt = status[1] / 4 ) : ( pktStatus->LoRa.SnrPkt = ( ( status[1] - 256 ) /4 ) ); - pktStatus->LoRa.SignalRssiPkt = -status[2] / 2; - break; - - case PACKET_TYPE_RESERVED: - // In that specific case, we set everything in the pktStatus to zeros - // and reset the packet type accordingly - memset( pktStatus, 0, sizeof( PacketStatus_t ) ); - pktStatus->packetType = PACKET_TYPE_RESERVED; - break; - } -} - -int8_t SX126x::GetRssiInst( void ) -{ - int8_t rssi; - - ReadCommand( RADIO_GET_RSSIINST, ( uint8_t* )&rssi, 1 ); - return -rssi / 2; -} - -void SX126x::GetStats( RxCounter_t *rxCounter ) -{ - uint8_t status[6]; - - - rxCounter->packetType = this -> GetPacketType( ); - ReadCommand( RADIO_GET_STATS, status, 6 ); - rxCounter->NbPktReceived = ( status[0] << 8 ) | status[1]; - rxCounter->NbPktCrcOk = ( status[2] << 8 ) | status[3]; - rxCounter->NbPktLengthError = ( status[4] << 8 ) | status[4]; -} - -void SX126x::ResetStats( ) -{ - uint8_t status[6]; - - memset( status, 0, sizeof( status ) ); - WriteCommand( RADIO_RESET_STATS, status, 6 ); -} - -uint8_t SX126x::GetError() -{ - uint8_t error; - - ReadCommand( RADIO_GET_ERROR, &error, 1 ); - return error; -} - - -void SX126x::SetDioIrqParams( uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask ) -{ - uint8_t buf[8]; - - buf[0] = ( uint8_t )( ( irqMask >> 8 ) & 0x00FF ); - buf[1] = ( uint8_t )( irqMask & 0x00FF ); - buf[2] = ( uint8_t )( ( dio1Mask >> 8 ) & 0x00FF ); - buf[3] = ( uint8_t )( dio1Mask & 0x00FF ); - buf[4] = ( uint8_t )( ( dio2Mask >> 8 ) & 0x00FF ); - buf[5] = ( uint8_t )( dio2Mask & 0x00FF ); - buf[6] = ( uint8_t )( ( dio3Mask >> 8 ) & 0x00FF ); - buf[7] = ( uint8_t )( dio3Mask & 0x00FF ); - WriteCommand( RADIO_CFG_DIOIRQ, buf, 8 ); -} - -uint16_t SX126x::GetIrqStatus( void ) -{ - uint8_t irqStatus[2]; - ReadCommand( RADIO_GET_IRQSTATUS, irqStatus, 2 ); - return ( irqStatus[0] << 8 ) | irqStatus[1]; -} - -void SX126x::ClearIrqStatus( uint16_t irq ) -{ - uint8_t buf[2]; - - buf[0] = ( uint8_t )( ( ( uint16_t )irq >> 8 ) & 0x00FF ); - buf[1] = ( uint8_t )( ( uint16_t )irq & 0x00FF ); - WriteCommand( RADIO_CLR_IRQSTATUS, buf, 2 ); -} - -void SX126x::Calibrate( CalibrationParams_t calibParam ) -{ - WriteCommand( RADIO_CALIBRATE, &calibParam.Value, 1 ); -} - -void SX126x::SetRegulatorMode( uint8_t mode ) -{ - WriteCommand( RADIO_SET_REGULATORMODE, &mode, 1 ); -} - - -void SX126x::SetLongPreamble( uint8_t enable ) -{ - WriteCommand( RADIO_SET_LONGPREAMBLE, &enable, 1 ); -} - -void SX126x::SetPayload( uint8_t *buffer, uint8_t size ) -{ - WriteBuffer( 0x00, buffer, size ); + WriteBuffer( 0x00, payload, size ); } uint8_t SX126x::GetPayload( uint8_t *buffer, uint8_t *size, uint8_t maxSize ) { - uint8_t offset; + uint8_t offset = 0; GetRxBufferStatus( size, &offset ); - if(*size > maxSize) + if( *size > maxSize ) { return 1; } @@ -468,14 +119,16 @@ void SX126x::SetCrcSeed( uint16_t seed ) { uint8_t buf[2]; + buf[0] = ( uint8_t )( ( seed >> 8 ) & 0xFF ); buf[1] = ( uint8_t )( seed & 0xFF ); - + switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_CRCSEEDBASEADDR, buf, 2 ); break; + default: break; } @@ -484,147 +137,721 @@ void SX126x::SetCrcPolynomial( uint16_t polynomial ) { uint8_t buf[2]; + buf[0] = ( uint8_t )( ( polynomial >> 8 ) & 0xFF ); buf[1] = ( uint8_t )( polynomial & 0xFF ); - + switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_CRCPOLYBASEADDR, buf, 2 ); break; + default: break; } } -void SX126x::SetWhiteningSeed( uint8_t seed ) +void SX126x::SetWhiteningSeed( uint16_t seed ) { + uint8_t regValue = 0; + switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: - WriteRegister( REG_LR_WHITSEEDBASEADDR, seed ); + regValue = ReadReg( REG_LR_WHITSEEDBASEADDR_MSB ) & 0xFE; + regValue = ( ( seed >> 8 ) & 0x01 ) | regValue; + WriteReg( REG_LR_WHITSEEDBASEADDR_MSB, regValue ); // only 1 bit. + WriteReg( REG_LR_WHITSEEDBASEADDR_LSB, ( uint8_t )seed ); break; + default: break; } } -int8_t SX126x::ParseHexFileLine( char* line ) +uint32_t SX126x::GetRandom( void ) +{ + uint8_t buf[] = { 0, 0, 0, 0 }; + + // Set radio in continuous reception + SetRx( 0 ); + + wait_ms( 1 ); + + ReadRegister( RANDOM_NUMBER_GENERATORBASEADDR, buf, 4 ); + + SetStandby( STDBY_RC ); + + return ( buf[0] << 24 ) | ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3]; +} + +void SX126x::SetSleep( SleepParams_t sleepConfig ) { - uint16_t addr; - uint16_t n; - uint8_t code; - uint8_t bytes[256]; +#ifdef ADV_DEBUG + printf("SetSleep "); +#endif + + AntSwOff( ); + + WriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 ); + OperatingMode = MODE_SLEEP; +} - if( GetHexFileLineFields( line, bytes, &addr, &n, &code ) != 0 ) +void SX126x::SetStandby( RadioStandbyModes_t standbyConfig ) +{ +#ifdef ADV_DEBUG + printf("SetStandby "); +#endif + WriteCommand( RADIO_SET_STANDBY, ( uint8_t* )&standbyConfig, 1 ); + if( standbyConfig == STDBY_RC ) + { + OperatingMode = MODE_STDBY_RC; + } + else { - if( code == 0 ) + OperatingMode = MODE_STDBY_XOSC; + } +} + +void SX126x::SetFs( void ) +{ +#ifdef ADV_DEBUG + printf("SetFs "); +#endif + WriteCommand( RADIO_SET_FS, 0, 0 ); + OperatingMode = MODE_FS; +} + +void SX126x::SetTx( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_TX; + +#ifdef ADV_DEBUG + printf("SetTx "); +#endif + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + WriteCommand( RADIO_SET_TX, buf, 3 ); +} + +void SX126x::SetRxBoosted( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_RX; + +#ifdef ADV_DEBUG + printf("SetRxBoosted "); +#endif + + WriteReg( REG_RX_GAIN, 0x96 ); // max LNA gain, increase current by ~2mA for around ~3dB in sensivity + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + WriteCommand( RADIO_SET_RX, buf, 3 ); +} + +void SX126x::SetRx( uint32_t timeout ) +{ + uint8_t buf[3]; + + OperatingMode = MODE_RX; + +#ifdef ADV_DEBUG + printf("SetRx "); +#endif + + buf[0] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( timeout & 0xFF ); + WriteCommand( RADIO_SET_RX, buf, 3 ); +} + +void SX126x::SetRxDutyCycle( uint32_t rxTime, uint32_t sleepTime ) +{ + uint8_t buf[6]; + + SetLongPreamble( true ); + + buf[0] = ( uint8_t )( ( rxTime >> 16 ) & 0xFF ); + buf[1] = ( uint8_t )( ( rxTime >> 8 ) & 0xFF ); + buf[2] = ( uint8_t )( rxTime & 0xFF ); + buf[3] = ( uint8_t )( ( sleepTime >> 16 ) & 0xFF ); + buf[4] = ( uint8_t )( ( sleepTime >> 8 ) & 0xFF ); + buf[5] = ( uint8_t )( sleepTime & 0xFF ); + WriteCommand( RADIO_SET_RXDUTYCYCLE, buf, 6 ); + OperatingMode = MODE_RX_DC; +} + +void SX126x::SetCad( void ) +{ + WriteCommand( RADIO_SET_CAD, 0, 0 ); + OperatingMode = MODE_CAD; +} + +void SX126x::SetTxContinuousWave( void ) +{ +#ifdef ADV_DEBUG + printf("SetTxContinuousWave "); +#endif + WriteCommand( RADIO_SET_TXCONTINUOUSWAVE, 0, 0 ); +} + +void SX126x::SetTxInfinitePreamble( void ) +{ +#ifdef ADV_DEBUG + printf("SetTxContinuousPreamble "); +#endif + WriteCommand( RADIO_SET_TXCONTINUOUSPREAMBLE, 0, 0 ); +} + +void SX126x::SetStopRxTimerOnPreambleDetect( bool enable ) +{ + WriteCommand( RADIO_SET_STOPRXTIMERONPREAMBLE, ( uint8_t* )&enable, 1 ); +} + +void SX126x::SetLoRaSymbNumTimeout( uint8_t SymbNum ) +{ + WriteCommand( RADIO_SET_LORASYMBTIMEOUT, &SymbNum, 1 ); +} + +void SX126x::SetRegulatorMode( RadioRegulatorMode_t mode ) +{ +#ifdef ADV_DEBUG + printf("SetRegulatorMode "); +#endif + WriteCommand( RADIO_SET_REGULATORMODE, ( uint8_t* )&mode, 1 ); +} + +void SX126x::Calibrate( CalibrationParams_t calibParam ) +{ + WriteCommand( RADIO_CALIBRATE, &calibParam.Value, 1 ); +} + +void SX126x::SetLongPreamble( uint8_t enable ) +{ + WriteCommand( RADIO_SET_LONGPREAMBLE, &enable, 1 ); +} + +void SX126x::SetPaConfig( uint8_t paDutyCycle, uint8_t HpMax, uint8_t deviceSel, uint8_t paLUT ) +{ + uint8_t buf[4]; + +#ifdef ADV_DEBUG + printf("SetPaConfig "); +#endif + + buf[0] = paDutyCycle; + buf[1] = HpMax; + buf[2] = deviceSel; + buf[3] = paLUT; + WriteCommand( RADIO_SET_PACONFIG, buf, 4 ); +} + +void SX126x::SetRxTxFallbackMode( uint8_t fallbackMode ) +{ + WriteCommand( RADIO_SET_TXFALLBACKMODE, &fallbackMode, 1 ); +} + +void SX126x::SetDioIrqParams( uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask ) +{ + uint8_t buf[8]; + +#ifdef ADV_DEBUG + printf("SetDioIrqParams "); +#endif + + buf[0] = ( uint8_t )( ( irqMask >> 8 ) & 0x00FF ); + buf[1] = ( uint8_t )( irqMask & 0x00FF ); + buf[2] = ( uint8_t )( ( dio1Mask >> 8 ) & 0x00FF ); + buf[3] = ( uint8_t )( dio1Mask & 0x00FF ); + buf[4] = ( uint8_t )( ( dio2Mask >> 8 ) & 0x00FF ); + buf[5] = ( uint8_t )( dio2Mask & 0x00FF ); + buf[6] = ( uint8_t )( ( dio3Mask >> 8 ) & 0x00FF ); + buf[7] = ( uint8_t )( dio3Mask & 0x00FF ); + WriteCommand( RADIO_CFG_DIOIRQ, buf, 8 ); +} + +uint16_t SX126x::GetIrqStatus( void ) +{ + uint8_t irqStatus[2]; + + ReadCommand( RADIO_GET_IRQSTATUS, irqStatus, 2 ); + return ( irqStatus[0] << 8 ) | irqStatus[1]; +} + +void SX126x::SetDio2AsRfSwitchCtrl( uint8_t enable ) +{ +#ifdef ADV_DEBUG + printf("SetDio2AsRfSwitchCtrl "); +#endif + WriteCommand( RADIO_SET_RFSWITCHMODE, &enable, 1 ); +} + +void SX126x::SetDio3AsTcxoCtrl( RadioTcxoCtrlVoltage_t tcxoVoltage, uint32_t timeout ) +{ + uint8_t buf[4]; + + buf[0] = tcxoVoltage & 0x08; + buf[1] = ( uint8_t )( ( timeout >> 16 ) & 0xFF ); + buf[2] = ( uint8_t )( ( timeout >> 8 ) & 0xFF ); + buf[3] = ( uint8_t )( timeout & 0xFF ); + + WriteCommand( RADIO_SET_TCXOMODE, buf, 4 ); +} + +void SX126x::SetRfFrequency( uint32_t frequency ) +{ + uint8_t buf[4]; + uint32_t freq = 0; + +#ifdef ADV_DEBUG + printf("SetRfFrequency "); +#endif + + freq = ( uint32_t )( ( double )frequency / ( double )FREQ_STEP ); + buf[0] = ( uint8_t )( ( freq >> 24 ) & 0xFF ); + buf[1] = ( uint8_t )( ( freq >> 16 ) & 0xFF ); + buf[2] = ( uint8_t )( ( freq >> 8 ) & 0xFF ); + buf[3] = ( uint8_t )( freq & 0xFF ); + WriteCommand( RADIO_SET_RFFREQUENCY, buf, 4 ); +} + +void SX126x::SetPacketType( RadioPacketTypes_t packetType ) +{ +#ifdef ADV_DEBUG + printf("SetPacketType "); +#endif + + // Save packet type internally to avoid questioning the radio + this->PacketType = packetType; + + if( packetType == PACKET_TYPE_GFSK ) + { + WriteReg( REG_BIT_SYNC, 0x00 ); + } + + WriteCommand( RADIO_SET_PACKETTYPE, ( uint8_t* )&packetType, 1 ); +} + +RadioPacketTypes_t SX126x::GetPacketType( void ) +{ + return this->PacketType; +} + +void SX126x::SetTxParams( int8_t power, RadioRampTimes_t rampTime ) +{ + uint8_t buf[2]; + DigitalIn OPT( A3 ); + +#ifdef ADV_DEBUG + printf("SetTxParams "); +#endif + + if( GetDeviceType( ) == 1 ) // sx1261 + { + if( power == 15 ) { - WriteRegister( addr, bytes, n ); + SetPaConfig( 0x06, 0x00, 0x01, 0x00 ); } - if( code == 1 ) - { // end of file - //return 2; + else + { + SetPaConfig( 0x04, 0x00, 0x01, 0x00 ); + } + if( power >= 14 ) + { + power = 14; + } + else if( power < -3 ) + { + power = -3; } - if( code == 2 ) - { // begin of file - //return 3; + } + else // sx1262 + { + SetPaConfig( 0x04, 0x07, 0x00, 0x01 ); + if( power > 22 ) + { + power = 22; + } + else if( power < -3 ) + { + power = -3; + } + } + buf[0] = power; + if( OPT == 0 ) + { + if( ( uint8_t )rampTime < RADIO_RAMP_200_US ) + { + buf[1] = RADIO_RAMP_200_US; + } + else + { + buf[1] = ( uint8_t )rampTime; } } else { - return 0; + buf[1] = ( uint8_t )rampTime; + } + WriteCommand( RADIO_SET_TXPARAMS, buf, 2 ); +} + +void SX126x::SetModulationParams( ModulationParams_t *modulationParams ) +{ + uint8_t n; + uint32_t tempVal = 0; + uint8_t buf[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#ifdef ADV_DEBUG + printf("SetModulationParams "); +#endif + + // Check if required configuration corresponds to the stored packet type + // If not, silently update radio packet type + if( this->PacketType != modulationParams->PacketType ) + { + this->SetPacketType( modulationParams->PacketType ); } - return 1; + + switch( modulationParams->PacketType ) + { + case PACKET_TYPE_GFSK: + n = 8; + tempVal = ( uint32_t )( 32 * ( ( double )XTAL_FREQ / ( double )modulationParams->Params.Gfsk.BitRate ) ); + buf[0] = ( tempVal >> 16 ) & 0xFF; + buf[1] = ( tempVal >> 8 ) & 0xFF; + buf[2] = tempVal & 0xFF; + buf[3] = modulationParams->Params.Gfsk.ModulationShaping; + buf[4] = modulationParams->Params.Gfsk.Bandwidth; + tempVal = ( uint32_t )( ( double )modulationParams->Params.Gfsk.Fdev / ( double )FREQ_STEP ); + buf[5] = ( tempVal >> 16 ) & 0xFF; + buf[6] = ( tempVal >> 8 ) & 0xFF; + buf[7] = ( tempVal& 0xFF ); + break; + case PACKET_TYPE_LORA: + n = 4; + switch( modulationParams->Params.LoRa.Bandwidth ) + { + case LORA_BW_500: + modulationParams->Params.LoRa.LowDatarateOptimize = 0x00; + break; + case LORA_BW_250: + if( modulationParams->Params.LoRa.SpreadingFactor == 12 ) + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x00; + } + break; + case LORA_BW_125: + if( modulationParams->Params.LoRa.SpreadingFactor >= 11 ) + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x00; + } + break; + case LORA_BW_062: + if( modulationParams->Params.LoRa.SpreadingFactor >= 10 ) + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x00; + } + break; + case LORA_BW_041: + if( modulationParams->Params.LoRa.SpreadingFactor >= 9 ) + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x01; + } + else + { + modulationParams->Params.LoRa.LowDatarateOptimize = 0x00; + } + break; + case LORA_BW_031: + case LORA_BW_020: + case LORA_BW_015: + case LORA_BW_010: + case LORA_BW_007: + modulationParams->Params.LoRa.LowDatarateOptimize = 0x01; + break; + default: + break; + } + buf[0] = modulationParams->Params.LoRa.SpreadingFactor; + buf[1] = modulationParams->Params.LoRa.Bandwidth; + buf[2] = modulationParams->Params.LoRa.CodingRate; + buf[3] = modulationParams->Params.LoRa.LowDatarateOptimize; + break; + default: + case PACKET_TYPE_NONE: + return; + } + WriteCommand( RADIO_SET_MODULATIONPARAMS, buf, n ); } -int8_t SX126x::GetHexFileLineFields( char* line, uint8_t *bytes, uint16_t *addr, uint16_t *num, uint8_t *code ) +void SX126x::SetPacketParams( PacketParams_t *packetParams ) { - uint16_t sum, len, cksum; - char *ptr; + uint8_t n; + uint8_t crcVal = 0; + uint8_t buf[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *num = 0; - if( line[0] != ':' ) - { - return 0; - } - if( strlen( line ) < 11 ) - { - return 0; - } - ptr = line + 1; - if( !sscanf( ptr, "%02hx", &len ) ) - { - return 0; - } - ptr += 2; - if( strlen( line ) < ( 11 + ( len * 2 ) ) ) - { - return 0; - } - if( !sscanf( ptr, "%04hx", addr ) ) +#ifdef ADV_DEBUG + printf("SetPacketParams "); +#endif + + // Check if required configuration corresponds to the stored packet type + // If not, silently update radio packet type + if( this->PacketType != packetParams->PacketType ) { - return 0; - } - ptr += 4; - if( !sscanf( ptr, "%02hhx", code ) ) - { - return 0; - } - ptr += 2; - sum = ( len & 255 ) + ( ( *addr >> 8 ) & 255 ) + ( *addr & 255 ) + ( ( *code >> 8 ) & 255 ) + ( *code & 255 ); - while( *num != len ) - { - if( !sscanf( ptr, "%02hhx", &bytes[*num] ) ) - { - return 0; - } - ptr += 2; - sum += bytes[*num] & 255; - ( *num )++; - if( *num >= 256 ) - { - return 0; - } - } - if( !sscanf( ptr, "%02hx", &cksum ) ) - { - return 0; - } - if( ( ( sum & 255 ) + ( cksum & 255 ) ) & 255 ) - { - return 0; // checksum error + this->SetPacketType( packetParams->PacketType ); } - return 1; + switch( packetParams->PacketType ) + { + case PACKET_TYPE_GFSK: + if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_IBM ) + { + SetCrcSeed( CRC_IBM_SEED ); + SetCrcPolynomial( CRC_POLYNOMIAL_IBM ); + crcVal = RADIO_CRC_2_BYTES; + } + else if( packetParams->Params.Gfsk.CrcLength == RADIO_CRC_2_BYTES_CCIT ) + { + SetCrcSeed( CRC_CCITT_SEED ); + SetCrcPolynomial( CRC_POLYNOMIAL_CCITT ); + crcVal = RADIO_CRC_2_BYTES_INV; + } + else + { + crcVal = packetParams->Params.Gfsk.CrcLength; + } + n = 9; + // convert preamble length from byte to bit + packetParams->Params.Gfsk.PreambleLength = packetParams->Params.Gfsk.PreambleLength << 3; + + buf[0] = ( packetParams->Params.Gfsk.PreambleLength >> 8 ) & 0xFF; + buf[1] = packetParams->Params.Gfsk.PreambleLength; + buf[2] = packetParams->Params.Gfsk.PreambleMinDetect; + buf[3] = ( packetParams->Params.Gfsk.SyncWordLength << 3 ); // convert from byte to bit + buf[4] = packetParams->Params.Gfsk.AddrComp; + buf[5] = packetParams->Params.Gfsk.HeaderType; + buf[6] = packetParams->Params.Gfsk.PayloadLength; + buf[7] = crcVal; + buf[8] = packetParams->Params.Gfsk.DcFree; + break; + case PACKET_TYPE_LORA: + n = 6; + buf[0] = ( packetParams->Params.LoRa.PreambleLength >> 8 ) & 0xFF; + buf[1] = packetParams->Params.LoRa.PreambleLength; + buf[2] = packetParams->Params.LoRa.HeaderType; + buf[3] = packetParams->Params.LoRa.PayloadLength; + buf[4] = packetParams->Params.LoRa.CrcMode; + buf[5] = packetParams->Params.LoRa.InvertIQ; + break; + default: + case PACKET_TYPE_NONE: + return; + } + WriteCommand( RADIO_SET_PACKETPARAMS, buf, n ); +} + +void SX126x::SetCadParams( RadioLoRaCadSymbols_t cadSymbolNum, uint8_t cadDetPeak, uint8_t cadDetMin, RadioCadExitModes_t cadExitMode, uint32_t cadTimeout ) +{ + uint8_t buf[7]; + + buf[0] = ( uint8_t )cadSymbolNum; + buf[1] = cadDetPeak; + buf[2] = cadDetMin; + buf[3] = ( uint8_t )cadExitMode; + buf[4] = ( uint8_t )( ( cadTimeout >> 16 ) & 0xFF ); + buf[5] = ( uint8_t )( ( cadTimeout >> 8 ) & 0xFF ); + buf[6] = ( uint8_t )( cadTimeout & 0xFF ); + WriteCommand( RADIO_SET_CADPARAMS, buf, 5 ); + OperatingMode = MODE_CAD; +} + +void SX126x::SetBufferBaseAddresses( uint8_t txBaseAddress, uint8_t rxBaseAddress ) +{ + uint8_t buf[2]; + +#ifdef ADV_DEBUG + printf("SetBufferBaseAddresses "); +#endif + + buf[0] = txBaseAddress; + buf[1] = rxBaseAddress; + WriteCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 ); +} + +RadioStatus_t SX126x::GetStatus( void ) +{ + uint8_t stat = 0; + RadioStatus_t status; + + ReadCommand( RADIO_GET_STATUS, ( uint8_t * )&stat, 1 ); + status.Value = stat; + return status; +} + +int8_t SX126x::GetRssiInst( void ) +{ + int8_t rssi; + + ReadCommand( RADIO_GET_RSSIINST, ( uint8_t* )&rssi, 1 ); + return( -( rssi / 2 ) ); +} + +void SX126x::GetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPointer ) +{ + uint8_t status[2]; + + ReadCommand( RADIO_GET_RXBUFFERSTATUS, status, 2 ); + + // In case of LORA fixed header, the payloadLength is obtained by reading + // the register REG_LR_PAYLOADLENGTH + if( ( this->GetPacketType( ) == PACKET_TYPE_LORA ) && ( ReadReg( REG_LR_PACKETPARAMS ) >> 7 == 1 ) ) + { + *payloadLength = ReadReg( REG_LR_PAYLOADLENGTH ); + } + else + { + *payloadLength = status[0]; + } + *rxStartBufferPointer = status[1]; +} + +void SX126x::GetPacketStatus( PacketStatus_t *pktStatus ) +{ + uint8_t status[3]; + + ReadCommand( RADIO_GET_PACKETSTATUS, status, 3 ); + + pktStatus->packetType = this -> GetPacketType( ); + switch( pktStatus->packetType ) + { + case PACKET_TYPE_GFSK: + pktStatus->Params.Gfsk.RxStatus = status[0]; + pktStatus->Params.Gfsk.RssiSync = -status[1] / 2; + pktStatus->Params.Gfsk.RssiAvg = -status[2] / 2; + pktStatus->Params.Gfsk.FreqError = 0; + break; + + case PACKET_TYPE_LORA: + pktStatus->Params.LoRa.RssiPkt = -status[0] / 2; + ( status[1] < 128 ) ? ( pktStatus->Params.LoRa.SnrPkt = status[1] / 4 ) : ( pktStatus->Params.LoRa.SnrPkt = ( ( status[1] - 256 ) /4 ) ); + pktStatus->Params.LoRa.SignalRssiPkt = -status[2] / 2; + pktStatus->Params.LoRa.FreqError = FrequencyError; + break; + + default: + case PACKET_TYPE_NONE: + // In that specific case, we set everything in the pktStatus to zeros + // and reset the packet type accordingly + memset( pktStatus, 0, sizeof( PacketStatus_t ) ); + pktStatus->packetType = PACKET_TYPE_NONE; + break; + } +} + +RadioError_t SX126x::GetDeviceErrors( void ) +{ + RadioError_t error; + + ReadCommand( RADIO_GET_ERROR, ( uint8_t * )&error, 2 ); + return error; +} + +void SX126x::ClearIrqStatus( uint16_t irq ) +{ + uint8_t buf[2]; +#ifdef ADV_DEBUG + printf("ClearIrqStatus "); +#endif + buf[0] = ( uint8_t )( ( ( uint16_t )irq >> 8 ) & 0x00FF ); + buf[1] = ( uint8_t )( ( uint16_t )irq & 0x00FF ); + WriteCommand( RADIO_CLR_IRQSTATUS, buf, 2 ); +} + +void SX126x::SetPollingMode( void ) +{ + this->PollingMode = true; +} + +void SX126x::SetInterruptMode( void ) +{ + this->PollingMode = false; } void SX126x::OnDioIrq( void ) { - if( onCustomDioIrq != NULL ) + /* + * When polling mode is activated, it is up to the application to call + * ProcessIrqs( ). Otherwise, the driver automatically calls ProcessIrqs( ) + * on radio interrupt. + */ + if( this->PollingMode == true ) + { + this->IrqState = true; + } + else { - onCustomDioIrq(); - return; + this->ProcessIrqs( ); + } +} + +void SX126x::ProcessIrqs( void ) +{ + if( this->PollingMode == true ) + { + if( this->IrqState == true ) + { + __disable_irq( ); + this->IrqState = false; + __enable_irq( ); + } + else + { + return; + } } uint16_t irqRegs = GetIrqStatus( ); - LastIrqs = irqRegs; -// printf("0x%04x\n\r", irqRegs ); ClearIrqStatus( IRQ_RADIO_ALL ); +#ifdef ADV_DEBUG + printf("0x%04x\n\r", irqRegs ); +#endif -#if( SX126x_DEBUG == 1 ) - DigitalOut TEST_PIN_1( D14 ); - DigitalOut TEST_PIN_2( D15 ); - for( int i = 0x8000; i != 0; i >>= 1 ) + if( ( irqRegs & IRQ_HEADER_VALID ) == IRQ_HEADER_VALID ) { - TEST_PIN_2 = 0; - TEST_PIN_1 = ( ( irqRegs & i ) != 0 ) ? 1 : 0; - TEST_PIN_2 = 1; + // LoRa Only + FrequencyError = 0x000000 | ( ( 0x0F & ReadReg( 0x076A ) ) << 16 ); + FrequencyError = FrequencyError | ( ReadReg( 0x076B ) << 8 ); + FrequencyError = FrequencyError | ( ReadReg( 0x076c ) ); } - TEST_PIN_1 = 0; - TEST_PIN_2 = 0; -#endif + + if( ( irqRegs & IRQ_SYNCWORD_VALID ) == IRQ_SYNCWORD_VALID ) + { + // GFSK Only + FrequencyError = 0x000000 | ( ( 0x0F & ReadReg( 0x06B0 ) ) << 8 ); + FrequencyError = FrequencyError | ( ReadReg( 0x06B1 ) ); + } if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE ) { @@ -652,19 +879,27 @@ } } + if( ( irqRegs & IRQ_CAD_DONE ) == IRQ_CAD_DONE ) + { + if( cadDone != NULL ) + { + cadDone( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ); + } + } + if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ) { - if( ( rxTxTimeout != NULL ) && ( OperatingMode == MODE_TX ) ) + if( ( txTimeout != NULL ) && ( OperatingMode == MODE_TX ) ) { - rxTxTimeout( IRQ_TX_TIMEOUT ); + txTimeout( ); } - else if( ( rxTxTimeout != NULL ) && ( OperatingMode == MODE_RX ) ) + else if( ( rxTimeout != NULL ) && ( OperatingMode == MODE_RX ) ) { - rxTxTimeout( IRQ_RX_TIMEOUT ); + rxTimeout( ); } else { - rxTxTimeout( IRQ_XYZ ); + assert_param( FAIL ); } } @@ -697,7 +932,7 @@ } } - //IRQ_HEADER_ERROR = 0x0020, + //IRQ_HEADER_ERROR = 0x0020, if( irqRegs & IRQ_HEADER_ERROR ) { if( rxError != NULL ) @@ -705,19 +940,7 @@ rxError( IRQ_HEADER_ERROR_CODE ); } } - - //IRQ_CAD_DONE = 0x0080, - //IRQ_CAD_ACTIVITY_DETECTED = 0x0100, - if( irqRegs & IRQ_CAD_DONE ) - { - bool detected = ( ( irqRegs & IRQ_CAD_ACTIVITY_DETECTED ) == IRQ_CAD_ACTIVITY_DETECTED ); - - if( cadDone != NULL ) - { - cadDone( detected ); - } - - }*/ +*/ }