working

Dependencies:   C027_Support IBMIoTClientCellularExample MQTT mbed

Fork of MQTT-GSM-GPS-CAN-SMS by Babu Alikapati

main.cpp

Committer:
alikapatibabu
Date:
2017-02-22
Revision:
19:689b00477c81
Parent:
18:e9e87362018b

File content as of revision 19:689b00477c81:

/*******************************************************************************
 * Copyright (c) 2014 IBM Corp.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *   http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *    Sam Danbury - initial implementation
 *    Ian Craggs - refactoring to remove STL and other changes
 *    Sam Grove  - added check for Ethernet cable.
 *    Chris Styles - Added additional menu screen for software revision
 *
 * To do :
 *    Add magnetometer sensor output to IoT data stream
 *
 *******************************************************************************/

#define USE_CELLULAR    // Enable this switch on the C027 to use cellular

#include "MQTTClient.h"
#include "Arial12x12.h"
//#include "rtos.h"

// Update this to the next number *before* a commit
#define __APP_SW_REVISION__ "11"
#define BOARD_NAME "IoT u-blox"

// Configuration values needed to connect to IBM IoT Cloud
#define ORG "quickstart"             // For a registered connection, replace with your org
#define ID ""                        // For a registered connection, replace with your id
#define AUTH_TOKEN ""                // For a registered connection, replace with your auth-token
#define TYPE_NAME DEFAULT_TYPE_NAME  // For a registered connection, replace with your type

#define MQTT_PORT 1883
#define MQTT_TLS_PORT 8883
#define IBM_IOT_PORT MQTT_PORT

#define MQTT_MAX_PACKET_SIZE 250

#define MAX_SMS_LEN  160
char strMobilenumber[32] = "xxxxxxxxxxx";

//------------------------------------------------------------------------------------
// You need to configure these cellular modem / SIM parameters.
// These parameters are ignored for LISA-C200 variants and can be left NULL.
//------------------------------------------------------------------------------------
# include "MDM.h"
//! Set your secret SIM pin here (e.g. "1234"). Check your SIM manual.
# define SIMPIN      NULL
/*! The APN of your network operator SIM, sometimes it is "internet" check your
    contract with the network operator. You can also try to look-up your settings in
    google: https://www.google.de/search?q=APN+list */
# define APN         NULL
//! Set the user name for your APN, or NULL if not needed
# define USERNAME    NULL
//! Set the password for your APN, or NULL if not needed
# define PASSWORD    NULL
//------------------------------------------------------------------------------------
# include "GPS.h"
//------------------------------------------------------------------------------------

PwmOut r(D5);
PwmOut g(D9);
PwmOut b(D8);

DigitalOut led2(LED2);


#define LED2_OFF 0
#define LED2_ON 1

static uint32_t linkStatus(void)
{
    return true;
}

#define DEFAULT_TYPE_NAME "iotsample-mbed-c027"

#define MQTT_CLIENT_TYPE MQTTSocket
#include "MQTTSocket.h"

bool quickstartMode = true;
char org[11] = "jne5sm";
char type[30] = "hud";
char id[30] = "emb001";                 // device ID
char auth_token[30] = "Embitel123"; // Auth_token is only used in non-quickstart mode

bool connected = false;
bool shieldConnected = false;
char* joystickPos = "CENTRE";
int blink_interval = 0;

CAN can1(CANRD, CANTD);

struct vehicleParams {

    unsigned int speed;
    unsigned int EngRpm;
    unsigned int FuelLevel;
    unsigned int EngCoolantTemp;
    unsigned int A_BCall;
    unsigned int A_ECall;
    bool ABSIndcnON;
    

};

// Endzeit
time_t timeStop;

unsigned char readBit(char strByte, char intRow) // Is a bit of a byte from , counting from the right , intRow = 0 - 7.
{
    return strByte >> intRow & 1;
}

void off()
{
    r = g = b = 1.0;    // 1 is off, 0 is full brightness
}

void red()
{
    r = 0.7;
    g = 1.0;
    b = 1.0;    // 1 is off, 0 is full brightness
}

void yellow()
{
    r = 0.7;
    g = 0.7;
    b = 1.0;    // 1 is off, 0 is full brightness
}

void green()
{
    r = 1.0;
    g = 0.7;
    b = 1.0;    // 1 is off, 0 is full brightness
}


void flashing_yellow(void const *args)
{
    bool on = false;
    while (!connected) {  // flashing yellow only while connecting
        on = !on;
        if (on)
            yellow();
        else
            off();
        wait(0.5);
    }
}


