BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | MQTT client for lwIP |
2 | |||
3 | Author: Erik Andersson |
||
4 | |||
5 | Details of the MQTT protocol can be found at: |
||
6 | http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html |
||
7 | |||
8 | ----------------------------------------------------------------- |
||
9 | 1. Initial steps, reserve memory and make connection to server: |
||
10 | |||
11 | 1.1: Provide storage |
||
12 | |||
13 | Static allocation: |
||
14 | mqtt_client_t static_client; |
||
15 | example_do_connect(&static_client); |
||
16 | |||
17 | Dynamic allocation: |
||
18 | mqtt_client_t *client = mqtt_client_new(); |
||
19 | if(client != NULL) { |
||
20 | example_do_connect(&client); |
||
21 | } |
||
22 | |||
23 | 1.2: Establish Connection with server |
||
24 | |||
25 | void example_do_connect(mqtt_client_t *client) |
||
26 | { |
||
27 | struct mqtt_connect_client_info_t ci; |
||
28 | err_t err; |
||
29 | |||
30 | /* Setup an empty client info structure */ |
||
31 | memset(&ci, 0, sizeof(ci)); |
||
32 | |||
33 | /* Minimal amount of information required is client identifier, so set it here */ |
||
34 | ci.client_id = "lwip_test"; |
||
35 | |||
36 | /* Initiate client and connect to server, if this fails immediately an error code is returned |
||
37 | otherwise mqtt_connection_cb will be called with connection result after attempting |
||
38 | to establish a connection with the server. |
||
39 | For now MQTT version 3.1.1 is always used */ |
||
40 | |||
41 | err = mqtt_client_connect(client, ip_addr, MQTT_PORT, mqtt_connection_cb, 0, &ci); |
||
42 | |||
43 | /* For now just print the result code if something goes wrong */ |
||
44 | if(err != ERR_OK) { |
||
45 | printf("mqtt_connect return %d\n", err); |
||
46 | } |
||
47 | } |
||
48 | |||
49 | Connection to server can also be probed by calling mqtt_client_is_connected(client) |
||
50 | |||
51 | ----------------------------------------------------------------- |
||
52 | 2. Implementing the connection status callback |
||
53 | |||
54 | |||
55 | static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) |
||
56 | { |
||
57 | err_t err; |
||
58 | if(status == MQTT_CONNECT_ACCEPTED) { |
||
59 | printf("mqtt_connection_cb: Successfully connected\n"); |
||
60 | |||
61 | /* Setup callback for incoming publish requests */ |
||
62 | mqtt_set_inpub_callback(client, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, arg); |
||
63 | |||
64 | /* Subscribe to a topic named "subtopic" with QoS level 1, call mqtt_sub_request_cb with result */ |
||
65 | err = mqtt_subscribe(client, "subtopic", 1, mqtt_sub_request_cb, arg); |
||
66 | |||
67 | if(err != ERR_OK) { |
||
68 | printf("mqtt_subscribe return: %d\n", err); |
||
69 | } |
||
70 | } else { |
||
71 | printf("mqtt_connection_cb: Disconnected, reason: %d\n", status); |
||
72 | |||
73 | /* Its more nice to be connected, so try to reconnect */ |
||
74 | example_do_connect(client); |
||
75 | } |
||
76 | } |
||
77 | |||
78 | static void mqtt_sub_request_cb(void *arg, err_t result) |
||
79 | { |
||
80 | /* Just print the result code here for simplicity, |
||
81 | normal behaviour would be to take some action if subscribe fails like |
||
82 | notifying user, retry subscribe or disconnect from server */ |
||
83 | printf("Subscribe result: %d\n", result); |
||
84 | } |
||
85 | |||
86 | ----------------------------------------------------------------- |
||
87 | 3. Implementing callbacks for incoming publish and data |
||
88 | |||
89 | /* The idea is to demultiplex topic and create some reference to be used in data callbacks |
||
90 | Example here uses a global variable, better would be to use a member in arg |
||
91 | If RAM and CPU budget allows it, the easiest implementation might be to just take a copy of |
||
92 | the topic string and use it in mqtt_incoming_data_cb |
||
93 | */ |
||
94 | static int inpub_id; |
||
95 | static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) |
||
96 | { |
||
97 | printf("Incoming publish at topic %s with total length %u\n", topic, (unsigned int)tot_len); |
||
98 | |||
99 | /* Decode topic string into a user defined reference */ |
||
100 | if(strcmp(topic, "print_payload") == 0) { |
||
101 | inpub_id = 0; |
||
102 | } else if(topic[0] == 'A') { |
||
103 | /* All topics starting with 'A' might be handled at the same way */ |
||
104 | inpub_id = 1; |
||
105 | } else { |
||
106 | /* For all other topics */ |
||
107 | inpub_id = 2; |
||
108 | } |
||
109 | } |
||
110 | |||
111 | static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) |
||
112 | { |
||
113 | printf("Incoming publish payload with length %d, flags %u\n", len, (unsigned int)flags); |
||
114 | |||
115 | if(flags & MQTT_DATA_FLAG_LAST) { |
||
116 | /* Last fragment of payload received (or whole part if payload fits receive buffer |
||
117 | See MQTT_VAR_HEADER_BUFFER_LEN) */ |
||
118 | |||
119 | /* Call function or do action depending on reference, in this case inpub_id */ |
||
120 | if(inpub_id == 0) { |
||
121 | /* Don't trust the publisher, check zero termination */ |
||
122 | if(data[len-1] == 0) { |
||
123 | printf("mqtt_incoming_data_cb: %s\n", (const char *)data); |
||
124 | } |
||
125 | } else if(inpub_id == 1) { |
||
126 | /* Call an 'A' function... */ |
||
127 | } else { |
||
128 | printf("mqtt_incoming_data_cb: Ignoring payload...\n"); |
||
129 | } |
||
130 | } else { |
||
131 | /* Handle fragmented payload, store in buffer, write to file or whatever */ |
||
132 | } |
||
133 | } |
||
134 | |||
135 | ----------------------------------------------------------------- |
||
136 | 4. Using outgoing publish |
||
137 | |||
138 | |||
139 | void example_publish(mqtt_client_t *client, void *arg) |
||
140 | { |
||
141 | const char *pub_payload= "PubSubHubLubJub"; |
||
142 | err_t err; |
||
143 | u8_t qos = 2; /* 0 1 or 2, see MQTT specification */ |
||
144 | u8_t retain = 0; /* No don't retain such crappy payload... */ |
||
145 | err = mqtt_publish(client, "pub_topic", pub_payload, strlen(pub_payload), qos, retain, mqtt_pub_request_cb, arg); |
||
146 | if(err != ERR_OK) { |
||
147 | printf("Publish err: %d\n", err); |
||
148 | } |
||
149 | } |
||
150 | |||
151 | /* Called when publish is complete either with sucess or failure */ |
||
152 | static void mqtt_pub_request_cb(void *arg, err_t result) |
||
153 | { |
||
154 | if(result != ERR_OK) { |
||
155 | printf("Publish result: %d\n", result); |
||
156 | } |
||
157 | } |
||
158 | |||
159 | ----------------------------------------------------------------- |
||
160 | 5. Disconnecting |
||
161 | |||
162 | Simply call mqtt_disconnect(client) |