Statistics
| Branch: | Tag: | Revision:

mongoose / examples / nRF51 / http / bleconfig.c @ eaef5bd1

History | View | Annotate | Download (18.1 KB)

1
/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
2
 *
3
 * The information contained herein is property of Nordic Semiconductor ASA.
4
 * Terms and conditions of usage are described in detail in NORDIC
5
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
6
 *
7
 * Licensees are granted free, non-transferable use of the information. NO
8
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
9
 * the file.
10
 *
11
 */
12

    
13
/* clang-format off */
14

    
15
/** @file
16
 *
17
 * @defgroup iot_sdk_tcp_server main.c
18
 * @{
19
 * @ingroup iot_sdk_app_lwip
20
 * @brief This file contains the source code for LwIP TCP Server sample application.
21
 *
22
 */
23

    
24
#include <stdbool.h>
25
#include <stdint.h>
26
#include "boards.h"
27
#include "app_timer_appsh.h"
28
#include "app_scheduler.h"
29
#include "app_button.h"
30
#include "nordic_common.h"
31
#include "softdevice_handler_appsh.h"
32
#include "ble_advdata.h"
33
#include "ble_srv_common.h"
34
#include "ble_ipsp.h"
35
#include "ble_6lowpan.h"
36
#include "mem_manager.h"
37
#include "app_trace.h"
38

    
39
/*
40
 * arm-none-eabi-gcc has BYTE_ORDER already defined, so in order to avoid
41
 * warnings in lwip, we have to undefine it
42
 *
43
 * TODO: Check if in the future versions of nRF5 SDK that changes.
44
 *       Current version of nRF51 SDK: 0.8.0
45
 *                          nRF5 SDK:  0.9.0
46
 */
47
#undef BYTE_ORDER
48
#include "lwip/init.h"
49
#include "lwip/inet6.h"
50
#include "lwip/ip6.h"
51
#include "lwip/ip6_addr.h"
52
#include "lwip/netif.h"
53
/*lint -save -e607 */
54
#include "lwip/tcp.h"
55
/*lint -restore */
56
#include "lwip/timers.h"
57
#include "nrf_platform_port.h"
58
#include "app_util_platform.h"
59

    
60
#define DEVICE_NAME                         "LwIPTCPServer"                                         /**< Device name used in BLE undirected advertisement. */
61

    
62
#define APP_TIMER_PRESCALER                 NRF51_DRIVER_TIMER_PRESCALER                            /**< Value of the RTC1 PRESCALER register. */
63
#define APP_TIMER_MAX_TIMERS                1                                                       /**< Maximum number of simultaneously created timers. */
64
#define APP_TIMER_OP_QUEUE_SIZE             1
65
#define LWIP_SYS_TIMER_INTERVAL             APP_TIMER_TICKS(250, APP_TIMER_PRESCALER)               /**< Interval for timer used as trigger to send. */
66

    
67
#define SCHED_MAX_EVENT_DATA_SIZE           128                                                     /**< Maximum size of scheduler events. */
68
#define SCHED_QUEUE_SIZE                    12                                                      /**< Maximum number of events in the scheduler queue. */
69

    
70
#define ADVERTISING_LED                     BSP_LED_0_MASK                                          /**< Is on when device is advertising. */
71
#define CONNECTED_LED                       BSP_LED_1_MASK                                          /**< Is on when device is connected. */
72
#define TCP_CONNECTED_LED                   BSP_LED_2_MASK                                          /**< Is on when device is connected. */
73
#define DISPLAY_LED_0                       BSP_LED_0_MASK                                          /**< LED used for displaying mod 4 of data payload received on UDP port. */
74
#define DISPLAY_LED_1                       BSP_LED_1_MASK                                          /**< LED used for displaying mod 4 of data payload received on UDP port. */
75
#define DISPLAY_LED_2                       BSP_LED_2_MASK                                          /**< LED used for displaying mod 4 of data payload received on UDP port. */
76
#define DISPLAY_LED_3                       BSP_LED_3_MASK                                          /**< LED used for displaying mod 4 of data payload received on UDP port. */
77
#define ALL_APP_LED                        (BSP_LED_0_MASK | BSP_LED_1_MASK | \
78
    BSP_LED_2_MASK | BSP_LED_3_MASK)                        /**< Define used for simultaneous operation of all application LEDs. */