void flashing_red(void const *args)  // to be used when the connection is lost
{
    bool on = false;
    while (!connected) {
        on = !on;
        if (on)
            red();
        else
            off();
        wait(2.0);
    }
}

int connect(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack)
{
    const char* iot_ibm = ".messaging.internetofthings.ibmcloud.com";

    char hostname[strlen(org) + strlen(iot_ibm) + 1];
    sprintf(hostname, "%s%s", org, iot_ibm);
    DEBUG("hostname is %s\n", hostname);
    int rc = ipstack->connect(hostname, IBM_IOT_PORT);
    if (rc != 0){
        DEBUG("connect Error: %d \n", rc);
        return rc;
    }
    
    // Construct clientId - d:org:type:id
    char clientId[strlen(org) + strlen(type) + strlen(id) + 5];
    sprintf(clientId, "d:%s:%s:%s", org, type, id);
    DEBUG("clientid is %s\n", clientId);

    // MQTT Connect
    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;
    data.clientID.cstring = clientId;

    if (!quickstartMode) {
        data.username.cstring = "use-token-auth";
        data.password.cstring = auth_token;
    }
    if ((rc = client->connect(data)) == 0) {
        connected = true;
        green();
        wait(2);
     }
    return rc;
}


int getConnTimeout(int attemptNumber)
{
    // First 10 attempts try within 3 seconds, next 10 attempts retry after every 1 minute
    // after 20 attempts, retry every 10 minutes
    return (attemptNumber < 10) ? 3 : (attemptNumber < 20) ? 60 : 600;
}

void attemptConnect(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack)
{
    int retryAttempt = 0;
    connected = false;

    // make sure a cable is connected before starting to connect
    while (!linkStatus()) {
        wait(1.0f);
        WARN("Internet link not present. Check cable connection\n");
    }
    while (connect(client, ipstack) != 0) {
        //Thread red_thread(flashing_red);

        int timeout = getConnTimeout(++retryAttempt);
        WARN("Retry attempt number %d waiting %d\n", retryAttempt, timeout);

        // if ipstack and client were on the heap we could deconstruct and goto a label where they are constructed
        //  or maybe just add the proper members to do this disconnect and call attemptConnect(...)

        // this works - reset the system when the retry count gets to a threshold
        if (retryAttempt == 5)
            NVIC_SystemReset();
        else
            wait(timeout);
    }
}


int publish(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/cmd/gps/fmt/json";

    char buf[250];
    int l = 0;
    l += sprintf(buf+l,"{\"lat\":100,\"long\":50}");

    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);

    LOG("Publishing %s\n", buf);
    LOG("Publiching Topic: %s\n",pubTopic);
    return client->publish(pubTopic, message);

}

int publishMdm(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, MDMParser* mdm)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/cmd/modem/fmt/json";
    char buf[250];
    int l = 0;
    MDMParser::IP ip = mdm->getIpAddress();
    l += sprintf(buf+l,"{\"d\":{\"ip\":\"" IPSTR "\"", IPNUM(ip));
    MDMParser::NetStatus sta;
    mdm->checkNetStatus(&sta);
    if (sta.rssi)             l += sprintf(buf+l,",\"rssi\":%d",sta.rssi);
    if (sta.ber)              l += sprintf(buf+l,",\"ber\":%d",sta.ber);
    if (*sta.opr)             l += sprintf(buf+l,",\"operator\":\"%s\"",sta.opr);
    l += sprintf(buf+l,"}}");

    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);

    LOG("Publishing %s\n", buf);
    return client->publish(pubTopic, message);
}

int publishGps(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, double lat, double lon)
{
    MQTT::Message message;

    char* pubTopic = "iot-2/evt/gps/fmt/json";
    char buf[250];
    //lat = 500.2323;
    //lon = 700.2323;
    sprintf(buf,"{\"lat\":\"%.6f\",\"long\":\"%.6f\"}", lat, lon);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing GPS %s\n", buf);
    return client->publish(pubTopic, message);
}

int publishSpeed(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int speed)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/speed/fmt/json";
    char buf[250];
    //speed = 0x11;
    sprintf(buf,"{\"value\":\"%1d\"}", speed);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing Speed %s \n", buf);
    return client->publish(pubTopic, message);
}

int publishFuelLevel(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int FuelLevel)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/FuelLevel/fmt/json";
    char buf[250];
    //speed = 0x11;
    sprintf(buf,"{\"value\":\"%1d\"}", FuelLevel);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing FuelLevel %s \n", buf);
    return client->publish(pubTopic, message);
}

