Simple sample that demonstrates reading the FXOS8700CQ accelerometer, convert the data to JSON and send to an Azure IoT Hub.

Dependencies:   azure_umqtt_c iothub_mqtt_transport mbed-rtos mbed wolfSSL Socket lwip-eth lwip-sys lwip

main.cpp

Committer:
markrad
Date:
2017-04-25
Revision:
7:2564d95cbf81
Parent:
6:0bffe8529f60

File content as of revision 7:2564d95cbf81:

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file at https://github.com/Azure/azure-iot-sdks/blob/master/LICENSE for full license information.

/* -------------------------------------------------------------------------- *\

   Simple progam to demonstrate reading the FRDM-K64F FXOS8700CQ 
   accelerometer, convert the data to JSON and send to an Azure IoT Hub. You 
   must provide your hub's connection string in the variable 
   'connectionString'.

   markrad

\* -------------------------------------------------------------------------- */

#include <string.h>
#include <limits.h>

#include "SingletonFXOS8700CQ.h"

#include "iothub_client.h"
#include "iothub_message.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/platform.h"
#include "iothubtransportmqtt.h"
#include "lock.h"

#include "certs.h"
#include "NTPClient.h"

NTPClient ntp;

/*
int readingToJSON(char *buffer, int bufferlen, READING &reading)
{
    static const char READING[] = "\"reading\"";
    static const char ACCELEROMETER[] = "\"accelerometer\"";
    static const char MAGNOMETER[] = "\"magnometer\"";
    static const char X[] = "\"X\"";
    static const char Y[] = "\"Y\"";
    static const char Z[] = "\"Z\"";
    static const char STARTOBJ[] = " : {\n";
    static const char ENDOBJ[] = "}\n";
    static const char PREPEND[] = "{\n";
    static const int MINBUFFERLEN = 
        sizeof(READING) + 
        sizeof(ACCELEROMETER) +
        sizeof(MAGNOMETER) +
        2 * (sizeof(X) + sizeof(Y) + sizeof(Z)) +
        3 * sizeof(STARTOBJ) +
        4 * sizeof(ENDOBJ) +
        sizeof(PREPEND) +
        6 * 9;
    static const char numConvert[] = "%d";
    
    char toNum[10];
    char work[MINBUFFERLEN + 1];
    
    if (buffer == NULL)
        return 0;
    
    buffer[0] = '\0';
        
    strcpy(work, PREPEND);
    strcat(work, READING);
    strcat(work, STARTOBJ);
    strcat(work, ACCELEROMETER);
    strcat(work, STARTOBJ);
    strcat(work, X);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.accelerometer.x);
    strcat(work, toNum);
    strcat(work, ",\n");
    strcat(work, Y);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.accelerometer.y);
    strcat(work, toNum);
    strcat(work, ",\n");
    strcat(work, Z);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.accelerometer.z);
    strcat(work, toNum);
    strcat(work, "\n");
    strcat(work, ENDOBJ);
    strcat(work, MAGNOMETER);
    strcat(work, STARTOBJ);
    strcat(work, X);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.magnometer.x);
    strcat(work, toNum);
    strcat(work, ",\n");
    strcat(work, Y);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.magnometer.y);
    strcat(work, toNum);
    strcat(work, ",\n");
    strcat(work, Z);
    strcat(work, " : ");
    sprintf(toNum, numConvert, reading.magnometer.z);
    strcat(work, toNum);
    strcat(work, "\n");
    strcat(work, ENDOBJ);
    strcat(work, ENDOBJ);
    strcat(work, ENDOBJ);
    
    if (strlen(work) + 1 < bufferlen)
        strcpy(buffer, work); 
    
    return strlen(work);
}
*/

