2 * Copyright (c) 2020, 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.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/logging.h>
55 #define MULTICAST_ADDR "ff03::1"
56 #define MULTICAST_PORT 123
58 #define SLEEPY_POLL_PERIOD_MS 5000
59 #define MTD_MESSAGE "mtd button"
60 #define FTD_MESSAGE "ftd button"
63 typedef struct ButtonArray
65 GPIO_Port_TypeDef port;
71 void setNetworkConfiguration(otInstance *aInstance);
72 void handleNetifStateChanged(uint32_t aFlags, void *aContext);
73 void gpioInit(void (*gpioCallback)(uint8_t pin));
74 void buttonCallback(uint8_t pin);
76 void applicationTick(void);
77 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
80 static otInstance * instance;
81 static otUdpSocket sMtdSocket;
82 static otSockAddr sMulticastSockAddr;
83 static const ButtonArray_t sButtonArray[BSP_BUTTON_COUNT] = BSP_BUTTON_INIT;
84 static bool sButtonPressed = false;
85 static bool sRxOnIdleButtonPressed = false;
86 static bool sLedOn = false;
87 static bool sAllowDeepSleep = false;
88 static bool sTaskletsPendingSem = true;
90 int main(int argc, char *argv[])
92 otLinkModeConfig config;
94 otSysInit(argc, argv);
95 gpioInit(buttonCallback);
97 instance = otInstanceInitSingle();
100 otCliUartInit(instance);
102 otLinkSetPollPeriod(instance, SLEEPY_POLL_PERIOD_MS);
103 setNetworkConfiguration(instance);
104 otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
106 config.mRxOnWhenIdle = true;
107 config.mSecureDataRequests = true;
108 config.mDeviceType = 0;
109 config.mNetworkData = 0;
110 otThreadSetLinkMode(instance, config);
113 otIp6SetEnabled(instance, true);
114 otThreadSetEnabled(instance, true);
115 efr32SetSleepCallback(sleepCb);
117 while (!otSysPseudoResetWasRequested())
119 otTaskletsProcess(instance);
120 otSysProcessDrivers(instance);
124 // Put the EFR32 into deep sleep if callback sleepCb permits.
128 otInstanceFinalize(instance);
133 * Callback from efr32Sleep to indicate if it is ok to go into sleep mode.
134 * This runs with interrupts disabled.
139 allow = (sAllowDeepSleep && !sTaskletsPendingSem);
140 sTaskletsPendingSem = false;
144 void otTaskletsSignalPending(otInstance *aInstance)
147 sTaskletsPendingSem = true;
151 * Override default network settings, such as panid, so the devices can join a network
153 void setNetworkConfiguration(otInstance *aInstance)
155 static char aNetworkName[] = "SleepyEFR32";
156 otOperationalDataset aDataset;
158 memset(&aDataset, 0, sizeof(otOperationalDataset));
161 * Fields that can be configured in otOperationDataset to override defaults:
162 * Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
163 * Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
165 aDataset.mActiveTimestamp = 1;
166 aDataset.mComponents.mIsActiveTimestampPresent = true;
168 /* Set Channel to 15 */
169 aDataset.mChannel = 15;
170 aDataset.mComponents.mIsChannelPresent = true;
172 /* Set Pan ID to 2222 */
173 aDataset.mPanId = (otPanId)0x2222;
174 aDataset.mComponents.mIsPanIdPresent = true;
176 /* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
177 uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
178 memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
179 aDataset.mComponents.mIsExtendedPanIdPresent = true;
181 /* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
182 uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5};
183 memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
184 aDataset.mComponents.mIsMasterKeyPresent = true;
186 /* Set Network Name to SleepyEFR32 */
187 size_t length = strlen(aNetworkName);
188 assert(length <= OT_NETWORK_NAME_MAX_SIZE);
189 memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
190 aDataset.mComponents.mIsNetworkNamePresent = true;
192 otDatasetSetActive(aInstance, &aDataset);
195 void handleNetifStateChanged(uint32_t aFlags, void *aContext)
197 otLinkModeConfig config;
199 if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
201 otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
205 case OT_DEVICE_ROLE_LEADER:
206 case OT_DEVICE_ROLE_ROUTER:
209 case OT_DEVICE_ROLE_CHILD:
210 config.mRxOnWhenIdle = 0;
211 config.mSecureDataRequests = true;
212 config.mDeviceType = 0;
213 config.mNetworkData = 0;
214 otThreadSetLinkMode(instance, config);
215 sAllowDeepSleep = true;
218 case OT_DEVICE_ROLE_DETACHED:
219 case OT_DEVICE_ROLE_DISABLED:
226 * Provide, if required an "otPlatLog()" function
228 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
229 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
231 OT_UNUSED_VARIABLE(aLogLevel);
232 OT_UNUSED_VARIABLE(aLogRegion);
233 OT_UNUSED_VARIABLE(aFormat);
236 va_start(ap, aFormat);
237 otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
242 void gpioInit(void (*callback)(uint8_t pin))
244 // set up button GPIOs to input with pullups
245 for (int i = 0; i < BSP_BUTTON_COUNT; i++)
247 GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
249 // set up interrupt based callback function on falling edge
251 GPIOINT_CallbackRegister(sButtonArray[0].pin, callback);
252 GPIOINT_CallbackRegister(sButtonArray[1].pin, callback);
253 GPIO_IntConfig(sButtonArray[0].port, sButtonArray[0].pin, false, true, true);
254 GPIO_IntConfig(sButtonArray[1].port, sButtonArray[1].pin, false, true, true);
266 memset(&sMulticastSockAddr, 0, sizeof sMulticastSockAddr);
267 otIp6AddressFromString(MULTICAST_ADDR, &sMulticastSockAddr.mAddress);
268 sMulticastSockAddr.mPort = MULTICAST_PORT;
270 memset(&sockaddr, 0, sizeof(sockaddr));
271 sockaddr.mPort = RECV_PORT;
273 error = otUdpOpen(instance, &sMtdSocket, mtdReceiveCallback, NULL);
275 if (error != OT_ERROR_NONE)
280 error = otUdpBind(instance, &sMtdSocket, &sockaddr);
282 if (error != OT_ERROR_NONE)
284 otUdpClose(instance, &sMtdSocket);
289 void buttonCallback(uint8_t pin)
291 if ((pin & 0x01) == 0x01)
293 sButtonPressed = true;
295 else if ((pin & 0x01) == 0x00)
297 sRxOnIdleButtonPressed = true;
301 void applicationTick(void)
304 otMessageInfo messageInfo;
305 otMessage * message = NULL;
306 char * payload = MTD_MESSAGE;
307 otLinkModeConfig config;
309 if (sRxOnIdleButtonPressed == true)
311 sRxOnIdleButtonPressed = false;
312 sAllowDeepSleep = !sAllowDeepSleep;
313 config.mRxOnWhenIdle = !sAllowDeepSleep;
314 config.mSecureDataRequests = true;
315 config.mDeviceType = 0;
316 config.mNetworkData = 0;
317 otThreadSetLinkMode(instance, config);
320 if (sButtonPressed == true)
322 sButtonPressed = false;
324 memset(&messageInfo, 0, sizeof(messageInfo));
325 memcpy(&messageInfo.mPeerAddr, &sMulticastSockAddr.mAddress, sizeof messageInfo.mPeerAddr);
326 messageInfo.mPeerPort = sMulticastSockAddr.mPort;
328 message = otUdpNewMessage(instance, NULL);
332 error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
334 if (error == OT_ERROR_NONE)
336 error = otUdpSend(instance, &sMtdSocket, message, &messageInfo);
338 if (error == OT_ERROR_NONE)
347 otMessageFree(message);
352 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
354 OT_UNUSED_VARIABLE(aContext);
355 OT_UNUSED_VARIABLE(aMessage);
356 OT_UNUSED_VARIABLE(aMessageInfo);
360 length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
363 if (strcmp((char *)buf, FTD_MESSAGE) == 0)