![](/media/cache/profiles/nikki.png.50x50_q85.jpg)
19E042PIM 2021/22 T3 Key
Dependencies: Adafruit_GFX 19E042PIM_MB_PINS
main.cpp@0:e60b621e14a5, 2021-12-15 (annotated)
- Committer:
- tzwell
- Date:
- Wed Dec 15 22:31:26 2021 +0000
- Revision:
- 0:e60b621e14a5
Test 3 key, first commit.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
tzwell | 0:e60b621e14a5 | 1 | /* |
tzwell | 0:e60b621e14a5 | 2 | * Upon receiving 'start' mcu starts sending voltage values stampled from POT1. |
tzwell | 0:e60b621e14a5 | 3 | * When 'stop' is received, sending is stopped, while after receving 'oled', |
tzwell | 0:e60b621e14a5 | 4 | * message transaction is displayed on OLED display. |
tzwell | 0:e60b621e14a5 | 5 | * |
tzwell | 0:e60b621e14a5 | 6 | * University of Belgrade - School of Electrical Engineering |
tzwell | 0:e60b621e14a5 | 7 | * Department of Electronics |
tzwell | 0:e60b621e14a5 | 8 | * Bulevar Kralja Aleksandra 73, 11120 Belgrade, Serbia |
tzwell | 0:e60b621e14a5 | 9 | * |
tzwell | 0:e60b621e14a5 | 10 | * December 2021. |
tzwell | 0:e60b621e14a5 | 11 | * |
tzwell | 0:e60b621e14a5 | 12 | */ |
tzwell | 0:e60b621e14a5 | 13 | |
tzwell | 0:e60b621e14a5 | 14 | /* |
tzwell | 0:e60b621e14a5 | 15 | * Includes: |
tzwell | 0:e60b621e14a5 | 16 | */ |
tzwell | 0:e60b621e14a5 | 17 | #include "mbed.h" |
tzwell | 0:e60b621e14a5 | 18 | #include "mb_pins.h" |
tzwell | 0:e60b621e14a5 | 19 | #include "platform/mbed_thread.h" |
tzwell | 0:e60b621e14a5 | 20 | #include "MQTTClientMbedOs.h" |
tzwell | 0:e60b621e14a5 | 21 | #include "Adafruit_GFX.h" |
tzwell | 0:e60b621e14a5 | 22 | #include "Adafruit_GFX_Config.h" |
tzwell | 0:e60b621e14a5 | 23 | #include "Adafruit_SSD1306.h" |
tzwell | 0:e60b621e14a5 | 24 | |
tzwell | 0:e60b621e14a5 | 25 | /* |
tzwell | 0:e60b621e14a5 | 26 | * User defines: |
tzwell | 0:e60b621e14a5 | 27 | */ |
tzwell | 0:e60b621e14a5 | 28 | // Scaler to 3v3L |
tzwell | 0:e60b621e14a5 | 29 | #define VOLTAGE_SCALER 3.3f |
tzwell | 0:e60b621e14a5 | 30 | // Client yield timeout in miliseconds: |
tzwell | 0:e60b621e14a5 | 31 | #define YIELD_TIMEOUT_MS 500 |
tzwell | 0:e60b621e14a5 | 32 | // MQTT message buffer length: |
tzwell | 0:e60b621e14a5 | 33 | #define BUFF_LEN 15 |
tzwell | 0:e60b621e14a5 | 34 | // Sampling period: |
tzwell | 0:e60b621e14a5 | 35 | #define SAMPLE_PERIOD 10 |
tzwell | 0:e60b621e14a5 | 36 | // Sampling period scaler: |
tzwell | 0:e60b621e14a5 | 37 | #define SAMPLE_SCALER SAMPLE_PERIOD*1000/YIELD_TIMEOUT_MS |
tzwell | 0:e60b621e14a5 | 38 | // I2C bus pins: |
tzwell | 0:e60b621e14a5 | 39 | #define D_SDA PB_14 |
tzwell | 0:e60b621e14a5 | 40 | #define D_SCL PB_13 |
tzwell | 0:e60b621e14a5 | 41 | // I2C address, 60d or 0x3c: |
tzwell | 0:e60b621e14a5 | 42 | #define I2C_REAL_ADD 0x3c |
tzwell | 0:e60b621e14a5 | 43 | #define I2C_ADDRESS I2C_REAL_ADD << 1 |
tzwell | 0:e60b621e14a5 | 44 | // Set OLED width and heigth [pixel]: |
tzwell | 0:e60b621e14a5 | 45 | #define OLED_WIDTH_PX 128 |
tzwell | 0:e60b621e14a5 | 46 | #define OLED_HEIGHT_PX 64 |
tzwell | 0:e60b621e14a5 | 47 | // State machine conditions (list of commands): |
tzwell | 0:e60b621e14a5 | 48 | #define START_COND "start" |
tzwell | 0:e60b621e14a5 | 49 | #define STOP_COND "stop" |
tzwell | 0:e60b621e14a5 | 50 | #define OLED_COND "oled" |
tzwell | 0:e60b621e14a5 | 51 | |
tzwell | 0:e60b621e14a5 | 52 | |
tzwell | 0:e60b621e14a5 | 53 | /* |
tzwell | 0:e60b621e14a5 | 54 | * Global user variables/objects: |
tzwell | 0:e60b621e14a5 | 55 | */ |
tzwell | 0:e60b621e14a5 | 56 | // Left potentiometer: |
tzwell | 0:e60b621e14a5 | 57 | AnalogIn pot1(MB_POT1); |
tzwell | 0:e60b621e14a5 | 58 | // Right LED on the motherboard: |
tzwell | 0:e60b621e14a5 | 59 | DigitalOut led2(MB_LED2); |
tzwell | 0:e60b621e14a5 | 60 | // Pointer to a WiFi network object: |
tzwell | 0:e60b621e14a5 | 61 | WiFiInterface *wifi; |
tzwell | 0:e60b621e14a5 | 62 | // Creating TCP socket: |
tzwell | 0:e60b621e14a5 | 63 | TCPSocket socket; |
tzwell | 0:e60b621e14a5 | 64 | // Creating MQTT client using the TCP socket; |
tzwell | 0:e60b621e14a5 | 65 | MQTTClient client(&socket); |
tzwell | 0:e60b621e14a5 | 66 | // Sent message handler: |
tzwell | 0:e60b621e14a5 | 67 | MQTT::Message message_sent; |
tzwell | 0:e60b621e14a5 | 68 | // Received message handler: |
tzwell | 0:e60b621e14a5 | 69 | MQTT::Message message_received; |
tzwell | 0:e60b621e14a5 | 70 | // Initialize I2C: |
tzwell | 0:e60b621e14a5 | 71 | I2C i2c(D_SDA,D_SCL); |
tzwell | 0:e60b621e14a5 | 72 | // Initialize OLED display: |
tzwell | 0:e60b621e14a5 | 73 | Adafruit_SSD1306_I2c myOled(i2c,PB_5,I2C_ADDRESS,OLED_HEIGHT_PX,OLED_WIDTH_PX); |
tzwell | 0:e60b621e14a5 | 74 | // MQTT topics: |
tzwell | 0:e60b621e14a5 | 75 | char* topic_pub = "pubpim"; |
tzwell | 0:e60b621e14a5 | 76 | char* topic_sub = "subpim"; |
tzwell | 0:e60b621e14a5 | 77 | // HiveMQ broker connectivity information: |
tzwell | 0:e60b621e14a5 | 78 | const char* hostname = "broker.hivemq.com"; |
tzwell | 0:e60b621e14a5 | 79 | int port = 1883; |
tzwell | 0:e60b621e14a5 | 80 | // Flag indicating that pot values should be sent: |
tzwell | 0:e60b621e14a5 | 81 | char sending_allowed = 0; |
tzwell | 0:e60b621e14a5 | 82 | // Flag indicating that OLED display preview is enabled: |
tzwell | 0:e60b621e14a5 | 83 | char oled_allowed = 0; |
tzwell | 0:e60b621e14a5 | 84 | //Pseudo-timer for avoiding long CPU idle periods: |
tzwell | 0:e60b621e14a5 | 85 | int pseudo_timer = 0; |
tzwell | 0:e60b621e14a5 | 86 | // Message buffer to be sent: |
tzwell | 0:e60b621e14a5 | 87 | char buf[BUFF_LEN]; |
tzwell | 0:e60b621e14a5 | 88 | // Message processing status: |
tzwell | 0:e60b621e14a5 | 89 | char msgrcv = 0; |
tzwell | 0:e60b621e14a5 | 90 | |
tzwell | 0:e60b621e14a5 | 91 | /* |
tzwell | 0:e60b621e14a5 | 92 | * Publish pot value: |
tzwell | 0:e60b621e14a5 | 93 | */ |
tzwell | 0:e60b621e14a5 | 94 | void publishPot() |
tzwell | 0:e60b621e14a5 | 95 | { |
tzwell | 0:e60b621e14a5 | 96 | sprintf(buf, "V = %1.2f\r\n", pot1*VOLTAGE_SCALER); |
tzwell | 0:e60b621e14a5 | 97 | message_sent.qos = MQTT::QOS0; |
tzwell | 0:e60b621e14a5 | 98 | message_sent.retained = false; |
tzwell | 0:e60b621e14a5 | 99 | message_sent.dup = false; |
tzwell | 0:e60b621e14a5 | 100 | message_sent.payload = (void*)buf; |
tzwell | 0:e60b621e14a5 | 101 | message_sent.payloadlen = strlen(buf); |
tzwell | 0:e60b621e14a5 | 102 | client.publish(topic_pub, message_sent); |
tzwell | 0:e60b621e14a5 | 103 | } |
tzwell | 0:e60b621e14a5 | 104 | |
tzwell | 0:e60b621e14a5 | 105 | /* |
tzwell | 0:e60b621e14a5 | 106 | * MQTT traffic previewed on OLED: |
tzwell | 0:e60b621e14a5 | 107 | */ |
tzwell | 0:e60b621e14a5 | 108 | void oledPreview() |
tzwell | 0:e60b621e14a5 | 109 | { |
tzwell | 0:e60b621e14a5 | 110 | myOled.clearDisplay(); |
tzwell | 0:e60b621e14a5 | 111 | myOled.setTextCursor(0, 0); |
tzwell | 0:e60b621e14a5 | 112 | myOled.printf("Sent: %.*s\n", strlen(buf), buf); |
tzwell | 0:e60b621e14a5 | 113 | myOled.printf("Received: %.*s\n", message_received.payloadlen, (char*)message_received.payload); |
tzwell | 0:e60b621e14a5 | 114 | myOled.display(); |
tzwell | 0:e60b621e14a5 | 115 | } |
tzwell | 0:e60b621e14a5 | 116 | |
tzwell | 0:e60b621e14a5 | 117 | /* |
tzwell | 0:e60b621e14a5 | 118 | * Check if payload satisfies any of the state machine conditions: |
tzwell | 0:e60b621e14a5 | 119 | */ |
tzwell | 0:e60b621e14a5 | 120 | int checkCondition (char* payload, int payloadlen, char* condition) |
tzwell | 0:e60b621e14a5 | 121 | { |
tzwell | 0:e60b621e14a5 | 122 | char not_satisfied = 0; |
tzwell | 0:e60b621e14a5 | 123 | char cnt = 0; |
tzwell | 0:e60b621e14a5 | 124 | while(cnt != payloadlen) |
tzwell | 0:e60b621e14a5 | 125 | { |
tzwell | 0:e60b621e14a5 | 126 | if (payload[cnt] != condition[cnt]) |
tzwell | 0:e60b621e14a5 | 127 | not_satisfied = 1; |
tzwell | 0:e60b621e14a5 | 128 | cnt++; |
tzwell | 0:e60b621e14a5 | 129 | } |
tzwell | 0:e60b621e14a5 | 130 | return not_satisfied; |
tzwell | 0:e60b621e14a5 | 131 | } |
tzwell | 0:e60b621e14a5 | 132 | |
tzwell | 0:e60b621e14a5 | 133 | /* |
tzwell | 0:e60b621e14a5 | 134 | * MQTT message received function: |
tzwell | 0:e60b621e14a5 | 135 | */ |
tzwell | 0:e60b621e14a5 | 136 | void messageArrived(MQTT::MessageData& md) |
tzwell | 0:e60b621e14a5 | 137 | { |
tzwell | 0:e60b621e14a5 | 138 | MQTT::Message &message = md.message; |
tzwell | 0:e60b621e14a5 | 139 | message_received = md.message; |
tzwell | 0:e60b621e14a5 | 140 | msgrcv = 1; |
tzwell | 0:e60b621e14a5 | 141 | printf("Message from the browser: %.*s\r\n", message.payloadlen, (char*)message.payload); |
tzwell | 0:e60b621e14a5 | 142 | } |
tzwell | 0:e60b621e14a5 | 143 | |
tzwell | 0:e60b621e14a5 | 144 | /* |
tzwell | 0:e60b621e14a5 | 145 | * State machine update upon receiving a message: |
tzwell | 0:e60b621e14a5 | 146 | */ |
tzwell | 0:e60b621e14a5 | 147 | void stateCheck() |
tzwell | 0:e60b621e14a5 | 148 | { |
tzwell | 0:e60b621e14a5 | 149 | char message_buff[BUFF_LEN]; |
tzwell | 0:e60b621e14a5 | 150 | |
tzwell | 0:e60b621e14a5 | 151 | // Copy payload into a char arrray: |
tzwell | 0:e60b621e14a5 | 152 | sprintf(message_buff, "%.*s",message_received.payloadlen, (char*)message_received.payload); |
tzwell | 0:e60b621e14a5 | 153 | |
tzwell | 0:e60b621e14a5 | 154 | // State machine: |
tzwell | 0:e60b621e14a5 | 155 | if(!checkCondition(message_buff, strlen(message_buff), START_COND)) |
tzwell | 0:e60b621e14a5 | 156 | { |
tzwell | 0:e60b621e14a5 | 157 | sending_allowed = 1; |
tzwell | 0:e60b621e14a5 | 158 | } |
tzwell | 0:e60b621e14a5 | 159 | else if (!checkCondition(message_buff, strlen(message_buff), STOP_COND)) |
tzwell | 0:e60b621e14a5 | 160 | { |
tzwell | 0:e60b621e14a5 | 161 | sending_allowed = 0; |
tzwell | 0:e60b621e14a5 | 162 | } |
tzwell | 0:e60b621e14a5 | 163 | else if (!checkCondition(message_buff, strlen(message_buff), OLED_COND)) |
tzwell | 0:e60b621e14a5 | 164 | { |
tzwell | 0:e60b621e14a5 | 165 | oled_allowed = 1; |
tzwell | 0:e60b621e14a5 | 166 | myOled.begin(); |
tzwell | 0:e60b621e14a5 | 167 | oledPreview(); |
tzwell | 0:e60b621e14a5 | 168 | } |
tzwell | 0:e60b621e14a5 | 169 | // Mark the end of message processing: |
tzwell | 0:e60b621e14a5 | 170 | msgrcv = 0; |
tzwell | 0:e60b621e14a5 | 171 | } |
tzwell | 0:e60b621e14a5 | 172 | |
tzwell | 0:e60b621e14a5 | 173 | |
tzwell | 0:e60b621e14a5 | 174 | /* |
tzwell | 0:e60b621e14a5 | 175 | * Main: |
tzwell | 0:e60b621e14a5 | 176 | */ |
tzwell | 0:e60b621e14a5 | 177 | int main() |
tzwell | 0:e60b621e14a5 | 178 | { |
tzwell | 0:e60b621e14a5 | 179 | // Create a default network interface: |
tzwell | 0:e60b621e14a5 | 180 | wifi = WiFiInterface::get_default_instance(); |
tzwell | 0:e60b621e14a5 | 181 | |
tzwell | 0:e60b621e14a5 | 182 | // Connect to the network with the parameters specified in 'mbed_app.json': |
tzwell | 0:e60b621e14a5 | 183 | printf("\nConnecting to %s...\n", MBED_CONF_APP_WIFI_SSID); |
tzwell | 0:e60b621e14a5 | 184 | wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2); |
tzwell | 0:e60b621e14a5 | 185 | // Mark connection done: |
tzwell | 0:e60b621e14a5 | 186 | printf("\nConnected.\r\n"); |
tzwell | 0:e60b621e14a5 | 187 | |
tzwell | 0:e60b621e14a5 | 188 | // Open TCP socket using WiFi network interface: |
tzwell | 0:e60b621e14a5 | 189 | socket.open(wifi); |
tzwell | 0:e60b621e14a5 | 190 | // Connect to the HiveMQ broker over the internet: |
tzwell | 0:e60b621e14a5 | 191 | socket.connect(hostname, port); |
tzwell | 0:e60b621e14a5 | 192 | // Fill connect data with default values: |
tzwell | 0:e60b621e14a5 | 193 | MQTTPacket_connectData data = MQTTPacket_connectData_initializer; |
tzwell | 0:e60b621e14a5 | 194 | // Change only ID and protocol version: |
tzwell | 0:e60b621e14a5 | 195 | data.MQTTVersion = 3; |
tzwell | 0:e60b621e14a5 | 196 | data.clientID.cstring = "pim-60"; |
tzwell | 0:e60b621e14a5 | 197 | |
tzwell | 0:e60b621e14a5 | 198 | // Establish MQTT connection: |
tzwell | 0:e60b621e14a5 | 199 | client.connect(data); |
tzwell | 0:e60b621e14a5 | 200 | // Subscribe to the topic specified by topic_sub: |
tzwell | 0:e60b621e14a5 | 201 | client.subscribe(topic_sub, MQTT::QOS2, messageArrived); |
tzwell | 0:e60b621e14a5 | 202 | |
tzwell | 0:e60b621e14a5 | 203 | while (true) |
tzwell | 0:e60b621e14a5 | 204 | { |
tzwell | 0:e60b621e14a5 | 205 | // Show that the loop is running by switching motherboard LED2: |
tzwell | 0:e60b621e14a5 | 206 | led2 = !led2; |
tzwell | 0:e60b621e14a5 | 207 | |
tzwell | 0:e60b621e14a5 | 208 | // If the message is received, check state machine current state: |
tzwell | 0:e60b621e14a5 | 209 | if (msgrcv) |
tzwell | 0:e60b621e14a5 | 210 | stateCheck(); |
tzwell | 0:e60b621e14a5 | 211 | |
tzwell | 0:e60b621e14a5 | 212 | // If 'oled' was received: |
tzwell | 0:e60b621e14a5 | 213 | if (oled_allowed) |
tzwell | 0:e60b621e14a5 | 214 | oledPreview(); |
tzwell | 0:e60b621e14a5 | 215 | |
tzwell | 0:e60b621e14a5 | 216 | // If the pseudo-timer has counted 10s: |
tzwell | 0:e60b621e14a5 | 217 | if( pseudo_timer == (SAMPLE_SCALER)) |
tzwell | 0:e60b621e14a5 | 218 | { |
tzwell | 0:e60b621e14a5 | 219 | // If 'start' was received: |
tzwell | 0:e60b621e14a5 | 220 | if(sending_allowed == 1) |
tzwell | 0:e60b621e14a5 | 221 | publishPot(); |
tzwell | 0:e60b621e14a5 | 222 | // Reset pseudo-timer: |
tzwell | 0:e60b621e14a5 | 223 | pseudo_timer = 0; |
tzwell | 0:e60b621e14a5 | 224 | } |
tzwell | 0:e60b621e14a5 | 225 | //Increment pseudo-timer: |
tzwell | 0:e60b621e14a5 | 226 | pseudo_timer++; |
tzwell | 0:e60b621e14a5 | 227 | // Need to call yield API to maintain connection: |
tzwell | 0:e60b621e14a5 | 228 | client.yield(YIELD_TIMEOUT_MS); |
tzwell | 0:e60b621e14a5 | 229 | } |
tzwell | 0:e60b621e14a5 | 230 | } |