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