2 * Copyright (c) 2019, The OpenThread Authors.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
35 #include "gpiointerrupt.h"
36 #include "hal-config-board.h"
37 #include "hal_common.h"
38 #include "openthread-system.h"
39 #include "platform-efr32.h"
40 #include <common/logging.hpp>
41 #include <openthread-core-config.h>
42 #include <openthread/cli.h>
43 #include <openthread/config.h>
44 #include <openthread/dataset_ftd.h>
45 #include <openthread/diag.h>
46 #include <openthread/instance.h>
47 #include <openthread/link.h>
48 #include <openthread/message.h>
49 #include <openthread/tasklet.h>
50 #include <openthread/thread.h>
51 #include <openthread/udp.h>
52 #include <openthread/platform/alarm-milli.h>
53 #include <openthread/platform/logging.h>
56 #define MULTICAST_ADDR "ff03::1"
57 #define MULTICAST_PORT 123
59 #define SLEEPY_POLL_PERIOD_MS 5000
60 #define MTD_MESSAGE "mtd is awake"
61 #define FTD_MESSAGE "ftd button"
64 typedef struct ButtonArray
66 GPIO_Port_TypeDef port;
71 void deviceOutOfSleepCb(void);
73 void setNetworkConfiguration(otInstance *aInstance);
74 void handleNetifStateChanged(uint32_t aFlags, void *aContext);
75 void gpioInit(void (*gpioCallback)(uint8_t pin));
76 void buttonCallback(uint8_t pin);
78 void applicationTick(void);
79 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
82 static otInstance * instance;
83 static otUdpSocket sMtdSocket;
84 static otSockAddr sMulticastSockAddr;
85 static const ButtonArray_t sButtonArray[BSP_BUTTON_COUNT] = BSP_BUTTON_INIT;
86 static bool sButtonPressed = false;
87 static bool sRxOnIdleButtonPressed = false;
88 static bool sLedOn = false;
89 static bool sAllowDeepSleep = false;
90 static bool sTaskletsPendingSem = true;
92 int main(int argc, char *argv[])
94 otLinkModeConfig config;
96 otSysInit(argc, argv);
97 gpioInit(buttonCallback);
99 instance = otInstanceInitSingle();
102 otCliUartInit(instance);
104 otLinkSetPollPeriod(instance, SLEEPY_POLL_PERIOD_MS);
105 setNetworkConfiguration(instance);
106 otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
108 config.mRxOnWhenIdle = true;
109 config.mSecureDataRequests = true;
110 config.mDeviceType = 0;
111 config.mNetworkData = 0;
112 otThreadSetLinkMode(instance, config);
115 otIp6SetEnabled(instance, true);
116 otThreadSetEnabled(instance, true);
117 efr32SetSleepCallback(sleepCb, deviceOutOfSleepCb);
119 while (!otSysPseudoResetWasRequested())
121 otTaskletsProcess(instance);
122 otSysProcessDrivers(instance);
126 // Put the EFR32 into deep sleep if callback sleepCb permits.
130 otInstanceFinalize(instance);
134 void deviceOutOfSleepCb(void)
136 static uint32_t udpPacketSendTimer = 0;
138 if (udpPacketSendTimer == 0)
140 udpPacketSendTimer = otPlatAlarmMilliGetNow();
143 if ((otPlatAlarmMilliGetNow() - udpPacketSendTimer) >= 5000)
145 sButtonPressed = true;
146 udpPacketSendTimer = 0;
151 * Callback from efr32Sleep to indicate if it is ok to go into sleep mode.
152 * This runs with interrupts disabled.
157 allow = (sAllowDeepSleep && !sTaskletsPendingSem);
158 sTaskletsPendingSem = false;
162 void otTaskletsSignalPending(otInstance *aInstance)
165 sTaskletsPendingSem = true;
169 * Override default network settings, such as panid, so the devices can join a network
171 void setNetworkConfiguration(otInstance *aInstance)
173 static char aNetworkName[] = "SleepyEFR32";
174 otOperationalDataset aDataset;
176 memset(&aDataset, 0, sizeof(otOperationalDataset));
179 * Fields that can be configured in otOperationDataset to override defaults:
180 * Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
181 * Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
183 aDataset.mActiveTimestamp = 1;
184 aDataset.mComponents.mIsActiveTimestampPresent = true;
186 /* Set Channel to 15 */
187 aDataset.mChannel = 15;
188 aDataset.mComponents.mIsChannelPresent = true;
190 /* Set Pan ID to 2222 */
191 aDataset.mPanId = (otPanId)0x2222;
192 aDataset.mComponents.mIsPanIdPresent = true;
194 /* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
195 uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
196 memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
197 aDataset.mComponents.mIsExtendedPanIdPresent = true;
199 /* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
200 uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5};
201 memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
202 aDataset.mComponents.mIsMasterKeyPresent = true;
204 /* Set Network Name to SleepyEFR32 */
205 size_t length = strlen(aNetworkName);
206 assert(length <= OT_NETWORK_NAME_MAX_SIZE);
207 memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
208 aDataset.mComponents.mIsNetworkNamePresent = true;
210 otDatasetSetActive(aInstance, &aDataset);
213 void handleNetifStateChanged(uint32_t aFlags, void *aContext)
215 otLinkModeConfig config;
217 if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
219 otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
223 case OT_DEVICE_ROLE_LEADER:
224 case OT_DEVICE_ROLE_ROUTER:
227 case OT_DEVICE_ROLE_CHILD:
228 config.mRxOnWhenIdle = 0;
229 config.mSecureDataRequests = true;
230 config.mDeviceType = 0;
231 config.mNetworkData = 0;
232 otThreadSetLinkMode(instance, config);
233 sAllowDeepSleep = true;
236 case OT_DEVICE_ROLE_DETACHED:
237 case OT_DEVICE_ROLE_DISABLED:
244 * Provide, if required an "otPlatLog()" function
246 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
247 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
249 OT_UNUSED_VARIABLE(aLogLevel);
250 OT_UNUSED_VARIABLE(aLogRegion);
251 OT_UNUSED_VARIABLE(aFormat);
254 va_start(ap, aFormat);
255 otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
260 void gpioInit(void (*callback)(uint8_t pin))
262 // set up button GPIOs to input with pullups
263 for (int i = 0; i < BSP_BUTTON_COUNT; i++)
265 GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
267 // set up interrupt based callback function on falling edge
269 GPIOINT_CallbackRegister(sButtonArray[0].pin, callback);
270 GPIOINT_CallbackRegister(sButtonArray[1].pin, callback);
271 GPIO_IntConfig(sButtonArray[0].port, sButtonArray[0].pin, false, true, true);
272 GPIO_IntConfig(sButtonArray[1].port, sButtonArray[1].pin, false, true, true);
284 memset(&sMulticastSockAddr, 0, sizeof sMulticastSockAddr);
285 otIp6AddressFromString(MULTICAST_ADDR, &sMulticastSockAddr.mAddress);
286 sMulticastSockAddr.mPort = MULTICAST_PORT;
288 memset(&sockaddr, 0, sizeof(sockaddr));
289 sockaddr.mPort = RECV_PORT;
291 error = otUdpOpen(instance, &sMtdSocket, mtdReceiveCallback, NULL);
293 if (error != OT_ERROR_NONE)
298 error = otUdpBind(instance, &sMtdSocket, &sockaddr);
300 if (error != OT_ERROR_NONE)
302 otUdpClose(instance, &sMtdSocket);
307 void buttonCallback(uint8_t pin)
309 if ((pin & 0x01) == 0x01)
311 sButtonPressed = true;
313 else if ((pin & 0x01) == 0x00)
315 sRxOnIdleButtonPressed = true;
319 void applicationTick(void)
322 otMessageInfo messageInfo;
323 otMessage * message = NULL;
324 char * payload = MTD_MESSAGE;
325 otLinkModeConfig config;
327 if (sRxOnIdleButtonPressed == true)
329 sRxOnIdleButtonPressed = false;
330 sAllowDeepSleep = !sAllowDeepSleep;
331 config.mRxOnWhenIdle = !sAllowDeepSleep;
332 config.mSecureDataRequests = true;
333 config.mDeviceType = 0;
334 config.mNetworkData = 0;
335 otThreadSetLinkMode(instance, config);
338 if (sButtonPressed == true)
340 sButtonPressed = false;
342 memset(&messageInfo, 0, sizeof(messageInfo));
343 memcpy(&messageInfo.mPeerAddr, &sMulticastSockAddr.mAddress, sizeof messageInfo.mPeerAddr);
344 messageInfo.mPeerPort = sMulticastSockAddr.mPort;
346 message = otUdpNewMessage(instance, NULL);
350 error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
352 if (error == OT_ERROR_NONE)
354 error = otUdpSend(instance, &sMtdSocket, message, &messageInfo);
356 if (error == OT_ERROR_NONE)
365 otMessageFree(message);
370 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
372 OT_UNUSED_VARIABLE(aContext);
373 OT_UNUSED_VARIABLE(aMessage);
374 OT_UNUSED_VARIABLE(aMessageInfo);
378 length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
381 if (strcmp((char *)buf, FTD_MESSAGE) == 0)