19E042PIM 2021/22 T3 Key

Dependencies:   Adafruit_GFX 19E042PIM_MB_PINS

main.cpp

Committer:
tzwell
Date:
2021-12-15
Revision:
0:e60b621e14a5

File content as of revision 0:e60b621e14a5:

/*
 * Upon receiving 'start' mcu starts sending voltage values stampled from POT1. 
 * When 'stop' is received, sending is stopped, while after receving 'oled',
 * message transaction is displayed on OLED display. 
 *
 * University of Belgrade - School of Electrical Engineering
 * Department of Electronics
 * Bulevar Kralja Aleksandra 73, 11120 Belgrade, Serbia
 *
 * December 2021.
 *
 */
 
/*
 * Includes:
 */ 
#include "mbed.h"
#include "mb_pins.h"
#include "platform/mbed_thread.h"
#include "MQTTClientMbedOs.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GFX_Config.h"
#include "Adafruit_SSD1306.h"

/*
 * User defines:
 */  
// Scaler to 3v3L
#define VOLTAGE_SCALER                                                      3.3f
// Client yield timeout in miliseconds:
#define YIELD_TIMEOUT_MS                                                     500
// MQTT message buffer length:
#define BUFF_LEN                                                              15
// Sampling period:
#define SAMPLE_PERIOD                                                         10
// Sampling period scaler:
#define SAMPLE_SCALER                        SAMPLE_PERIOD*1000/YIELD_TIMEOUT_MS
// I2C bus pins:
#define D_SDA                  PB_14 
#define D_SCL                  PB_13     
// I2C address, 60d or 0x3c:
#define I2C_REAL_ADD                                                        0x3c
#define I2C_ADDRESS                                            I2C_REAL_ADD << 1 
// Set OLED width and heigth [pixel]:
#define OLED_WIDTH_PX                                                        128
#define OLED_HEIGHT_PX                                                        64
// State machine conditions (list of commands):
#define START_COND                                                       "start"
#define STOP_COND                                                         "stop"
#define OLED_COND                                                         "oled"


/*
 * Global user variables/objects:
 */ 
// Left potentiometer:
AnalogIn pot1(MB_POT1);
// Right LED on the motherboard:
DigitalOut led2(MB_LED2);
// Pointer to a WiFi network object:
WiFiInterface *wifi;
// Creating TCP socket:
TCPSocket socket;
// Creating MQTT client using the TCP socket;
MQTTClient client(&socket);
// Sent message handler:
MQTT::Message message_sent;
// Received message handler:
MQTT::Message message_received;
// Initialize I2C:
I2C i2c(D_SDA,D_SCL);
// Initialize OLED display:
Adafruit_SSD1306_I2c myOled(i2c,PB_5,I2C_ADDRESS,OLED_HEIGHT_PX,OLED_WIDTH_PX);
// MQTT topics:
char* topic_pub = "pubpim";
char* topic_sub = "subpim";
// HiveMQ broker connectivity information:
const char* hostname = "broker.hivemq.com";
int port = 1883;
// Flag indicating that pot values should be sent:
char sending_allowed = 0;
// Flag indicating that OLED display preview is enabled:
char oled_allowed = 0;
//Pseudo-timer for avoiding long CPU idle periods:
int pseudo_timer = 0;
// Message buffer to be sent:
char buf[BUFF_LEN];
// Message processing status:
char msgrcv = 0;

/*
 * Publish pot value:
 */
void publishPot()
{
    sprintf(buf, "V = %1.2f\r\n", pot1*VOLTAGE_SCALER);
    message_sent.qos = MQTT::QOS0;
    message_sent.retained = false;
    message_sent.dup = false;
    message_sent.payload = (void*)buf;
    message_sent.payloadlen = strlen(buf);
    client.publish(topic_pub, message_sent); 
}

/*
 * MQTT traffic previewed on OLED:
 */
void oledPreview()
{
    myOled.clearDisplay();
    myOled.setTextCursor(0, 0);
    myOled.printf("Sent: %.*s\n", strlen(buf), buf);
    myOled.printf("Received: %.*s\n", message_received.payloadlen, (char*)message_received.payload);
    myOled.display();     
}

/*
 * Check if payload satisfies any of the state machine conditions:
 */
int checkCondition (char* payload, int payloadlen, char* condition)
{
    char not_satisfied = 0;
    char cnt = 0;
    while(cnt != payloadlen)
    {
        if (payload[cnt] != condition[cnt])
            not_satisfied = 1;
        cnt++;
    }
    return not_satisfied;
}

/*
 * MQTT message received function:
 */
void messageArrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;
    message_received = md.message;
    msgrcv = 1;
    printf("Message from the browser: %.*s\r\n", message.payloadlen, (char*)message.payload);
}

/*
 * State machine update upon receiving a message:
 */
void stateCheck()
{
    char message_buff[BUFF_LEN];
    
    // Copy payload into a char arrray:
    sprintf(message_buff, "%.*s",message_received.payloadlen, (char*)message_received.payload);
    
    // State machine:     
    if(!checkCondition(message_buff, strlen(message_buff), START_COND))
    {
        sending_allowed = 1;
    }
    else if (!checkCondition(message_buff, strlen(message_buff), STOP_COND))
    {
        sending_allowed = 0;
    }
    else if (!checkCondition(message_buff, strlen(message_buff), OLED_COND))
    {
        oled_allowed = 1;            
        myOled.begin();
        oledPreview();
    } 
    // Mark the end of message processing:   
    msgrcv = 0;
}


/*
 * Main:
 */
int main()
{
    // Create a default network interface:
    wifi = WiFiInterface::get_default_instance();
    
    // Connect to the network with the parameters specified in 'mbed_app.json':
    printf("\nConnecting to %s...\n", MBED_CONF_APP_WIFI_SSID);
    wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2);
    // Mark connection done:
    printf("\nConnected.\r\n");
    
    // Open TCP socket using WiFi network interface:
    socket.open(wifi);
    // Connect to the HiveMQ broker over the internet:
    socket.connect(hostname, port);
    // Fill connect data with default values:
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    // Change only ID and protocol version:
    data.MQTTVersion = 3;
    data.clientID.cstring = "pim-60";
    
    // Establish MQTT connection:
    client.connect(data);
    // Subscribe to the topic specified by topic_sub:
    client.subscribe(topic_sub, MQTT::QOS2, messageArrived);
    
    while (true) 
    {
        // Show that the loop is running by switching motherboard LED2:
        led2 = !led2;
        
        // If the message is received, check state machine current state:
        if (msgrcv)
            stateCheck();
        
        // If 'oled' was received:
        if (oled_allowed)
            oledPreview();        
            
        // If the pseudo-timer has counted 10s:
        if( pseudo_timer == (SAMPLE_SCALER))
        {
            // If 'start' was received:
            if(sending_allowed == 1) 
                publishPot();
            // Reset pseudo-timer:     
            pseudo_timer = 0;
        }
        //Increment pseudo-timer:
        pseudo_timer++;
        // Need to call yield API to maintain connection:
        client.yield(YIELD_TIMEOUT_MS);
    }
}