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