79

    
80
#define APP_ADV_TIMEOUT                     0                                                       /**< Time for which the device must be advertising in non-connectable mode (in seconds). 0 disables timeout. */
81
#define APP_ADV_ADV_INTERVAL                MSEC_TO_UNITS(100, UNIT_0_625_MS)                       /**< The advertising interval. This value can vary between 100ms to 10.24s). */
82

    
83
#define DEAD_BEEF                           0xDEADBEEF                                              /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
84

    
85
#define APPL_LOG                            app_trace_log                                           /**< Macro for logging application messages on UART, in case ENABLE_DEBUG_LOG_SUPPORT is not defined, no logging occurs. */
86
#define APPL_DUMP                           app_trace_dump                                          /**< Macro for dumping application data on UART, in case ENABLE_DEBUG_LOG_SUPPORT is not defined, no logging occurs. */
87

    
88
#define TCP_SERVER_PORT                     9000                                                    /**< TCP server listen port number. */
89
#define TCP_DATA_SIZE                       8                                                       /**< UDP Data size sent on remote. */
90

    
91
typedef enum
92
{
93
  TCP_STATE_IDLE,
94
  TCP_STATE_REQUEST_CONNECTION,
95
  TCP_STATE_CONNECTED,
96
  TCP_STATE_DATA_TX_IN_PROGRESS,
97
  TCP_STATE_DISCONNECTED
98
}tcp_state_t;
99

    
100
eui64_t                                     eui64_local_iid;                                        /**< Local EUI64 value that is used as the IID for*/
101
static ble_gap_adv_params_t                 m_adv_params;                                           /**< Parameters to be passed to the stack when starting advertising. */
102
static app_timer_id_t                       m_sys_timer_id;                                         /**< System Timer used to service LwIP timers periodically. */
103
static struct tcp_pcb                     * mp_tcp_port;                                            /**< TCP Port to listen on. */
104
static tcp_state_t                          m_tcp_state;                                            /**< TCP State information. */
105

    
106

    
107

    
108

    
109
/**@brief Function for error handling, which is called when an error has occurred.
110
 *
111
 * @warning This handler is an example only and does not fit a final product. You need to analyse
112
 *          how your product is supposed to react in case of error.
113
 *
114
 * @param[in] error_code  Error code supplied to the handler.
115
 * @param[in] line_num    Line number where the handler is called.
116
 * @param[in] p_file_name Pointer to the file name.
117
 */
118
void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
119
{
120
  //Halt the application and notify of error using the LEDs.
121
  APPL_LOG("[** ASSERT **]: Error 0x%08lX, Line %ld, File %s\r\n",error_code, line_num, p_file_name);
122
  LEDS_ON(ALL_APP_LED);
123
  for(;;)
124
  {
125
  }
126

    
127
  // @note: In case on assert, it is desired to only recover and reset, uncomment the line below.
128
  //NVIC_SystemReset();
129
}
130

    
131

    
132
/**@brief Callback function for asserts in the SoftDevice.
133
 *
134
 * @details This function will be called in case of an assert in the SoftDevice.
135
 *
136
 * @warning This handler is an example only and does not fit a final product. You need to analyse
137
 *          how your product is supposed to react in case of Assert.
138
 * @warning On assert from the SoftDevice, the system can only recover on reset.
139
 *
140
 * @param[in]   line_num   Line number of the failing ASSERT call.
141
 * @param[in]   file_name  File name of the failing ASSERT call.
142
 */
