mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-22 14:48:04 +08:00
440 lines
12 KiB
C
440 lines
12 KiB
C
|
|
||
|
/* 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"
|
||
|
|
||
|
/*
|
||
|
* arm-none-eabi-gcc has BYTE_ORDER already defined, so in order to avoid
|
||
|
* warnings in lwip, we have to undefine it
|
||
|
*
|
||
|
* TODO: Check if in the future versions of nRF5 SDK that changes.
|
||
|
* Current version of nRF51 SDK: 0.8.0
|
||
|
* nRF5 SDK: 0.9.0
|
||
|
*/
|
||
|
#undef BYTE_ORDER
|
||
|
#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"
|
||
|
|
||
|
#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. */
|
||
|
|
||
|
#ifdef 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 tcp_state_t m_tcp_state; /**< TCP State information. */
|
||
|
|
||
|
#ifdef 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)
|
||
|
{
|
||
|
#ifdef 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)
|
||
|
{
|
||
|
#ifdef 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);
|
||
|
}
|
||
|
|
||
|
#ifdef 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},
|
||
|
#ifdef 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);
|
||
|
}
|
||
|
|
||
|
#ifdef 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[] =
|
||
|
{
|
||
|
#ifdef 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.
|
||
|
}
|
||
|
|
||
|
#ifdef 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();
|
||
|
|
||
|
#ifdef 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;
|
||
|
#ifdef 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("BLE init done\n");
|
||
|
}
|
||
|
|
||
|
void bleconfig_poll(void) {
|
||
|
//Execute event schedule.
|
||
|
app_sched_execute();
|
||
|
sys_check_timeouts();
|
||
|
}
|
||
|
|