Morse Micro IoT SDK  2.9.7
udp_broadcast.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2023 Morse Micro
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
101#include <string.h>
102#include <endian.h>
103#include "mmosal.h"
104#include "mmwlan.h"
105#include "mmconfig.h"
106
107#include "mmipal.h"
108#include "lwip/icmp.h"
109#include "lwip/tcpip.h"
110#include "lwip/udp.h"
111
112#include "mm_app_common.h"
113
114/* Application default configurations. */
115
117#define DEFAULT_BROADCAST_PACKET_COUNT 10
119#define DEFAULT_UDP_PORT 1337
121#define DEFAULT_PACKET_INTERVAL_MS 10000
123#define BROADCAST_PACKET_MAX_TX_PAYLOAD_LEN 35
125#define BROADCAST_PACKET_TX_PAYLOAD_FMT "G'day World, packet no. %lu."
127#define DEFAULT_UDP_BROADCAST_MODE TX_MODE
129#define DEFAULT_UDP_BROADCAST_ID 0
130
132#define MMBC_KEY 0x43424d4d
133
136{
141 RX_MODE
143
145PACK_STRUCT_STRUCT struct udp_broadcast_rx_payload
146{
148 uint32_t key;
150 struct
151 {
153 uint8_t red;
155 uint8_t green;
157 uint8_t blue;
158 } data[];
159};
160
163{
167 uint32_t id;
168};
169
172
185static void udp_raw_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
186 const ip_addr_t *addr, u16_t port)
187{
188 LWIP_UNUSED_ARG(pcb);
189 LWIP_UNUSED_ARG(addr);
190 LWIP_UNUSED_ARG(port);
191
192 if (p == NULL)
193 {
194 return;
195 }
196
197 struct udp_broadcast_rx_metadata *metadata = (struct udp_broadcast_rx_metadata *)arg;
198 struct udp_broadcast_rx_payload *payload = (struct udp_broadcast_rx_payload *)p->payload;
199 uint32_t current_time_ms = mmosal_get_time_ms();
200
201 /* This is the minimum length we need to prevent reading off the end of the payload. */
202 uint32_t min_payload_len =
203 sizeof(payload->key) + (sizeof(payload->data[0]) * (metadata->id + 1));
204
205 if (p->len < min_payload_len)
206 {
207 printf("Payload length to short. Len: %u. Min len: %lu\n", p->len, min_payload_len);
208 goto exit;
209 }
210
211 if (le32toh(payload->key) != MMBC_KEY)
212 {
213 printf("Invalid payload received.\n");
214 goto exit;
215 }
216
217 printf("Valid payload received. \n"
218 " Time since last: %lums\n"
219 " Data recieved: 0x%02x%02x%02x\n\n",
220 (current_time_ms - metadata->last_rx_time_ms),
221 payload->data[metadata->id].red,
222 payload->data[metadata->id].green,
223 payload->data[metadata->id].blue);
224
225 metadata->last_rx_time_ms = current_time_ms;
226
227 mmhal_set_led(LED_RED, payload->data[metadata->id].red);
228 mmhal_set_led(LED_GREEN, payload->data[metadata->id].green);
229 mmhal_set_led(LED_BLUE, payload->data[metadata->id].blue);
230
231exit:
232 pbuf_free(p);
233}
234
241static void udp_broadcast_rx_start(struct udp_pcb *pcb)
242{
243 mmconfig_read_uint32("udp_broadcast.id", &(rx_metadata.id));
244
245 LOCK_TCPIP_CORE();
246 udp_recv(pcb, udp_raw_recv, &rx_metadata);
247 UNLOCK_TCPIP_CORE();
248}
249
258static void udp_broadcast_tx_start(struct udp_pcb *pcb)
259{
260 err_t err;
261 uint32_t count;
262 uint32_t packet_count = DEFAULT_BROADCAST_PACKET_COUNT;
263 uint32_t packet_interval_ms = DEFAULT_PACKET_INTERVAL_MS;
264
265 /* Read out any params from configstore if they exist. If they don't the variables will retain
266 * their current values. */
267 mmconfig_read_uint32("udp_broadcast.packet_count", &packet_count);
268 mmconfig_read_uint32("udp_broadcast.packet_interval_ms", &packet_interval_ms);
269
270 for (count = 0; (count < packet_count) || (packet_count == 0); count++)
271 {
272 printf("Sending Broadcast UDP packet no. %lu.\n", count);
273
274 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, BROADCAST_PACKET_MAX_TX_PAYLOAD_LEN, PBUF_RAM);
275 if (p == NULL)
276 {
277 printf("Failed to allocate pbuf for transmit\n");
278 break;
279 }
280 snprintf((char *)p->payload, p->len, BROADCAST_PACKET_TX_PAYLOAD_FMT, count);
281
282 LOCK_TCPIP_CORE();
283 err = udp_send(pcb, p);
284 if (err)
285 {
286 printf("Failed to send, err:%d.\n", err);
287 break;
288 }
289 UNLOCK_TCPIP_CORE();
290
291 pbuf_free(p);
292
293 mmosal_task_sleep(packet_interval_ms);
294 }
295}
296
304static struct udp_pcb *init_udp_pcb(void)
305{
306 struct udp_pcb *pcb = NULL;
307 err_t err;
308 uint32_t port_num = DEFAULT_UDP_PORT;
309
310 mmconfig_read_uint32("udp_broadcast.port", &port_num);
311 if (port_num > UINT16_MAX)
312 {
313 port_num = DEFAULT_UDP_PORT;
314 printf("Specified port number is too large. Falling back to %lu\n", port_num);
315 }
316
317 LOCK_TCPIP_CORE();
318 pcb = udp_new();
319
320 if (pcb == NULL)
321 {
322 printf("Error creating PCB.\n");
323 goto exit;
324 }
325
326 err = udp_bind(pcb, IP_ADDR_ANY, (uint16_t)port_num);
327 if (err)
328 {
329 printf("Failed to bind, err:%d.\n", err);
330 udp_remove(pcb);
331 pcb = NULL;
332 goto exit;
333 }
334
335exit:
336 UNLOCK_TCPIP_CORE();
337 return pcb;
338}
339
347{
349 char mode_str[32];
350 if (mmconfig_read_string("udp_broadcast.mode", mode_str, sizeof(mode_str)) > 0)
351 {
352 if (strcasecmp(mode_str, "tx") == 0)
353 {
354 mode = TX_MODE;
355 }
356 else if (strcasecmp(mode_str, "rx") == 0)
357 {
358 mode = RX_MODE;
359 }
360 else
361 {
362 printf("Unknown mode: %s. Reverting to default.\n", mode_str);
363 }
364 }
365
366 return mode;
367}
368
373void app_init(void)
374{
375 struct udp_pcb *pcb;
376 enum udp_broadcast_mode mode;
377
378 printf("\n\nMorse UDP broadcast Demo (Built " __DATE__ " " __TIME__ ")\n\n");
379
380 /* Initialize and connect to Wi-Fi, blocks till connected */
383
384 pcb = init_udp_pcb();
385 if (pcb == NULL)
386 {
387 return;
388 }
389
390 mode = get_mode();
391 if (mode == TX_MODE)
392 {
394
395 /* Since we have broadcast all the packets we're going to send lets clean up. */
396 LOCK_TCPIP_CORE();
397 udp_remove(pcb);
398 UNLOCK_TCPIP_CORE();
400 }
401 else
402 {
403 /* Since this registers a callback we leave the WLAN interface up and just allow this
404 * app_init thread to be cleaned up. */
406 }
407}
int mmconfig_read_string(const char *key, char *buffer, int bufsize)
Returns the persistent store string value identified by the key.
int mmconfig_read_uint32(const char *key, uint32_t *value)
Returns the unsigned integer stored in persistent store identified by the key.
void mmhal_set_led(uint8_t led, uint8_t level)
Set the specified LED to the requested level.
void mmosal_task_sleep(uint32_t duration_ms)
Sleep for a period of time, yielding during that time.
uint32_t mmosal_get_time_ms(void)
Get the system time in milliseconds.
Morse Micro application helper routines for initializing/de-initializing the Wireless LAN interface a...
void app_wlan_stop(void)
Disconnects from Wi-Fi and de-initializes the WLAN interface.
void app_wlan_init(void)
Initializes the WLAN interface (and dependencies) using settings specified in the config store.
void app_wlan_start(void)
Starts the WLAN interface and connects to Wi-Fi using settings specified in the config store.
Struct used in rx mode for storing state.
uint32_t id
ID of the device, used to retrieve data from the payload.
uint32_t last_rx_time_ms
The last time in milliseconds that a valid payload was received.
UDP broadcast rx payload format.
uint8_t blue
Blue intensity.
uint8_t red
Red intensity.
uint32_t key
Key used to identify payload.
uint8_t green
Green intensity.
struct udp_broadcast_rx_payload::@0 data[]
Flexible array member used to access color data for each ID.
static struct udp_pcb * init_udp_pcb(void)
Initialize the UDP protocol control block.
#define BROADCAST_PACKET_MAX_TX_PAYLOAD_LEN
Maximum length of broadcast tx packet payload.
#define DEFAULT_UDP_PORT
UDP port to bind too.
#define BROADCAST_PACKET_TX_PAYLOAD_FMT
Format string to use for the tx packet payload.
static enum udp_broadcast_mode get_mode(void)
Get the mode from config store.
static void udp_broadcast_rx_start(struct udp_pcb *pcb)
Set a receive callback for the UDP PCB.
static void udp_broadcast_tx_start(struct udp_pcb *pcb)
Broadcast a udp packet every DEFAULT_PACKET_INTERVAL_MS until DEFAULT_BROADCAST_PACKET_COUNT packets ...
static void udp_raw_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
Callback function to handle received data from the UDP pcb.
udp_broadcast_mode
Enumeration of the various broadcast modes that can be used.
@ TX_MODE
Transmit mode.
@ RX_MODE
Receive mode.
#define DEFAULT_PACKET_INTERVAL_MS
Interval between successive packet transmission.
#define DEFAULT_UDP_BROADCAST_MODE
Default mode for the application.
void app_init(void)
Main entry point to the application.
static struct udp_broadcast_rx_metadata rx_metadata
Global data structure used in RX mode to record metadata.
#define MMBC_KEY
Key used to identify received broadcast packets.
#define DEFAULT_BROADCAST_PACKET_COUNT
Number of broadcast packet to transmit.