Nenad Tepavac 2020/0028
Dependencies: mbed Adafruit_GFX 19E042PIM_MB_PINS
main3.txt@0:981049ce9511, 2022-01-17 (annotated)
- Committer:
- ostoja
- Date:
- Mon Jan 17 16:01:04 2022 +0000
- Revision:
- 0:981049ce9511
Nenad Tepavac 2020/0028;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
ostoja | 0:981049ce9511 | 1 | #include "mbed.h" |
ostoja | 0:981049ce9511 | 2 | #include "Adafruit_GFX.h" |
ostoja | 0:981049ce9511 | 3 | #include "Adafruit_GFX_Config.h" |
ostoja | 0:981049ce9511 | 4 | #include "Adafruit_SSD1306.h" |
ostoja | 0:981049ce9511 | 5 | #include "mb_pins.h" |
ostoja | 0:981049ce9511 | 6 | #include "platform/mbed_thread.h" |
ostoja | 0:981049ce9511 | 7 | #include "MQTTClientMbedOs.h" |
ostoja | 0:981049ce9511 | 8 | |
ostoja | 0:981049ce9511 | 9 | // I2C bus pins: |
ostoja | 0:981049ce9511 | 10 | #define D_SDA PB_14 |
ostoja | 0:981049ce9511 | 11 | #define D_SCL PB_13 |
ostoja | 0:981049ce9511 | 12 | // I2C address, 60d or 0x3c: |
ostoja | 0:981049ce9511 | 13 | #define I2C_REAL_ADD 0x3c |
ostoja | 0:981049ce9511 | 14 | #define I2C_ADDRESS I2C_REAL_ADD << 1 |
ostoja | 0:981049ce9511 | 15 | // Set OLED width and heigth [pixel]: |
ostoja | 0:981049ce9511 | 16 | #define OLED_WIDTH_PX 128 |
ostoja | 0:981049ce9511 | 17 | #define OLED_HEIGHT_PX 64 |
ostoja | 0:981049ce9511 | 18 | // I2C frequency: |
ostoja | 0:981049ce9511 | 19 | #define I2C_FREQUENCY 400000 |
ostoja | 0:981049ce9511 | 20 | // Multipliers of POT1 and POT2 for OLED rectangle position: |
ostoja | 0:981049ce9511 | 21 | #define WIDTH_SCALER 128 |
ostoja | 0:981049ce9511 | 22 | #define HEIGHT_SCALER 64 |
ostoja | 0:981049ce9511 | 23 | // Initial rectangle position: |
ostoja | 0:981049ce9511 | 24 | #define INITIAL_X_POSITION OLED_WIDTH_PX / 2 |
ostoja | 0:981049ce9511 | 25 | #define INITIAL_Y_POSITION OLED_HEIGHT_PX / 2 |
ostoja | 0:981049ce9511 | 26 | // Refresh rate: |
ostoja | 0:981049ce9511 | 27 | #define REFRESH_RATE_MS 5 |
ostoja | 0:981049ce9511 | 28 | // Half of the potentiometer return value: |
ostoja | 0:981049ce9511 | 29 | #define HALF_INTERVAL 0.5f |
ostoja | 0:981049ce9511 | 30 | // LED2 blinking rate: |
ostoja | 0:981049ce9511 | 31 | #define BLINKING_RATE_MS 250 |
ostoja | 0:981049ce9511 | 32 | // Scaler to 3v3L |
ostoja | 0:981049ce9511 | 33 | #define VOLTAGE_SCALER 3.3f |
ostoja | 0:981049ce9511 | 34 | // Client yield timeout in miliseconds: |
ostoja | 0:981049ce9511 | 35 | #define YIELD_TIMEOUT_MS 1000 |
ostoja | 0:981049ce9511 | 36 | // Maximum number of networks to scan for: |
ostoja | 0:981049ce9511 | 37 | #define MAX_NETWORKS 15 |
ostoja | 0:981049ce9511 | 38 | // Small delay for network information printing: |
ostoja | 0:981049ce9511 | 39 | #define PRINTF_DELAY_MS 10 |
ostoja | 0:981049ce9511 | 40 | |
ostoja | 0:981049ce9511 | 41 | // Initialize I2C: |
ostoja | 0:981049ce9511 | 42 | I2C i2c(PB_14,PB_13); |
ostoja | 0:981049ce9511 | 43 | |
ostoja | 0:981049ce9511 | 44 | // Initialize OLED display: |
ostoja | 0:981049ce9511 | 45 | Adafruit_SSD1306_I2c myOled(i2c,PB_5,I2C_ADDRESS,OLED_HEIGHT_PX,OLED_WIDTH_PX); |
ostoja | 0:981049ce9511 | 46 | |
ostoja | 0:981049ce9511 | 47 | // Left potentiometer: |
ostoja | 0:981049ce9511 | 48 | AnalogIn pot1(MB_POT1); |
ostoja | 0:981049ce9511 | 49 | // Left button on the motherboard: |
ostoja | 0:981049ce9511 | 50 | InterruptIn sw1(MB_SW1); |
ostoja | 0:981049ce9511 | 51 | // Right LED on the motherboard: |
ostoja | 0:981049ce9511 | 52 | DigitalOut led2(MB_LED2); |
ostoja | 0:981049ce9511 | 53 | DigitalIn sw2(MB_SW2); |
ostoja | 0:981049ce9511 | 54 | int sw2_state; |
ostoja | 0:981049ce9511 | 55 | // Pointer to a WiFi network object: |
ostoja | 0:981049ce9511 | 56 | WiFiInterface *wifi; |
ostoja | 0:981049ce9511 | 57 | // Creating TCP socket: |
ostoja | 0:981049ce9511 | 58 | TCPSocket socket; |
ostoja | 0:981049ce9511 | 59 | // Creating MQTT client using the TCP socket; |
ostoja | 0:981049ce9511 | 60 | MQTTClient client(&socket); |
ostoja | 0:981049ce9511 | 61 | // Message handler: |
ostoja | 0:981049ce9511 | 62 | MQTT::Message message; |
ostoja | 0:981049ce9511 | 63 | |
ostoja | 0:981049ce9511 | 64 | char* topic = "pubpim"; |
ostoja | 0:981049ce9511 | 65 | char* topic_sub = "subpim"; |
ostoja | 0:981049ce9511 | 66 | // Counter of arrived messages: |
ostoja | 0:981049ce9511 | 67 | int arrivedcount = 0; |
ostoja | 0:981049ce9511 | 68 | int send_voltage = 0; |
ostoja | 0:981049ce9511 | 69 | // Flag indicating that button is not pressed: |
ostoja | 0:981049ce9511 | 70 | int button_pressed=0; |
ostoja | 0:981049ce9511 | 71 | // HiveMQ broker connectivity information: |
ostoja | 0:981049ce9511 | 72 | const char* hostname = "broker.hivemq.com"; |
ostoja | 0:981049ce9511 | 73 | int port = 1883; |
ostoja | 0:981049ce9511 | 74 | // Returning a string for a provided network encryption: |
ostoja | 0:981049ce9511 | 75 | const char *sec2str(nsapi_security_t sec) |
ostoja | 0:981049ce9511 | 76 | { |
ostoja | 0:981049ce9511 | 77 | switch (sec) |
ostoja | 0:981049ce9511 | 78 | { |
ostoja | 0:981049ce9511 | 79 | case NSAPI_SECURITY_NONE: |
ostoja | 0:981049ce9511 | 80 | return "None"; |
ostoja | 0:981049ce9511 | 81 | case NSAPI_SECURITY_WEP: |
ostoja | 0:981049ce9511 | 82 | return "WEP"; |
ostoja | 0:981049ce9511 | 83 | case NSAPI_SECURITY_WPA: |
ostoja | 0:981049ce9511 | 84 | return "WPA"; |
ostoja | 0:981049ce9511 | 85 | case NSAPI_SECURITY_WPA2: |
ostoja | 0:981049ce9511 | 86 | return "WPA2"; |
ostoja | 0:981049ce9511 | 87 | case NSAPI_SECURITY_WPA_WPA2: |
ostoja | 0:981049ce9511 | 88 | return "WPA/WPA2"; |
ostoja | 0:981049ce9511 | 89 | case NSAPI_SECURITY_UNKNOWN: |
ostoja | 0:981049ce9511 | 90 | default: |
ostoja | 0:981049ce9511 | 91 | return "Unknown"; |
ostoja | 0:981049ce9511 | 92 | } |
ostoja | 0:981049ce9511 | 93 | } |
ostoja | 0:981049ce9511 | 94 | |
ostoja | 0:981049ce9511 | 95 | int scan_networks(WiFiInterface *wifi) |
ostoja | 0:981049ce9511 | 96 | { |
ostoja | 0:981049ce9511 | 97 | printf("Scan:\n"); |
ostoja | 0:981049ce9511 | 98 | |
ostoja | 0:981049ce9511 | 99 | // Scan only for the number of networks, first parameter is NULL: |
ostoja | 0:981049ce9511 | 100 | int count = wifi->scan(NULL, 0); |
ostoja | 0:981049ce9511 | 101 | // If there are no networks, count == 0, if there is an error, counter < 0: |
ostoja | 0:981049ce9511 | 102 | if (count <= 0) |
ostoja | 0:981049ce9511 | 103 | { |
ostoja | 0:981049ce9511 | 104 | printf("scan() failed with return value: %d\n", count); |
ostoja | 0:981049ce9511 | 105 | return 0; |
ostoja | 0:981049ce9511 | 106 | } |
ostoja | 0:981049ce9511 | 107 | |
ostoja | 0:981049ce9511 | 108 | // Limit number of network arbitrary to some reasonable number: |
ostoja | 0:981049ce9511 | 109 | count = count < MAX_NETWORKS ? count : MAX_NETWORKS; |
ostoja | 0:981049ce9511 | 110 | |
ostoja | 0:981049ce9511 | 111 | // Create a local pointer to an object, which is an array of WiFi APs: |
ostoja | 0:981049ce9511 | 112 | WiFiAccessPoint *ap = new WiFiAccessPoint[count]; |
ostoja | 0:981049ce9511 | 113 | // Now scan again for 'count' networks and populate the array of APs: |
ostoja | 0:981049ce9511 | 114 | count = wifi->scan(ap, count); |
ostoja | 0:981049ce9511 | 115 | |
ostoja | 0:981049ce9511 | 116 | // This time, the number of entries to 'ap' is returned: |
ostoja | 0:981049ce9511 | 117 | if (count <= 0) |
ostoja | 0:981049ce9511 | 118 | { |
ostoja | 0:981049ce9511 | 119 | printf("scan() failed with return value: %d\n", count); |
ostoja | 0:981049ce9511 | 120 | return 0; |
ostoja | 0:981049ce9511 | 121 | } |
ostoja | 0:981049ce9511 | 122 | |
ostoja | 0:981049ce9511 | 123 | // Print out the parameters of each AP: |
ostoja | 0:981049ce9511 | 124 | for (int i = 0; i < count; i++) |
ostoja | 0:981049ce9511 | 125 | { |
ostoja | 0:981049ce9511 | 126 | printf("Network: %s secured: %s BSSID: %hhX:%hhX:%hhX:%hhx:%hhx:%hhx RSSI: %hhd Ch: %hhd\n", ap[i].get_ssid(), |
ostoja | 0:981049ce9511 | 127 | sec2str(ap[i].get_security()), ap[i].get_bssid()[0], ap[i].get_bssid()[1], ap[i].get_bssid()[2], |
ostoja | 0:981049ce9511 | 128 | ap[i].get_bssid()[3], ap[i].get_bssid()[4], ap[i].get_bssid()[5], ap[i].get_rssi(), ap[i].get_channel()); |
ostoja | 0:981049ce9511 | 129 | thread_sleep_for(PRINTF_DELAY_MS); |
ostoja | 0:981049ce9511 | 130 | } |
ostoja | 0:981049ce9511 | 131 | printf("%d networks available.\n", count); |
ostoja | 0:981049ce9511 | 132 | |
ostoja | 0:981049ce9511 | 133 | // Since 'ap' is dynamically allocated pointer to the array of objects, it |
ostoja | 0:981049ce9511 | 134 | // needs to be deleted: |
ostoja | 0:981049ce9511 | 135 | delete[] ap; |
ostoja | 0:981049ce9511 | 136 | return count; |
ostoja | 0:981049ce9511 | 137 | } |
ostoja | 0:981049ce9511 | 138 | |
ostoja | 0:981049ce9511 | 139 | void print_text(int len, char buf[100]){ |
ostoja | 0:981049ce9511 | 140 | if(arrivedcount > 5){ |
ostoja | 0:981049ce9511 | 141 | arrivedcount = 0; |
ostoja | 0:981049ce9511 | 142 | myOled.clearDisplay(); |
ostoja | 0:981049ce9511 | 143 | } |
ostoja | 0:981049ce9511 | 144 | for(int i = 0;i < len; i++){ |
ostoja | 0:981049ce9511 | 145 | myOled.drawChar(10 + i * 6,1 + 10 * arrivedcount,buf[i],1,0,1); |
ostoja | 0:981049ce9511 | 146 | } |
ostoja | 0:981049ce9511 | 147 | myOled.display(); |
ostoja | 0:981049ce9511 | 148 | } |
ostoja | 0:981049ce9511 | 149 | |
ostoja | 0:981049ce9511 | 150 | void messageArrived(MQTT::MessageData& md) |
ostoja | 0:981049ce9511 | 151 | { |
ostoja | 0:981049ce9511 | 152 | MQTT::Message &message = md.message; |
ostoja | 0:981049ce9511 | 153 | //printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id); |
ostoja | 0:981049ce9511 | 154 | printf("Message from the browser: %.*s\r\n", message.payloadlen, (char*)message.payload); |
ostoja | 0:981049ce9511 | 155 | char buf[100]; |
ostoja | 0:981049ce9511 | 156 | sprintf(buf,"%.*s", message.payloadlen, (char*)message.payload); |
ostoja | 0:981049ce9511 | 157 | |
ostoja | 0:981049ce9511 | 158 | printf("%s\r\n",buf); |
ostoja | 0:981049ce9511 | 159 | |
ostoja | 0:981049ce9511 | 160 | ++arrivedcount; |
ostoja | 0:981049ce9511 | 161 | print_text(message.payloadlen,(char*)message.payload); |
ostoja | 0:981049ce9511 | 162 | |
ostoja | 0:981049ce9511 | 163 | if(strcmp(buf,"start")==0){ |
ostoja | 0:981049ce9511 | 164 | send_voltage = 1; |
ostoja | 0:981049ce9511 | 165 | } |
ostoja | 0:981049ce9511 | 166 | |
ostoja | 0:981049ce9511 | 167 | if(strcmp(buf,"stop")==0){ |
ostoja | 0:981049ce9511 | 168 | send_voltage = 0; |
ostoja | 0:981049ce9511 | 169 | } |
ostoja | 0:981049ce9511 | 170 | } |
ostoja | 0:981049ce9511 | 171 | |
ostoja | 0:981049ce9511 | 172 | void buttonFunction() { |
ostoja | 0:981049ce9511 | 173 | button_pressed=1; |
ostoja | 0:981049ce9511 | 174 | } |
ostoja | 0:981049ce9511 | 175 | |
ostoja | 0:981049ce9511 | 176 | int main() |
ostoja | 0:981049ce9511 | 177 | { |
ostoja | 0:981049ce9511 | 178 | myOled.begin(); |
ostoja | 0:981049ce9511 | 179 | i2c.frequency(I2C_FREQUENCY); |
ostoja | 0:981049ce9511 | 180 | // Set the interrupt event: |
ostoja | 0:981049ce9511 | 181 | sw1.fall(&buttonFunction); |
ostoja | 0:981049ce9511 | 182 | |
ostoja | 0:981049ce9511 | 183 | // Create a default network interface: |
ostoja | 0:981049ce9511 | 184 | wifi = WiFiInterface::get_default_instance(); |
ostoja | 0:981049ce9511 | 185 | if (!wifi) { |
ostoja | 0:981049ce9511 | 186 | printf("ERROR: No WiFiInterface found.\n"); |
ostoja | 0:981049ce9511 | 187 | return -1; |
ostoja | 0:981049ce9511 | 188 | } |
ostoja | 0:981049ce9511 | 189 | |
ostoja | 0:981049ce9511 | 190 | // Scan for available networks and aquire information about Access Points: |
ostoja | 0:981049ce9511 | 191 | int count = scan_networks(wifi); |
ostoja | 0:981049ce9511 | 192 | if (count == 0) { |
ostoja | 0:981049ce9511 | 193 | printf("No WIFI APs found - can't continue further.\n"); |
ostoja | 0:981049ce9511 | 194 | return -1; |
ostoja | 0:981049ce9511 | 195 | } |
ostoja | 0:981049ce9511 | 196 | |
ostoja | 0:981049ce9511 | 197 | // Connect to the network with the parameters specified in 'mbed_app.json': |
ostoja | 0:981049ce9511 | 198 | printf("\nConnecting to %s...\n", MBED_CONF_APP_WIFI_SSID); |
ostoja | 0:981049ce9511 | 199 | int ret = wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2); |
ostoja | 0:981049ce9511 | 200 | if (ret != 0) { |
ostoja | 0:981049ce9511 | 201 | printf("\nConnection error: %d\n", ret); |
ostoja | 0:981049ce9511 | 202 | return -1; |
ostoja | 0:981049ce9511 | 203 | } |
ostoja | 0:981049ce9511 | 204 | |
ostoja | 0:981049ce9511 | 205 | // Print out the information aquired: |
ostoja | 0:981049ce9511 | 206 | printf("Success\n\n"); |
ostoja | 0:981049ce9511 | 207 | printf("MAC: %s\n", wifi->get_mac_address()); |
ostoja | 0:981049ce9511 | 208 | printf("IP: %s\n", wifi->get_ip_address()); |
ostoja | 0:981049ce9511 | 209 | printf("Netmask: %s\n", wifi->get_netmask()); |
ostoja | 0:981049ce9511 | 210 | printf("Gateway: %s\n", wifi->get_gateway()); |
ostoja | 0:981049ce9511 | 211 | printf("RSSI: %d\n\n", wifi->get_rssi()); |
ostoja | 0:981049ce9511 | 212 | |
ostoja | 0:981049ce9511 | 213 | // Open TCP socket using WiFi network interface: |
ostoja | 0:981049ce9511 | 214 | socket.open(wifi); |
ostoja | 0:981049ce9511 | 215 | // Connect to the HiveMQ broker: |
ostoja | 0:981049ce9511 | 216 | socket.connect(hostname, port); |
ostoja | 0:981049ce9511 | 217 | // Fill connect data with default values: |
ostoja | 0:981049ce9511 | 218 | MQTTPacket_connectData data = MQTTPacket_connectData_initializer; |
ostoja | 0:981049ce9511 | 219 | // Change only ID and protocol version: |
ostoja | 0:981049ce9511 | 220 | data.MQTTVersion = 3; |
ostoja | 0:981049ce9511 | 221 | data.clientID.cstring = "NUCLEO-L476RG-60"; |
ostoja | 0:981049ce9511 | 222 | |
ostoja | 0:981049ce9511 | 223 | // Connect the |
ostoja | 0:981049ce9511 | 224 | int rc = 0; |
ostoja | 0:981049ce9511 | 225 | if ((rc = client.connect(data)) != 0) |
ostoja | 0:981049ce9511 | 226 | printf("rc from MQTT connect is %d\r\n", rc); |
ostoja | 0:981049ce9511 | 227 | |
ostoja | 0:981049ce9511 | 228 | if ((rc = client.subscribe(topic_sub, MQTT::QOS2, messageArrived)) != 0) |
ostoja | 0:981049ce9511 | 229 | printf("rc from MQTT subscribe is %d\r\n", rc); |
ostoja | 0:981049ce9511 | 230 | |
ostoja | 0:981049ce9511 | 231 | while (true) { |
ostoja | 0:981049ce9511 | 232 | |
ostoja | 0:981049ce9511 | 233 | // Show that the loop is running by switching motherboard LED2: |
ostoja | 0:981049ce9511 | 234 | led2 = !led2; |
ostoja | 0:981049ce9511 | 235 | //thread_sleep_for(BLINKING_RATE_MS); |
ostoja | 0:981049ce9511 | 236 | if (button_pressed==1 && send_voltage == 1) { |
ostoja | 0:981049ce9511 | 237 | button_pressed=0; |
ostoja | 0:981049ce9511 | 238 | // QoS 0 |
ostoja | 0:981049ce9511 | 239 | char buf[100]; |
ostoja | 0:981049ce9511 | 240 | sprintf(buf, "V(POT1) = %1.2f\r\n", pot1*VOLTAGE_SCALER); |
ostoja | 0:981049ce9511 | 241 | message.qos = MQTT::QOS0; |
ostoja | 0:981049ce9511 | 242 | message.retained = false; |
ostoja | 0:981049ce9511 | 243 | message.dup = false; |
ostoja | 0:981049ce9511 | 244 | message.payload = (void*)buf; |
ostoja | 0:981049ce9511 | 245 | message.payloadlen = strlen(buf)+1; |
ostoja | 0:981049ce9511 | 246 | client.publish(topic, message); |
ostoja | 0:981049ce9511 | 247 | ++arrivedcount; |
ostoja | 0:981049ce9511 | 248 | print_text(14,buf); |
ostoja | 0:981049ce9511 | 249 | |
ostoja | 0:981049ce9511 | 250 | } |
ostoja | 0:981049ce9511 | 251 | // Need to call yield API to maintain connection: |
ostoja | 0:981049ce9511 | 252 | client.yield(YIELD_TIMEOUT_MS); |
ostoja | 0:981049ce9511 | 253 | } |
ostoja | 0:981049ce9511 | 254 | } |