143
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
144
{
145
  app_error_handler(DEAD_BEEF, line_num, p_file_name);
146
}
147

    
148

    
149
/**@brief Function for the LEDs initialization.
150
 *
151
 * @details Initializes all LEDs used by this application.
152
 */
153
static void leds_init(void)
154
{
155
  // Configure application LED pins.
156
  LEDS_CONFIGURE(ALL_APP_LED);
157

    
158
  // Turn off all LED on initialization.
159
  LEDS_OFF(ALL_APP_LED);
160
}
161

    
162

    
163
/**@brief Function for initializing the Advertising functionality.
164
 *
165
 * @details Encodes the required advertising data and passes it to the stack.
166
 *          Also builds a structure to be passed to the stack when starting advertising.
167
 */
168
static void advertising_init(void)
169
{
170
  uint32_t                err_code;
171
  ble_advdata_t           advdata;
172
  uint8_t                 flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
173
  ble_gap_conn_sec_mode_t sec_mode;
174
  ble_gap_addr_t          my_addr;
175

    
176
  BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
177

    
178
  err_code = sd_ble_gap_device_name_set(&sec_mode,
179
      (const uint8_t *)DEVICE_NAME,
180
      strlen(DEVICE_NAME));
181
  APP_ERROR_CHECK(err_code);
182

    
183
  err_code = sd_ble_gap_address_get(&my_addr);
184
  APP_ERROR_CHECK(err_code);
185

    
186
  my_addr.addr[5]   = 0x00;
187
  my_addr.addr_type = BLE_GAP_ADDR_TYPE_PUBLIC;
188

    
189
  err_code = sd_ble_gap_address_set(&my_addr);
190
  APP_ERROR_CHECK(err_code);
191

    
192
  IPV6_EUI64_CREATE_FROM_EUI48(eui64_local_iid.identifier,
193
      my_addr.addr,
194
      my_addr.addr_type);
195

    
196
  ble_uuid_t adv_uuids[] =
197
  {
198
    {BLE_UUID_IPSP_SERVICE,         BLE_UUID_TYPE_BLE}
199
  };
200

    
201
  //Build and set advertising data.
202
  memset(&advdata, 0, sizeof(advdata));
203

    
204
  advdata.name_type               = BLE_ADVDATA_FULL_NAME;
205
  advdata.flags                   = flags;
206
  advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
207
  advdata.uuids_complete.p_uuids  = adv_uuids;
208

    
209
  err_code = ble_advdata_set(&advdata, NULL);
210
  APP_ERROR_CHECK(err_code);
211

    
212
  //Initialize advertising parameters (used when starting advertising).
213
  memset(&m_adv_params, 0, sizeof(m_adv_params));
214

    
215
  m_adv_params.type        = BLE_GAP_ADV_TYPE_ADV_IND;
216
  m_adv_params.p_peer_addr = NULL;                             // Undirected advertisement.
217
  m_adv_params.fp          = BLE_GAP_ADV_FP_ANY;
218
  m_adv_params.interval    = APP_ADV_ADV_INTERVAL;
219
  m_adv_params.timeout     = APP_ADV_TIMEOUT;
220
}
221

    
222

    
223
/**@brief Function for starting advertising.
224
*/
225
static void advertising_start(void)
226
{
227
  uint32_t err_code;
228

    
229
  err_code = sd_ble_gap_adv_start(&m_adv_params);
230
  APP_ERROR_CHECK(err_code);
231

    
232
  LEDS_ON(ADVERTISING_LED);
233
}
234

    
235

    
236
/**@brief Function for handling the Application's BLE Stack events.
237
 *
238
 * @param[in]   p_ble_evt   Bluetooth stack event.
239
 */
