demo project

Dependencies:   AX-12A Dynamixel mbed iothub_client EthernetInterface NTPClient ConfigFile SDFileSystem iothub_amqp_transport mbed-rtos proton-c-mbed wolfSSL

IothubRobotArm.cpp

Committer:
henryrawas
Date:
2016-02-04
Revision:
33:8b9dcbf6d8ec
Parent:
27:4239713d9690

File content as of revision 33:8b9dcbf6d8ec:

// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "mbed.h"
#include "rtos.h"

#include "EthernetInterface.h"
#include "mbed/logging.h"
#include "mbed/mbedtime.h"
#include <NTPClient.h>

#include "iothub_mod_client.h"
#include "iothub_message.h"
#include "threadapi.h"
#include "crt_abstractions.h"
#include "iothubtransportamqp.h"

#include "MeasureBuf.h"
#include "IothubRobotArm.h"
#include "IothubSerial.h"

#ifdef MBED_BUILD_TIMESTAMP
#include "certs.h"
#endif // MBED_BUILD_TIMESTAMP

#include "RobotArmCfg.h"

extern void ShowLedColor(int col);

// method to initialize platform - Time of day
int setupRealTime(void)
{
    int result;

    (void)printf("setupRealTime begin\r\n");
    if (EthernetInterface::connect())
    {
        (void)printf("Error initializing EthernetInterface.\r\n");
        result = __LINE__;
    }
    else
    {
        (void)printf("setupRealTime NTP begin\r\n");
        NTPClient ntp;
        if (ntp.setTime("0.pool.ntp.org") != 0)
        {
            (void)printf("Failed setting time.\r\n");
            result = __LINE__;
        }
        else
        {
            (void)printf("set time correctly!\r\n");
            result = 0;
        }
        (void)printf("setupRealTime NTP end\r\n");
        EthernetInterface::disconnect();
    }
    (void)printf("setupRealTime end\r\n");

    return result;
}

// method to initialize platform - Ethernet
int InitEthernet()
{
    (void)printf("Initializing ethernet..\r\n");

    /* These are needed in order to initialize the time provider for Proton-C */
    mbedtime_init();

    if (EthernetInterface::init())
    {
        (void)printf("Error initializing EthernetInterface.\r\n");
        return -1;
    }

    if (setupRealTime() != 0)
    {
        (void)printf("Failed setting up real time clock\r\n");
        return -1;
    }

    if (EthernetInterface::connect())
    {
        (void)printf("Error connecting EthernetInterface.\r\n");
        return -1;
    }
    
    return 0;
}

// IoTHub SDK stuff
DEFINE_ENUM_STRINGS(IOTHUB_CLIENT_CONFIRMATION_RESULT, IOTHUB_CLIENT_CONFIRMATION_RESULT_VALUES);

typedef struct EVENT_INSTANCE_TAG
{
    IOTHUB_MESSAGE_HANDLE messageHandle;
    int messageTrackingId;  // For tracking the messages within the user callback.
} EVENT_INSTANCE;


// message buffers to use
#define MESSAGE_LEN         1024
static char msgText[MESSAGE_LEN];

// a larger MESSAGE_COUNT results in being able to send as data is available
// but requires more heap space to hold buffers
#define MESSAGE_COUNT       4
EVENT_INSTANCE messages[MESSAGE_COUNT];


// context for send & receive
static int receiveContext;
static int callbackCounter;
static int msgNumber;

static  IOTHUB_CLIENT_HANDLE iotHubClientHandle;

// used to detect send confirmation timeout
#define SEND_CONFIRM_TO  30000
RtosTimer* confirmTimer;

// object for IoTHub interface
IothubRobotArm iotRobot;


// pass received commands to device
extern void ControlArmCommands(const char* cmd);

// callback for incoming messages
static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    int* counter = (int*)userContextCallback;
    const char* buffer;
    size_t size;
    char cmdbuf[20];
    
    if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) == IOTHUB_MESSAGE_OK)
    {
        int slen = size;

        if (size >= 20)
            slen = 19;
        strncpy(cmdbuf, buffer, slen);
        cmdbuf[slen] = 0;
        (void)printf(cmdbuf);
        (void)printf("\r\n");
        ControlArmCommands((const char*)cmdbuf);
    }

    (*counter)++;
    return IOTHUBMESSAGE_ACCEPTED;
}

// callback for completion of sent messages
static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    EVENT_INSTANCE* eventInstance = (EVENT_INSTANCE*)userContextCallback;
    if (eventInstance == NULL)
    {
        printf("SendConfirmation with NULL context\r\n");
        return;
    }

    (void)printf("Confirmation received\r\n");

    confirmTimer->stop();
    callbackCounter++;
    IoTHubMessage_Destroy(eventInstance->messageHandle);
}


