local for mbed5
sx126x.cpp
- Committer:
- GregCr
- Date:
- 2016-09-06
- Revision:
- 0:deaafdfde3bb
- Child:
- 1:35d34672a089
File content as of revision 0:deaafdfde3bb:
/* / _____) _ | | ( (____ _____ ____ _| |_ _____ ____| |__ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| (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 "sx1261.h" #include "sx1261-hal.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 }, \ } /*! * \brief Radio hardware registers initialization */ const RadioRegisters_t RadioRegsInit[] = RADIO_INIT_REGISTERS_VALUE; void SX1261::Init( void ) { Reset( ); IoIrqInit( dioIrq ); Wakeup( ); SetRegistersDefault( ); } void SX1261::SetRegistersDefault( void ) { for( uint8_t i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ ) { WriteRegister( RadioRegsInit[i].Addr, RadioRegsInit[i].Value ); } } uint16_t SX1261::GetFirmwareVersion( void ) { return( ( ( ReadRegister( 0xA8 ) ) << 8 ) | ( ReadRegister( 0xA9 ) ) ); } RadioStatus_t SX1261::GetStatus( void ) { uint8_t stat = 0; RadioStatus_t status; ReadCommand( RADIO_GET_STATUS, ( uint8_t * )&stat, 1 ); status.Value = stat; return( status ); } void SX1261::SetSleep( SleepParams_t sleepConfig ) { WriteCommand( RADIO_SET_SLEEP, &sleepConfig.Value, 1 ); OperatingMode = MODE_SLEEP; } void SX1261::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 SX1261::SetFs( void ) { WriteCommand( RADIO_SET_FS, 0, 0 ); OperatingMode = MODE_FS; } void SX1261::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 SX1261::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 SX1261::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 SX1261::SetCad( void ) { WriteCommand( RADIO_SET_CAD, 0, 0 ); OperatingMode = MODE_CAD; } void SX1261::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 SX1261::SetTxContinuousWave( void ) { WriteCommand( RADIO_SET_TXCONTINUOUSWAVE, 0, 0 ); } void SX1261::SetTxContinuousPreamble( void ) { WriteCommand( RADIO_SET_TXCONTINUOUSPREAMBLE, 0, 0 ); } void SX1261::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 SX1261::GetPacketType( void ) { return this->PacketType; } void SX1261::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 SX1261::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 SX1261::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 SX1261::SetBufferBaseAddresses( uint8_t txBaseAddress, uint8_t rxBaseAddress ) { uint8_t buf[2]; buf[0] = txBaseAddress; buf[1] = rxBaseAddress; WriteCommand( RADIO_SET_BUFFERBASEADDRESS, buf, 2 ); } void SX1261::SetModulationParams( ModulationParams_t *modulationParams ) { uint8_t n; // 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: n = 8; break; case PACKET_TYPE_GMSK: n = 8; break; case PACKET_TYPE_BPSK: n = 5; break; case PACKET_TYPE_LORA: case PACKET_TYPE_RANGING: n = 3; break; case PACKET_TYPE_NONE: return; } WriteCommand( RADIO_SET_MODULATIONPARAMS, modulationParams->Params.Buffer, n ); } void SX1261::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_BPSK: n = 8; break; case PACKET_TYPE_LORA: case PACKET_TYPE_RANGING: n = 5; break; case PACKET_TYPE_NONE: return; } WriteCommand( RADIO_SET_PACKETPARAMS, packetParams->Params.Buffer, n ); } void SX1261::GetRxBufferStatus( uint8_t *payloadLength, uint8_t *rxStartBufferPointer ) { uint8_t status[2]; ReadCommand( RADIO_GET_RXBUFFERSTATUS, status, 2 ); *payloadLength = status[0]; *rxStartBufferPointer = status[1]; } void SX1261::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: case PACKET_TYPE_RANGING: 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_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; } } int8_t SX1261::GetRssiInst( void ) { int8_t rssi; ReadCommand( RADIO_GET_RSSIINST, ( uint8_t* )&rssi, 1 ); return -rssi / 2; } void SX1261::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 SX1261::ResetStats( ) { uint8_t status[6]; memset( status, 0, sizeof( status ) ); WriteCommand( RADIO_RESET_STATS, status, 6 ); } uint8_t SX1261::GetError() { uint8_t error; ReadCommand( RADIO_GET_ERROR, &error, 1 ); return error; } void SX1261::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 SX1261::GetIrqStatus( void ) { uint8_t irqStatus[2]; ReadCommand( RADIO_GET_IRQSTATUS, irqStatus, 2 ); return ( irqStatus[0] << 8 ) | irqStatus[1]; } void SX1261::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 SX1261::Calibrate( CalibrationParams_t calibParam ) { WriteCommand( RADIO_CALIBRATE, &calibParam.Value, 1 ); } void SX1261::SetRegulatorMode( uint8_t mode ) { WriteCommand( RADIO_SET_REGULATORMODE, &mode, 1 ); } void SX1261::SetLongPreamble( uint8_t enable ) { WriteCommand( RADIO_SET_LONGPREAMBLE, &enable, 1 ); } void SX1261::SetPayload( uint8_t *buffer, uint8_t size ) { WriteBuffer( 0x00, buffer, size ); } uint8_t SX1261::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 SX1261::SendPayload( uint8_t *payload, uint8_t size, uint32_t timeout ) { SetPayload( payload, size ); SetTx( timeout ); } uint8_t SX1261::SetSyncWord( uint8_t *syncWord ) { uint8_t syncwordSize = 8; WriteRegister( REG_LR_SYNCWORDBASEADDRESS, syncWord, syncwordSize ); return 0; } void SX1261::SetCrcSeed( uint8_t *seed ) { switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_CRCSEEDBASEADDR, seed, 2 ); break; default: break; } } void SX1261::SetCrcPolynomial( uint8_t *polynomial ) { switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_CRCPOLYBASEADDR, polynomial, 2 ); break; default: break; } } void SX1261::SetWhiteningSeed( uint8_t seed ) { switch( GetPacketType( ) ) { case PACKET_TYPE_GFSK: WriteRegister( REG_LR_WHITSEEDBASEADDR, seed ); break; default: break; } } void SX1261::SetRangingIdLength( RadioRangingIdCheckLen_t length ) { switch( GetPacketType( ) ) { case PACKET_TYPE_RANGING: WriteRegister( REG_LR_RANGINGIDCHECKLENGTH, ( ( ( ( uint8_t )length ) & 0x03 ) << 6 ) | ( ReadRegister( REG_LR_RANGINGIDCHECKLENGTH ) & 0x3F ) ); break; default: break; } } void SX1261::SetDeviceRangingAddress( uint32_t address ) { uint8_t addrArray[] = { ( uint8_t )( ( address >> 24 ) & 0xFF ) , ( uint8_t )( ( address >> 16 ) & 0xFF ), ( uint8_t )( ( address >> 8 ) & 0xFF ), ( uint8_t )( ( address >> 0 ) & 0xFF ) }; WriteRegister( REG_LR_DEVICERANGINGADDR, addrArray, 4 ); } void SX1261::SetRangingRequestAddress( uint32_t address ) { uint8_t addrArray[] = { ( uint8_t )( ( address >> 24 ) & 0xFF ) , ( uint8_t )( ( address >> 16 ) & 0xFF ), ( uint8_t )( ( address >> 8 ) & 0xFF ), ( uint8_t )( ( address >> 0 ) & 0xFF ) }; WriteRegister( REG_LR_REQUESTRANGINGADDR, addrArray, 4 ); } int32_t SX1261::GetRangingResult( RadioRangingResultType_t resultType ) { int32_t val = 0; uint32_t addr = REG_LR_RANGINGRESULTRAWBASEADDR + (uint8_t)resultType; //switch( GetPacketType( ) ) //{ // case PACKET_TYPE_RANGING: val = ( ( ReadRegister( addr ) << 16 ) | ( ReadRegister( addr + 1 ) << 8 ) | ( ReadRegister( addr + 2 ) ) ); if( ( val & 0x800000 ) == 0x800000 ) { val |= 0xFF000000; } // break; // default: // break; //} return val; } void SX1261::SetRangingCalibration( uint16_t cal ) { WriteRegister( REG_LR_RANGINGRERXTXDELAYCAL, ( uint8_t )( ( cal >> 8 ) & 0xFF ) ); WriteRegister( REG_LR_RANGINGRERXTXDELAYCAL + 1, ( uint8_t )( ( cal ) & 0xFF ) ); } int8_t SX1261::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 SX1261::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 SX1261::OnDioIrq( void ) { if(onCustomDioIrq != NULL) { onCustomDioIrq(); return; } uint16_t irqRegs = GetIrqStatus( ); LastIrqs = irqRegs; ClearIrqStatus( IRQ_RADIO_ALL ); #if( SX1261_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 //IRQ_TX_DONE = 0x0001, if( irqRegs & IRQ_TX_DONE ) { if( txDone != NULL ) { txDone( ); } } //IRQ_RX_DONE = 0x0002, if( irqRegs & IRQ_RX_DONE ) { if( rxDone != NULL ) { rxDone( ); } } //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_GFSK_ERROR = 0x0040, //IRQ_LORA_CRC_ERROR = 0x0040, //shared with IRQ_GFSK_ERROR if( irqRegs & IRQ_GFSK_ERROR ) // same as IRQ_LORA_CRC_ERROR { if( rxError != NULL ) { rxError( IRQ_GFSK_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 ); } } //IRQ_RX_TX_TIMEOUT = 0x0200, if( ( irqRegs & IRQ_RX_TX_TIMEOUT ) == IRQ_RX_TX_TIMEOUT ) { if( rxTxTimeout != NULL ) { rxTxTimeout( ); } } //IRQ_RANGING_SLAVE_REQUEST_VALID = 0x0400, if( irqRegs & IRQ_RANGING_SLAVE_REQUEST_VALID) { if( rangingDone != NULL ) { rangingDone( IRQ_RANGING_SLAVE_VALID_CODE ); } } //IRQ_RANGING_SLAVE_REQUEST_DISCARDED = 0x0800, if( irqRegs & IRQ_RANGING_SLAVE_REQUEST_DISCARDED ) { if( rangingDone != NULL ) { rangingDone( IRQ_RANGING_SLAVE_ERROR_CODE ); } } //IRQ_RANGING_SLAVE_RESPONSE_DONE = 0x1000, if( irqRegs & IRQ_RANGING_SLAVE_RESPONSE_DONE ) { if( rangingDone != NULL ) { rangingDone( IRQ_RANGING_SLAVE_RESPONSE_DONE_CODE ); } } //IRQ_RANGING_MASTER_RESULT_VALID = 0x2000, if( irqRegs & IRQ_RANGING_MASTER_RESULT_VALID ) { if( rangingDone != NULL ) { rangingDone( IRQ_RANGING_MASTER_VALID_CODE ); } } //IRQ_RANGING_MASTER_RESULT_TIMEOUT = 0x4000, if( irqRegs & IRQ_RANGING_MASTER_RESULT_TIMEOUT ) { if( rangingDone != NULL ) { rangingDone( IRQ_RANGING_MASTER_TIMEOUT_CODE ); } } }