240
static void on_ble_evt(ble_evt_t * p_ble_evt)
241
{
242
  switch (p_ble_evt->header.evt_id)
243
  {
244
    case BLE_GAP_EVT_CONNECTED:
245
      APPL_LOG ("[APPL]: Connected.\r\n");
246
      break;
247
    case BLE_GAP_EVT_DISCONNECTED:
248
      APPL_LOG ("[APPL]: Disconnected.\r\n");
249
      advertising_start();
250
      break;
251
    default:
252
      break;
253
  }
254
}
255

    
256

    
257
/**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler.
258
 *
259
 * @details This function is called from the BLE Stack event interrupt handler after a BLE stack
260
 *          event has been received.
261
 *
262
 * @param[in]   p_ble_evt   Bluetooth stack event.
263
 */
264
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
265
{
266
  ble_ipsp_evt_handler(p_ble_evt);
267
  on_ble_evt(p_ble_evt);
268
}
269

    
270

    
271
/**@brief Function for initializing the BLE stack.
272
 *
273
 * @details Initializes the SoftDevice and the BLE event interrupt.
274
 */
275
static void ble_stack_init(void)
276
{
277
  uint32_t err_code;
278

    
279
  // Initialize the SoftDevice handler module.
280
  SOFTDEVICE_HANDLER_APPSH_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, true);
281

    
282
  // Register with the SoftDevice handler module for BLE events.
283
  err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
284
  APP_ERROR_CHECK(err_code);
285
}
286

    
287

    
288
/**@brief Function for the Event Scheduler initialization.
289
*/
290
static void scheduler_init(void)
291
{
292
  APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
293
}
294

    
295

    
296
/**@brief Function to TCP port.
297
 *
298
 * @details Function to close the TCP port and reset any information on the port.
299
 */
300
static void tcp_port_close(struct tcp_pcb * p_pcb)
301
{
302
  m_tcp_state = TCP_STATE_REQUEST_CONNECTION;
303

    
304
  //Reset all information set on and/or callback registered for the  port.
305
  tcp_arg(p_pcb, NULL);
306
  tcp_sent(p_pcb, NULL);
307
  tcp_recv(p_pcb, NULL);
308
  tcp_err(p_pcb, NULL);
309
  tcp_poll(p_pcb, NULL, 0);
310

    
311
  UNUSED_VARIABLE(tcp_close(p_pcb));
312

    
313
  LEDS_OFF((DISPLAY_LED_0 | DISPLAY_LED_1 | DISPLAY_LED_2 | DISPLAY_LED_3));
314
  LEDS_ON(CONNECTED_LED);
315
}
316

    
317

    
318
/**@brief TCP Port Write complete callback.
319
 *
320
 * @details Calbback registered to be notified of the write complete event on the TCP port.
321
 *          In case write complete is notified with 'zero' length, port is closed.
322
 *
323
 * @param[in]   p_arg     Receive argument set on the port.
324
 * @param[in]   p_pcb     PCB identifier of the port.
325
 * @param[in]   len       Length of data written successfully.
326
 *
327
 * @retval ERR_OK.
328
 */
329
static err_t tcp_write_complete(void           * p_arg,
330
    struct tcp_pcb * p_pcb,
331
    u16_t            len)
332
{
333
  UNUSED_PARAMETER(p_arg);
334
  UNUSED_PARAMETER(p_pcb);
335

    
336
  if (len != 0)
337
  {
338
    //Write complete, reset the state to connected from transmit pending.
339
    m_tcp_state = TCP_STATE_CONNECTED;
340
  }
341
  else
342
  {
343
    //Something is not right on the port, close the port.
344
    tcp_port_close(mp_tcp_port);
345
  }
346
  return ERR_OK;
347
}
348

    
349

    
350
/**@brief Send test data on the port.
351
 *
352
 * @details Sends TCP data in Request of size 8 in format described in description above.
353
 *
354
 * @param[in]   p_pcb     PCB identifier of the port.
355
 */
