1 /*!
2  * \file      sx1276-board.c
3  *
4  * \brief     Target board SX1276 driver implementation
5  *
6  * \copyright Revised BSD License, see section \ref LICENSE.
7  *
8  * \code
9  *                ______                              _
10  *               / _____)             _              | |
11  *              ( (____  _____ ____ _| |_ _____  ____| |__
12  *               \____ \| ___ |    (_   _) ___ |/ ___)  _ \
13  *               _____) ) ____| | | || |_| ____( (___| | | |
14  *              (______/|_____)_|_|_| \__)_____)\____)_| |_|
15  *              (C)2013-2017 Semtech
16  *
17  * \endcode
18  *
19  * \author    Miguel Luis ( Semtech )
20  *
21  * \author    Gregory Cristian ( Semtech )
22  */
23 #include <stdlib.h>
24 #include "utilities.h"
25 #include "board-config.h"
26 #include "delay.h"
27 #include "radio.h"
28 #include "sx1276-board.h"
29 
30 /*!
31  * \brief Gets the board PA selection configuration
32  *
33  * \param [IN] power Selects the right PA according to the wanted power.
34  * \retval PaSelect RegPaConfig PaSelect value
35  */
36 static uint8_t SX1276GetPaSelect( int8_t power );
37 
38 /*!
39  * Flag used to set the RF switch control pins in low power mode when the radio is not active.
40  */
41 static bool RadioIsActive = false;
42 
43 /*!
44  * Radio driver structure initialization
45  */
46 const struct Radio_s Radio =
47 {
48     SX1276Init,
49     SX1276GetStatus,
50     SX1276SetModem,
51     SX1276SetChannel,
52     SX1276IsChannelFree,
53     SX1276Random,
54     SX1276SetRxConfig,
55     SX1276SetTxConfig,
56     SX1276CheckRfFrequency,
57     SX1276GetTimeOnAir,
58     SX1276Send,
59     SX1276SetSleep,
60     SX1276SetStby,
61     SX1276SetRx,
62     SX1276StartCad,
63     SX1276SetTxContinuousWave,
64     SX1276ReadRssi,
65     SX1276Write,
66     SX1276Read,
67     SX1276WriteBuffer,
68     SX1276ReadBuffer,
69     SX1276SetMaxPayloadLength,
70     SX1276SetPublicNetwork,
71     SX1276GetWakeupTime,
72     NULL, // void ( *IrqProcess )( void )
73     NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only
74     NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only
75 };
76 
77 /*!
78  * TCXO power control pin
79  */
80 Gpio_t TcxoPower;
81 
82 /*!
83  * Antenna switch GPIO pins objects
84  */
85 Gpio_t AntSwitchRx;
86 Gpio_t AntSwitchTxBoost;
87 Gpio_t AntSwitchTxRfo;
88 
89 /*!
90  * Debug GPIO pins objects
91  */
92 #if defined( USE_RADIO_DEBUG )
93 Gpio_t DbgPinTx;
94 Gpio_t DbgPinRx;
95 #endif
96 
SX1276IoInit(void)97 void SX1276IoInit( void )
98 {
99     GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
100 
101     GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
102     GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
103     GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
104     GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
105     GpioInit( &SX1276.DIO4, RADIO_DIO_4, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
106     GpioInit( &SX1276.DIO5, RADIO_DIO_5, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
107 }
108 
SX1276IoIrqInit(DioIrqHandler ** irqHandlers)109 void SX1276IoIrqInit( DioIrqHandler **irqHandlers )
110 {
111     GpioSetInterrupt( &SX1276.DIO0, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[0] );
112     GpioSetInterrupt( &SX1276.DIO1, IRQ_RISING_FALLING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[1] );
113     GpioSetInterrupt( &SX1276.DIO2, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[2] );
114     GpioSetInterrupt( &SX1276.DIO3, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[3] );
115     GpioSetInterrupt( &SX1276.DIO4, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[4] );
116     GpioSetInterrupt( &SX1276.DIO5, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[5] );
117 }
118 
SX1276IoDeInit(void)119 void SX1276IoDeInit( void )
120 {
121     GpioInit( &SX1276.Spi.Nss, RADIO_NSS, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
122 
123     GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
124     GpioInit( &SX1276.DIO1, RADIO_DIO_1, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
125     GpioInit( &SX1276.DIO2, RADIO_DIO_2, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
126     GpioInit( &SX1276.DIO3, RADIO_DIO_3, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
127     GpioInit( &SX1276.DIO4, RADIO_DIO_4, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
128     GpioInit( &SX1276.DIO5, RADIO_DIO_5, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
129 }
130 
SX1276IoDbgInit(void)131 void SX1276IoDbgInit( void )
132 {
133 #if defined( USE_RADIO_DEBUG )
134     GpioInit( &DbgPinTx, RADIO_DBG_PIN_TX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
135     GpioInit( &DbgPinRx, RADIO_DBG_PIN_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
136 #endif
137 }
138 
SX1276IoTcxoInit(void)139 void SX1276IoTcxoInit( void )
140 {
141     GpioInit( &TcxoPower, RADIO_TCXO_POWER, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
142 }
143 
SX1276SetBoardTcxo(uint8_t state)144 void SX1276SetBoardTcxo( uint8_t state )
145 {
146     if( state == true )
147     {
148         if( GpioRead( &TcxoPower ) == 0 )
149         { // TCXO OFF power it up.
150             // Power ON the TCXO
151             GpioWrite( &TcxoPower, 1 );
152             DelayMs( BOARD_TCXO_WAKEUP_TIME );
153         }
154     }
155     else
156     {
157         // Power OFF the TCXO
158         GpioWrite( &TcxoPower, 0 );
159     }
160 }
161 
SX1276GetBoardTcxoWakeupTime(void)162 uint32_t SX1276GetBoardTcxoWakeupTime( void )
163 {
164     return BOARD_TCXO_WAKEUP_TIME;
165 }
166 
SX1276Reset(void)167 void SX1276Reset( void )
168 {
169     // Enables the TCXO if available on the board design
170     SX1276SetBoardTcxo( true );
171 
172     // Set RESET pin to 0
173     GpioInit( &SX1276.Reset, RADIO_RESET, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
174 
175     // Wait 1 ms
176     DelayMs( 1 );
177 
178     // Configure RESET as input
179     GpioInit( &SX1276.Reset, RADIO_RESET, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 1 );
180 
181     // Wait 6 ms
182     DelayMs( 6 );
183 }
184 
SX1276SetRfTxPower(int8_t power)185 void SX1276SetRfTxPower( int8_t power )
186 {
187     uint8_t paConfig = 0;
188     uint8_t paDac = 0;
189 
190     paConfig = SX1276Read( REG_PACONFIG );
191     paDac = SX1276Read( REG_PADAC );
192 
193     paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | SX1276GetPaSelect( power );
194 
195     if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
196     {
197         if( power > 17 )
198         {
199             paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON;
200         }
201         else
202         {
203             paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF;
204         }
205         if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON )
206         {
207             if( power < 5 )
208             {
209                 power = 5;
210             }
211             if( power > 20 )
212             {
213                 power = 20;
214             }
215             paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F );
216         }
217         else
218         {
219             if( power < 2 )
220             {
221                 power = 2;
222             }
223             if( power > 17 )
224             {
225                 power = 17;
226             }
227             paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F );
228         }
229     }
230     else
231     {
232         if( power > 0 )
233         {
234             if( power > 15 )
235             {
236                 power = 15;
237             }
238             paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 7 << 4 ) | ( power );
239         }
240         else
241         {
242             if( power < -4 )
243             {
244                 power = -4;
245             }
246             paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( 0 << 4 ) | ( power + 4 );
247         }
248     }
249     SX1276Write( REG_PACONFIG, paConfig );
250     SX1276Write( REG_PADAC, paDac );
251 }
252 
SX1276GetPaSelect(int8_t power)253 static uint8_t SX1276GetPaSelect( int8_t power )
254 {
255     if( power > 14 )
256     {
257         return RF_PACONFIG_PASELECT_PABOOST;
258     }
259     else
260     {
261         return RF_PACONFIG_PASELECT_RFO;
262     }
263 }
264 
SX1276SetAntSwLowPower(bool status)265 void SX1276SetAntSwLowPower( bool status )
266 {
267     if( RadioIsActive != status )
268     {
269         RadioIsActive = status;
270 
271         if( status == false )
272         {
273             SX1276AntSwInit( );
274         }
275         else
276         {
277             SX1276AntSwDeInit( );
278         }
279     }
280 }
281 
SX1276AntSwInit(void)282 void SX1276AntSwInit( void )
283 {
284     GpioInit( &AntSwitchRx, RADIO_ANT_SWITCH_RX, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
285     GpioInit( &AntSwitchTxBoost, RADIO_ANT_SWITCH_TX_BOOST, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
286     GpioInit( &AntSwitchTxRfo, RADIO_ANT_SWITCH_TX_RFO, PIN_OUTPUT, PIN_PUSH_PULL, PIN_NO_PULL, 0 );
287 }
288 
SX1276AntSwDeInit(void)289 void SX1276AntSwDeInit( void )
290 {
291     GpioInit( &AntSwitchRx, RADIO_ANT_SWITCH_RX, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
292     GpioInit( &AntSwitchTxBoost, RADIO_ANT_SWITCH_TX_BOOST, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
293     GpioInit( &AntSwitchTxRfo, RADIO_ANT_SWITCH_TX_RFO, PIN_ANALOGIC, PIN_OPEN_DRAIN, PIN_NO_PULL, 0 );
294 }
295 
SX1276SetAntSw(uint8_t opMode)296 void SX1276SetAntSw( uint8_t opMode )
297 {
298     uint8_t paConfig =  SX1276Read( REG_PACONFIG );
299     switch( opMode )
300     {
301     case RFLR_OPMODE_TRANSMITTER:
302         if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST )
303         {
304             GpioWrite( &AntSwitchTxBoost, 1 );
305         }
306         else
307         {
308             GpioWrite( &AntSwitchTxRfo, 1 );
309         }
310         break;
311     case RFLR_OPMODE_RECEIVER:
312     case RFLR_OPMODE_RECEIVER_SINGLE:
313     case RFLR_OPMODE_CAD:
314     default:
315         GpioWrite( &AntSwitchRx, 1 );
316         break;
317     }
318 }
319 
SX1276CheckRfFrequency(uint32_t frequency)320 bool SX1276CheckRfFrequency( uint32_t frequency )
321 {
322     // Implement check. Currently all frequencies are supported
323     return true;
324 }
325 
SX1276GetDio1PinState(void)326 uint32_t SX1276GetDio1PinState( void )
327 {
328     return GpioRead( &SX1276.DIO1 );
329 }
330 
331 #if defined( USE_RADIO_DEBUG )
SX1276DbgPinTxWrite(uint8_t state)332 void SX1276DbgPinTxWrite( uint8_t state )
333 {
334     GpioWrite( &DbgPinTx, state );
335 }
336 
SX1276DbgPinRxWrite(uint8_t state)337 void SX1276DbgPinRxWrite( uint8_t state )
338 {
339     GpioWrite( &DbgPinRx, state );
340 }
341 #endif
342