static int JSONifyData(char *buffer, int bufferlen, int reading)
{
    static const char *format = "{ \"device\": \"%s\", \"timestamp\": \"%s\", \"epochoffset\": %d, \"reading\": %f }";
    static const char *timeFormat = "%FT%X";
    char timeOut[80];
    double work;
    int rc;
    time_t rawtime = 0;
    struct tm *ptm;
    
    // gmtime() does not work on the FRDM K64F - set RTC to UTC
    rawtime = time(NULL);
    ptm = localtime(&rawtime);
    
    strftime(timeOut, sizeof(timeOut), timeFormat, ptm);
    printf("rawtime=%d;time=%s\r\n", rawtime, timeOut);
    work = sqrt((double)reading);
    rc = snprintf(buffer, bufferlen, format, "mydevice", timeOut, rawtime, work);   
    
    if (rc < 0)
        printf("*** ERROR *** out of buffer space\r\n");
        
    return rc;
}    

static LOCK_HANDLE msgLock;
static int msgCount = 0;
static Timer t;
static int CONNECTIONTIMEOUT = (20 * 1000);

static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    int* counter = (int*)userContextCallback;
    const char* buffer;
    size_t size;

    if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) != IOTHUB_MESSAGE_OK)
    {
        (void)printf("unable to retrieve the message data\r\n");
    }
    else
    {
        (void)printf("Received Message [%d] with Data: <<<%.*s>>> & Size=%d\r\n", *counter, (int)size, buffer, (int)size);
    }

    // Some device specific action code goes here...
    (*counter)++;

    return IOTHUBMESSAGE_ACCEPTED;
}

static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    int* messageTrackingId = (int*)userContextCallback;
    
    (void)printf("Confirmation received for message tracking id = %d with result = %s\r\n", 
        *messageTrackingId, ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
        
    free(userContextCallback);
    Lock(msgLock);
    msgCount--;
        
    if (result == IOTHUB_CLIENT_CONFIRMATION_OK)
    {
        t.stop();
        t.reset();
    }

    Unlock(msgLock);

}

void stall(Serial &pc, char *message)
{
    printf(message);
    printf("stalled ");
    
    while(true) 
    {
        pc.putc('.'); // idle dots
        wait(1.0);
    }
}

IOTHUB_CLIENT_HANDLE setupConnection(Serial &pc, const char *connectionString, IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol, void *receiveContext)
{
    IOTHUB_CLIENT_HANDLE iotHubClientHandle = NULL;
    
    printf("Calling platform_init\r\n");
    
    while (platform_init())
    {
        pc.putc('P');
        wait(1.0);
        platform_deinit();
    }
    
//    if (platform_init() != 0)
//        stall(pc, "Failed to initialize platform\n");
        
    printf("Calling IoTHubClient_CreateFromConnectionString\r\n");
    if ((iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, protocol)) == NULL)
        stall(pc, "ERROR: Could not create iotHubClientHandle\n");
        
    bool traceOn = false;
    //bool traceOn = true;
    
    printf("Calling IoTHubClient_SetOption logtrace with %d\r\n", traceOn);
    IoTHubClient_SetOption(iotHubClientHandle, "logtrace", &traceOn);

    // For mbed add the certificate information
    printf("Calling IoTHubClient_SetOption TrustedCerts\r\n");

    if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
        stall(pc, "ERROR: failure to set option \"TrustedCerts\"\n");

    printf("Calling IoTHubClient_SetMessageCallback\r\n");

    if (IoTHubClient_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, receiveContext) != IOTHUB_CLIENT_OK)
        stall(pc, "ERROR: IoTHubClient_SetMessageCallback failed\r\n");
    
    return iotHubClientHandle;
}

void terminateConnection(Serial &pc, IOTHUB_CLIENT_HANDLE iotHubClientHandle)
{
    printf("Calling IoTHubClient_Destroy\r\n");
    IoTHubClient_Destroy(iotHubClientHandle);
    printf("Calling platform_deinit\r\n");
    platform_deinit();
    printf("Connection terminated\r\n");
}    