356
static void tcp_send_data(struct tcp_pcb * p_pcb, uint32_t sequence_number)
357
{
358
  err_t  err = ERR_OK;
359

    
360
  if (m_tcp_state != TCP_STATE_DATA_TX_IN_PROGRESS)
361
  {
362
    //Register callback to get notification of data reception is complete.
363
    tcp_sent(p_pcb, tcp_write_complete);
364
    uint8_t tcp_data[TCP_DATA_SIZE];
365

    
366
    tcp_data[0] = (uint8_t )((sequence_number >> 24) & 0x000000FF);
367
    tcp_data[1] = (uint8_t )((sequence_number >> 16) & 0x000000FF);
368
    tcp_data[2] = (uint8_t )((sequence_number >> 8)  & 0x000000FF);
369
    tcp_data[3] = (uint8_t )(sequence_number         & 0x000000FF);
370

    
371
    tcp_data[4] = 'P';
372
    tcp_data[5] = 'o';
373
    tcp_data[6] = 'n';
374
    tcp_data[7] = 'g';
375

    
376
    //Enqueue data for transmission.
377
    err = tcp_write(p_pcb, tcp_data, TCP_DATA_SIZE, 1);
378

    
379
    if (err != ERR_OK)
380
    {
381
      APPL_LOG ("[APPL]: Failed to send TCP packet, reason %d\r\n", err);
382
    }
383
    else
384
    {
385
      m_tcp_state = TCP_STATE_DATA_TX_IN_PROGRESS;
386
    }
387
  }
388
  else
389
  {
390
    //Wait for tx to be complete.
391
  }
392
}
393

    
394

    
395
/**@brief Callback registered for receiving data on the TCP Port.
396
 *
397
 * @param[in]   p_arg     Receive argument set on the TCP port.
398
 * @param[in]   p_pcb     TCP PCB on which data is received.
399
 * @param[in]   p_buffer  Buffer with received data.
400
 * @param[in]   err       Event result indicating error associated with the receive,
401
 *                        if any, else ERR_OK.
402
 */
403
err_t tcp_recv_data_handler(void           * p_arg,
404
    struct tcp_pcb * p_pcb,
405
    struct pbuf    * p_buffer,
406
    err_t            err)
407
{
408
  APPL_LOG ("[APPL]: >> TCP Data.\r\n");
409

    
410
  //Check event result before proceeding.
411
  if (err == ERR_OK)
412
  {
413
    uint8_t *p_data = p_buffer->payload;
414

    
415
    if (p_buffer->len == TCP_DATA_SIZE)
416
    {
417
      uint32_t sequence_number = 0;
418

    
419
      sequence_number  = ((p_data[0] << 24) & 0xFF000000);
420
      sequence_number |= ((p_data[1] << 16) & 0x00FF0000);
421
      sequence_number |= ((p_data[2] << 8)  & 0x0000FF00);
422
      sequence_number |= (p_data[3]         & 0x000000FF);
423

    
424
      LEDS_OFF(ALL_APP_LED);
425

    
426
      if (sequence_number & 0x00000001)
427
      {
428
        LEDS_ON(DISPLAY_LED_0);
429
      }
430
      if (sequence_number & 0x00000002)
431
      {
432
        LEDS_ON(DISPLAY_LED_1);
433
      }
434
      if (sequence_number & 0x00000004)
435
      {
436
        LEDS_ON(DISPLAY_LED_2);
437
      }
438
      if (sequence_number & 0x00000008)
439
      {
440
        LEDS_ON(DISPLAY_LED_3);
441
      }
442

    
443
      //Send Response
444
      tcp_send_data(p_pcb, sequence_number);
445
    }
446
    else
447
    {
448
      APPL_LOG ("[APPL]: TCP data received in incorrect format.\r\n");
449
    }
450
    // All is good with the data received, process it.
451
    tcp_recved(p_pcb, p_buffer->tot_len);
452
    UNUSED_VARIABLE(pbuf_free(p_buffer));
453
  }
454
  else
455
  {
456
    //Free the buffer in case its not NULL.
457
    if (p_buffer != NULL)
458
    {
459
      UNUSED_VARIABLE(pbuf_free(p_buffer));
460
    }
461

    
462
    //Something is not right with the port, close the port.
463
    tcp_port_close(mp_tcp_port);
464
  }
465

    
466
  return ERR_OK;
467
}
468

    
469

    
470

    
471

    
472

    
473
/**@brief Function for initializing IP stack.
474
 *
475
 * @details Initialize the IP Stack and its driver.
476
 */
