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