void calibrate(double *pmean, double *pdeviation)
{
    READING reading;
    const int calibrationPeriod = 10;    // in seconds
    SingletonFXOS8700CQ &sfxos = SingletonFXOS8700CQ::getInstance();
    
    double *data = new double[calibrationPeriod * 50];
    int i;
    double sum = 0.0;
    double mean = 0.0;
    double temp;
    
    printf("Calibrating...\r\n");
    
    i = calibrationPeriod * 50;
    
    while (i > 0)
    {
        if (sfxos.getInt2Triggered())
        {
            sfxos.setInt2Triggered(false);
            sfxos.getData(reading);
            data[i] = sqrt((double)(reading.accelerometer.x * reading.accelerometer.x) + (reading.accelerometer.y * reading.accelerometer.y));
//            data[i] = reading.accelerometer.x + reading.accelerometer.y;
            printf("x=%d\t\ty=%d\t\tsum=%f\r\n", reading.accelerometer.x, reading.accelerometer.y, data[i]);
            sum += data[i];
            --i;
        }
        else
        {
            printf("WARNING: Sensor was not ready in time during calibration\r\n");
        }
        wait_ms(20);
    }
    
    mean = (double)sum / (double)(calibrationPeriod * 50);
    
    for (i = 0; i < calibrationPeriod * 50; i++)
    {
        temp += ((float)data[i] - mean) * ((float)data[i] - mean);
    }
    
    temp /= (double)(calibrationPeriod * 50);
    
    delete [] data;
    
    *pmean = mean;
    *pdeviation = sqrt(temp);
    
    printf("Calibration complete - mean=%f; devation=%f\r\n", *pmean, *pdeviation);
}

