mirror of
https://github.com/espressif/openthread.git
synced 2026-07-28 22:57:47 +00:00
[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:
committed by
Jonathan Hui
parent
0aa39f8d13
commit
1b9c50112e
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user