mongoose/examples/nRF52/bleconfig.c

435 lines
12 KiB
C
Raw Normal View History

/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
/* clang-format off */
#include <stdbool.h>
#include <stdint.h>
#include "boards.h"
#include "sdk_config.h"
#include "app_timer_appsh.h"
#include "app_scheduler.h"
#include "app_button.h"
#include "nordic_common.h"
#include "softdevice_handler_appsh.h"
#include "ble_advdata.h"
#include "ble_srv_common.h"
#include "ble_ipsp.h"
#include "ble_6lowpan.h"
#include "mem_manager.h"
#include "app_trace.h"
#include "lwip/init.h"
#include "lwip/inet6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
/*lint -save -e607 */
#include "lwip/tcp.h"
/*lint -restore */
#include "lwip/timers.h"
#include "nrf_platform_port.h"
#include "app_util_platform.h"
#include "iot_timer.h"
#include "ipv6_medium.h"
#include "SEGGER_RTT.h"
#include "myboard.h"
#include "app_cfg.h"
#define SCHED_MAX_EVENT_DATA_SIZE 128 /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 12 /**< Maximum number of events in the scheduler queue. */
#if COMMISSIONING_ENABLED
#define ERASE_BUTTON_PIN_NO BSP_BUTTON_3 /**< Button used to erase commissioning settings. */
#endif // COMMISSIONING_ENABLED
#define APP_TIMER_OP_QUEUE_SIZE 5
#define LWIP_SYS_TICK_MS 100 /**< Interval for timer used as trigger to send. */
#define LED_BLINK_INTERVAL_MS 300 /**< LED blinking interval. */
#define MAX_LENGTH_FILENAME 128 /**< Max length of filename to copy for the debug error handler. */
#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. */
#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. */
#define TCP_SERVER_PORT 9000 /**< TCP server listen port number. */
#define TCP_DATA_SIZE 8 /**< UDP Data size sent on remote. */
typedef enum
{
TCP_STATE_IDLE,
TCP_STATE_REQUEST_CONNECTION,
TCP_STATE_CONNECTED,
TCP_STATE_DATA_TX_IN_PROGRESS,
TCP_STATE_DISCONNECTED
}tcp_state_t;
APP_TIMER_DEF(m_iot_timer_tick_src_id); /**< System Timer used to service CoAP and LWIP periodically. */
eui64_t eui64_local_iid; /**< Local EUI64 value that is used as the IID for*/
static ipv6_medium_instance_t m_ipv6_medium;
static struct tcp_pcb * mp_tcp_port; /**< TCP Port to listen on. */
static tcp_state_t m_tcp_state; /**< TCP State information. */
#if COMMISSIONING_ENABLED
static bool m_power_off_on_failure = false;
static bool m_identity_mode_active;
#endif // COMMISSIONING_ENABLED
/**@brief Function to handle interface up event. */
void nrf_driver_interface_up(void)
{
#if COMMISSIONING_ENABLED
commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_STOP_RESET);
#endif // COMMISSIONING_ENABLED
APPL_LOG ("[APPL]: IPv6 interface up.\r\n");
sys_check_timeouts();
m_tcp_state = TCP_STATE_REQUEST_CONNECTION;
LEDS_OFF(LED_ONE);
LEDS_ON(LED_TWO);
}
/**@brief Function to handle interface down event. */
void nrf_driver_interface_down(void)
{
#if COMMISSIONING_ENABLED
commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_START);
#endif // COMMISSIONING_ENABLED
APPL_LOG ("[APPL]: IPv6 interface down.\r\n");
LEDS_OFF((DISPLAY_LED_0 | DISPLAY_LED_1 | DISPLAY_LED_2 | DISPLAY_LED_3));
LEDS_ON(LED_ONE);
m_tcp_state = TCP_STATE_DISCONNECTED;
}
/**@brief Timer callback used for periodic servicing of LwIP protocol timers.
*
* @details Timer callback used for periodic servicing of LwIP protocol timers.
*
* @param[in] p_context Pointer used for passing context. No context used in this application.
*/
static void system_timer_callback(iot_timer_time_in_ms_t wall_clock_value)
{
UNUSED_VARIABLE(wall_clock_value);
sys_check_timeouts();
}
/**@brief Function for starting connectable mode.
*/
static void connectable_mode_enter(void)
{
uint32_t err_code = ipv6_medium_connectable_mode_enter(m_ipv6_medium.ipv6_medium_instance_id);
APP_ERROR_CHECK(err_code);
APPL_LOG("[APPL]: Physical layer in connectable mode.\r\n");
LEDS_OFF(LED_TWO);
LEDS_ON(LED_ONE);
}
/**@brief Function for updating the wall clock of the IoT Timer module.
*/
static void iot_timer_tick_callback(void * p_context)
{
UNUSED_VARIABLE(p_context);
uint32_t err_code = iot_timer_update();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for the LEDs initialization.
*
* @details Initializes all LEDs used by this application.
*/
static void leds_init(void)
{
// Configure application LED pins.
LEDS_CONFIGURE(ALL_APP_LED);
// Turn off all LED on initialization.
LEDS_OFF(ALL_APP_LED);
}
#if COMMISSIONING_ENABLED
/**@brief Timer callback used for controlling board LEDs to represent application state.
*
*/
static void blink_timeout_handler(iot_timer_time_in_ms_t wall_clock_value)
{
UNUSED_PARAMETER(wall_clock_value);
static bool id_mode_previously_enabled;
if ((id_mode_previously_enabled == false) && (m_identity_mode_active == true))
{
LEDS_OFF(LED_THREE | LED_FOUR);
}
if ((id_mode_previously_enabled == true) && (m_identity_mode_active == true))
{
LEDS_INVERT(LED_THREE | LED_FOUR);
}
if ((id_mode_previously_enabled == true) && (m_identity_mode_active == false))
{
LEDS_OFF(LED_THREE | LED_FOUR);
}
id_mode_previously_enabled = m_identity_mode_active;
}
#endif // COMMISSIONING_ENABLED
/**@brief Function for the Timer initialization.
*
* @details Initializes the timer module. This creates and starts application timers.
*/
static void timers_init(void)
{
uint32_t err_code;
// Initialize timer module.
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
// Create a sys timer.
err_code = app_timer_create(&m_iot_timer_tick_src_id,
APP_TIMER_MODE_REPEATED,
iot_timer_tick_callback);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing the IoT Timer. */
static void iot_timer_init(void)
{
uint32_t err_code;
static const iot_timer_client_t list_of_clients[] =
{
{system_timer_callback, LWIP_SYS_TICK_MS},
#if COMMISSIONING_ENABLED
{blink_timeout_handler, LED_BLINK_INTERVAL_MS},
{commissioning_time_tick, SEC_TO_MILLISEC(COMMISSIONING_TICK_INTERVAL_SEC)}
#endif // COMMISSIONING_ENABLED
};
// The list of IoT Timer clients is declared as a constant.
static const iot_timer_clients_list_t iot_timer_clients =
{
(sizeof(list_of_clients) / sizeof(iot_timer_client_t)),
&(list_of_clients[0]),
};
// Passing the list of clients to the IoT Timer module.
err_code = iot_timer_client_list_set(&iot_timer_clients);
APP_ERROR_CHECK(err_code);
// Starting the app timer instance that is the tick source for the IoT Timer.
err_code = app_timer_start(m_iot_timer_tick_src_id, \
APP_TIMER_TICKS(IOT_TIMER_RESOLUTION_IN_MS, APP_TIMER_PRESCALER), \
NULL);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for initializing IP stack.
*
* @details Initialize the IP Stack and its driver.
*/
static void ip_stack_init(void)
{
uint32_t err_code;
err_code = ipv6_medium_eui64_get(m_ipv6_medium.ipv6_medium_instance_id, \
&eui64_local_iid);
APP_ERROR_CHECK(err_code);
err_code = nrf_mem_init();
APP_ERROR_CHECK(err_code);
//Initialize LwIP stack.
lwip_init();
//Initialize LwIP stack driver.
err_code = nrf_driver_init();
APP_ERROR_CHECK(err_code);
}
#if COMMISSIONING_ENABLED
/**@brief Function for handling button events.
*
* @param[in] pin_no The pin number of the button pressed.
* @param[in] button_action The action performed on button.
*/
static void button_event_handler(uint8_t pin_no, uint8_t button_action)
{
if ((button_action == APP_BUTTON_PUSH) && (pin_no == ERASE_BUTTON_PIN_NO))
{
APPL_LOG("[APPL]: Erasing all commissioning settings from persistent storage... \r\n");
commissioning_settings_clear();
return;
}
return;
}
/**@brief Function for the Button initialization.
*
* @details Initializes all Buttons used by this application.
*/
static void buttons_init(void)
{
uint32_t err_code;
static app_button_cfg_t buttons[] =
{
#if COMMISSIONING_ENABLED
{ERASE_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler}
#endif // COMMISSIONING_ENABLED
};
#define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50, APP_TIMER_PRESCALER)
err_code = app_button_init(buttons, \
sizeof(buttons) / sizeof(buttons[0]), \
BUTTON_DETECTION_DELAY);
APP_ERROR_CHECK(err_code);
err_code = app_button_enable();
APP_ERROR_CHECK(err_code);
}
#endif // COMMISSIONING_ENABLED
/**@brief Function for the Event Scheduler initialization.
*/
static void scheduler_init(void)
{
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
static void on_ipv6_medium_evt(ipv6_medium_evt_t * p_ipv6_medium_evt)
{
switch (p_ipv6_medium_evt->ipv6_medium_evt_id)
{
case IPV6_MEDIUM_EVT_CONN_UP:
{
APPL_LOG("[APPL]: Physical layer: connected.\r\n");
LEDS_OFF(LED_ONE);
LEDS_ON(LED_TWO);
break;
}
case IPV6_MEDIUM_EVT_CONN_DOWN:
{
APPL_LOG("[APPL]: Physical layer: disconnected.\r\n");
connectable_mode_enter();
break;
}
default:
{
break;
}
}
}
static void on_ipv6_medium_error(ipv6_medium_error_t * p_ipv6_medium_error)
{
// Do something.
}
#if COMMISSIONING_ENABLED
void commissioning_id_mode_cb(mode_control_cmd_t control_command)
{
switch (control_command)
{
case CMD_IDENTITY_MODE_ENTER:
{
LEDS_OFF(LED_THREE | LED_FOUR);
m_identity_mode_active = true;
break;
}
case CMD_IDENTITY_MODE_EXIT:
{
m_identity_mode_active = false;
LEDS_OFF((LED_THREE | LED_FOUR));
break;
}
default:
{
break;
}
}
}
void commissioning_power_off_cb(bool power_off_on_failure)
{
m_power_off_on_failure = power_off_on_failure;
APPL_LOG("[APPL]: Commissioning: do power_off on failure: %s.\r\n", \
m_power_off_on_failure ? "true" : "false");
}
#endif // COMMISSIONING_ENABLED
void bleconfig_init(void) {
uint32_t err_code;
//Initialize.
app_trace_init();
leds_init();
timers_init();
iot_timer_init();
#if COMMISSIONING_ENABLED
err_code = pstorage_init();
APP_ERROR_CHECK(err_code);
buttons_init();
#endif // COMMISSIONING_ENABLED
static ipv6_medium_init_params_t ipv6_medium_init_params;
memset(&ipv6_medium_init_params, 0x00, sizeof(ipv6_medium_init_params));
ipv6_medium_init_params.ipv6_medium_evt_handler = on_ipv6_medium_evt;
ipv6_medium_init_params.ipv6_medium_error_handler = on_ipv6_medium_error;
ipv6_medium_init_params.use_scheduler = true;
#if COMMISSIONING_ENABLED
ipv6_medium_init_params.commissioning_id_mode_cb = commissioning_id_mode_cb;
ipv6_medium_init_params.commissioning_power_off_cb = commissioning_power_off_cb;
#endif // COMMISSIONING_ENABLED
err_code = ipv6_medium_init(&ipv6_medium_init_params, \
IPV6_MEDIUM_ID_BLE, \
&m_ipv6_medium);
APP_ERROR_CHECK(err_code);
eui48_t ipv6_medium_eui48;
err_code = ipv6_medium_eui48_get(m_ipv6_medium.ipv6_medium_instance_id, \
&ipv6_medium_eui48);
ipv6_medium_eui48.identifier[EUI_48_SIZE - 1] = 0x00;
err_code = ipv6_medium_eui48_set(m_ipv6_medium.ipv6_medium_instance_id, \
&ipv6_medium_eui48);
APP_ERROR_CHECK(err_code);
ip_stack_init();
scheduler_init();
//Start execution.
connectable_mode_enter();
APPL_LOG(0, "BLE init done\n");
}
void bleconfig_poll(void) {
//Execute event schedule.
app_sched_execute();
}