int main()
{
    const char *connectionString = "HostName=MarkRadHub1.azure-devices.net;DeviceId=mrcc3200;SharedAccessKey=8pGKChTBsz0VGw234iLX7XDDKwcyWRC7hsrVZEHfZHs=";
    const char *ntpServer = "0.pool.ntp.org";
    const int ntpRefreshInterval = 60 * 60;
    const int ledInterval = 300 / 20;

    READING reading;
    Serial pc(USBTX, USBRX); // Primary output to demonstrate library
    SingletonFXOS8700CQ &sfxos = SingletonFXOS8700CQ::getInstance();
    IOTHUB_CLIENT_HANDLE iotHubClientHandle;
    int receiveContext = 0;
    int transmitCounter = 0;
    double mean;
    double deviation;
    DigitalOut ledBlue(LED_BLUE);    
    
    pc.baud(115200); // Print quickly! 200Hz x line of output data!
    ledBlue = 1;
    
    printf("\n\n\rFXOS8700CQ identity = %X\r\n", sfxos.getWhoAmI());
    
    msgLock = Lock_Init();  // TODO: Check error code
    
    sfxos.enable();
    sfxos.getData(reading);
    
    int rc;

    int LOOPCOUNT = -1;     // Set to -1 to run forever
    
    int localMsgCount;
    int *userContext;
    IOTHUB_MESSAGE_HANDLE msgHandle;
    int elapsedTime = 0;
    
    char buffer[200];
    
    iotHubClientHandle = setupConnection(pc, connectionString, MQTT_Protocol, &receiveContext);
    calibrate(&mean, &deviation);
    
    int readCount = 0;
    int32_t maxVal = LONG_MIN;
    int32_t curVal;
    time_t lastUpdate = 0;
    int ntpRc;
    int ledOffAt = 0;
    
    while (NTP_OK != (ntpRc = ntp.setTime("0.pool.ntp.org")))
    {
        printf("ERROR: Failed to set current time from NTP server - rc = %d\r\n", ntpRc);
        wait_ms(100);
    }
    
    lastUpdate = time(NULL);
    
    while (LOOPCOUNT)
    {
        if (sfxos.getInt2Triggered())
        {
            sfxos.setInt2Triggered(false);
            sfxos.getData(reading);
            curVal = (reading.accelerometer.x * reading.accelerometer.x) + (reading.accelerometer.y * reading.accelerometer.y);
            
            if (curVal > maxVal)
            {
                maxVal = curVal;
                //printf("new maxVal=%d\r\n", maxVal);
            }
            
            //rc = readingToJSON(buffer, sizeof(buffer), reading);
            
            //if (rc > sizeof(buffer))
                //printf("ERROR: JSON buffer too small - require %d characters\n", rc);

            if (++readCount >= 50)
            {
                Lock(msgLock);
                localMsgCount = msgCount;
                Unlock(msgLock);
                
                if (localMsgCount < 2)
                {
                    rc = JSONifyData(buffer, sizeof(buffer), maxVal);
                    //printf("DATA >>>%s<<<\r\n", buffer);
                    
                    if ((msgHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)buffer, rc)) == NULL)
                    {
                        (void)printf("ERROR: iotHubMessageHandle is NULL!\r\n");
                    }
                    else
                    {
                        userContext = (int *) malloc(sizeof(userContext));
                        
                        if (userContext != NULL)
                        {
                            *userContext = transmitCounter;
        
                            if (IoTHubClient_SendEventAsync(iotHubClientHandle, msgHandle, SendConfirmationCallback, userContext) != IOTHUB_CLIENT_OK)
                            {
                                (void)printf("ERROR: IoTHubClient_LL_SendEventAsync..........FAILED!\r\n");
                            }
                            else
                            {
                                (void)printf("IoTHubClient_LL_SendEventAsync accepted message [%d] for transmission to IoT Hub.\r\n", (int)transmitCounter);
                                ledBlue = 0;
                                ledOffAt = ledInterval;
                            }
                            
                            IoTHubMessage_Destroy(msgHandle);
                            Lock(msgLock);
                            msgCount++;
                            t.start();
                            Unlock(msgLock);
                            
                            transmitCounter++;
                        }
                        else
                        {
                            (void)printf("ERROR: malloc - unable to allocate user context\r\n");
                        }
                    }
                }
                else
                {
                    (void)printf("WARNING: Message dropped queue length %d\r\n", localMsgCount);
                }
                
                Lock(msgLock);
                elapsedTime = t.read_ms();
                Unlock(msgLock);
                
                if (elapsedTime > CONNECTIONTIMEOUT)
                {
                    printf("No response for %d milliseconds - attempt reconnection\r\n", elapsedTime);
                    NVIC_SystemReset(); // Just blow it all away
                    terminateConnection(pc, iotHubClientHandle);
                    iotHubClientHandle = setupConnection(pc, connectionString, MQTT_Protocol, &receiveContext);
                    printf("Reconnection complete\r\n");
                }
                            
                if (LOOPCOUNT > 0)
                    LOOPCOUNT--;
                    
                readCount = 0;
                maxVal = LONG_MIN;
                
                if (time(NULL) - lastUpdate > ntpRefreshInterval)
                {
                    while (NTP_OK != (ntpRc = ntp.setTime("0.pool.ntp.org")))
                    {
                        printf("ERROR: Failed to set current time from NTP server - rc = %d\r\n", ntpRc);
                        wait_ms(100);
                    }
                    
                    lastUpdate = time(NULL);
                }
            }
        }
        else
        {
            printf("WARNING: Sensor was not ready in time\r\n");
        }
        
        if (!((int)ledBlue) && --ledOffAt <= 0)
        {
            ledBlue = 1;
        }
        
        // Read at 50 hz
        wait_ms(20);
    }
    
    printf("Loop complete - clean up\n");
    
    terminateConnection(pc, iotHubClientHandle);
    Lock_Deinit(msgLock);
    
    printf("Test complete\n");
    

    while(true) 
    {
        pc.putc('.'); // idle dots
        wait(1.0);
    }
}