#include <stdbool.h> | |
#include <stdint.h> | |
#include "boards.h" | |
#include "nrf_log.h" | |
#include "nrf_delay.h" | |
#ifdef SOFTDEVICE_PRESENT | |
#include "nrf_sdh.h" | |
#include "nrf_sdh_ble.h" | |
#include "nrf_sdh_soc.h" | |
#endif | |
#include "nrf_drv_clock.h" | |
#if NRF_CRYPTO_ENABLED | |
#include "nrf_crypto.h" | |
#endif | |
#include "mem_manager.h" | |
#include "app_timer.h" | |
#include "app_button.h" | |
#if NRF_LOG_ENABLED | |
#include "nrf_log_ctrl.h" | |
#include "nrf_log_default_backends.h" | |
#include "nrf_log_backend_uart.h" | |
#endif // NRF_LOG_ENABLED | |
#include <openthread/instance.h> | |
#include <openthread/thread.h> | |
#include <openthread/tasklet.h> | |
#include <openthread/link.h> | |
#include <openthread/dataset.h> | |
#include <openthread/error.h> | |
#include <openthread/icmp6.h> | |
#include <openthread/platform/openthread-system.h> | |
extern "C" { | |
#include <openthread/platform/platform-softdevice.h> | |
} | |
#include <Weave/DeviceLayer/WeaveDeviceLayer.h> | |
#include <Weave/DeviceLayer/ThreadStackManager.h> | |
#include <Weave/DeviceLayer/nRF5/GroupKeyStoreImpl.h> | |
#include <Weave/DeviceLayer/internal/testing/ConfigUnitTest.h> | |
#include <Weave/DeviceLayer/internal/testing/GroupKeyStoreUnitTest.h> | |
#include <Weave/DeviceLayer/internal/testing/SystemClockUnitTest.h> | |
using namespace ::nl; | |
using namespace ::nl::Inet; | |
using namespace ::nl::Weave; | |
using namespace ::nl::Weave::DeviceLayer; | |
// ================================================================================ | |
// Test App Feature Config | |
// ================================================================================ | |
#define TIMER_TEST_ENABLED 1 | |
#define BUTTON_TEST_ENABLED 1 | |
#define TEST_TASK_ENABLED 0 | |
#define RUN_UNIT_TESTS 0 | |
#define WOBLE_ENABLED 1 | |
#define OPENTHREAD_ENABLED 1 | |
#define OPENTHREAD_TEST_NETWORK_ENABLED 1 | |
// ================================================================================ | |
// OpenThread Test Network Information | |
// ================================================================================ | |
#if OPENTHREAD_TEST_NETWORK_ENABLED | |
#define OPENTHREAD_TEST_NETWORK_NAME "WARP" | |
#define OPENTHREAD_TEST_NETWORK_PANID 0x7777 | |
#define OPENTHREAD_TEST_NETWORK_EXTENDED_PANID { 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 } | |
#define OPENTHREAD_TEST_NETWORK_CHANNEL 26 | |
#define OPENTHREAD_TEST_NETWORK_MASTER_KEY { 0xB8, 0x98, 0x3A, 0xED, 0x95, 0x40, 0x64, 0xCC, 0x4B, 0xAC, 0xB3, 0xF6, 0xF1, 0x45, 0xD1, 0x98 } | |
#endif // OPENTHREAD_TEST_NETWORK_ENABLED | |
// ================================================================================ | |
// Logging Support | |
// ================================================================================ | |
#if NRF_LOG_ENABLED | |
#define LOGGER_STACK_SIZE (800) | |
#define LOGGER_PRIORITY 3 | |
static TaskHandle_t sLoggerTaskHandle; | |
static void LoggerTaskMain(void * arg) | |
{ | |
UNUSED_PARAMETER(arg); | |
NRF_LOG_INFO("Logging task running"); | |
while (1) | |
{ | |
NRF_LOG_FLUSH(); | |
// Wait for a signal that more logging output might be pending. | |
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); | |
} | |
} | |
extern "C" void vApplicationIdleHook( void ) | |
{ | |
xTaskNotifyGive(sLoggerTaskHandle); | |
} | |
namespace nl { | |
namespace Weave { | |
namespace DeviceLayer { | |
/** | |
* Called whenever a Weave or LwIP log message is emitted. | |
*/ | |
void OnLogOutput(void) | |
{ | |
xTaskNotifyGive(sLoggerTaskHandle); | |
} | |
} // namespace DeviceLayer | |
} // namespace Weave | |
} // namespace nl | |
#endif //NRF_LOG_ENABLED | |
// ================================================================================ | |
// Test Task | |
// ================================================================================ | |
#if TEST_TASK_ENABLED | |
#define TEST_TASK_STACK_SIZE (800) | |
#define TEST_TASK_PRIORITY 1 | |
static TaskHandle_t sTestTaskHandle; | |
static void TestTaskAlive() | |
{ | |
bsp_board_led_invert(BSP_BOARD_LED_2); | |
} | |
static void TestTaskMain(void * pvParameter) | |
{ | |
NRF_LOG_INFO("Test task running"); | |
bsp_board_led_invert(BSP_BOARD_LED_1); | |
#if RUN_UNIT_TESTS | |
Internal::RunSystemClockUnitTest(); | |
NRF_LOG_INFO("System clock test complete"); | |
// Test the core configuration interface | |
Internal::NRF5Config::RunConfigUnitTest(); | |
NRF_LOG_INFO("NRF5Config test complete"); | |
// Test the group key store | |
{ | |
Internal::GroupKeyStoreImpl groupKeyStore; | |
err = groupKeyStore.Init(); | |
APP_ERROR_CHECK(err); | |
Internal::RunGroupKeyStoreUnitTest<Internal::GroupKeyStoreImpl>(&groupKeyStore); | |
} | |
NRF_LOG_INFO("GroupKeyStore test complete"); | |
NRF_LOG_INFO("Unit tests done"); | |
#endif | |
while (true) | |
{ | |
const TickType_t delay = pdMS_TO_TICKS(1000); | |
vTaskDelay(delay); | |
TestTaskAlive(); | |
} | |
} | |
#endif // TEST_TASK_ENABLED | |
// ================================================================================ | |
// Test Timer | |
// ================================================================================ | |
#if TIMER_TEST_ENABLED | |
#define TIMER_PERIOD_MS 1000 | |
static void TimerEventHandler(void * p_context) | |
{ | |
bsp_board_led_invert(BSP_BOARD_LED_3); | |
} | |
static void InitTimerTest(void) | |
{ | |
ret_code_t ret; | |
APP_TIMER_DEF(sTestTimer); | |
ret = app_timer_init(); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("app_timer_init() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
ret = app_timer_create(&sTestTimer, APP_TIMER_MODE_REPEATED, TimerEventHandler); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("app_timer_create() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
ret = app_timer_start(sTestTimer, pdMS_TO_TICKS(TIMER_PERIOD_MS), NULL); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("app_timer_start() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
NRF_LOG_INFO("Timer test enabled"); | |
} | |
#endif // TIMER_TEST_ENABLED | |
// ================================================================================ | |
// Button Test | |
// ================================================================================ | |
#if BUTTON_TEST_ENABLED | |
#define TEST_BUTTON_PIN BUTTON_1 | |
#define TEST_BUTTON_DEBOUNCE_PERIOD_MS 50 | |
static void ButtonEventHandler(uint8_t pin_no, uint8_t button_action) | |
{ | |
int buttonNum; | |
switch (pin_no) | |
{ | |
case BUTTON_1: | |
buttonNum = 1; | |
break; | |
case BUTTON_2: | |
buttonNum = 2; | |
break; | |
case BUTTON_3: | |
buttonNum = 4; | |
break; | |
case BUTTON_4: | |
buttonNum = 4; | |
break; | |
default: | |
buttonNum = -1; | |
break; | |
} | |
NRF_LOG_INFO("Button %d %s", buttonNum, (button_action == APP_BUTTON_PUSH) ? "PUSH" : "RELEASE"); | |
} | |
static void InitButtonTest(void) | |
{ | |
ret_code_t ret; | |
static app_button_cfg_t sButtons[] = | |
{ | |
{ TEST_BUTTON_PIN, APP_BUTTON_ACTIVE_LOW, BUTTON_PULL, ButtonEventHandler } | |
}; | |
ret = app_button_init(sButtons, ARRAY_SIZE(sButtons), pdMS_TO_TICKS(TEST_BUTTON_DEBOUNCE_PERIOD_MS)); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("app_button_init() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
ret = app_button_enable(); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("app_button_enable() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
NRF_LOG_INFO("Button test enabled"); | |
} | |
#endif // BUTTON_TEST_ENABLED | |
// ================================================================================ | |
// SoftDevice Support | |
// ================================================================================ | |
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
static void OnSoCEvent(uint32_t sys_evt, void * p_context) | |
{ | |
UNUSED_PARAMETER(p_context); | |
#if OPENTHREAD_ENABLED | |
otSysSoftdeviceSocEvtHandler(sys_evt); | |
#endif // OPENTHREAD_ENABLED | |
} | |
#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
// ================================================================================ | |
// J-Link Monitor Mode Debugging Support | |
// ================================================================================ | |
#if JLINK_MMD | |
extern "C" void JLINK_MONITOR_OnExit(void) | |
{ | |
} | |
extern "C" void JLINK_MONITOR_OnEnter(void) | |
{ | |
} | |
extern "C" void JLINK_MONITOR_OnPoll(void) | |
{ | |
} | |
#endif // JLINK_MMD | |
// ================================================================================ | |
// Main Code | |
// ================================================================================ | |
int main(void) | |
{ | |
ret_code_t ret; | |
#if JLINK_MMD | |
NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOWEST); | |
#endif | |
// Initialize clock driver. | |
ret = nrf_drv_clock_init(); | |
APP_ERROR_CHECK(ret); | |
nrf_drv_clock_lfclk_request(NULL); | |
// Wait for the clock to be ready. | |
while (!nrf_clock_lf_is_running()) { } | |
#if NRF_LOG_ENABLED | |
// Initialize logging component | |
ret = NRF_LOG_INIT(NULL); | |
APP_ERROR_CHECK(ret); | |
// Initialize logging backends | |
NRF_LOG_DEFAULT_BACKENDS_INIT(); | |
// Start LOGGER task. | |
if (xTaskCreate(LoggerTaskMain, "LOGGER", LOGGER_STACK_SIZE / sizeof(StackType_t), NULL, LOGGER_PRIORITY, &sLoggerTaskHandle) != pdPASS) | |
{ | |
APP_ERROR_HANDLER(0); | |
} | |
#endif | |
NRF_LOG_INFO("=================================================="); | |
NRF_LOG_INFO("openweave-nrf52840-bringup starting"); | |
NRF_LOG_INFO("=================================================="); | |
// Configure LED-pins as outputs | |
bsp_board_init(BSP_INIT_LEDS); | |
bsp_board_led_invert(BSP_BOARD_LED_0); | |
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
NRF_LOG_INFO("Enabling SoftDevice"); | |
ret = nrf_sdh_enable_request(); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("nrf_sdh_enable_request() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
NRF_LOG_INFO("Waiting for SoftDevice to be enabled"); | |
while (!nrf_sdh_is_enabled()) { } | |
// Register a handler for SOC events. | |
NRF_SDH_SOC_OBSERVER(m_soc_observer, NRF_SDH_SOC_STACK_OBSERVER_PRIO, OnSoCEvent, NULL); | |
NRF_LOG_INFO("SoftDevice enable complete"); | |
#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
ret = nrf_mem_init(); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("nrf_mem_init() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#if NRF_CRYPTO_ENABLED | |
ret = nrf_crypto_init(); | |
if (ret != NRF_SUCCESS) | |
{ | |
NRF_LOG_INFO("nrf_crypto_init() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#endif | |
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
{ | |
uint32_t appRAMStart = 0; | |
// Configure the BLE stack using the default settings. | |
// Fetch the start address of the application RAM. | |
ret = nrf_sdh_ble_default_cfg_set(WEAVE_DEVICE_LAYER_BLE_CONN_CFG_TAG, &appRAMStart); | |
APP_ERROR_CHECK(ret); | |
// Enable BLE stack. | |
ret = nrf_sdh_ble_enable(&appRAMStart); | |
APP_ERROR_CHECK(ret); | |
} | |
#endif // defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT | |
NRF_LOG_INFO("Initializing Weave stack"); | |
ret = PlatformMgr().InitWeaveStack(); | |
if (ret != WEAVE_NO_ERROR) | |
{ | |
NRF_LOG_INFO("PlatformMgr().InitWeaveStack() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#if !WOBLE_ENABLED | |
ret = ConnectivityMgr().SetWoBLEServiceMode(ConnectivityManager::kWoBLEServiceMode_Disabled); | |
if (ret != WEAVE_NO_ERROR) | |
{ | |
NRF_LOG_INFO("ConnectivityMgr().SetWoBLEServiceMode() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#endif // WOBLE_ENABLED | |
#if OPENTHREAD_ENABLED | |
NRF_LOG_INFO("Initializing OpenThread stack"); | |
otSysInit(0, NULL); | |
ret = ThreadStackMgr().InitThreadStack(); | |
if (ret != WEAVE_NO_ERROR) | |
{ | |
NRF_LOG_INFO("ThreadStackMgr().InitThreadStack() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#endif // OPENTHREAD_ENABLED | |
NRF_LOG_INFO("Starting Weave task"); | |
ret = PlatformMgr().StartEventLoopTask(); | |
if (ret != WEAVE_NO_ERROR) | |
{ | |
NRF_LOG_INFO("PlatformMgr().StartEventLoopTask() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#if OPENTHREAD_ENABLED | |
NRF_LOG_INFO("Starting OpenThread task"); | |
// Start OpenThread task | |
ret = ThreadStackMgrImpl().StartThreadTask(); | |
if (ret != WEAVE_NO_ERROR) | |
{ | |
NRF_LOG_INFO("ThreadStackMgr().StartThreadTask() failed"); | |
APP_ERROR_HANDLER(ret); | |
} | |
#endif // OPENTHREAD_ENABLED | |
#if OPENTHREAD_TEST_NETWORK_ENABLED | |
{ | |
otError otRet; | |
otInstance * otInst = ThreadStackMgrImpl().OTInstance(); | |
if (!otDatasetIsCommissioned(otInst)) | |
{ | |
NRF_LOG_INFO("Commissioning test Thread network"); | |
otRet = otThreadSetNetworkName(otInst, OPENTHREAD_TEST_NETWORK_NAME); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otThreadSetNetworkName() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
otRet = otLinkSetPanId(otInst, OPENTHREAD_TEST_NETWORK_PANID); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otLinkSetPanId() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
{ | |
struct otExtendedPanId exPanId = { OPENTHREAD_TEST_NETWORK_EXTENDED_PANID }; | |
otRet = otThreadSetExtendedPanId(otInst, &exPanId); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otThreadSetExtendedPanId() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
} | |
otRet = otLinkSetChannel(otInst, OPENTHREAD_TEST_NETWORK_CHANNEL); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otLinkSetChannel() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
{ | |
struct otMasterKey masterKey = { OPENTHREAD_TEST_NETWORK_MASTER_KEY }; | |
otRet = otThreadSetMasterKey(otInst, &masterKey); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otThreadSetMasterKey() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
} | |
otRet = otThreadSetEnabled(otInst, true); | |
if (otRet != OT_ERROR_NONE) | |
{ | |
NRF_LOG_INFO("otThreadSetEnabled() failed"); | |
APP_ERROR_HANDLER(otRet); | |
} | |
} | |
else | |
{ | |
NRF_LOG_INFO("Thread network already commissioned"); | |
} | |
NRF_LOG_INFO("OpenThread initialization complete"); | |
} | |
#endif // OPENTHREAD_TEST_NETWORK_ENABLED | |
#if TEST_TASK_ENABLED | |
NRF_LOG_INFO("Starting test task"); | |
// Start Test task | |
if (xTaskCreate(TestTaskMain, "TEST", TEST_TASK_STACK_SIZE / sizeof(StackType_t), NULL, TEST_TASK_PRIORITY, &sTestTaskHandle) != pdPASS) | |
{ | |
NRF_LOG_INFO("Failed to create TEST task"); | |
} | |
#endif // TEST_TASK_ENABLED | |
#if TIMER_TEST_ENABLED | |
InitTimerTest(); | |
#endif | |
#if BUTTON_TEST_ENABLED | |
InitButtonTest(); | |
#endif | |
// Activate deep sleep mode | |
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; | |
NRF_LOG_INFO("Starting FreeRTOS scheduler"); | |
/* Start FreeRTOS scheduler. */ | |
vTaskStartScheduler(); | |
// Should never get here | |
NRF_LOG_INFO("vTaskStartScheduler() failed"); | |
APP_ERROR_HANDLER(0); | |
} |