Morse Micro IoT SDK  2.10.4
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
102#include <string.h>
103#include <endian.h>
104#include "mmosal.h"
105#include "mmwlan.h"
106#include "mmconfig.h"
107
108#include "mmipal.h"
109#include "lwip/icmp.h"
110#include "lwip/tcpip.h"
111#include "lwip/udp.h"
112
113#include "mm_app_common.h"
114
115/* Application default configurations. */
116
118#define DEFAULT_BROADCAST_PACKET_COUNT 10
120#define DEFAULT_UDP_PORT 1337
122#define DEFAULT_PACKET_INTERVAL_MS 10000
124#define BROADCAST_PACKET_MAX_TX_PAYLOAD_LEN 35
126#define BROADCAST_PACKET_TX_PAYLOAD_FMT "G'day World, packet no. %lu."
128#define DEFAULT_UDP_BROADCAST_MODE TX_MODE
130#define DEFAULT_UDP_BROADCAST_ID 0
131
133#define MMBC_KEY 0x43424d4d
134
137{
142 RX_MODE
144
146PACK_STRUCT_STRUCT struct udp_broadcast_rx_payload
147{
149 uint32_t key;
150
152 struct
153 {
155 uint8_t red;
157 uint8_t green;
159 uint8_t blue;
160 } data[];
161};
162
165{
169 uint32_t id;
170};
171
174
187static void udp_raw_recv(void *arg,
188 struct udp_pcb *pcb,
189 struct pbuf *p,
190 const ip_addr_t *addr,
191 u16_t port)
192{
193 LWIP_UNUSED_ARG(pcb);
194 LWIP_UNUSED_ARG(addr);
195 LWIP_UNUSED_ARG(port);
196
197 if (p == NULL)
198 {
199 return;
200 }
201
202 struct udp_broadcast_rx_metadata *metadata = (struct udp_broadcast_rx_metadata *)arg;
203 struct udp_broadcast_rx_payload *payload = (struct udp_broadcast_rx_payload *)p->payload;
204 uint32_t current_time_ms = mmosal_get_time_ms();
205
206 /* This is the minimum length we need to prevent reading off the end of the payload. */
207 uint32_t min_payload_len =
208 sizeof(payload->key) + (sizeof(payload->data[0]) * (metadata->id + 1));
209
210 if (p->len < min_payload_len)
211 {
212 printf("Payload length to short. Len: %u. Min len: %lu\n", p->len, min_payload_len);
213 goto exit;
214 }
215
216 if (le32toh(payload->key) != MMBC_KEY)
217 {
218 printf("Invalid payload received.\n");
219 goto exit;
220 }
221
222 printf("Valid payload received. \n"
223 " Time since last: %lums\n"
224 " Data recieved: 0x%02x%02x%02x\n\n",
225 (current_time_ms - metadata->last_rx_time_ms),
226 payload->data[metadata->id].red,
227 payload->data[metadata->id].green,
228 payload->data[metadata->id].blue);
229
230 metadata->last_rx_time_ms = current_time_ms;
231
232 mmhal_set_led(LED_RED, payload->data[metadata->id].red);
233 mmhal_set_led(LED_GREEN, payload->data[metadata->id].green);
234 mmhal_set_led(LED_BLUE, payload->data[metadata->id].blue);
235
236exit:
237 pbuf_free(p);
238}
239
246static void udp_broadcast_rx_start(struct udp_pcb *pcb)
247{
248 mmconfig_read_uint32("udp_broadcast.id", &(rx_metadata.id));
249
250 LOCK_TCPIP_CORE();
251 udp_recv(pcb, udp_raw_recv, &rx_metadata);
252 UNLOCK_TCPIP_CORE();
253}
254
263static void udp_broadcast_tx_start(struct udp_pcb *pcb)
264{
265 err_t err;
266 uint32_t count;
267 uint32_t packet_count = DEFAULT_BROADCAST_PACKET_COUNT;
268 uint32_t packet_interval_ms = DEFAULT_PACKET_INTERVAL_MS;
269
270 /* Read out any params from configstore if they exist. If they don't the variables will retain
271 * their current values. */
272 mmconfig_read_uint32("udp_broadcast.packet_count", &packet_count);
273 mmconfig_read_uint32("udp_broadcast.packet_interval_ms", &packet_interval_ms);
274
275 for (count = 0; (count < packet_count) || (packet_count == 0); count++)
276 {
277 printf("Sending Broadcast UDP packet no. %lu.\n", count);
278
279 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, BROADCAST_PACKET_MAX_TX_PAYLOAD_LEN, PBUF_RAM);
280 if (p == NULL)
281 {
282 printf("Failed to allocate pbuf for transmit\n");
283 break;
284 }
285 snprintf((char *)p->payload, p->len, BROADCAST_PACKET_TX_PAYLOAD_FMT, count);
286
287 LOCK_TCPIP_CORE();
288 err = udp_send(pcb, p);
289 if (err)
290 {
291 printf("Failed to send, err:%d.\n", err);
292 break;
293 }
294 UNLOCK_TCPIP_CORE();
295
296 pbuf_free(p);
297
298 mmosal_task_sleep(packet_interval_ms);
299 }
300}
301
309static struct udp_pcb *init_udp_pcb(void)
310{
311 struct udp_pcb *pcb = NULL;
312 err_t err;
313 uint32_t port_num = DEFAULT_UDP_PORT;
314
315 mmconfig_read_uint32("udp_broadcast.port", &port_num);
316 if (port_num > UINT16_MAX)
317 {
318 port_num = DEFAULT_UDP_PORT;
319 printf("Specified port number is too large. Falling back to %lu\n", port_num);
320 }
321
322 LOCK_TCPIP_CORE();
323 pcb = udp_new();
324
325 if (pcb == NULL)
326 {
327 printf("Error creating PCB.\n");
328 goto exit;
329 }
330
331 err = udp_bind(pcb, IP_ADDR_ANY, (uint16_t)port_num);
332 if (err)
333 {
334 printf("Failed to bind, err:%d.\n", err);
335 udp_remove(pcb);
336 pcb = NULL;
337 goto exit;
338 }
339
340exit:
341 UNLOCK_TCPIP_CORE();
342 return pcb;
343}
344
352{
354 char mode_str[32];
355 if (mmconfig_read_string("udp_broadcast.mode", mode_str, sizeof(mode_str)) > 0)
356 {
357 if (strcasecmp(mode_str, "tx") == 0)
358 {
359 mode = TX_MODE;
360 }
361 else if (strcasecmp(mode_str, "rx") == 0)
362 {
363 mode = RX_MODE;
364 }
365 else
366 {
367 printf("Unknown mode: %s. Reverting to default.\n", mode_str);
368 }
369 }
370
371 return mode;
372}
373
378void app_init(void)
379{
380 struct udp_pcb *pcb;
381 enum udp_broadcast_mode mode;
382
383 printf("\n\nMorse UDP broadcast Demo (Built " __DATE__ " " __TIME__ ")\n\n");
384
385 /* Initialize and connect to Wi-Fi, blocks till connected */
388
389 pcb = init_udp_pcb();
390 if (pcb == NULL)
391 {
392 return;
393 }
394
395 mode = get_mode();
396 if (mode == TX_MODE)
397 {
399
400 /* Since we have broadcast all the packets we're going to send lets clean up. */
401 LOCK_TCPIP_CORE();
402 udp_remove(pcb);
403 UNLOCK_TCPIP_CORE();
405 }
406 else
407 {
408 /* Since this registers a callback we leave the WLAN interface up and just allow this
409 * app_init thread to be cleaned up. */
411 }
412}
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.