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