[efr32] add support for entering EM2 low-power mode for sleepy devices (#3758)

Changes to EFR32 platform to allow entering EM2 low-power mode for sleepy devices
sleepy-demo applications added to examples/platforms/efr32.
This commit is contained in:
Marven Gilhespie
2019-05-03 09:10:39 -07:00
committed by Jonathan Hui
parent 0aa39f8d13
commit 1b9c50112e
13 changed files with 1396 additions and 25 deletions
+3
View File
@@ -1984,6 +1984,9 @@ examples/platforms/cc2650/Makefile
examples/platforms/cc2652/Makefile
examples/platforms/da15000/Makefile
examples/platforms/efr32/Makefile
examples/platforms/efr32/sleepy-demo/Makefile
examples/platforms/efr32/sleepy-demo/efr32-sleepy-demo-ftd/Makefile
examples/platforms/efr32/sleepy-demo/efr32-sleepy-demo-mtd/Makefile
examples/platforms/emsk/Makefile
examples/platforms/gp712/Makefile
examples/platforms/kw41z/Makefile
+24
View File
@@ -45,6 +45,13 @@ EFR32MG_SDK_SRCDIR = $(top_srcdir)/third_party/silabs
libopenthread_efr32_a_CPPFLAGS = \
-D__START=main \
-D__STARTUP_CLEAR_BSS \
-DPLATFORM_HEADER=\"@top_builddir@/third_party/silabs/gecko_sdk_suite/v2.5/platform/base/hal/micro/cortexm3/compiler/gcc.h\" \
-Wno-sign-compare \
-DCORTEXM3 \
-DPHY=EMBER_PHY_RAIL \
-DMICRO=EMBER_MICRO_CORTEXM3_EFR32 \
-DCORTEXM3_EFM32_MICRO \
-DPLAT=EMBER_PLATFORM_CORTEXM3 \
-I$(top_srcdir)/include \
-I$(top_srcdir)/examples/platforms \
-I$(top_srcdir)/examples/platforms/efr32/$(EFR32_BOARD_DIR) \
@@ -60,6 +67,11 @@ libopenthread_efr32_a_CPPFLAGS =
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/plugin/pa-conversions \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/common/bsp \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/EFR32MG12_$(BOARD)/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/ \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32 \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/plugin \
-I$(EFR32MG_SDK_SRCDIR)/platform/CMSIS/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/Device/SiliconLabs/EFR32MG12P/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/common/inc \
@@ -145,4 +157,16 @@ libopenthread_efr32_a_LIBADD
$(shell find $(top_builddir)/examples/platforms/utils $(Dash)type f $(Dash)name "*.o") \
$(shell find $(top_builddir)/third_party/jlink/SEGGER_RTT_V640/RTT $(Dash)type f $(Dash)name "*.o")
DIST_SUBDIRS = \
sleepy-demo \
$(NULL)
SUBDIRS = \
sleepy-demo \
$(NULL)
PRETTY_SUBDIRS = \
sleepy-demo \
$(NULL)
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
+3
View File
@@ -13,6 +13,9 @@ has rich memory and peripheral resources which can support all OpenThread
capabilities. See the "Run the example with EFR32 boards" section below
for an example using basic OpenThread capabilities.
See [sleepy-demo/README.md](sleepy-demo/README.md) for instructions for an example that uses the low-energy
modes of the EFR32 when running as a Sleepy End Device.
[efr32mg12p]: http://www.silabs.com/products/wireless/mesh-networking/efr32mg-mighty-gecko-zigbee-thread-soc/device.EFR32MG12P432F1024GL125
## Toolchain
+87 -23
View File
@@ -32,13 +32,16 @@
*
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <openthread/config.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include "common/logging.hpp"
#include "platform-efr32.h"
#include "utils/code_utils.h"
#include "em_core.h"
@@ -47,12 +50,25 @@
#define XTAL_ACCURACY 200
#define US_IN_MS 1000
// Minimum duration of an alarm in milliseconds. Used to avoid setting the absolute
// expiry time of an alarm to the current time or slightly in the past.
#define TIMER_EPSILON_MS 1
// The longest Rail can set a timer is 53 minutes. Timers of a longer duration
// must wake up before this and set another timer for the remainder. We currently
// split long delays in 30 minute intervals using a value of 1800000.
#define RAIL_TIMER_MAX_DELTA_MS 1800000
static uint32_t sTimerHi = 0;
static uint32_t sTimerLo = 0;
static uint32_t sAlarmT0 = 0;
static uint32_t sAlarmDt = 0;
static bool sIsRunning = false;
static void RAILCb_TimerExpired(RAIL_Handle_t aHandle)
{
}
void efr32AlarmInit(void)
{
}
@@ -94,10 +110,40 @@ uint32_t otPlatTimeGetXtalAccuracy(void)
void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t t0, uint32_t dt)
{
OT_UNUSED_VARIABLE(aInstance);
uint32_t expires_microsec;
RAIL_Status_t status;
sAlarmT0 = t0;
sAlarmDt = dt;
sIsRunning = true;
assert(gRailHandle != NULL);
if (sIsRunning)
{
RAIL_CancelTimer(gRailHandle);
}
sAlarmT0 = t0;
sAlarmDt = dt;
if (dt > RAIL_TIMER_MAX_DELTA_MS)
{
dt = RAIL_TIMER_MAX_DELTA_MS;
}
else if (dt < TIMER_EPSILON_MS)
{
dt = TIMER_EPSILON_MS;
}
expires_microsec = (t0 + dt) * US_IN_MS;
status = RAIL_SetTimer(gRailHandle, expires_microsec, RAIL_TIME_ABSOLUTE, RAILCb_TimerExpired);
if (status == RAIL_STATUS_NO_ERROR)
{
sIsRunning = true;
}
else
{
sIsRunning = false;
otLogCritPlat("Alarm set timer, status: %d, dt: %u, t0: %u", status, dt, t0);
}
}
void otPlatAlarmMilliStop(otInstance *aInstance)
@@ -105,33 +151,56 @@ void otPlatAlarmMilliStop(otInstance *aInstance)
OT_UNUSED_VARIABLE(aInstance);
sIsRunning = false;
assert(gRailHandle != NULL);
RAIL_CancelTimer(gRailHandle);
}
void efr32AlarmProcess(otInstance *aInstance)
{
uint32_t now = otPlatAlarmMilliGetNow();
uint32_t expires;
bool fire = false;
uint32_t now;
uint32_t new_expires_microsec;
uint32_t dt;
RAIL_Status_t status;
otEXPECT(sIsRunning);
expires = sAlarmT0 + sAlarmDt;
assert(gRailHandle != NULL);
if (sAlarmT0 <= now)
{
fire = (expires >= sAlarmT0 && expires <= now);
}
else
{
fire = (expires >= sAlarmT0 || expires <= now);
}
if (fire)
if (RAIL_IsTimerExpired(gRailHandle))
{
sIsRunning = false;
#if OPENTHREAD_ENABLE_DIAG
if (sAlarmDt > RAIL_TIMER_MAX_DELTA_MS)
{
now = otPlatAlarmMilliGetNow();
dt = (sAlarmT0 + sAlarmDt) - now;
if (dt > RAIL_TIMER_MAX_DELTA_MS)
{
dt = RAIL_TIMER_MAX_DELTA_MS;
}
else if (dt < TIMER_EPSILON_MS)
{
dt = TIMER_EPSILON_MS;
}
new_expires_microsec = (now + dt) * US_IN_MS;
status = RAIL_SetTimer(gRailHandle, new_expires_microsec, RAIL_TIME_ABSOLUTE, RAILCb_TimerExpired);
if (status == RAIL_STATUS_NO_ERROR)
{
sIsRunning = true;
}
else
{
sIsRunning = false;
otLogCritPlat("Alarm set timer, status: %d, expires: %u, dt: %u, now: %u", status, sAlarmT0 + sAlarmDt,
dt, now);
}
}
#if OPENTHREAD_ENABLE_DIAG
if (otPlatDiagModeGet())
{
otPlatDiagAlarmFired(aInstance);
@@ -142,11 +211,6 @@ void efr32AlarmProcess(otInstance *aInstance)
otPlatAlarmMilliFired(aInstance);
}
}
exit:
return;
}
void RAILCb_TimerExpired(void)
{
}
+26
View File
@@ -41,10 +41,14 @@
#include "em_system.h"
#include "core_cm4.h"
#include "rail.h"
// Global OpenThread instance structure
extern otInstance *sInstance;
// Global reference to rail handle
extern RAIL_Handle_t gRailHandle;
/**
* This function initializes the alarm service used by OpenThread.
*
@@ -109,4 +113,26 @@ void efr32LogInit(void);
*/
void efr32LogDeinit(void);
/**
* Registers the sleep callback handler. The callback is used to check that
* the application has no work pending and that it is safe to put the EFR32
* into a low energy sleep mode.
*
* The callback should return true if it is ok to enter sleep mode. Note
* that the callback itself is run with interrupts disabled and so should
* be kept as short as possible. Anny interrupt including those from timers
* will wake the EFR32 out of sleep mode.
*
* @param[in] aCallback Callback function.
*
*/
void efr32SetSleepCallback(bool (*aCallback)(void));
/**
* Put the EFR32 into a low power mode. Before sleeping it will call a callback
* in the application registered with efr32SetSleepCallback to ensure that there
* is no outstanding work in the application to do.
*/
void efr32Sleep(void);
#endif // PLATFORM_EFR32_H_
+16
View File
@@ -45,6 +45,7 @@
#include "utils/soft_source_match_table.h"
#include "board_config.h"
#include "em_cmu.h"
#include "em_core.h"
#include "em_system.h"
#include "openthread-core-efr32-config.h"
@@ -53,6 +54,7 @@
#include "rail.h"
#include "rail_config.h"
#include "rail_ieee802154.h"
#include "rtcdriver.h"
enum
{
@@ -102,6 +104,8 @@ typedef enum
ENERGY_SCAN_MODE_ASYNC
} energyScanMode;
RAIL_Handle_t gRailHandle;
static volatile bool sTransmitBusy = false;
static bool sPromiscuous = false;
static bool sIsSrcMatchEnabled = false;
@@ -178,6 +182,11 @@ static RAIL_Handle_t efr32RailConfigInit(efr32BandConfig *aBandConfig)
handle = RAIL_Init(&aBandConfig->mRailConfig, NULL);
assert(handle != NULL);
if (gRailHandle == NULL)
{
gRailHandle = handle;
}
status = RAIL_ConfigData(handle, &railDataConfig);
assert(status == RAIL_STATUS_NO_ERROR);
@@ -288,8 +297,15 @@ static void efr32BandConfigInit(void (*aEventCallback)(RAIL_Handle_t railHandle,
void efr32RadioInit(void)
{
RAIL_Status_t status;
efr32BandConfigInit(RAILCb_Generic);
CMU_ClockEnable(cmuClock_PRS, true);
RTCDRV_Init();
status = RAIL_ConfigSleep(gRailHandle, RAIL_SLEEP_CONFIG_TIMERSYNC_ENABLED);
assert(status == RAIL_STATUS_NO_ERROR);
sReceiveFrame.mLength = 0;
sReceiveFrame.mPsdu = sReceivePsdu;
sTransmitFrame.mLength = 0;
@@ -0,0 +1,54 @@
#
# Copyright (c) 2019, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
# Always package (e.g. for 'make dist') these subdirectories.
DIST_SUBDIRS = \
efr32-sleepy-demo-mtd \
efr32-sleepy-demo-ftd \
$(NULL)
# Always build (e.g. for 'make all') these subdirectories.
SUBDIRS = \
$(NULL)
if OPENTHREAD_ENABLE_EXECUTABLE
SUBDIRS += efr32-sleepy-demo-mtd efr32-sleepy-demo-ftd
endif
# Always pretty (e.g. for 'make pretty') these subdirectories.
PRETTY_SUBDIRS = \
efr32-sleepy-demo-mtd \
efr32-sleepy-demo-ftd \
$(NULL)
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
@@ -0,0 +1,100 @@
# EFR32 Sleepy Demo Example
The EFR32 Sleepy applications demonstrates Sleepy End Device behaviour using
the EFR32's low power EM2 mode. The steps below will take you through the
process of building and running the demo
For setting up the build environment refer to [examples/platforms/efr32/README.md](../README.md).
## 1. Build
```bash
$ cd <path-to-openthread>
$ ./bootstrap
$ make -f examples/Makefile-efr32 COMMISSIONER=1 JOINER=1 DHCP6_CLIENT=1 DHCP6_SERVER=1 BOARD=BRD4161A
```
Convert the resulting executables into S-Record format and append a s37 suffix.
```bash
$ cd output/efr32/bin
$ arm-none-eabi-objcopy -O srec efr32-sleepy-demo-mtd efr32-sleepy-demo-mtd.s37
$ arm-none-eabi-objcopy -O srec efr32-sleepy-demo-ftd efr32-sleepy-demo-ftd.s37
```
In Silicon Labs Simplicity Studio flash one device with the efr32-sleepy-demo-mtd.s37
image and the other device with the efr32-sleepy-demo-ftd.s37 image.
For instructions on flashing firmware see [examples/platforms/efr32/README.md](../README.md#flash-binaries)
## 2. Starting nodes
For demonstration purposes the network settings are hardcoded within the source files.
The devices start Thread and form a network within a few seconds of powering on. In a real-life
application the devices should implement and go through a commissioning process to create
a network and add devices.
When the efr32-sleepy-demo-ftd device is started in the CLI the user shall see:
```
efr32-sleepy-demo-ftd started
efr32-sleepy-demo-ftd changed to leader
```
When the efr32-sleepy-demo-mtd device starts it joins the preconfigured Thread network
before disabling Rx-On-Idle to become a Sleepy-End-Device.
Use the command "child table" in the FTD console and observe the R flag of the child is 0.
```
> child table
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|S|D|N| Extended MAC |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
| 1 | 0x8401 | 240 | 3 | 3 | 3 |0|1|0|0| 8e8582dbd78c243c |
Done
```
## 3. Buttons on the MTD
Pressing button 0 on the MTD toggles between operating as a Minimal End Device (MED) and
a Sleepy End Device (SED) with the RX off when idle.
Pressing button 1 on the MTD sends a multicast UDP message containing the
string "mtd button". The FTD listens on the multicast address and will toggle
LED 0 and display a message in the CLI showing "Message Received: mtd button".
## 4. Buttons on the FTD
Pressing either button 0 or 1 on the FTD will send a UDP message to the FTD containing the string
"ftd button". The MTD must first send a multicast message by pressing the MTD's button 1 so that
the FTD knows the address of the MTD to send messages to.
This will toggle the state of LED0 on the MTD. If the MTD is operating as a sleepy end device then
the MTD polls the parent every 5 seconds for messages and will update the LED state on the
next poll.
## 5. Monitoring power consumption of the MTD
Open the Energy Profiler within Silicon Labs Simplicity Studio. Within the Quick Access menu
select Start Energy Capture... and select the MTD device. When operating as a Sleepy End Device
with no LEDs on the current should be under 20 microamps with occassional spikes during waking
and polling the parent. With the LED on the MTD has a current consumption of approximately 1mA.
When operating as a Minial End Device with the Rx on Idle observe that the current is in the order
of 10ma.
With further configuration of GPIOs and peripherals it is possible to reduce the sleepy current
consumption further.
## 6. Notes on sleeping, sleepy callback and interrupts
To allow the EFR32 to enter sleepy mode the application must register a callback with efr32SetSleepCallback.
The return value of callback is used to indicate that the application has no further work to do and that
it is safe to go into a low power mode. The callback is called with interrupts disabled so should do
the minimum required to check if it can sleep.
@@ -0,0 +1,162 @@
#
# Copyright (c) 2019, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
include $(top_srcdir)/examples/platforms/Makefile.platform.am
override CFLAGS := $(filter-out -Wconversion,$(CFLAGS))
override CXXFLAGS := $(filter-out -Wconversion,$(CXXFLAGS))
EFR32_BOARD_DIR = $(shell echo $(BOARD) | tr A-Z a-z)
EFR32MG_SDK_SRCDIR = $(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.5
$(top_builddir)/examples/platforms/efr32/libopenthread-efr32.a:
(cd $(top_builddir)/examples/platforms/efr32/ && $(MAKE) $(AM_MAKEFLAGS) libopenthread-efr32.a )
bin_PROGRAMS = \
$(NULL)
CPPFLAGS_COMMON += \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/examples/platforms \
-DPLATFORM_HEADER=\"@top_builddir@/third_party/silabs/gecko_sdk_suite/v2.5/platform/base/hal/micro/cortexm3/compiler/gcc.h\" \
-Wno-sign-compare \
-DCORTEXM3 \
-D__START=main \
-DPHY=EMBER_PHY_RAIL \
-DMICRO=EMBER_MICRO_CORTEXM3_EFR32 \
-DCORTEXM3_EFM32_MICRO \
-DPLAT=EMBER_PLATFORM_CORTEXM3 \
-D__STARTUP_CLEAR_BSS \
-I$(top_srcdir)/include \
-I$(top_srcdir)/examples/platforms \
-I$(top_srcdir)/examples/platforms/efr32/$(EFR32_BOARD_DIR) \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/third_party/silabs/rail_config \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/common \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/chip/efr32 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/protocol/ieee802154 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/chip/efr32/rf/common/cortex \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/hal \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/hal/efr32 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/plugin/pa-conversions \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/common/bsp \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/EFR32MG12_$(BOARD)/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/CMSIS/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/ \
-I$(EFR32MG_SDK_SRCDIR)/platform/Device/SiliconLabs/EFR32MG12P/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/common/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/gpiointerrupt/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/uartdrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/uartdrv/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/ustimer/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/dmadrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/dmadrv/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/rtcdrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emlib/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/halconfig/inc/hal-config \
-I$(EFR32MG_SDK_SRCDIR)/util/plugin/plugin-common/fem-control \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/plugin \
-I$(EFR32MG_SDK_SRCDIR)/protocol/thread \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32 \
-I$(EFR32MG_SDK_SRCDIR)/protocol/thread/stack \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
$(NULL)
LDADD_COMMON += \
$(NULL)
LDFLAGS_COMMON += \
$(NULL)
LIBTOOLFLAGS_COMMON += \
$(NULL)
SOURCES_COMMON += \
main.c \
$(NULL)
if OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
LDADD_COMMON += \
$(top_builddir)/third_party/mbedtls/libmbedcrypto.a \
$(NULL)
endif # OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
if OPENTHREAD_ENABLE_DIAG
LDADD_COMMON += \
$(top_builddir)/src/diag/libopenthread-diag.a \
$(NULL)
endif # OPENTHREAD_ENABLE_DIAG
if OPENTHREAD_ENABLE_EXECUTABLE
bin_PROGRAMS += \
efr32-sleepy-demo-ftd \
$(NULL)
endif
efr32_sleepy_demo_ftd_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_ftd_LDADD = \
$(top_builddir)/src/cli/libopenthread-cli-ftd.a \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(LDADD_COMMON) \
$(top_builddir)/src/core/libopenthread-ftd.a \
$(LDADD_COMMON) \
$(NULL)
efr32_sleepy_demo_ftd_LDFLAGS = \
$(LDFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_ftd_LIBTOOLFLAGS = \
$(LIBTOOLFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_ftd_SOURCES = \
$(SOURCES_COMMON) \
$(NULL)
if OPENTHREAD_ENABLE_LINKER_MAP
efr32_sleepy_demo_ftd_LDFLAGS += -Wl,-Map=efr32-sleepy-demo-ftd.map
endif
if OPENTHREAD_BUILD_COVERAGE
CPPFLAGS_COMMON += \
-DOPENTHREAD_ENABLE_COVERAGE \
$(NULL)
CLEANFILES = $(wildcard *.gcda *.gcno)
endif # OPENTHREAD_BUILD_COVERAGE
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
@@ -0,0 +1,329 @@
/*
* Copyright (c) 2019, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "bsp.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "gpiointerrupt.h"
#include "hal-config-board.h"
#include "hal_common.h"
#include "openthread-system.h"
#include "rtcdriver.h"
#include <assert.h>
#include <common/logging.hpp>
#include <openthread-core-config.h>
#include <string.h>
#include <openthread/cli.h>
#include <openthread/config.h>
#include <openthread/dataset_ftd.h>
#include <openthread/diag.h>
#include <openthread/instance.h>
#include <openthread/message.h>
#include <openthread/tasklet.h>
#include <openthread/thread.h>
#include <openthread/udp.h>
#include <openthread/platform/logging.h>
// Constants
#define MULTICAST_ADDR "ff03::1"
#define MULTICAST_PORT 123
#define RECV_PORT 234
#define MTD_MESSAGE "mtd button"
#define FTD_MESSAGE "ftd button"
// Types
typedef struct ButtonArray
{
GPIO_Port_TypeDef port;
unsigned int pin;
} ButtonArray_t;
// Prototypes
void setNetworkConfiguration(otInstance *aInstance);
void OTCALL handleNetifStateChanged(uint32_t aFlags, void *aContext);
void gpioInit(void (*gpioCallback)(uint8_t pin));
void buttonCallback(uint8_t pin);
void initUdp(void);
void applicationTick(void);
void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
// Variables
static otInstance * instance;
static otUdpSocket sFtdSocket;
static bool sLedOn = false;
static bool sHaveSwitchAddress = false;
static otIp6Address sSwitchAddress;
static bool sFtdButtonPressed = false;
static const ButtonArray_t sButtonArray[BSP_BUTTON_COUNT] = BSP_BUTTON_INIT;
void otTaskletsSignalPending(otInstance *aInstance)
{
(void)aInstance;
}
int main(int argc, char *argv[])
{
otSysInit(argc, argv);
gpioInit(buttonCallback);
instance = otInstanceInitSingle();
assert(instance);
otCliUartInit(instance);
otCliOutputFormat("efr32-sleepy-demo-ftd started\r\n");
setNetworkConfiguration(instance);
otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
initUdp();
otIp6SetEnabled(instance, true);
otThreadSetEnabled(instance, true);
#if OPENTHREAD_ENABLE_DIAG
otDiagInit(instance);
#endif
while (!otSysPseudoResetWasRequested())
{
otTaskletsProcess(instance);
otSysProcessDrivers(instance);
applicationTick();
}
otInstanceFinalize(instance);
return 0;
}
/*
* Provide, if required an "otPlatLog()" function
*/
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
{
OT_UNUSED_VARIABLE(aLogLevel);
OT_UNUSED_VARIABLE(aLogRegion);
OT_UNUSED_VARIABLE(aFormat);
va_list ap;
va_start(ap, aFormat);
otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
va_end(ap);
}
#endif
/**
* Override default network settings, such as panid, so the devices can join a network
*/
void setNetworkConfiguration(otInstance *aInstance)
{
static char aNetworkName[] = "SleepyEFR32";
otOperationalDataset aDataset;
memset(&aDataset, 0, sizeof(otOperationalDataset));
/*
* Fields that can be configured in otOperationDataset to override defaults:
* Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
* Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
*/
aDataset.mActiveTimestamp = 1;
aDataset.mComponents.mIsActiveTimestampPresent = true;
/* Set Channel to 15 */
aDataset.mChannel = 15;
aDataset.mComponents.mIsChannelPresent = true;
/* Set Pan ID to 2222 */
aDataset.mPanId = (otPanId)0x2222;
aDataset.mComponents.mIsPanIdPresent = true;
/* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
aDataset.mComponents.mIsExtendedPanIdPresent = true;
/* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5};
memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
aDataset.mComponents.mIsMasterKeyPresent = true;
/* Set Network Name to SleepyEFR32 */
size_t length = strlen(aNetworkName);
assert(length <= OT_NETWORK_NAME_MAX_SIZE);
memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
aDataset.mComponents.mIsNetworkNamePresent = true;
otDatasetSetActive(aInstance, &aDataset);
}
void OTCALL handleNetifStateChanged(uint32_t aFlags, void *aContext)
{
if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
{
otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
switch (changedRole)
{
case OT_DEVICE_ROLE_LEADER:
otCliOutputFormat("efr32-sleepy-demo-ftd changed to leader\r\n");
break;
case OT_DEVICE_ROLE_ROUTER:
otCliOutputFormat("efr32-sleepy-demo-ftd changed to router\r\n");
break;
case OT_DEVICE_ROLE_CHILD:
break;
case OT_DEVICE_ROLE_DETACHED:
case OT_DEVICE_ROLE_DISABLED:
break;
}
}
}
void gpioInit(void (*callback)(uint8_t pin))
{
// set up button GPIOs to input with pullups
for (int i = 0; i < BSP_BUTTON_COUNT; i++)
{
GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
}
// set up interrupt based callback function on falling edge
GPIOINT_Init();
GPIOINT_CallbackRegister(sButtonArray[0].pin, callback);
GPIOINT_CallbackRegister(sButtonArray[1].pin, callback);
GPIO_IntConfig(sButtonArray[0].port, sButtonArray[0].pin, false, true, true);
GPIO_IntConfig(sButtonArray[1].port, sButtonArray[1].pin, false, true, true);
BSP_LedsInit();
BSP_LedClear(0);
BSP_LedClear(1);
}
void initUdp(void)
{
otError error;
otSockAddr sockaddr;
memset(&sockaddr, 0, sizeof(sockaddr));
otIp6AddressFromString(MULTICAST_ADDR, &sockaddr.mAddress);
sockaddr.mPort = MULTICAST_PORT;
sockaddr.mScopeId = OT_NETIF_INTERFACE_ID_THREAD;
error = otUdpOpen(instance, &sFtdSocket, sFtdReceiveCallback, NULL);
if (error != OT_ERROR_NONE)
{
otCliOutputFormat("FTD failed to open udp multicast\r\n");
return;
}
error = otUdpBind(&sFtdSocket, &sockaddr);
if (error != OT_ERROR_NONE)
{
otUdpClose(&sFtdSocket);
otCliOutputFormat("FTD failed to bind udp multicast\r\n");
return;
}
}
void buttonCallback(uint8_t pin)
{
OT_UNUSED_VARIABLE(pin);
sFtdButtonPressed = true;
}
void applicationTick(void)
{
otError error = 0;
otMessageInfo messageInfo;
otMessage * message = NULL;
char * payload = FTD_MESSAGE;
if (sFtdButtonPressed == true)
{
sFtdButtonPressed = false;
if (sHaveSwitchAddress)
{
memset(&messageInfo, 0, sizeof(messageInfo));
memcpy(&messageInfo.mPeerAddr, &sSwitchAddress, sizeof messageInfo.mPeerAddr);
messageInfo.mPeerPort = RECV_PORT;
messageInfo.mInterfaceId = OT_NETIF_INTERFACE_ID_THREAD;
message = otUdpNewMessage(instance, NULL);
if (message != NULL)
{
error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
if (error == OT_ERROR_NONE)
{
error = otUdpSend(&sFtdSocket, message, &messageInfo);
if (error == OT_ERROR_NONE)
{
return;
}
}
}
if (message != NULL)
{
otMessageFree(message);
}
}
}
}
void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aMessage);
OT_UNUSED_VARIABLE(aMessageInfo);
uint8_t buf[1500];
int length;
sLedOn = !sLedOn;
if (sLedOn)
{
BSP_LedSet(0);
}
else
{
BSP_LedClear(0);
}
length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
buf[length] = '\0';
otCliOutputFormat("Message Received: %s\r\n", buf);
sHaveSwitchAddress = true;
memcpy(&sSwitchAddress, &aMessageInfo->mPeerAddr, sizeof sSwitchAddress);
}
@@ -0,0 +1,162 @@
#
# Copyright (c) 2019, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
include $(top_srcdir)/examples/platforms/Makefile.platform.am
override CFLAGS := $(filter-out -Wconversion,$(CFLAGS))
override CXXFLAGS := $(filter-out -Wconversion,$(CXXFLAGS))
EFR32_BOARD_DIR = $(shell echo $(BOARD) | tr A-Z a-z)
EFR32MG_SDK_SRCDIR = $(top_srcdir)/third_party/silabs/gecko_sdk_suite/v2.5
$(top_builddir)/examples/platforms/efr32/libopenthread-efr32.a:
(cd $(top_builddir)/examples/platforms/efr32/ && $(MAKE) $(AM_MAKEFLAGS) libopenthread-efr32.a )
bin_PROGRAMS = \
$(NULL)
CPPFLAGS_COMMON += \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/examples/platforms \
-DPLATFORM_HEADER=\"@top_builddir@/third_party/silabs/gecko_sdk_suite/v2.5/platform/base/hal/micro/cortexm3/compiler/gcc.h\" \
-Wno-sign-compare \
-DCORTEXM3 \
-D__START=main \
-DPHY=EMBER_PHY_RAIL \
-DMICRO=EMBER_MICRO_CORTEXM3_EFR32 \
-DCORTEXM3_EFM32_MICRO \
-DPLAT=EMBER_PLATFORM_CORTEXM3 \
-D__STARTUP_CLEAR_BSS \
-I$(top_srcdir)/include \
-I$(top_srcdir)/examples/platforms \
-I$(top_srcdir)/examples/platforms/efr32/$(EFR32_BOARD_DIR) \
-I$(top_srcdir)/src/core \
-I$(top_srcdir)/third_party/silabs/rail_config \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/common \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/chip/efr32 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/protocol/ieee802154 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/chip/efr32/rf/common/cortex \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/hal \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/hal/efr32 \
-I$(EFR32MG_SDK_SRCDIR)/platform/radio/rail_lib/plugin/pa-conversions \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/common/bsp \
-I$(EFR32MG_SDK_SRCDIR)/hardware/kit/EFR32MG12_$(BOARD)/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/CMSIS/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/ \
-I$(EFR32MG_SDK_SRCDIR)/platform/Device/SiliconLabs/EFR32MG12P/Include \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/common/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/gpiointerrupt/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/uartdrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/uartdrv/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/ustimer/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/dmadrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/dmadrv/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/emdrv/rtcdrv/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/emlib/inc \
-I$(EFR32MG_SDK_SRCDIR)/platform/halconfig/inc/hal-config \
-I$(EFR32MG_SDK_SRCDIR)/util/plugin/plugin-common/fem-control \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32/config \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/plugin \
-I$(EFR32MG_SDK_SRCDIR)/protocol/thread \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal/micro/cortexm3/efm32 \
-I$(EFR32MG_SDK_SRCDIR)/protocol/thread/stack \
-I$(EFR32MG_SDK_SRCDIR)/platform/base/hal \
-Wno-unused-parameter \
-Wno-missing-field-initializers \
$(NULL)
LDADD_COMMON += \
$(NULL)
LDFLAGS_COMMON += \
$(NULL)
LIBTOOLFLAGS_COMMON += \
$(NULL)
SOURCES_COMMON += \
main.c \
$(NULL)
if OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
LDADD_COMMON += \
$(top_builddir)/third_party/mbedtls/libmbedcrypto.a \
$(NULL)
endif # OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
if OPENTHREAD_ENABLE_DIAG
LDADD_COMMON += \
$(top_builddir)/src/diag/libopenthread-diag.a \
$(NULL)
endif # OPENTHREAD_ENABLE_DIAG
if OPENTHREAD_ENABLE_EXECUTABLE
bin_PROGRAMS += \
efr32-sleepy-demo-mtd \
$(NULL)
endif
efr32_sleepy_demo_mtd_CPPFLAGS = \
$(CPPFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_mtd_LDADD = \
$(top_builddir)/src/cli/libopenthread-cli-mtd.a \
$(top_builddir)/src/core/libopenthread-mtd.a \
$(LDADD_COMMON) \
$(top_builddir)/src/core/libopenthread-mtd.a \
$(LDADD_COMMON) \
$(NULL)
efr32_sleepy_demo_mtd_LDFLAGS = \
$(LDFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_mtd_LIBTOOLFLAGS = \
$(LIBTOOLFLAGS_COMMON) \
$(NULL)
efr32_sleepy_demo_mtd_SOURCES = \
$(SOURCES_COMMON) \
$(NULL)
if OPENTHREAD_ENABLE_LINKER_MAP
efr32_sleepy_demo_mtd_LDFLAGS += -Wl,-Map=efr32_sleepy_demo_mtd_.map
endif
if OPENTHREAD_BUILD_COVERAGE
CPPFLAGS_COMMON += \
-DOPENTHREAD_ENABLE_COVERAGE \
$(NULL)
CLEANFILES = $(wildcard *.gcda *.gcno)
endif # OPENTHREAD_BUILD_COVERAGE
include $(abs_top_nlbuild_autotools_dir)/automake/post.am
@@ -0,0 +1,384 @@
/*
* Copyright (c) 2019, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <string.h>
#include "bsp.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "gpiointerrupt.h"
#include "hal-config-board.h"
#include "hal_common.h"
#include "openthread-system.h"
#include "platform-efr32.h"
#include "rtcdriver.h"
#include <common/logging.hpp>
#include <openthread-core-config.h>
#include <openthread/cli.h>
#include <openthread/config.h>
#include <openthread/dataset_ftd.h>
#include <openthread/diag.h>
#include <openthread/instance.h>
#include <openthread/link.h>
#include <openthread/message.h>
#include <openthread/tasklet.h>
#include <openthread/thread.h>
#include <openthread/udp.h>
#include <openthread/platform/logging.h>
// Constants
#define MULTICAST_ADDR "ff03::1"
#define MULTICAST_PORT 123
#define RECV_PORT 234
#define SLEEPY_POLL_PERIOD_MS 5000
#define MTD_MESSAGE "mtd button"
#define FTD_MESSAGE "ftd button"
// Types
typedef struct ButtonArray
{
GPIO_Port_TypeDef port;
unsigned int pin;
} ButtonArray_t;
// Prototypes
bool sleepCb(void);
void setNetworkConfiguration(otInstance *aInstance);
void OTCALL handleNetifStateChanged(uint32_t aFlags, void *aContext);
void gpioInit(void (*gpioCallback)(uint8_t pin));
void buttonCallback(uint8_t pin);
void initUdp(void);
void applicationTick(void);
void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
// Variables
static otInstance * instance;
static otUdpSocket sMtdSocket;
static otSockAddr sMulticastSockAddr;
static const ButtonArray_t sButtonArray[BSP_BUTTON_COUNT] = BSP_BUTTON_INIT;
static bool sButtonPressed = false;
static bool sRxOnIdleButtonPressed = false;
static bool sLedOn = false;
static bool sAllowDeepSleep = false;
static bool sTaskletsPendingSem = true;
int main(int argc, char *argv[])
{
otLinkModeConfig config;
otSysInit(argc, argv);
gpioInit(buttonCallback);
instance = otInstanceInitSingle();
assert(instance);
otCliUartInit(instance);
otLinkSetPollPeriod(instance, SLEEPY_POLL_PERIOD_MS);
setNetworkConfiguration(instance);
otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
config.mRxOnWhenIdle = true;
config.mSecureDataRequests = true;
config.mDeviceType = 0;
config.mNetworkData = 0;
otThreadSetLinkMode(instance, config);
initUdp();
otIp6SetEnabled(instance, true);
otThreadSetEnabled(instance, true);
efr32SetSleepCallback(sleepCb);
#if OPENTHREAD_ENABLE_DIAG
otDiagInit(instance);
#endif
while (!otSysPseudoResetWasRequested())
{
otTaskletsProcess(instance);
otSysProcessDrivers(instance);
applicationTick();
// Put the EFR32 into deep sleep if callback sleepCb permits.
efr32Sleep();
}
otInstanceFinalize(instance);
return 0;
}
/*
* Callback from efr32Sleep to indicate if it is ok to go into sleep mode.
* This runs with interrupts disabled.
*/
bool sleepCb(void)
{
bool allow;
allow = (sAllowDeepSleep && !sTaskletsPendingSem);
sTaskletsPendingSem = false;
return allow;
}
void otTaskletsSignalPending(otInstance *aInstance)
{
(void)aInstance;
sTaskletsPendingSem = true;
}
/*
* Override default network settings, such as panid, so the devices can join a network
*/
void setNetworkConfiguration(otInstance *aInstance)
{
static char aNetworkName[] = "SleepyEFR32";
otOperationalDataset aDataset;
memset(&aDataset, 0, sizeof(otOperationalDataset));
/*
* Fields that can be configured in otOperationDataset to override defaults:
* Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
* Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
*/
aDataset.mActiveTimestamp = 1;
aDataset.mComponents.mIsActiveTimestampPresent = true;
/* Set Channel to 15 */
aDataset.mChannel = 15;
aDataset.mComponents.mIsChannelPresent = true;
/* Set Pan ID to 2222 */
aDataset.mPanId = (otPanId)0x2222;
aDataset.mComponents.mIsPanIdPresent = true;
/* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
aDataset.mComponents.mIsExtendedPanIdPresent = true;
/* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5};
memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
aDataset.mComponents.mIsMasterKeyPresent = true;
/* Set Network Name to SleepyEFR32 */
size_t length = strlen(aNetworkName);
assert(length <= OT_NETWORK_NAME_MAX_SIZE);
memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
aDataset.mComponents.mIsNetworkNamePresent = true;
otDatasetSetActive(aInstance, &aDataset);
}
void OTCALL handleNetifStateChanged(uint32_t aFlags, void *aContext)
{
otLinkModeConfig config;
if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
{
otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
switch (changedRole)
{
case OT_DEVICE_ROLE_LEADER:
case OT_DEVICE_ROLE_ROUTER:
break;
case OT_DEVICE_ROLE_CHILD:
config.mRxOnWhenIdle = 0;
config.mSecureDataRequests = true;
config.mDeviceType = 0;
config.mNetworkData = 0;
otThreadSetLinkMode(instance, config);
sAllowDeepSleep = true;
break;
case OT_DEVICE_ROLE_DETACHED:
case OT_DEVICE_ROLE_DISABLED:
break;
}
}
}
/*
* Provide, if required an "otPlatLog()" function
*/
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
{
OT_UNUSED_VARIABLE(aLogLevel);
OT_UNUSED_VARIABLE(aLogRegion);
OT_UNUSED_VARIABLE(aFormat);
va_list ap;
va_start(ap, aFormat);
otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
va_end(ap);
}
#endif
void gpioInit(void (*callback)(uint8_t pin))
{
// set up button GPIOs to input with pullups
for (int i = 0; i < BSP_BUTTON_COUNT; i++)
{
GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
}
// set up interrupt based callback function on falling edge
GPIOINT_Init();
GPIOINT_CallbackRegister(sButtonArray[0].pin, callback);
GPIOINT_CallbackRegister(sButtonArray[1].pin, callback);
GPIO_IntConfig(sButtonArray[0].port, sButtonArray[0].pin, false, true, true);
GPIO_IntConfig(sButtonArray[1].port, sButtonArray[1].pin, false, true, true);
BSP_LedsInit();
BSP_LedClear(0);
BSP_LedClear(1);
}
void initUdp(void)
{
otError error;
otSockAddr sockaddr;
memset(&sMulticastSockAddr, 0, sizeof sMulticastSockAddr);
otIp6AddressFromString(MULTICAST_ADDR, &sMulticastSockAddr.mAddress);
sMulticastSockAddr.mPort = MULTICAST_PORT;
sMulticastSockAddr.mScopeId = OT_NETIF_INTERFACE_ID_THREAD;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.mPort = RECV_PORT;
sockaddr.mScopeId = OT_NETIF_INTERFACE_ID_THREAD;
error = otUdpOpen(instance, &sMtdSocket, mtdReceiveCallback, NULL);
if (error != OT_ERROR_NONE)
{
return;
}
error = otUdpBind(&sMtdSocket, &sockaddr);
if (error != OT_ERROR_NONE)
{
otUdpClose(&sMtdSocket);
return;
}
}
void buttonCallback(uint8_t pin)
{
if ((pin & 0x01) == 0x01)
{
sButtonPressed = true;
}
else if ((pin & 0x01) == 0x00)
{
sRxOnIdleButtonPressed = true;
}
}
void applicationTick(void)
{
otError error = 0;
otMessageInfo messageInfo;
otMessage * message = NULL;
char * payload = MTD_MESSAGE;
otLinkModeConfig config;
if (sRxOnIdleButtonPressed == true)
{
sRxOnIdleButtonPressed = false;
sAllowDeepSleep = !sAllowDeepSleep;
config.mRxOnWhenIdle = !sAllowDeepSleep;
config.mSecureDataRequests = true;
config.mDeviceType = 0;
config.mNetworkData = 0;
otThreadSetLinkMode(instance, config);
}
if (sButtonPressed == true)
{
sButtonPressed = false;
memset(&messageInfo, 0, sizeof(messageInfo));
memcpy(&messageInfo.mPeerAddr, &sMulticastSockAddr.mAddress, sizeof messageInfo.mPeerAddr);
messageInfo.mPeerPort = sMulticastSockAddr.mPort;
messageInfo.mInterfaceId = sMulticastSockAddr.mScopeId;
message = otUdpNewMessage(instance, NULL);
if (message != NULL)
{
error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
if (error == OT_ERROR_NONE)
{
error = otUdpSend(&sMtdSocket, message, &messageInfo);
if (error == OT_ERROR_NONE)
{
return;
}
}
}
if (message != NULL)
{
otMessageFree(message);
}
}
}
void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
{
OT_UNUSED_VARIABLE(aContext);
OT_UNUSED_VARIABLE(aMessage);
OT_UNUSED_VARIABLE(aMessageInfo);
uint8_t buf[1500];
int length;
length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
buf[length] = '\0';
if (strcmp((char *)buf, FTD_MESSAGE) == 0)
{
sLedOn = !sLedOn;
if (sLedOn)
{
BSP_LedSet(0);
}
else
{
BSP_LedClear(0);
}
}
}
+46 -2
View File
@@ -34,19 +34,24 @@
#include <string.h>
#include <openthread/tasklet.h>
#include <openthread/platform/uart.h>
#include "common/logging.hpp"
#include "bsp.h"
#include "em_chip.h"
#include "em_core.h"
#include "em_emu.h"
#include "em_system.h"
#include "hal-config.h"
#include "hal_common.h"
#include "rail.h"
#include "rtcdriver.h"
#include "openthread-core-efr32-config.h"
#include "platform-efr32.h"
#include "hal-config.h"
#if (HAL_FEM_ENABLE)
#include "fem-control.h"
#endif
@@ -58,6 +63,7 @@
void halInitChipSpecific(void);
otInstance *sInstance;
static bool (*sCanSleepCallback)(void);
void otSysInit(int argc, char *argv[])
{
@@ -98,6 +104,44 @@ void otSysDeinit(void)
#endif
}
void efr32SetSleepCallback(bool (*aCallback)(void))
{
sCanSleepCallback = aCallback;
}
void efr32Sleep(void)
{
bool canDeepSleep = false;
int wakeupProcessTime = 1000;
CORE_DECLARE_IRQ_STATE;
if (RAIL_Sleep(wakeupProcessTime, &canDeepSleep) == RAIL_STATUS_NO_ERROR)
{
if (canDeepSleep)
{
CORE_ENTER_ATOMIC();
if (sCanSleepCallback != NULL && sCanSleepCallback())
{
EMU_EnterEM2(true);
}
CORE_EXIT_ATOMIC();
while (RAIL_Wake(0) != RAIL_STATUS_NO_ERROR)
{
}
}
else
{
CORE_ENTER_ATOMIC();
if (sCanSleepCallback != NULL && sCanSleepCallback())
{
EMU_EnterEM1();
}
CORE_EXIT_ATOMIC();
}
}
}
void otSysProcessDrivers(otInstance *aInstance)
{
sInstance = aInstance;