e54fe821352c49586a4a7f9792a93b0538a33501
[platform/upstream/connectedhomeip.git] / third_party / openthread / repo / examples / platforms / efr32mg21 / sleepy-demo / sleepy-demo-ftd / 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 "bsp.h"
30 #include "em_cmu.h"
31 #include "em_emu.h"
32 #include "gpiointerrupt.h"
33 #include "hal-config-board.h"
34 #include "hal_common.h"
35 #include "openthread-system.h"
36 #include <assert.h>
37 #include <common/logging.hpp>
38 #include <openthread-core-config.h>
39 #include <string.h>
40 #include <openthread/cli.h>
41 #include <openthread/config.h>
42 #include <openthread/dataset_ftd.h>
43 #include <openthread/diag.h>
44 #include <openthread/instance.h>
45 #include <openthread/message.h>
46 #include <openthread/tasklet.h>
47 #include <openthread/thread.h>
48 #include <openthread/udp.h>
49 #include <openthread/platform/logging.h>
50
51 // Constants
52 #define MULTICAST_ADDR "ff03::1"
53 #define MULTICAST_PORT 123
54 #define RECV_PORT 234
55 #define MTD_MESSAGE "mtd button"
56 #define FTD_MESSAGE "ftd button"
57
58 // Types
59 typedef struct ButtonArray
60 {
61     GPIO_Port_TypeDef port;
62     unsigned int      pin;
63 } ButtonArray_t;
64
65 // Prototypes
66 void setNetworkConfiguration(otInstance *aInstance);
67 void handleNetifStateChanged(uint32_t aFlags, void *aContext);
68 void gpioInit(void (*gpioCallback)(uint8_t pin));
69 void buttonCallback(uint8_t pin);
70 void initUdp(void);
71 void applicationTick(void);
72 void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
73
74 // Variables
75 static otInstance *        instance;
76 static otUdpSocket         sFtdSocket;
77 static bool                sLedOn             = false;
78 static bool                sHaveSwitchAddress = false;
79 static otIp6Address        sSwitchAddress;
80 static bool                sFtdButtonPressed              = false;
81 static const ButtonArray_t sButtonArray[BSP_BUTTON_COUNT] = BSP_BUTTON_INIT;
82
83 void otTaskletsSignalPending(otInstance *aInstance)
84 {
85     (void)aInstance;
86 }
87
88 int main(int argc, char *argv[])
89 {
90     otSysInit(argc, argv);
91     gpioInit(buttonCallback);
92
93     instance = otInstanceInitSingle();
94     assert(instance);
95
96     otCliUartInit(instance);
97     otCliOutputFormat("sleepy-demo-ftd started\r\n");
98
99     setNetworkConfiguration(instance);
100     otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
101     initUdp();
102
103     otIp6SetEnabled(instance, true);
104     otThreadSetEnabled(instance, true);
105
106     while (!otSysPseudoResetWasRequested())
107     {
108         otTaskletsProcess(instance);
109         otSysProcessDrivers(instance);
110         applicationTick();
111     }
112
113     otInstanceFinalize(instance);
114     return 0;
115 }
116
117 /*
118  * Provide, if required an "otPlatLog()" function
119  */
120 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
121 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
122 {
123     OT_UNUSED_VARIABLE(aLogLevel);
124     OT_UNUSED_VARIABLE(aLogRegion);
125     OT_UNUSED_VARIABLE(aFormat);
126
127     va_list ap;
128     va_start(ap, aFormat);
129     otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
130     va_end(ap);
131 }
132 #endif
133
134 /**
135  * Override default network settings, such as panid, so the devices can join a network
136  */
137 void setNetworkConfiguration(otInstance *aInstance)
138 {
139     static char          aNetworkName[] = "SleepyEFR32";
140     otOperationalDataset aDataset;
141
142     memset(&aDataset, 0, sizeof(otOperationalDataset));
143
144     /*
145      * Fields that can be configured in otOperationDataset to override defaults:
146      *     Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID, Delay Timer,
147      *     Channel, Channel Mask Page 0, Network Master Key, PSKc, Security Policy
148      */
149     aDataset.mActiveTimestamp                      = 1;
150     aDataset.mComponents.mIsActiveTimestampPresent = true;
151
152     /* Set Channel to 15 */
153     aDataset.mChannel                      = 15;
154     aDataset.mComponents.mIsChannelPresent = true;
155
156     /* Set Pan ID to 2222 */
157     aDataset.mPanId                      = (otPanId)0x2222;
158     aDataset.mComponents.mIsPanIdPresent = true;
159
160     /* Set Extended Pan ID to C0DE1AB5C0DE1AB5 */
161     uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = {0xC0, 0xDE, 0x1A, 0xB5, 0xC0, 0xDE, 0x1A, 0xB5};
162     memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
163     aDataset.mComponents.mIsExtendedPanIdPresent = true;
164
165     /* Set master key to 1234C0DE1AB51234C0DE1AB51234C0DE */
166     uint8_t key[OT_MASTER_KEY_SIZE] = {0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5, 0x12, 0x34, 0xC0, 0xDE, 0x1A, 0xB5};
167     memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
168     aDataset.mComponents.mIsMasterKeyPresent = true;
169
170     /* Set Network Name to SleepyEFR32 */
171     size_t length = strlen(aNetworkName);
172     assert(length <= OT_NETWORK_NAME_MAX_SIZE);
173     memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
174     aDataset.mComponents.mIsNetworkNamePresent = true;
175
176     otDatasetSetActive(aInstance, &aDataset);
177 }
178
179 void handleNetifStateChanged(uint32_t aFlags, void *aContext)
180 {
181     if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
182     {
183         otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
184
185         switch (changedRole)
186         {
187         case OT_DEVICE_ROLE_LEADER:
188             otCliOutputFormat("sleepy-demo-ftd changed to leader\r\n");
189             break;
190         case OT_DEVICE_ROLE_ROUTER:
191             otCliOutputFormat("sleepy-demo-ftd changed to router\r\n");
192             break;
193
194         case OT_DEVICE_ROLE_CHILD:
195             break;
196
197         case OT_DEVICE_ROLE_DETACHED:
198         case OT_DEVICE_ROLE_DISABLED:
199             break;
200         }
201     }
202 }
203
204 void gpioInit(void (*callback)(uint8_t pin))
205 {
206     // set up button GPIOs to input with pullups
207     for (int i = 0; i < BSP_BUTTON_COUNT; i++)
208     {
209         GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
210     }
211     // set up interrupt based callback function on falling edge
212     GPIOINT_Init();
213     GPIOINT_CallbackRegister(sButtonArray[0].pin, callback);
214     GPIOINT_CallbackRegister(sButtonArray[1].pin, callback);
215     GPIO_IntConfig(sButtonArray[0].port, sButtonArray[0].pin, false, true, true);
216     GPIO_IntConfig(sButtonArray[1].port, sButtonArray[1].pin, false, true, true);
217
218     BSP_LedsInit();
219     BSP_LedClear(0);
220     BSP_LedClear(1);
221 }
222
223 void initUdp(void)
224 {
225     otError    error;
226     otSockAddr sockaddr;
227
228     memset(&sockaddr, 0, sizeof(sockaddr));
229
230     otIp6AddressFromString(MULTICAST_ADDR, &sockaddr.mAddress);
231     sockaddr.mPort = MULTICAST_PORT;
232
233     error = otUdpOpen(instance, &sFtdSocket, sFtdReceiveCallback, NULL);
234     if (error != OT_ERROR_NONE)
235     {
236         otCliOutputFormat("FTD failed to open udp multicast\r\n");
237         return;
238     }
239
240     error = otUdpBind(instance, &sFtdSocket, &sockaddr);
241     if (error != OT_ERROR_NONE)
242     {
243         otUdpClose(instance, &sFtdSocket);
244         otCliOutputFormat("FTD failed to bind udp multicast\r\n");
245         return;
246     }
247 }
248
249 void buttonCallback(uint8_t pin)
250 {
251     OT_UNUSED_VARIABLE(pin);
252     sFtdButtonPressed = true;
253 }
254
255 void applicationTick(void)
256 {
257     otError       error = 0;
258     otMessageInfo messageInfo;
259     otMessage *   message = NULL;
260     char *        payload = FTD_MESSAGE;
261
262     if (sFtdButtonPressed == true)
263     {
264         sFtdButtonPressed = false;
265
266         if (sHaveSwitchAddress)
267         {
268             memset(&messageInfo, 0, sizeof(messageInfo));
269             memcpy(&messageInfo.mPeerAddr, &sSwitchAddress, sizeof messageInfo.mPeerAddr);
270             messageInfo.mPeerPort = RECV_PORT;
271
272             message = otUdpNewMessage(instance, NULL);
273
274             if (message != NULL)
275             {
276                 error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
277
278                 if (error == OT_ERROR_NONE)
279                 {
280                     error = otUdpSend(instance, &sFtdSocket, message, &messageInfo);
281
282                     if (error == OT_ERROR_NONE)
283                     {
284                         return;
285                     }
286                 }
287             }
288
289             if (message != NULL)
290             {
291                 otMessageFree(message);
292             }
293         }
294     }
295 }
296
297 void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
298 {
299     OT_UNUSED_VARIABLE(aContext);
300     OT_UNUSED_VARIABLE(aMessage);
301     OT_UNUSED_VARIABLE(aMessageInfo);
302     uint8_t buf[1500];
303     int     length;
304
305     sLedOn = !sLedOn;
306
307     if (sLedOn)
308     {
309         BSP_LedSet(0);
310     }
311     else
312     {
313         BSP_LedClear(0);
314     }
315
316     length      = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
317     buf[length] = '\0';
318     otCliOutputFormat("Message Received: %s\r\n", buf);
319
320     sHaveSwitchAddress = true;
321     memcpy(&sSwitchAddress, &aMessageInfo->mPeerAddr, sizeof sSwitchAddress);
322 }