static void SendCallback(IOTHUB_CLIENT_HANDLE iotHubClientHandle, void* userContextCallback)
{
    iotRobot.SendMessage(iotHubClientHandle, userContextCallback);
}

// communication timeout
void CommunicationTO(void const * tid)
{
    (void)printf("*** Iothub thread communication Timeout\r\n");
    ShowLedColor(2);
}

// entry point to start IoTHub connection
bool StartIothubThread()
{
    InitEthernet();
    
    confirmTimer = new RtosTimer(CommunicationTO, osTimerOnce, (void *)osThreadGetId());
  
    iotRobot.Init();
 
    return true;
}

// stop IoTHub connection
void EndIothubThread()
{
    iotRobot.Terminate();
}

// IoTHub connection for RobotArm
// sends and receives messages between RobotArm and IoTHub
IothubRobotArm::IothubRobotArm()
{
    iotHubClientHandle = NULL;
}

bool IothubRobotArm::Init()
{
    receiveContext = 0;
    callbackCounter = 0;
    msgNumber = 0;
    
    (void)printf("Starting the IoTHub RobotArm connection\r\n");
    
    if (connectionString[0] == '[')
    {
        // forgot to replace placeholder
        (void)printf("ERROR: connectionString is not set to a device connection!\r\n");
        return false;
    }

    if ((iotHubClientHandle = IoTHubClient_Mod_CreateFromConnectionString(connectionString, AMQP_Protocol)) == NULL)
    {
        (void)printf("ERROR: iotHubClientHandle is NULL!\r\n");
        return false;
    }
    else
    {
#ifdef MBED_BUILD_TIMESTAMP
        // For mbed add the certificate information
        if (IoTHubClient_Mod_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
        {
            printf("failure to set option \"TrustedCerts\"\r\n");
            return false;
        }
#endif // MBED_BUILD_TIMESTAMP

        /* Setting Message call back, so we can receive Commands. */
        if (IoTHubClient_Mod_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK)
        {
            (void)printf("ERROR: IoTHubClient_SetMessageCallback..........FAILED!\r\n");
            return false;
        }
        else
        {
            (void)printf("IoTHubClient_SetMessageCallback...successful.\r\n");
        }

        /* Setting Send call back, so we can send from worker thread. */
        if (IoTHubClient_Mod_SetSendCallback(iotHubClientHandle, SendCallback, &receiveContext) != IOTHUB_CLIENT_OK)
        {
            (void)printf("ERROR: IoTHubClient_SetSendCallback..........FAILED!\r\n");
            return false;
        }
        else
        {
            (void)printf("IoTHubClient_SetSendCallback...successful.\r\n");
        }
    }
    return true;
}

void IothubRobotArm::Terminate()
{
    if (iotHubClientHandle != NULL)
    {
        IoTHubClient_Mod_Destroy(iotHubClientHandle);
        iotHubClientHandle = NULL;
    }
}

// Invoked from callback
void IothubRobotArm::SendMessage(IOTHUB_CLIENT_HANDLE iotHubClient, void* userContextCallback)
{
    // send until circular buf empty or no sending buffers avail
    // may drop message if confirmations are slow
    while (msgNumber - callbackCounter < MESSAGE_COUNT)
    {
        // get buffer from array
        int i = msgNumber % MESSAGE_COUNT;
    
        int msglen = 0;

        // get alert if any, otherwise get measure data
        msglen = _msgSerialize.AlertBufToString(msgText, MESSAGE_LEN);
        if (msglen == 0)
        {
            msglen = _msgSerialize.MeasureBufToString(msgText, MESSAGE_LEN);
        }
        
        if (msglen > 0)
        {
            if ((messages[i].messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)msgText, msglen)) == NULL)
            {
                (void)printf("ERROR: iotHubMessageHandle is NULL!\r\n");
            }
            else
            {
                messages[i].messageTrackingId = msgNumber;

                confirmTimer->stop();
                if (IoTHubClient_Mod_SendEventAsync(iotHubClient, messages[i].messageHandle, SendConfirmationCallback, &messages[i]) != IOTHUB_CLIENT_OK)
                {
                    (void)printf("ERROR: IoTHubClient_SendEventAsync..........FAILED!\r\n");
                }
                else
                {
                    confirmTimer->start(SEND_CONFIRM_TO);
                   (void)printf("Send async completed\r\n");
                }
                msgNumber++;
            }
        }
        else if (msglen == 0)
        {
           break;
        }
        else if (msglen < 0)
        {
            (void)printf("ERROR: Serialized message too big for buffer\r\n");
            break;
        }
    } // while

}