CIS441 Proj MS 2b

Dependencies:   TextLCD MQTT

Communication.cpp

Committer:
kchen7
Date:
2019-12-13
Revision:
16:cb7cbf2cc23b
Parent:
15:1d611d264a1f

File content as of revision 16:cb7cbf2cc23b:

#include "Communication.h"

MQTT::Client<MQTTNetwork, Countdown>* Communication::client(MQTT::Client<MQTTNetwork, Countdown>* new_client) {
    static MQTT::Client<MQTTNetwork, Countdown>* client = NULL;
    if (new_client != NULL) {
        client = new_client;
    }
    return client;
}

const char* Communication::mac_address(const char* new_add) {
    static const char* mac_address = NULL;
    if (new_add != NULL) {
        mac_address = new_add;
    }
    //printf("mac_address %s\n", mac_address); 
    return mac_address;
}

Communication::Communication() {}

/*
    This function sets up the wifi module and connects it to the SSID 
    configured in the configuration file. It also prints out the MAC address 
    of the module, which is needed if you are trying to use campus wifi.
    This function returns NULL if there are any issues.
*/
WiFiInterface* Communication::setup_wifi() {
    // Get a handle to the WiFi module
    WiFiInterface* wifi = WiFiInterface::get_default_instance();
    
    // Connect the module to the wifi, based on the SSID and password 
    // specified in the mbed_app.json configuration file
    // If you are using AirPennNet-Device, this will not succeed until the MAC
    // address (printed shortly after this) is registered
    printf("Connecting to wifi\r\n");
    int rc = wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2);
    
    if (rc != 0) {
        printf("Problem connecting to wifi\r\n");  
        return NULL;
    }
    printf("Wifi connected\r\n");  
    return wifi;
}

/*
    This function creates the MQTT client and connects it to the MQTT broker
    that we have setup for the course. If there are any errors with the 
    connection, it will return NULL
*/
MQTT::Client<MQTTNetwork, Countdown>* Communication::setup_mqtt(MQTTNetwork &network) {
    // the hostname and port point to a Google Cloud MQTT server we setup for
    // this project
    const char* hostname = "34.68.206.11";
    int port = 1883;
    
    // Create the underlying network connection to the MQTT server
    printf("Connecting to %s:%d\r\n", hostname, port); 
    int rc = network.connect(hostname, port);
    if (rc != 0) {
        printf("There was an error with the TCP connect: %d\r\n", rc);
        return NULL;
    }
            
    printf("Connected to %s:%d\r\n", hostname, port);

    // Connect the MQTT client to the server
    MQTT::Client<MQTTNetwork, Countdown>* client = new MQTT::Client<MQTTNetwork, Countdown>(network);
    rc = client->connect();
    if (rc != 0) {
        printf("There was an error with the MQTT connect: %d\r\n", rc);
        return NULL;
    }
    
    printf("MQTT connect successful!\r\n");
        
    return client;
}

//callback for update/control messages
void Communication::update_message_arrived(MQTT::MessageData& md)
{
    printf("UPDATE MESSAGE ARRIVED\r\n"); 
    MQTT::Message &message = md.message;
    char* payload = (char*)message.payload;
    printf("%s\r\n", payload);
    int id = payload[0] - 48;
    int speed = payload[3] - 48;
    if(payload[4] != 'x') {
        speed = speed * 10 + payload[4] - 48;
    }
    Road::road_in_use(NULL)->update_car_speed(id, speed);
}

//callback for sync messages
void Communication::sync_message_arrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;
    char* payload = (char*)message.payload;
    //printf("%s\r\n", payload);
    if (strcmp (Communication::mac_address(NULL), payload) != 0) {
        //printf("not matching address\r\n");
        Road::ready(1);
    }
}

//initialize the client
int Communication::init() {
    WiFiInterface* wifi = setup_wifi();
    
    // There was a problem connecting the wifi, so exit
    if (wifi == NULL) {
        return -1;   
    }
    
    Communication::mac_address(wifi->get_mac_address());
    
    // Create the network object needed by the MQTT client
    MQTTNetwork* network = (MQTTNetwork*)malloc(sizeof(MQTTNetwork)); 
    new (network) MQTTNetwork(wifi); 
    //MQTTNetwork network(wifi);
    Communication::client(setup_mqtt(*network));
    
    // There was a problem connecting the MQTT client, so exit
    if (Communication::client(NULL) == NULL) {
        return -1;   
    }
    char* update_topic; 
    if (strcmp(Communication::mac_address(NULL), "2c:3a:e8:0b:7b:21") == 0) {
        update_topic = "Chen_Goldsmith_Update/2c:3a:e8:0b:7b:21"; 
    } else {
        update_topic =  "Chen_Goldsmith_Update/dc:4f:22:51:24:20"; 
    } 
    printf("%s\r\n", update_topic); 
    int rc = Communication::client(NULL)->subscribe(update_topic, MQTT::QOS1, update_message_arrived);
    if (rc != 0) {
        printf("Failed subscribe updates\r\n"); 
        return -1;
    }
    char* sync_topic = "Chen_Goldsmith_Sync";
    rc = Communication::client(NULL)->subscribe(sync_topic, MQTT::QOS1, sync_message_arrived);
    if (rc != 0) {
        printf("Failed subscribe sync\r\n"); 
        return -1;
    }
    
    printf("Successfully subscribed, init() returning 1\n"); 
    return 1;
}

int Communication::publish_car_info(int id, int pos, int speed) {
    MQTT::Message message;
 
    char* topic = "Chen_Goldsmith_Car_Info";
    char buf[50];
    const char* mac = Communication::mac_address(NULL); 
    sprintf(buf, "%d, %d, %d, %s", id, pos, speed, mac);
    int rc = Communication::client(NULL)->publish(topic, (char*) buf, strlen(buf), MQTT::QOS1);
    
    if (rc != 0) {
        return -1;   
    } else {
        return 0;
    }
}

int Communication::publish_road_ready() {
    MQTT::Message message;
 
    char* topic = "Chen_Goldsmith_Sync";
    char buf[100];
    sprintf(buf, "%s", Communication::mac_address(NULL));
    int rc = Communication::client(NULL)->publish(topic, (char*) buf, strlen(buf)+1, MQTT::QOS1);
    if (rc != 0) {
        return -1;   
    } else {
        printf("successful publish: ready\r\n");
        return 0;
    }
}

void Communication::yield(int time) {
    Communication::client(NULL)->yield(time); 
}

void Communication::disconnect() {
    Communication::client(NULL)->disconnect();
}