![](/media/cache/profiles/olja.png.50x50_q85.png)
Student project, Faculty of Electrical Engineering, University of Belgrade
Dependencies: SSD1308_128x64_I2C Adafruit_GFX 19E042PIM_MB_PINS
main.cpp@1:c994530bdb3d, 2021-11-27 (annotated)
- Committer:
- tzwell
- Date:
- Sat Nov 27 20:33:49 2021 +0000
- Revision:
- 1:c994530bdb3d
- Parent:
- 0:6380a1c94d6c
- Child:
- 2:4c2c7c8d608b
Commented in more detail
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tzwell | 0:6380a1c94d6c | 1 | /* |
tzwell | 0:6380a1c94d6c | 2 | * Program implements MQTT client on a NUCLEO-L476RG board |
tzwell | 0:6380a1c94d6c | 3 | * using arm mbed-mqtt library and ESP-WROOM-02 WiFi modem. |
tzwell | 0:6380a1c94d6c | 4 | * |
tzwell | 0:6380a1c94d6c | 5 | * University of Belgrade - School of Electrical Engineering |
tzwell | 0:6380a1c94d6c | 6 | * Department of Electronics |
tzwell | 0:6380a1c94d6c | 7 | * Bulevar Kralja Aleksandra 73, 11120 Belgrade, Serbia |
tzwell | 0:6380a1c94d6c | 8 | * |
tzwell | 0:6380a1c94d6c | 9 | * November 2021. |
tzwell | 0:6380a1c94d6c | 10 | * |
tzwell | 0:6380a1c94d6c | 11 | */ |
tzwell | 0:6380a1c94d6c | 12 | |
tzwell | 0:6380a1c94d6c | 13 | #include "mbed.h" |
tzwell | 0:6380a1c94d6c | 14 | #include "mb_pins.h" |
tzwell | 0:6380a1c94d6c | 15 | #include "platform/mbed_thread.h" |
tzwell | 0:6380a1c94d6c | 16 | #include "MQTTClientMbedOs.h" |
tzwell | 0:6380a1c94d6c | 17 | |
tzwell | 0:6380a1c94d6c | 18 | |
tzwell | 0:6380a1c94d6c | 19 | // LED2 blinking rate: |
tzwell | 0:6380a1c94d6c | 20 | #define BLINKING_RATE_MS 250 |
tzwell | 0:6380a1c94d6c | 21 | // Scaler to 3v3L |
tzwell | 0:6380a1c94d6c | 22 | #define VOLTAGE_SCALER 3.3f |
tzwell | 0:6380a1c94d6c | 23 | // Client yield timeout in miliseconds: |
tzwell | 0:6380a1c94d6c | 24 | #define YIELD_TIMEOUT_MS 1000 |
tzwell | 0:6380a1c94d6c | 25 | // Maximum number of networks to scan for: |
tzwell | 0:6380a1c94d6c | 26 | #define MAX_NETWORKS 15 |
tzwell | 0:6380a1c94d6c | 27 | // Small delay for network information printing: |
tzwell | 0:6380a1c94d6c | 28 | #define PRINTF_DELAY_MS 10 |
tzwell | 0:6380a1c94d6c | 29 | |
tzwell | 0:6380a1c94d6c | 30 | |
tzwell | 0:6380a1c94d6c | 31 | // Left potentiometer: |
tzwell | 0:6380a1c94d6c | 32 | AnalogIn pot1(MB_POT1); |
tzwell | 0:6380a1c94d6c | 33 | // Left button on the motherboard: |
tzwell | 0:6380a1c94d6c | 34 | InterruptIn sw1(MB_SW1); |
tzwell | 0:6380a1c94d6c | 35 | // Right LED on the motherboard: |
tzwell | 0:6380a1c94d6c | 36 | DigitalOut led2(MB_LED2); |
tzwell | 1:c994530bdb3d | 37 | // Pointer to a WiFi network object: |
tzwell | 0:6380a1c94d6c | 38 | WiFiInterface *wifi; |
tzwell | 0:6380a1c94d6c | 39 | // Creating TCP socket: |
tzwell | 0:6380a1c94d6c | 40 | TCPSocket socket; |
tzwell | 0:6380a1c94d6c | 41 | // Creating MQTT client using the TCP socket; |
tzwell | 0:6380a1c94d6c | 42 | MQTTClient client(&socket); |
tzwell | 0:6380a1c94d6c | 43 | // Message handler: |
tzwell | 0:6380a1c94d6c | 44 | MQTT::Message message; |
tzwell | 0:6380a1c94d6c | 45 | |
tzwell | 0:6380a1c94d6c | 46 | char* topic = "mbed-sample-pub"; |
tzwell | 0:6380a1c94d6c | 47 | char* topic_sub = "mbed-sample-sub"; |
tzwell | 0:6380a1c94d6c | 48 | // Counter of arrived messages: |
tzwell | 0:6380a1c94d6c | 49 | int arrivedcount = 0; |
tzwell | 0:6380a1c94d6c | 50 | // Flag indicating that button is not pressed: |
tzwell | 0:6380a1c94d6c | 51 | int button_pressed=0; |
tzwell | 1:c994530bdb3d | 52 | // HiveMQ broker connectivity information: |
tzwell | 1:c994530bdb3d | 53 | const char* hostname = "broker.hivemq.com"; |
tzwell | 1:c994530bdb3d | 54 | int port = 1883; |
tzwell | 0:6380a1c94d6c | 55 | // Returning a string for a provided network encryption: |
tzwell | 0:6380a1c94d6c | 56 | const char *sec2str(nsapi_security_t sec) |
tzwell | 0:6380a1c94d6c | 57 | { |
tzwell | 0:6380a1c94d6c | 58 | switch (sec) |
tzwell | 0:6380a1c94d6c | 59 | { |
tzwell | 0:6380a1c94d6c | 60 | case NSAPI_SECURITY_NONE: |
tzwell | 0:6380a1c94d6c | 61 | return "None"; |
tzwell | 0:6380a1c94d6c | 62 | case NSAPI_SECURITY_WEP: |
tzwell | 0:6380a1c94d6c | 63 | return "WEP"; |
tzwell | 0:6380a1c94d6c | 64 | case NSAPI_SECURITY_WPA: |
tzwell | 0:6380a1c94d6c | 65 | return "WPA"; |
tzwell | 0:6380a1c94d6c | 66 | case NSAPI_SECURITY_WPA2: |
tzwell | 0:6380a1c94d6c | 67 | return "WPA2"; |
tzwell | 0:6380a1c94d6c | 68 | case NSAPI_SECURITY_WPA_WPA2: |
tzwell | 0:6380a1c94d6c | 69 | return "WPA/WPA2"; |
tzwell | 0:6380a1c94d6c | 70 | case NSAPI_SECURITY_UNKNOWN: |
tzwell | 0:6380a1c94d6c | 71 | default: |
tzwell | 0:6380a1c94d6c | 72 | return "Unknown"; |
tzwell | 0:6380a1c94d6c | 73 | } |
tzwell | 0:6380a1c94d6c | 74 | } |
tzwell | 0:6380a1c94d6c | 75 | |
tzwell | 1:c994530bdb3d | 76 | int scan_networks(WiFiInterface *wifi) |
tzwell | 0:6380a1c94d6c | 77 | { |
tzwell | 0:6380a1c94d6c | 78 | printf("Scan:\n"); |
tzwell | 1:c994530bdb3d | 79 | |
tzwell | 1:c994530bdb3d | 80 | // Scan only for the number of networks, first parameter is NULL: |
tzwell | 1:c994530bdb3d | 81 | int count = wifi->scan(NULL, 0); |
tzwell | 1:c994530bdb3d | 82 | // If there are no networks, count == 0, if there is an error, counter < 0: |
tzwell | 0:6380a1c94d6c | 83 | if (count <= 0) |
tzwell | 0:6380a1c94d6c | 84 | { |
tzwell | 0:6380a1c94d6c | 85 | printf("scan() failed with return value: %d\n", count); |
tzwell | 0:6380a1c94d6c | 86 | return 0; |
tzwell | 0:6380a1c94d6c | 87 | } |
tzwell | 0:6380a1c94d6c | 88 | |
tzwell | 1:c994530bdb3d | 89 | // Limit number of network arbitrary to some reasonable number: |
tzwell | 0:6380a1c94d6c | 90 | count = count < MAX_NETWORKS ? count : MAX_NETWORKS; |
tzwell | 0:6380a1c94d6c | 91 | |
tzwell | 1:c994530bdb3d | 92 | // Create a local pointer to an object, which is an array of WiFi APs: |
tzwell | 1:c994530bdb3d | 93 | WiFiAccessPoint *ap = new WiFiAccessPoint[count]; |
tzwell | 1:c994530bdb3d | 94 | // Now scan again for 'count' networks and populate the array of APs: |
tzwell | 0:6380a1c94d6c | 95 | count = wifi->scan(ap, count); |
tzwell | 1:c994530bdb3d | 96 | |
tzwell | 1:c994530bdb3d | 97 | // This time, the number of entries to 'ap' is returned: |
tzwell | 0:6380a1c94d6c | 98 | if (count <= 0) |
tzwell | 0:6380a1c94d6c | 99 | { |
tzwell | 0:6380a1c94d6c | 100 | printf("scan() failed with return value: %d\n", count); |
tzwell | 0:6380a1c94d6c | 101 | return 0; |
tzwell | 0:6380a1c94d6c | 102 | } |
tzwell | 0:6380a1c94d6c | 103 | |
tzwell | 1:c994530bdb3d | 104 | // Print out the parameters of each AP: |
tzwell | 0:6380a1c94d6c | 105 | for (int i = 0; i < count; i++) |
tzwell | 0:6380a1c94d6c | 106 | { |
tzwell | 0:6380a1c94d6c | 107 | printf("Network: %s secured: %s BSSID: %hhX:%hhX:%hhX:%hhx:%hhx:%hhx RSSI: %hhd Ch: %hhd\n", ap[i].get_ssid(), |
tzwell | 0:6380a1c94d6c | 108 | sec2str(ap[i].get_security()), ap[i].get_bssid()[0], ap[i].get_bssid()[1], ap[i].get_bssid()[2], |
tzwell | 0:6380a1c94d6c | 109 | ap[i].get_bssid()[3], ap[i].get_bssid()[4], ap[i].get_bssid()[5], ap[i].get_rssi(), ap[i].get_channel()); |
tzwell | 0:6380a1c94d6c | 110 | thread_sleep_for(PRINTF_DELAY_MS); |
tzwell | 0:6380a1c94d6c | 111 | } |
tzwell | 0:6380a1c94d6c | 112 | printf("%d networks available.\n", count); |
tzwell | 1:c994530bdb3d | 113 | |
tzwell | 1:c994530bdb3d | 114 | // Since 'ap' is dynamically allocated pointer to the array of objects, it |
tzwell | 1:c994530bdb3d | 115 | // needs to be deleted: |
tzwell | 0:6380a1c94d6c | 116 | delete[] ap; |
tzwell | 0:6380a1c94d6c | 117 | return count; |
tzwell | 0:6380a1c94d6c | 118 | } |
tzwell | 0:6380a1c94d6c | 119 | |
tzwell | 0:6380a1c94d6c | 120 | void messageArrived(MQTT::MessageData& md) |
tzwell | 0:6380a1c94d6c | 121 | { |
tzwell | 0:6380a1c94d6c | 122 | MQTT::Message &message = md.message; |
tzwell | 0:6380a1c94d6c | 123 | //printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); |
tzwell | 0:6380a1c94d6c | 124 | printf("Message from the browser: %.*s\r\n", message.payloadlen, (char*)message.payload); |
tzwell | 0:6380a1c94d6c | 125 | ++arrivedcount; |
tzwell | 0:6380a1c94d6c | 126 | } |
tzwell | 0:6380a1c94d6c | 127 | |
tzwell | 0:6380a1c94d6c | 128 | void buttonFunction() { |
tzwell | 0:6380a1c94d6c | 129 | |
tzwell | 0:6380a1c94d6c | 130 | button_pressed=1; |
tzwell | 0:6380a1c94d6c | 131 | |
tzwell | 0:6380a1c94d6c | 132 | } |
tzwell | 0:6380a1c94d6c | 133 | |
tzwell | 0:6380a1c94d6c | 134 | int main() |
tzwell | 0:6380a1c94d6c | 135 | { |
tzwell | 1:c994530bdb3d | 136 | // Set the interrupt event: |
tzwell | 1:c994530bdb3d | 137 | sw1.fall(&buttonFunction); |
tzwell | 0:6380a1c94d6c | 138 | |
tzwell | 1:c994530bdb3d | 139 | // Create a default network interface: |
tzwell | 0:6380a1c94d6c | 140 | wifi = WiFiInterface::get_default_instance(); |
tzwell | 0:6380a1c94d6c | 141 | if (!wifi) { |
tzwell | 0:6380a1c94d6c | 142 | printf("ERROR: No WiFiInterface found.\n"); |
tzwell | 0:6380a1c94d6c | 143 | return -1; |
tzwell | 0:6380a1c94d6c | 144 | } |
tzwell | 1:c994530bdb3d | 145 | |
tzwell | 1:c994530bdb3d | 146 | // Scan for available networks and aquire information about Access Points: |
tzwell | 1:c994530bdb3d | 147 | int count = scan_networks(wifi); |
tzwell | 0:6380a1c94d6c | 148 | if (count == 0) { |
tzwell | 0:6380a1c94d6c | 149 | printf("No WIFI APs found - can't continue further.\n"); |
tzwell | 0:6380a1c94d6c | 150 | return -1; |
tzwell | 0:6380a1c94d6c | 151 | } |
tzwell | 1:c994530bdb3d | 152 | |
tzwell | 1:c994530bdb3d | 153 | // Connect to the network with the parameters specified in 'mbed_app.json': |
tzwell | 0:6380a1c94d6c | 154 | printf("\nConnecting to %s...\n", MBED_CONF_APP_WIFI_SSID); |
tzwell | 0:6380a1c94d6c | 155 | int ret = wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2); |
tzwell | 0:6380a1c94d6c | 156 | if (ret != 0) { |
tzwell | 0:6380a1c94d6c | 157 | printf("\nConnection error: %d\n", ret); |
tzwell | 0:6380a1c94d6c | 158 | return -1; |
tzwell | 0:6380a1c94d6c | 159 | } |
tzwell | 1:c994530bdb3d | 160 | |
tzwell | 1:c994530bdb3d | 161 | // Print out the information aquired: |
tzwell | 0:6380a1c94d6c | 162 | printf("Success\n\n"); |
tzwell | 0:6380a1c94d6c | 163 | printf("MAC: %s\n", wifi->get_mac_address()); |
tzwell | 0:6380a1c94d6c | 164 | printf("IP: %s\n", wifi->get_ip_address()); |
tzwell | 0:6380a1c94d6c | 165 | printf("Netmask: %s\n", wifi->get_netmask()); |
tzwell | 0:6380a1c94d6c | 166 | printf("Gateway: %s\n", wifi->get_gateway()); |
tzwell | 0:6380a1c94d6c | 167 | printf("RSSI: %d\n\n", wifi->get_rssi()); |
tzwell | 1:c994530bdb3d | 168 | |
tzwell | 1:c994530bdb3d | 169 | // Open TCP socket using WiFi network interface: |
tzwell | 0:6380a1c94d6c | 170 | socket.open(wifi); |
tzwell | 1:c994530bdb3d | 171 | // Connect to the HiveMQ broker: |
tzwell | 0:6380a1c94d6c | 172 | socket.connect(hostname, port); |
tzwell | 1:c994530bdb3d | 173 | // Fill connect data with default values: |
tzwell | 0:6380a1c94d6c | 174 | MQTTPacket_connectData data = MQTTPacket_connectData_initializer; |
tzwell | 1:c994530bdb3d | 175 | // Change only ID and protocol version: |
tzwell | 0:6380a1c94d6c | 176 | data.MQTTVersion = 3; |
tzwell | 0:6380a1c94d6c | 177 | data.clientID.cstring = "NUCLEO-L476RG-60"; |
tzwell | 0:6380a1c94d6c | 178 | |
tzwell | 1:c994530bdb3d | 179 | // Connect the |
tzwell | 1:c994530bdb3d | 180 | int rc = 0; |
tzwell | 0:6380a1c94d6c | 181 | if ((rc = client.connect(data)) != 0) |
tzwell | 0:6380a1c94d6c | 182 | printf("rc from MQTT connect is %d\r\n", rc); |
tzwell | 0:6380a1c94d6c | 183 | |
tzwell | 0:6380a1c94d6c | 184 | if ((rc = client.subscribe(topic_sub, MQTT::QOS2, messageArrived)) != 0) |
tzwell | 0:6380a1c94d6c | 185 | printf("rc from MQTT subscribe is %d\r\n", rc); |
tzwell | 0:6380a1c94d6c | 186 | |
tzwell | 0:6380a1c94d6c | 187 | while (true) { |
tzwell | 0:6380a1c94d6c | 188 | // Show that the loop is running by switching motherboard LED2: |
tzwell | 0:6380a1c94d6c | 189 | led2 = !led2; |
tzwell | 0:6380a1c94d6c | 190 | thread_sleep_for(BLINKING_RATE_MS); |
tzwell | 0:6380a1c94d6c | 191 | if (button_pressed==1) { |
tzwell | 0:6380a1c94d6c | 192 | button_pressed=0; |
tzwell | 0:6380a1c94d6c | 193 | // QoS 0 |
tzwell | 0:6380a1c94d6c | 194 | char buf[100]; |
tzwell | 0:6380a1c94d6c | 195 | sprintf(buf, "V(POT1) = %1.2f\r\n", pot1*VOLTAGE_SCALER); |
tzwell | 0:6380a1c94d6c | 196 | message.qos = MQTT::QOS0; |
tzwell | 0:6380a1c94d6c | 197 | message.retained = false; |
tzwell | 0:6380a1c94d6c | 198 | message.dup = false; |
tzwell | 0:6380a1c94d6c | 199 | message.payload = (void*)buf; |
tzwell | 0:6380a1c94d6c | 200 | message.payloadlen = strlen(buf)+1; |
tzwell | 0:6380a1c94d6c | 201 | client.publish(topic, message); |
tzwell | 0:6380a1c94d6c | 202 | } |
tzwell | 0:6380a1c94d6c | 203 | // Need to call yield API to maintain connection: |
tzwell | 0:6380a1c94d6c | 204 | client.yield(YIELD_TIMEOUT_MS); |
tzwell | 0:6380a1c94d6c | 205 | } |
tzwell | 0:6380a1c94d6c | 206 | } |