SX1261 and sx1262 common library
Dependents: SX126xDevKit SX1262PingPong SX126X_TXonly SX126X_PingPong_Demo ... more
Fork of SX126xLib by
sx126x.cpp
- Committer:
- GregCr
- Date:
- 2016-10-12
- Revision:
- 3:7e3595a9ebe0
- Parent:
- 2:4ff11ea92fbe
- Child:
- 4:c6ef863d0b07
File content as of revision 3:7e3595a9ebe0:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (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 "mbed.h" #include "sx126x.h" #include "sx126x-hal.h" #include "pram_c005.h" /*! * Radio registers definition * */ typedef struct { uint16_t Addr; //!< The address of the register 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 */ // { Address, RegValue } #define RADIO_INIT_REGISTERS_VALUE \ { \ { 0x0722, 0x53 }, \ { 0x0889, 0x01 }, \ } /*! * \brief Radio hardware registers initialization */ const RadioRegisters_t RadioRegsInit[] = RADIO_INIT_REGISTERS_VALUE; void SX126x::Init( void ) { Reset( ); IoIrqInit( dioIrq ); Wakeup( ); /****************************************************/ SetStandby( STDBY_RC ); WriteRegister( 0x610, 0x10 ); for( uint16_t i = 0; i < PRAM_COUNT; i++ ) { 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 ); } WriteRegister( 0x610, 0x00 ); WriteCommand( RADIO_SET_PRAMSWAPCMD, ( uint8_t[] ) { 2 } , 1 ); // RADIO_SET_PRAMSWAPCMD = 0x8D, /****************************************************/ SetRegistersDefault( ); } void SX126x::SetRegistersDefault( void ) { for( uint8_t i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ ) { WriteRegister( RadioRegsInit[i].Addr, RadioRegsInit[i].Value ); } } uint16_t SX126x::GetFirmwareVersion( void ) { return( ( ( ReadRegister( 0xA8 ) ) << 8 ) | ( ReadRegister( 0xA9 ) ) ); } 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 ); } void SX126x::SetSleep( SleepParams_t sleepConfig ) { WriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 ); OperatingMode = MODE_SLEEP; } void SX126x::SetStandby( RadioStandbyModes_t standbyConfig ) { WriteCommand( RADIO_SET_STANDBY, ( uint8_t* )&standbyConfig, 1 ); if( standbyConfig == STDBY_RC ) { OperatingMode = MODE_STDBY_RC; } else { OperatingMode = MODE_STDBY_XOSC; } } 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 ) { 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 ); } uint8_t SX126x::GetPayload( uint8_t *buffer, uint8_t *size, uint8_t maxSize ) { uint8_t offset; GetRxBufferStatus( size, &offset ); if(*size > maxSize) { return 1; } ReadBuffer( offset, buffer, *size ); return 0; } void SX126x::SendPayload( uint8_t *payload, uint8_t size, uint32_t timeout ) { SetPayload( payload, size ); SetTx( timeout ); } uint8_t SX126x::SetSyncWord( uint8_t *syncWord ) { WriteRegister( REG_LR_SYNCWORDBASEADDRESS, syncWord, 8 ); return 0; } 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; } } 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 ) { switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_WHITSEEDBASEADDR, seed ); break; default: break; } } int8_t SX126x::ParseHexFileLine( char* line ) { uint16_t addr; uint16_t n; uint8_t code; uint8_t bytes[256]; if( GetHexFileLineFields( line, bytes, &addr, &n, &code ) != 0 ) { if( code == 0 ) { WriteRegister( addr, bytes, n ); } if( code == 1 ) { // end of file //return 2; } if( code == 2 ) { // begin of file //return 3; } } else { return 0; } return 1; } int8_t SX126x::GetHexFileLineFields( char* line, uint8_t *bytes, uint16_t *addr, uint16_t *num, uint8_t *code ) { uint16_t sum, len, cksum; char *ptr; *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 ) ) { 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 } return 1; } void SX126x::OnDioIrq( void ) { if( onCustomDioIrq != NULL ) { onCustomDioIrq(); return; } uint16_t irqRegs = GetIrqStatus( ); LastIrqs = irqRegs; // printf("0x%04x\n\r", irqRegs ); ClearIrqStatus( IRQ_RADIO_ALL ); #if( SX126x_DEBUG == 1 ) DigitalOut TEST_PIN_1( D14 ); DigitalOut TEST_PIN_2( D15 ); for( int i = 0x8000; i != 0; i >>= 1 ) { TEST_PIN_2 = 0; TEST_PIN_1 = ( ( irqRegs & i ) != 0 ) ? 1 : 0; TEST_PIN_2 = 1; } TEST_PIN_1 = 0; TEST_PIN_2 = 0; #endif if( ( irqRegs & IRQ_TX_DONE ) == IRQ_TX_DONE ) { if( txDone != NULL ) { txDone( ); } } if( ( irqRegs & IRQ_RX_DONE ) == IRQ_RX_DONE ) { if( ( irqRegs & IRQ_CRC_ERROR ) == IRQ_CRC_ERROR ) { if( rxError != NULL ) { rxError( IRQ_CRC_ERROR_CODE ); } } else { if( rxDone != NULL ) { rxDone( ); } } } if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ) { if( ( rxTxTimeout != NULL ) && ( OperatingMode == MODE_TX ) ) { rxTxTimeout( IRQ_TX_TIMEOUT ); } else if( ( rxTxTimeout != NULL ) && ( OperatingMode == MODE_RX ) ) { rxTxTimeout( IRQ_RX_TIMEOUT ); } else { rxTxTimeout( IRQ_XYZ ); } } /* //IRQ_PREAMBLE_DETECTED = 0x0004, if( irqRegs & IRQ_PREAMBLE_DETECTED ) { if( rxPblSyncWordHeader != NULL ) { rxPblSyncWordHeader( IRQ_PBL_DETECT_CODE); } } //IRQ_SYNCWORD_VALID = 0x0008, if( irqRegs & IRQ_SYNCWORD_VALID ) { if( rxPblSyncWordHeader != NULL ) { rxPblSyncWordHeader( IRQ_SYNCWORD_VALID_CODE ); } } //IRQ_HEADER_VALID = 0x0010, if ( irqRegs & IRQ_HEADER_VALID ) { if( rxPblSyncWordHeader != NULL ) { rxPblSyncWordHeader( IRQ_HEADER_VALID_CODE ); } } //IRQ_HEADER_ERROR = 0x0020, if( irqRegs & IRQ_HEADER_ERROR ) { if( rxError != NULL ) { 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 ); } }*/ }