477
static void ip_stack_init(void)
478
{
479
  uint32_t err_code = nrf51_sdk_mem_init();
480
  APP_ERROR_CHECK(err_code);
481

    
482
  //Initialize LwIP stack.
483
  lwip_init();
484

    
485
  //Initialize LwIP stack driver.
486
  err_code = nrf51_driver_init();
487
  APP_ERROR_CHECK(err_code);
488
}
489

    
490

    
491
/**@brief Timer callback used for periodic servicing of LwIP protocol timers.
492
 *
493
 * @details Timer callback used for periodic servicing of LwIP protocol timers.
494
 *
495
 * @param[in]   p_context   Pointer used for passing context. No context used in this application.
496
 */
497
static void system_timer_callback(void * p_context)
498
{
499
  UNUSED_VARIABLE(p_context);
500
  sys_check_timeouts();
501
}
502

    
503

    
504
/**@brief Function for the Timer initialization.
505
 *
506
 * @details Initializes the timer module. This creates and starts application timers.
507
 */
508
static void timers_init(void)
509
{
510
  uint32_t err_code;
511

    
512
  // Initialize timer module.
513
  APP_TIMER_APPSH_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);
514

    
515
  // Create timers.
516
  err_code = app_timer_create(&m_sys_timer_id,
517
      APP_TIMER_MODE_REPEATED,
518
      system_timer_callback);
519
  APP_ERROR_CHECK(err_code);
520
}
521

    
522

    
523
/**@brief Function to handle interface up event. */
524
void nrf51_driver_interface_up(void)
525
{
526
  uint32_t err_code;
527

    
528
  APPL_LOG ("[APPL]: IPv6 interface up.\r\n");
529

    
530
  sys_check_timeouts();
531

    
532
  m_tcp_state = TCP_STATE_REQUEST_CONNECTION;
533

    
534
  err_code = app_timer_start(m_sys_timer_id, LWIP_SYS_TIMER_INTERVAL, NULL);
535
  APP_ERROR_CHECK(err_code);
536

    
537
  LEDS_OFF(ADVERTISING_LED);
538
  LEDS_ON(CONNECTED_LED);
539
}
540

    
541

    
542
/**@brief Function to handle interface down event. */
543
void nrf51_driver_interface_down(void)
544
{
545
  uint32_t err_code;
546

    
547
  APPL_LOG ("[APPL]: IPv6 interface down.\r\n");
548

    
549
  err_code = app_timer_stop(m_sys_timer_id);
550
  APP_ERROR_CHECK(err_code);
551

    
552
  LEDS_OFF((DISPLAY_LED_0 | DISPLAY_LED_1 | DISPLAY_LED_2 | DISPLAY_LED_3));
553
  LEDS_ON(ADVERTISING_LED);
554

    
555
  m_tcp_state = TCP_STATE_DISCONNECTED;
556
}
557

    
558
void bleconfig_init(void) {
559
  //Initialize.
560
  app_trace_init();
561
  leds_init();
562
  timers_init();
563
  ble_stack_init();
564
  advertising_init();
565
  ip_stack_init ();
566
  scheduler_init();
567

    
568
  APPL_LOG ("\r\n");
569
  APPL_LOG ("[APPL]: Init done.\r\n");
570

    
571
  //Start execution.
572
  advertising_start();
573
}
574

    
575
void bleconfig_poll(void) {
576
  //Execute event schedule.
577
  app_sched_execute();
578
}
579