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.
32 #include "gpiointerrupt.h"
33 #include "hal-config-board.h"
34 #include "hal_common.h"
35 #include "openthread-system.h"
37 #include <common/logging.hpp>
38 #include <openthread-core-config.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>
52 #define MULTICAST_ADDR "ff03::1"
53 #define MULTICAST_PORT 123
55 #define MTD_MESSAGE "mtd button"
56 #define FTD_MESSAGE "ftd button"
59 typedef struct ButtonArray
61 GPIO_Port_TypeDef port;
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);
71 void applicationTick(void);
72 void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo);
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;
83 void otTaskletsSignalPending(otInstance *aInstance)
88 int main(int argc, char *argv[])
90 otSysInit(argc, argv);
91 gpioInit(buttonCallback);
93 instance = otInstanceInitSingle();
96 otCliUartInit(instance);
97 otCliOutputFormat("sleepy-demo-ftd started\r\n");
99 setNetworkConfiguration(instance);
100 otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
103 otIp6SetEnabled(instance, true);
104 otThreadSetEnabled(instance, true);
106 while (!otSysPseudoResetWasRequested())
108 otTaskletsProcess(instance);
109 otSysProcessDrivers(instance);
113 otInstanceFinalize(instance);
118 * Provide, if required an "otPlatLog()" function
120 #if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_APP
121 void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
123 OT_UNUSED_VARIABLE(aLogLevel);
124 OT_UNUSED_VARIABLE(aLogRegion);
125 OT_UNUSED_VARIABLE(aFormat);
128 va_start(ap, aFormat);
129 otCliPlatLogv(aLogLevel, aLogRegion, aFormat, ap);
135 * Override default network settings, such as panid, so the devices can join a network
137 void setNetworkConfiguration(otInstance *aInstance)
139 static char aNetworkName[] = "SleepyEFR32";
140 otOperationalDataset aDataset;
142 memset(&aDataset, 0, sizeof(otOperationalDataset));
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
149 aDataset.mActiveTimestamp = 1;
150 aDataset.mComponents.mIsActiveTimestampPresent = true;
152 /* Set Channel to 15 */
153 aDataset.mChannel = 15;
154 aDataset.mComponents.mIsChannelPresent = true;
156 /* Set Pan ID to 2222 */
157 aDataset.mPanId = (otPanId)0x2222;
158 aDataset.mComponents.mIsPanIdPresent = true;
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;
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;
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;
176 otDatasetSetActive(aInstance, &aDataset);
179 void handleNetifStateChanged(uint32_t aFlags, void *aContext)
181 if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
183 otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
187 case OT_DEVICE_ROLE_LEADER:
188 otCliOutputFormat("sleepy-demo-ftd changed to leader\r\n");
190 case OT_DEVICE_ROLE_ROUTER:
191 otCliOutputFormat("sleepy-demo-ftd changed to router\r\n");
194 case OT_DEVICE_ROLE_CHILD:
197 case OT_DEVICE_ROLE_DETACHED:
198 case OT_DEVICE_ROLE_DISABLED:
204 void gpioInit(void (*callback)(uint8_t pin))
206 // set up button GPIOs to input with pullups
207 for (int i = 0; i < BSP_BUTTON_COUNT; i++)
209 GPIO_PinModeSet(sButtonArray[i].port, sButtonArray[i].pin, gpioModeInputPull, 1);
211 // set up interrupt based callback function on falling edge
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);
228 memset(&sockaddr, 0, sizeof(sockaddr));
230 otIp6AddressFromString(MULTICAST_ADDR, &sockaddr.mAddress);
231 sockaddr.mPort = MULTICAST_PORT;
233 error = otUdpOpen(instance, &sFtdSocket, sFtdReceiveCallback, NULL);
234 if (error != OT_ERROR_NONE)
236 otCliOutputFormat("FTD failed to open udp multicast\r\n");
240 error = otUdpBind(instance, &sFtdSocket, &sockaddr);
241 if (error != OT_ERROR_NONE)
243 otUdpClose(instance, &sFtdSocket);
244 otCliOutputFormat("FTD failed to bind udp multicast\r\n");
249 void buttonCallback(uint8_t pin)
251 OT_UNUSED_VARIABLE(pin);
252 sFtdButtonPressed = true;
255 void applicationTick(void)
258 otMessageInfo messageInfo;
259 otMessage * message = NULL;
260 char * payload = FTD_MESSAGE;
262 if (sFtdButtonPressed == true)
264 sFtdButtonPressed = false;
266 if (sHaveSwitchAddress)
268 memset(&messageInfo, 0, sizeof(messageInfo));
269 memcpy(&messageInfo.mPeerAddr, &sSwitchAddress, sizeof messageInfo.mPeerAddr);
270 messageInfo.mPeerPort = RECV_PORT;
272 message = otUdpNewMessage(instance, NULL);
276 error = otMessageAppend(message, payload, (uint16_t)strlen(payload));
278 if (error == OT_ERROR_NONE)
280 error = otUdpSend(instance, &sFtdSocket, message, &messageInfo);
282 if (error == OT_ERROR_NONE)
291 otMessageFree(message);
297 void sFtdReceiveCallback(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
299 OT_UNUSED_VARIABLE(aContext);
300 OT_UNUSED_VARIABLE(aMessage);
301 OT_UNUSED_VARIABLE(aMessageInfo);
316 length = otMessageRead(aMessage, otMessageGetOffset(aMessage), buf, sizeof(buf) - 1);
318 otCliOutputFormat("Message Received: %s\r\n", buf);
320 sHaveSwitchAddress = true;
321 memcpy(&sSwitchAddress, &aMessageInfo->mPeerAddr, sizeof sSwitchAddress);