1 /*
2  * Copyright (c) 2024 Analog Devices, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(app_main, LOG_LEVEL_DBG);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/net/mqtt.h>
12 #include <zephyr/net/net_if.h>
13 #include <zephyr/net/net_mgmt.h>
14 #include <zephyr/net/conn_mgr_monitor.h>
15 
16 #include "mqtt_client.h"
17 #include "device.h"
18 
19 #define NET_L4_EVENT_MASK (NET_EVENT_L4_CONNECTED | NET_EVENT_L4_DISCONNECTED)
20 
21 /* MQTT client struct */
22 static struct mqtt_client client_ctx;
23 
24 /* MQTT publish work item */
25 struct k_work_delayable mqtt_publish_work;
26 
27 static struct net_mgmt_event_callback net_l4_mgmt_cb;
28 
29 /* Network connection semaphore */
30 K_SEM_DEFINE(net_conn_sem, 0, 1);
31 
net_l4_evt_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)32 static void net_l4_evt_handler(struct net_mgmt_event_callback *cb,
33 				uint32_t mgmt_event, struct net_if *iface)
34 {
35 	switch (mgmt_event) {
36 	case NET_EVENT_L4_CONNECTED:
37 		k_sem_give(&net_conn_sem);
38 		LOG_INF("Network connectivity up!");
39 		break;
40 	case NET_EVENT_L4_DISCONNECTED:
41 		LOG_INF("Network connectivity down!");
42 		break;
43 	default:
44 		break;
45 	}
46 }
47 
48 /** Print the device's MAC address to console */
log_mac_addr(struct net_if * iface)49 void log_mac_addr(struct net_if *iface)
50 {
51 	struct net_linkaddr *mac;
52 
53 	mac = net_if_get_link_addr(iface);
54 
55 	LOG_INF("MAC Address: %02X:%02X:%02X:%02X:%02X:%02X",
56 		mac->addr[0], mac->addr[1], mac->addr[3],
57 		mac->addr[3], mac->addr[4], mac->addr[5]);
58 }
59 
60 /** The system work queue is used to handle periodic MQTT publishing.
61  *  Work queuing begins when the MQTT connection is established.
62  *  Use CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL to set the publish frequency.
63  */
64 
publish_work_handler(struct k_work * work)65 static void publish_work_handler(struct k_work *work)
66 {
67 	int rc;
68 
69 	if (mqtt_connected) {
70 		rc = app_mqtt_publish(&client_ctx);
71 		if (rc != 0) {
72 			LOG_INF("MQTT Publish failed [%d]", rc);
73 		}
74 		k_work_reschedule(&mqtt_publish_work,
75 					K_SECONDS(CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL));
76 	} else {
77 		k_work_cancel_delayable(&mqtt_publish_work);
78 	}
79 }
80 
main(void)81 int main(void)
82 {
83 	int rc;
84 	struct net_if *iface;
85 
86 	devices_ready();
87 
88 	iface = net_if_get_default();
89 	if (iface == NULL) {
90 		LOG_ERR("No network interface configured");
91 		return -ENETDOWN;
92 	}
93 
94 	log_mac_addr(iface);
95 
96 	/* Register callbacks for L4 events */
97 	net_mgmt_init_event_callback(&net_l4_mgmt_cb, &net_l4_evt_handler, NET_L4_EVENT_MASK);
98 	net_mgmt_add_event_callback(&net_l4_mgmt_cb);
99 
100 	LOG_INF("Bringing up network..");
101 
102 #if defined(CONFIG_NET_DHCPV4)
103 	net_dhcpv4_start(iface);
104 #else
105 	/* If using static IP, L4 Connect callback will happen,
106 	 * before conn mgr is initialised, so resend events here
107 	 * to check for connectivity
108 	 */
109 	conn_mgr_mon_resend_status();
110 #endif
111 
112 	/* Wait for network to come up */
113 	while (k_sem_take(&net_conn_sem, K_MSEC(MSECS_NET_POLL_TIMEOUT)) != 0) {
114 		LOG_INF("Waiting for network connection..");
115 	}
116 
117 	rc = app_mqtt_init(&client_ctx);
118 	if (rc != 0) {
119 		LOG_ERR("MQTT Init failed [%d]", rc);
120 		return rc;
121 	}
122 
123 	/* Initialise MQTT publish work item */
124 	k_work_init_delayable(&mqtt_publish_work, publish_work_handler);
125 
126 	/* Thread main loop */
127 	while (1) {
128 		/* Block until MQTT connection is up */
129 		app_mqtt_connect(&client_ctx);
130 
131 		/* We are now connected, begin queueing periodic MQTT publishes */
132 		k_work_reschedule(&mqtt_publish_work,
133 					K_SECONDS(CONFIG_NET_SAMPLE_MQTT_PUBLISH_INTERVAL));
134 
135 		/* Handle MQTT inputs and connection */
136 		app_mqtt_run(&client_ctx);
137 	}
138 
139 	return rc;
140 }
141