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