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