1 /*
2  * Copyright (c) 2022 G-Technologies Sdn. Bhd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_SHELL_MQTT_H_
8 #define ZEPHYR_INCLUDE_SHELL_MQTT_H_
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/shell/shell.h>
12 #include <zephyr/net/socket.h>
13 #include <zephyr/net/net_mgmt.h>
14 #include <zephyr/net/net_event.h>
15 #include <zephyr/net/conn_mgr_monitor.h>
16 #include <zephyr/net/mqtt.h>
17 #include <zephyr/sys/ring_buffer.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #define RX_RB_SIZE CONFIG_SHELL_MQTT_RX_BUF_SIZE
24 #define TX_BUF_SIZE CONFIG_SHELL_MQTT_TX_BUF_SIZE
25 #define SH_MQTT_BUFFER_SIZE 64
26 #define DEVICE_ID_BIN_MAX_SIZE 3
27 #define DEVICE_ID_HEX_MAX_SIZE ((DEVICE_ID_BIN_MAX_SIZE * 2) + 1)
28 #define SH_MQTT_TOPIC_RX_MAX_SIZE DEVICE_ID_HEX_MAX_SIZE + sizeof(CONFIG_SHELL_MQTT_TOPIC_RX_ID)
29 #define SH_MQTT_TOPIC_TX_MAX_SIZE DEVICE_ID_HEX_MAX_SIZE + sizeof(CONFIG_SHELL_MQTT_TOPIC_TX_ID)
30 
31 extern const struct shell_transport_api shell_mqtt_transport_api;
32 
33 struct shell_mqtt_tx_buf {
34 	/** tx buffer. */
35 	char buf[TX_BUF_SIZE];
36 
37 	/** Current tx buf length. */
38 	uint16_t len;
39 };
40 
41 /** MQTT-based shell transport. */
42 struct shell_mqtt {
43 	char device_id[DEVICE_ID_HEX_MAX_SIZE];
44 	char sub_topic[SH_MQTT_TOPIC_RX_MAX_SIZE];
45 	char pub_topic[SH_MQTT_TOPIC_TX_MAX_SIZE];
46 
47 	/** Handler function registered by shell. */
48 	shell_transport_handler_t shell_handler;
49 
50 	struct ring_buf rx_rb;
51 	uint8_t rx_rb_buf[RX_RB_SIZE];
52 	uint8_t *rx_rb_ptr;
53 
54 	struct shell_mqtt_tx_buf tx_buf;
55 
56 	/** Context registered by shell. */
57 	void *shell_context;
58 
59 	/** The mqtt client struct */
60 	struct mqtt_client mqtt_cli;
61 
62 	/* Buffers for MQTT client. */
63 	struct buffer {
64 		uint8_t rx[SH_MQTT_BUFFER_SIZE];
65 		uint8_t tx[SH_MQTT_BUFFER_SIZE];
66 	} buf;
67 
68 	struct k_mutex lock;
69 
70 	/** MQTT Broker details. */
71 	struct net_sockaddr_storage broker;
72 
73 	struct zsock_addrinfo *haddr;
74 	struct zsock_pollfd fds[1];
75 	int nfds;
76 
77 	struct mqtt_publish_param pub_data;
78 
79 	struct net_mgmt_event_callback mgmt_cb;
80 
81 	/** work */
82 	struct k_work_q workq;
83 	struct k_work net_disconnected_work;
84 	struct k_work_delayable connect_dwork;
85 	struct k_work_delayable subscribe_dwork;
86 	struct k_work_delayable process_dwork;
87 	struct k_work_delayable publish_dwork;
88 
89 	/** MQTT connection states */
90 	enum sh_mqtt_transport_state {
91 		SHELL_MQTT_TRANSPORT_DISCONNECTED,
92 		SHELL_MQTT_TRANSPORT_CONNECTED,
93 	} transport_state;
94 
95 	/** MQTT subscription states */
96 	enum sh_mqtt_subscribe_state {
97 		SHELL_MQTT_NOT_SUBSCRIBED,
98 		SHELL_MQTT_SUBSCRIBED,
99 	} subscribe_state;
100 
101 	/** Network states */
102 	enum sh_mqtt_network_state {
103 		SHELL_MQTT_NETWORK_DISCONNECTED,
104 		SHELL_MQTT_NETWORK_CONNECTED,
105 	} network_state;
106 };
107 
108 #define SHELL_MQTT_DEFINE(_name)                                                                   \
109 	static struct shell_mqtt _name##_shell_mqtt;                                               \
110 	struct shell_transport _name = { .api = &shell_mqtt_transport_api,                         \
111 					 .ctx = (struct shell_mqtt *)&_name##_shell_mqtt }
112 
113 /**
114  * @brief This function provides pointer to shell mqtt backend instance.
115  *
116  * Function returns pointer to the shell mqtt instance. This instance can be
117  * next used with shell_execute_cmd function in order to test commands behavior.
118  *
119  * @returns Pointer to the shell instance.
120  */
121 const struct shell *shell_backend_mqtt_get_ptr(void);
122 
123 /**
124  * @brief Function to define the device ID (devid) for which the shell mqtt backend uses as a
125  * client ID when it connects to the broker. It will publish its output to devid_tx and subscribe
126  * to devid_rx for input .
127  *
128  * @note This is a weak-linked function, and can be overridden if desired.
129  *
130  * @param id Pointer to the devid buffer
131  * @param id_max_len Maximum size of the devid buffer defined by DEVICE_ID_HEX_MAX_SIZE
132  *
133  * @return true if length of devid > 0
134  */
135 bool shell_mqtt_get_devid(char *id, int id_max_len);
136 
137 #ifdef __cplusplus
138 }
139 #endif
140 
141 #endif /* ZEPHYR_INCLUDE_SHELL_MQTT_H_ */
142