1 /*!
2  * \file      main.c
3  *
4  * \brief     Ping-Pong 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 <string.h>
24 #include "board.h"
25 #include "gpio.h"
26 #include "delay.h"
27 #include "timer.h"
28 #include "radio.h"
29 
30 #if defined( REGION_AS923 )
31 
32 #define RF_FREQUENCY                                923000000 // Hz
33 
34 #elif defined( REGION_AU915 )
35 
36 #define RF_FREQUENCY                                915000000 // Hz
37 
38 #elif defined( REGION_CN470 )
39 
40 #define RF_FREQUENCY                                470000000 // Hz
41 
42 #elif defined( REGION_CN779 )
43 
44 #define RF_FREQUENCY                                779000000 // Hz
45 
46 #elif defined( REGION_EU433 )
47 
48 #define RF_FREQUENCY                                433000000 // Hz
49 
50 #elif defined( REGION_EU868 )
51 
52 #define RF_FREQUENCY                                868000000 // Hz
53 
54 #elif defined( REGION_KR920 )
55 
56 #define RF_FREQUENCY                                920000000 // Hz
57 
58 #elif defined( REGION_IN865 )
59 
60 #define RF_FREQUENCY                                865000000 // Hz
61 
62 #elif defined( REGION_US915 )
63 
64 #define RF_FREQUENCY                                915000000 // Hz
65 
66 #elif defined( REGION_RU864 )
67 
68 #define RF_FREQUENCY                                864000000 // Hz
69 
70 #else
71     #error "Please define a frequency band in the compiler options."
72 #endif
73 
74 #define TX_OUTPUT_POWER                             14        // dBm
75 
76 #if defined( USE_MODEM_LORA )
77 
78 #define LORA_BANDWIDTH                              0         // [0: 125 kHz,
79                                                               //  1: 250 kHz,
80                                                               //  2: 500 kHz,
81                                                               //  3: Reserved]
82 #define LORA_SPREADING_FACTOR                       7         // [SF7..SF12]
83 #define LORA_CODINGRATE                             1         // [1: 4/5,
84                                                               //  2: 4/6,
85                                                               //  3: 4/7,
86                                                               //  4: 4/8]
87 #define LORA_PREAMBLE_LENGTH                        8         // Same for Tx and Rx
88 #define LORA_SYMBOL_TIMEOUT                         5         // Symbols
89 #define LORA_FIX_LENGTH_PAYLOAD_ON                  false
90 #define LORA_IQ_INVERSION_ON                        false
91 
92 #elif defined( USE_MODEM_FSK )
93 
94 #define FSK_FDEV                                    25000     // Hz
95 #define FSK_DATARATE                                50000     // bps
96 #define FSK_BANDWIDTH                               50000     // Hz
97 #define FSK_AFC_BANDWIDTH                           83333     // Hz
98 #define FSK_PREAMBLE_LENGTH                         5         // Same for Tx and Rx
99 #define FSK_FIX_LENGTH_PAYLOAD_ON                   false
100 
101 #else
102     #error "Please define a modem in the compiler options."
103 #endif
104 
105 typedef enum
106 {
107     LOWPOWER,
108     RX,
109     RX_TIMEOUT,
110     RX_ERROR,
111     TX,
112     TX_TIMEOUT,
113 }States_t;
114 
115 #define RX_TIMEOUT_VALUE                            1000
116 #define BUFFER_SIZE                                 64 // Define the payload size here
117 
118 const uint8_t PingMsg[] = "PING";
119 const uint8_t PongMsg[] = "PONG";
120 
121 uint16_t BufferSize = BUFFER_SIZE;
122 uint8_t Buffer[BUFFER_SIZE];
123 
124 States_t State = LOWPOWER;
125 
126 int8_t RssiValue = 0;
127 int8_t SnrValue = 0;
128 
129 /*!
130  * Radio events function pointer
131  */
132 static RadioEvents_t RadioEvents;
133 
134 /*!
135  * LED GPIO pins objects
136  */
137 extern Gpio_t Led1;
138 extern Gpio_t Led2;
139 
140 /*!
141  * \brief Function to be executed on Radio Tx Done event
142  */
143 void OnTxDone( void );
144 
145 /*!
146  * \brief Function to be executed on Radio Rx Done event
147  */
148 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
149 
150 /*!
151  * \brief Function executed on Radio Tx Timeout event
152  */
153 void OnTxTimeout( void );
154 
155 /*!
156  * \brief Function executed on Radio Rx Timeout event
157  */
158 void OnRxTimeout( void );
159 
160 /*!
161  * \brief Function executed on Radio Rx Error event
162  */
163 void OnRxError( void );
164 
165 /**
166  * Main application entry point.
167  */
main(void)168 int main( void )
169 {
170     bool isMaster = true;
171     uint8_t i;
172 
173     // Target board initialization
174     BoardInitMcu( );
175     BoardInitPeriph( );
176 
177     // Radio initialization
178     RadioEvents.TxDone = OnTxDone;
179     RadioEvents.RxDone = OnRxDone;
180     RadioEvents.TxTimeout = OnTxTimeout;
181     RadioEvents.RxTimeout = OnRxTimeout;
182     RadioEvents.RxError = OnRxError;
183 
184     Radio.Init( &RadioEvents );
185 
186     Radio.SetChannel( RF_FREQUENCY );
187 
188 #if defined( USE_MODEM_LORA )
189 
190     Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
191                                    LORA_SPREADING_FACTOR, LORA_CODINGRATE,
192                                    LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
193                                    true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
194 
195     Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
196                                    LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
197                                    LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
198                                    0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
199 
200     Radio.SetMaxPayloadLength( MODEM_LORA, BUFFER_SIZE );
201 
202 #elif defined( USE_MODEM_FSK )
203 
204     Radio.SetTxConfig( MODEM_FSK, TX_OUTPUT_POWER, FSK_FDEV, 0,
205                                   FSK_DATARATE, 0,
206                                   FSK_PREAMBLE_LENGTH, FSK_FIX_LENGTH_PAYLOAD_ON,
207                                   true, 0, 0, 0, 3000 );
208 
209     Radio.SetRxConfig( MODEM_FSK, FSK_BANDWIDTH, FSK_DATARATE,
210                                   0, FSK_AFC_BANDWIDTH, FSK_PREAMBLE_LENGTH,
211                                   0, FSK_FIX_LENGTH_PAYLOAD_ON, 0, true,
212                                   0, 0,false, true );
213 
214     Radio.SetMaxPayloadLength( MODEM_FSK, BUFFER_SIZE );
215 
216 #else
217     #error "Please define a frequency band in the compiler options."
218 #endif
219 
220     Radio.Rx( RX_TIMEOUT_VALUE );
221 
222     while( 1 )
223     {
224         switch( State )
225         {
226         case RX:
227             if( isMaster == true )
228             {
229                 if( BufferSize > 0 )
230                 {
231                     if( strncmp( ( const char* )Buffer, ( const char* )PongMsg, 4 ) == 0 )
232                     {
233                         // Indicates on a LED that the received frame is a PONG
234                         GpioToggle( &Led1 );
235 
236                         // Send the next PING frame
237                         Buffer[0] = 'P';
238                         Buffer[1] = 'I';
239                         Buffer[2] = 'N';
240                         Buffer[3] = 'G';
241                         // We fill the buffer with numbers for the payload
242                         for( i = 4; i < BufferSize; i++ )
243                         {
244                             Buffer[i] = i - 4;
245                         }
246                         DelayMs( 1 );
247                         Radio.Send( Buffer, BufferSize );
248                     }
249                     else if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
250                     { // A master already exists then become a slave
251                         isMaster = false;
252                         GpioToggle( &Led2 ); // Set LED off
253                         Radio.Rx( RX_TIMEOUT_VALUE );
254                     }
255                     else // valid reception but neither a PING or a PONG message
256                     {    // Set device as master ans start again
257                         isMaster = true;
258                         Radio.Rx( RX_TIMEOUT_VALUE );
259                     }
260                 }
261             }
262             else
263             {
264                 if( BufferSize > 0 )
265                 {
266                     if( strncmp( ( const char* )Buffer, ( const char* )PingMsg, 4 ) == 0 )
267                     {
268                         // Indicates on a LED that the received frame is a PING
269                         GpioToggle( &Led1 );
270 
271                         // Send the reply to the PONG string
272                         Buffer[0] = 'P';
273                         Buffer[1] = 'O';
274                         Buffer[2] = 'N';
275                         Buffer[3] = 'G';
276                         // We fill the buffer with numbers for the payload
277                         for( i = 4; i < BufferSize; i++ )
278                         {
279                             Buffer[i] = i - 4;
280                         }
281                         DelayMs( 1 );
282                         Radio.Send( Buffer, BufferSize );
283                     }
284                     else // valid reception but not a PING as expected
285                     {    // Set device as master and start again
286                         isMaster = true;
287                         Radio.Rx( RX_TIMEOUT_VALUE );
288                     }
289                 }
290             }
291             State = LOWPOWER;
292             break;
293         case TX:
294             // Indicates on a LED that we have sent a PING [Master]
295             // Indicates on a LED that we have sent a PONG [Slave]
296             GpioToggle( &Led2 );
297             Radio.Rx( RX_TIMEOUT_VALUE );
298             State = LOWPOWER;
299             break;
300         case RX_TIMEOUT:
301         case RX_ERROR:
302             if( isMaster == true )
303             {
304                 // Send the next PING frame
305                 Buffer[0] = 'P';
306                 Buffer[1] = 'I';
307                 Buffer[2] = 'N';
308                 Buffer[3] = 'G';
309                 for( i = 4; i < BufferSize; i++ )
310                 {
311                     Buffer[i] = i - 4;
312                 }
313                 DelayMs( 1 );
314                 Radio.Send( Buffer, BufferSize );
315             }
316             else
317             {
318                 Radio.Rx( RX_TIMEOUT_VALUE );
319             }
320             State = LOWPOWER;
321             break;
322         case TX_TIMEOUT:
323             Radio.Rx( RX_TIMEOUT_VALUE );
324             State = LOWPOWER;
325             break;
326         case LOWPOWER:
327         default:
328             // Set low power
329             break;
330         }
331 
332         BoardLowPowerHandler( );
333         // Process Radio IRQ
334         if( Radio.IrqProcess != NULL )
335         {
336             Radio.IrqProcess( );
337         }
338     }
339 }
340 
OnTxDone(void)341 void OnTxDone( void )
342 {
343     Radio.Sleep( );
344     State = TX;
345 }
346 
OnRxDone(uint8_t * payload,uint16_t size,int16_t rssi,int8_t snr)347 void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
348 {
349     Radio.Sleep( );
350     BufferSize = size;
351     memcpy( Buffer, payload, BufferSize );
352     RssiValue = rssi;
353     SnrValue = snr;
354     State = RX;
355 }
356 
OnTxTimeout(void)357 void OnTxTimeout( void )
358 {
359     Radio.Sleep( );
360     State = TX_TIMEOUT;
361 }
362 
OnRxTimeout(void)363 void OnRxTimeout( void )
364 {
365     Radio.Sleep( );
366     State = RX_TIMEOUT;
367 }
368 
OnRxError(void)369 void OnRxError( void )
370 {
371     Radio.Sleep( );
372     State = RX_ERROR;
373 }
374