int publishEngCoolantTemp(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int EngOilTemp)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/EngOilTemp/fmt/json";
    char buf[250];
    //speed = 0x11;
    sprintf(buf,"{\"value\":\"%1d\"}", EngOilTemp);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing EngOilTemp %s: %d \n", buf);
    return client->publish(pubTopic, message);
}

int publishA_BCall(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int A_BCall)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/FuelLevel/fmt/json";
    char buf[250];
    //speed = 0x11;
    sprintf(buf,"{\"value\":\"%1d\"}", A_BCall);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing A_BCall %s \n", buf);
    return client->publish(pubTopic, message);
}

int publishA_ECall(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int A_ECall)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/FuelLevel/fmt/json";
    char buf[250];
    //speed = 0x11;
    sprintf(buf,"{\"value\":\"%1d\"}", A_ECall);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing A_ECall %s \n", buf);
    return client->publish(pubTopic, message);
}

int publishEngRpm(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, int EngSpd)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/FuelLevel/fmt/json";
    char buf[250];
    sprintf(buf,"{\"value\":\"%1d\"}", 100);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing EngRpm %s \n", buf);
    return client->publish(pubTopic, message);
}

int publishABS(MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE>* client, MQTT_CLIENT_TYPE* ipstack, bool ABSIndcnON)
{
    MQTT::Message message;
    char* pubTopic = "iot-2/evt/ABSIndcnON/fmt/json";
    char buf[250];
    sprintf(buf,"{\"value\":\"%1d\"}", ABSIndcnON);
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    message.payload = (void*)buf;
    message.payloadlen = strlen(buf);
    LOG("Publishing ABS %s \n", buf);
    return client->publish(pubTopic, message);
}

void messageArrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;
    char topic[md.topicName.lenstring.len + 1];

    sprintf(topic, "%.*s", md.topicName.lenstring.len, md.topicName.lenstring.data);

    LOG("Message arrived on topic %s: %.*s\n",  topic, message.payloadlen, message.payload);

    // Command topic: iot-2/cmd/blink/fmt/json - cmd is the string between cmd/ and /fmt/
    char* start = strstr(topic, "/cmd/") + 5;
    int len = strstr(topic, "/fmt/") - start;

    if (memcmp(start, "blink", len) == 0) {
        char payload[message.payloadlen + 1];
        sprintf(payload, "%.*s", message.payloadlen, (char*)message.payload);

        char* pos = strchr(payload, '}');
        if (pos != NULL) {
            *pos = '\0';
            if ((pos = strchr(payload, ':')) != NULL) {
                int blink_rate = atoi(pos + 1);
                blink_interval = (blink_rate <= 0) ? 0 : (blink_rate > 50 ? 1 : 50/blink_rate);
            }
        }
    } else
        WARN("Unsupported command: %.*s\n", len, start);
}

void requestOBD2Data()
{

    CANMessage canSndMsg;
    canSndMsg.id = 0x7e0;
    canSndMsg.len=8;
    /* Fill All the data with 0x00 by default */
    canSndMsg.data[0] = 0x00;
    canSndMsg.data[1] = 0x00;
    canSndMsg.data[2] = 0x00;
    canSndMsg.data[3] = 0x00;
    canSndMsg.data[4] = 0x00;
    canSndMsg.data[5] = 0x00;
    canSndMsg.data[6] = 0x00;
    canSndMsg.data[7] = 0x00;
    //printf("Sending CAN Data...\n");
    can1.write(canSndMsg);
    wait_ms(100);

    /* request for Speed  OBD-II 0x0d */
    canSndMsg.data[0] = 0x02;
    canSndMsg.data[1] = 0x01;
    canSndMsg.data[2] = 0x0d;
    can1.write(canSndMsg);
    /* Wait 100ms for next request */
    wait_ms(100);

    /* request for Fuel Level OBD-II 0x0d */
    canSndMsg.data[0] = 0x02;
    canSndMsg.data[1] = 0x01;
    canSndMsg.data[2] = 0x2f;
    can1.write(canSndMsg);
    /* Wait 100ms for next request */
    wait_ms(100);

    /* request for Engine RPM OBD-II 0x0d */
    canSndMsg.data[0] = 0x02;
    canSndMsg.data[1] = 0x01;
    canSndMsg.data[2] = 0x0c;
    can1.write(canSndMsg);
    /* Wait 100ms for next request */
    wait_ms(100);

    /* request for Engine Coolant Temperature OBD-II 0x0d */
    canSndMsg.data[0] = 0x02;
    canSndMsg.data[1] = 0x01;
    canSndMsg.data[2] = 0x05;
    can1.write(canSndMsg);
    /* Wait 100ms for next request */
    wait_ms(100);
}

