ebb3169eb7aa83f565fd08e5a132bb70086b4250
[platform/upstream/connectedhomeip.git] / third_party / openthread / repo / examples / platforms / efr32mg21 / sleepy-demo / sleepy-demo-mtd / main.c
1 /*
2  *  Copyright (c) 2019, The OpenThread Authors.
3  *  All rights reserved.
4  *
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.
15  *
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.
27  */
28
29 #include <assert.h>
30 #include <string.h>
31
32 #include "bsp.h"
33 #include "em_cmu.h"
34 #include "em_emu.h"
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>
54
55 // Constants
56 #define MULTICAST_ADDR "ff03::1"
57 #define MULTICAST_PORT 123
58 #define RECV_PORT 234
59 #define SLEEPY_POLL_PERIOD_MS 5000
60 #define MTD_MESSAGE "mtd is awake"
61 #define FTD_MESSAGE "ftd button"
62
63 // Types
64 typedef struct ButtonArray
65 {
66     GPIO_Port_TypeDef port;
67     unsigned int      pin;
68 } ButtonArray_t;
69
70 // Prototypes
71 void deviceOutOfSleepCb(void);
72 bool sleepCb(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);
77 void initUdp(void);
78 void applicationTick(void);
79 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
80
81 // Variables
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;
91
92 int main(int argc, char *argv[])
93 {
94     otLinkModeConfig config;
95
96     otSysInit(argc, argv);
97     gpioInit(buttonCallback);
98
99     instance = otInstanceInitSingle();
100     assert(instance);
101
102     otCliUartInit(instance);
103
104     otLinkSetPollPeriod(instance, SLEEPY_POLL_PERIOD_MS);
105     setNetworkConfiguration(instance);
106     otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
107
108     config.mRxOnWhenIdle       = true;
109     config.mSecureDataRequests = true;
110     config.mDeviceType         = 0;
111     config.mNetworkData        = 0;
112     otThreadSetLinkMode(instance, config);
113
114     initUdp();
115     otIp6SetEnabled(instance, true);
116     otThreadSetEnabled(instance, true);
117     efr32SetSleepCallback(sleepCb, deviceOutOfSleepCb);
118
119     while (!otSysPseudoResetWasRequested())
120     {
121         otTaskletsProcess(instance);
122         otSysProcessDrivers(instance);
123
124         applicationTick();
125
126         // Put the EFR32 into deep sleep if callback sleepCb permits.
127         efr32Sleep();
128     }
129
130     otInstanceFinalize(instance);
131     return 0;
132 }
133
134 void deviceOutOfSleepCb(void)
135 {
136     static uint32_t udpPacketSendTimer = 0;
137
138     if (udpPacketSendTimer == 0)
139     {
140         udpPacketSendTimer = otPlatAlarmMilliGetNow();
141     }
142
143     if ((otPlatAlarmMilliGetNow() - udpPacketSendTimer) >= 5000)
144     {
145         sButtonPressed     = true;
146         udpPacketSendTimer = 0;
147     }
148 }
149
150 /*
151  * Callback from efr32Sleep to indicate if it is ok to go into sleep mode.
152  * This runs with interrupts disabled.
153  */
154 bool sleepCb(void)
155 {
156     bool allow;
157     allow               = (sAllowDeepSleep && !sTaskletsPendingSem);
158     sTaskletsPendingSem = false;
159     return allow;
160 }
161
162 void otTaskletsSignalPending(otInstance *aInstance)
163 {
164     (void)aInstance;
165     sTaskletsPendingSem = true;
166 }
167
168 /*
169  * Override default network settings, such as panid, so the devices can join a network
170  */
171 void setNetworkConfiguration(otInstance *aInstance)
172 {
173     static char          aNetworkName[] = "SleepyEFR32";
174     otOperationalDataset aDataset;
175
176     memset(&aDataset, 0, sizeof(otOperationalDataset));
177
178     /*
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
182      */
183     aDataset.mActiveTimestamp                      = 1;
184     aDataset.mComponents.mIsActiveTimestampPresent = true;
185
186     /* Set Channel to 15 */
187     aDataset.mChannel                      = 15;
188     aDataset.mComponents.mIsChannelPresent = true;
189
190     /* Set Pan ID to 2222 */
191     aDataset.mPanId                      = (otPanId)0x2222;
192     aDataset.mComponents.mIsPanIdPresent = true;
193
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;
198
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;
203
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;
209
210     otDatasetSetActive(aInstance, &aDataset);
211 }
212
213 void handleNetifStateChanged(uint32_t aFlags, void *aContext)
214 {
215     otLinkModeConfig config;
216
217     if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
218     {
219         otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
220
221         switch (changedRole)
222         {
223         case OT_DEVICE_ROLE_LEADER:
224         case OT_DEVICE_ROLE_ROUTER:
225             break;
226
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;
234             break;
235
236         case OT_DEVICE_ROLE_DETACHED:
237         case OT_DEVICE_ROLE_DISABLED:
238             break;
239         }
240     }
241 }
242
243 /*
244  * Provide, if required an "otPlatLog()" function
245  */
246 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
247 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
248 {
249     OT_UNUSED_VARIABLE(aLogLevel);
250     OT_UNUSED_VARIABLE(aLogRegion);
251     OT_UNUSED_VARIABLE(aFormat);
252
253     va_list ap;
254     va_start(ap, aFormat);
255     otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
256     va_end(ap);
257 }
258 #endif
259
260 void gpioInit(void (*callback)(uint8_t pin))
261 {
262     // set up button GPIOs to input with pullups
263     for (int i = 0; i < BSP_BUTTON_COUNT; i++)
264     {
265         GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
266     }
267     // set up interrupt based callback function on falling edge
268     GPIOINT_Init();
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);
273
274     BSP_LedsInit();
275     BSP_LedClear(0);
276     BSP_LedClear(1);
277 }
278
279 void initUdp(void)
280 {
281     otError    error;
282     otSockAddr sockaddr;
283
284     memset(&sMulticastSockAddr, 0, sizeof sMulticastSockAddr);
285     otIp6AddressFromString(MULTICAST_ADDR, &sMulticastSockAddr.mAddress);
286     sMulticastSockAddr.mPort = MULTICAST_PORT;
287
288     memset(&sockaddr, 0, sizeof(sockaddr));
289     sockaddr.mPort = RECV_PORT;
290
291     error = otUdpOpen(instance, &sMtdSocket, mtdReceiveCallback, NULL);
292
293     if (error != OT_ERROR_NONE)
294     {
295         return;
296     }
297
298     error = otUdpBind(instance, &sMtdSocket, &sockaddr);
299
300     if (error != OT_ERROR_NONE)
301     {
302         otUdpClose(instance, &sMtdSocket);
303         return;
304     }
305 }
306
307 void buttonCallback(uint8_t pin)
308 {
309     if ((pin & 0x01) == 0x01)
310     {
311         sButtonPressed = true;
312     }
313     else if ((pin & 0x01) == 0x00)
314     {
315         sRxOnIdleButtonPressed = true;
316     }
317 }
318
319 void applicationTick(void)
320 {
321     otError          error = 0;
322     otMessageInfo    messageInfo;
323     otMessage *      message = NULL;
324     char *           payload = MTD_MESSAGE;
325     otLinkModeConfig config;
326
327     if (sRxOnIdleButtonPressed == true)
328     {
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);
336     }
337
338     if (sButtonPressed == true)
339     {
340         sButtonPressed = false;
341
342         memset(&messageInfo, 0, sizeof(messageInfo));
343         memcpy(&messageInfo.mPeerAddr, &sMulticastSockAddr.mAddress, sizeof messageInfo.mPeerAddr);
344         messageInfo.mPeerPort = sMulticastSockAddr.mPort;
345
346         message = otUdpNewMessage(instance, NULL);
347
348         if (message != NULL)
349         {
350             error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
351
352             if (error == OT_ERROR_NONE)
353             {
354                 error = otUdpSend(instance, &sMtdSocket, message, &messageInfo);
355
356                 if (error == OT_ERROR_NONE)
357                 {
358                     return;
359                 }
360             }
361         }
362
363         if (message != NULL)
364         {
365             otMessageFree(message);
366         }
367     }
368 }
369
370 void mtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
371 {
372     OT_UNUSED_VARIABLE(aContext);
373     OT_UNUSED_VARIABLE(aMessage);
374     OT_UNUSED_VARIABLE(aMessageInfo);
375     uint8_t buf[1500];
376     int     length;
377
378     length      = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
379     buf[length] = '\0';
380
381     if (strcmp((char *)buf, FTD_MESSAGE) == 0)
382     {
383         sLedOn = !sLedOn;
384
385         if (sLedOn)
386         {
387             BSP_LedSet(0);
388         }
389         else
390         {
391             BSP_LedClear(0);
392         }
393     }
394 }