int main()
{

    quickstartMode = (strcmp(org, "quickstart") == 0);

    led2 = LED2_OFF; // K64F: turn off the main board LED
    //Thread yellow_thread(flashing_yellow);
    MDMSerial mdm;
    mdm.setDebug(3); // enable this for debugging issues
    if (!mdm.connect(SIMPIN, APN,USERNAME,PASSWORD))
        return -1;

    GPSI2C gps;

    MQTT_CLIENT_TYPE ipstack;
    MQTT::Client<MQTT_CLIENT_TYPE, Countdown, MQTT_MAX_PACKET_SIZE> client(ipstack);
    if (quickstartMode) {
        MDMParser::DevStatus dev;
        mdm.getDevStatus(&dev);
        if      (*dev.imei) strncpy(id, dev.imei, sizeof(id)-1);
        else if (*dev.meid) strncpy(id, dev.meid, sizeof(id)-1);
    }

    LOG("Trying to connect to MQTT Cloud\n", id);
    attemptConnect(&client, &ipstack);
    publishEngRpm(&client, &ipstack,100);
    LOG("GSM modem ready Create CAN \r\n");
    DigitalOut can_standby(CANS);
    can1.frequency(500000);
    can1.mode(CAN::Normal);
    can_standby = 0;
    
    char strReply[160];
    snprintf(strReply, MAX_SMS_LEN, "Sample SMS ");
    LOG("Sending Sample SMS\n \n");
    mdm.smsSend(strMobilenumber, strReply);

    blink_interval = 0;
    int count = 0;
    int count2 = 0;
    while (true) {
        if (++count == 100) {
            // Publish a message every second
            if ((publish(&client, &ipstack) != 0)) 
                attemptConnect(&client, &ipstack);   // if we have lost the connection
            count = 0;
        }
        
        if (++count2 == 10) {
            //Publish a message every second
            count2 = 0;
            while (1) {
                char buf[256];
                CANMessage canMsg;
                requestOBD2Data();
                vehicleParams Param;
                if(can1.read(canMsg)) {
                    switch(canMsg.data[2]) {
                        case 0x0d:
                          Param.speed = canMsg.data[3];
                          publishSpeed(&client, &ipstack,Param.speed);
                            break;
                        case 0x0c:
                            Param.EngRpm = canMsg.data[3];
                            publishEngRpm(&client, &ipstack,Param.EngRpm);
                            break;
                        case 0x2f:
                            Param.FuelLevel = canMsg.data[3];
                            publishFuelLevel(&client, &ipstack,Param.FuelLevel);
                            break;
                        case 0x05:
                            Param.EngCoolantTemp = canMsg.data[3];
                            publishEngCoolantTemp(&client, &ipstack,Param.EngCoolantTemp);
                            break;
                        case 0x22:
                            Param.ABSIndcnON = canMsg.data[3];
                            publishABS(&client, &ipstack,Param.ABSIndcnON);
                        case 0x08:
                            Param.A_BCall = canMsg.data[3];
                            publishA_BCall(&client, &ipstack,Param.A_BCall);
                        case 0x09:
                            Param.A_ECall = canMsg.data[3];
                            publishA_ECall(&client, &ipstack,Param.A_ECall);
                        default:
                            LOG("Not valid param..\n");
                            break;
                    }
                }
                int ret = gps.getMessage(buf, sizeof(buf));
              //  LOG("GPS: Return: %d \n", ret);
                if (ret <= 0) break;
                int len = LENGTH(ret);
                if ((PROTOCOL(ret) == GPSParser::NMEA) && (len > 6)) {
                    // talker is $GA=Galileo $GB=Beidou $GL=Glonass $GN=Combined $GP=GPS
                    if ((buf[0] == '$') || buf[1] == 'G') {
#define _CHECK_TALKER(s) ((buf[3] == s[0]) && (buf[4] == s[1]) && (buf[5] == s[2]))
                        if (_CHECK_TALKER("GGA")) {
                            LOG("%.*s\n", len, buf);
                            char ch;
                            double latitude, longitude, elevation;
                            static double lastLat = 0, lastLon = 0;
                            if (gps.getNmeaAngle(2,buf,len,latitude) && gps.getNmeaAngle(4,buf,len,longitude) &&
                                gps.getNmeaItem(6,buf,len,ch) && gps.getNmeaItem(9,buf,len,elevation)) {

                            LOG("GPS Location: %.5f %.5f %.1f %c\r\n", latitude, longitude, elevation, ch);
                            publishGps(&client, &ipstack, latitude, longitude);
                            lastLat = latitude;
                            lastLon = longitude;
                          }
                        }
                    }
                }
            }
        }
    }
}