Axeda demo software for u-blox C027 (GSM)

Dependencies:   mbed

AMMP/axPlatform.c

Committer:
AxedaCorp
Date:
2014-08-11
Revision:
1:ff6d8adaf6b9
Parent:
0:a725e8eab383

File content as of revision 1:ff6d8adaf6b9:

/************************************************************************************/
/* axPlatform.c                                                                    */
/* 2013 Axeda Corporation                                                          */
/*                                                                                  */
/* Defines methods for interaction with end points on the Axeda Platform.  This     */
/* is a device independent implementation which can be applied to any device that   */
/* supports ANSI C.                                                                 */
/************************************************************************************/

#include "axPlatform.h"
#include "axStatusCodes.h"
#include <string.h>
#include <stdlib.h>
#include "axTransport.h"
#include "axSerializer.h"
#include "cJSON.h"
#include "axConstants.h"
#include "axHTTP.h"

int handleResponse(HTTP_Transmission *response);

static const char *endpoints[8]= { "ammp", "data", "assets", "files", " ", "packages", "status", " "};
static const char *contentTypes[]= { "application/json", "multipart/form-data"};
static const char *buffer_keywords[]= {"alarms", "events", "data", "locations" };

const char URL_SEP='/';
const char ID_SEP='!';

/************************************************************************************/
/*ax_platform_upload()                                                              */
/*                                                                                  */
/*file(required) : a pointer to a structure that the data will be stored in.        */
/*name (required): a file name for the file. Can be arbitrarily assigned based on   */
/*                 source of the data.                                              */
/*hint(required): a string that allows you to tag the file for later retrieval      */
/*size(optional): should be populated if the data does not have an EOF character at */
/*                the end. If sending a memory block this will define the offset.   */
/*data(required): a pointer to the data that will be sent as this file              */
/*                                                                                  */
/*                                                                                  */
/************************************************************************************/
int ax_platform_upload(ax_platform *cloud, ax_deviceID *device, ax_file *file)
  {
  int retVal=AX_UNKNOWN;
  char *url=NULL;
  HTTP_Part fileDat;
  HTTP_Transmission response;
  fileDat.data=file->data;
  fileDat.data_sz=file->size;
  fileDat.file_name=file->name;
  fileDat.hint=file->hint;
  fileDat.next=NULL;

  url = getFileResource(url, device);

  int body_sz=strlen(file->hint)+12+strlen(file->name);
  char *body=malloc(sizeof(char)*body_sz);
  int bodyWrt=snprintf(body, body_sz, "name=\"hint\" \r\n %s",file->hint);
  if(bodyWrt>body_sz) { retVal=AX_GEN_STR_TRUNC; }
  printDebug(body);

  retVal=http_send_mpost(url, cloud->hostname, cloud->port, cloud->secure, NULL, NULL, 0, &fileDat, 1, &response);

  free(body);
  free(url);

return retVal;
}

/************************************************************************************/
/* ax_platform_ping()                                                               */
/*                                                                                  */
/* This function creates a ping message which acts as the device heartbeat.         */
/*                                                                                  */
/*                                                                                  */
/************************************************************************************/
int ax_platform_ping(ax_platform *cloud, ax_deviceID *device)
  {
  int retVal=AX_UNKNOWN;
  char *url=NULL;
  HTTP_Headers myHeader;
  HTTP_Transmission response;
  myHeader.contentType=getGeneralType(myHeader.contentType);
  url=getAgentResource(url, device);

//Send the request
  retVal= http_send_post(url, cloud->hostname, cloud->port, cloud->secure, &myHeader, NULL, 0, &response);
//Scan the response and act if there are egress messages.
  handleResponse(&response);
  free(url);
  return retVal;
  }

/************************************************************************************/
/*ax_platform_download()                                                            */
/*                                                                                  */
/*This function wil request a file from the platform with a specific file ID.  The  */
/*fileID itself will be transmitted down on a response message from the platform.   */
/*                                                                                  */
/*                                                                                  */
/************************************************************************************/
int ax_platform_download(ax_platform *cloud, ax_deviceID *device, ax_package_instruction *instr)
  {
    int retVal = AX_UNKNOWN;
    char *url=NULL;
    HTTP_Transmission response;
    url=getFileDownloadResource(url, device, instr->file_id);
	retVal=http_send_get(url, cloud->hostname, cloud->port, cloud->secure, &response);
//TODO: revisit what to do with response in this case.
    scm_file_write(instr->filename, response.body, response.body_length, instr);
    free(url);
    return retVal;
  }


/************************************************************************************/
/* ax_platform_register()                                                           */
/*                                                                                  */
/*This function creates a registration message to be sent to the cloud. The message */
/*contains information about the model, serial and expected ping interval. It also  */
/*allows the cloud to mark the device as online. If using the standalone thread func*/
/*-tion this method will be called automatically until successful.                  */
/*                                                                                  */
/*cloud(required) : a pointer to a structure that contains data about the cloud     */
/*device(required) : a pointer to a structure that contains the model and serial    */
/*pingRate(required) : an integer in milliseconds which tells the cloud how often to*/
/*                     expect a heartbeat ping                                      */
/*                                                                                  */
/*Returns: an integer value indicating whether or not it successfully registered    */
/************************************************************************************/
int ax_platform_register(ax_platform *cloud, ax_deviceID *device)
  {
  int retVal=AX_UNKNOWN;
  char *url=NULL;
  char *fullRequest=NULL;
  cJSON *requestBody;
  HTTP_Headers myHeader;
  HTTP_Transmission response;
  myHeader.contentType=getGeneralType(myHeader.contentType);
  url = getRegistrationResource(url, device);
  int urlLength=strlen(url);
  url[urlLength]='\0';

  requestBody=getRegistrationJSON(device, cloud->ping_rate);

  fullRequest=cJSON_PrintUnformatted(requestBody);
  int contentLength=strlen(fullRequest);

  retVal= http_send_post(url, cloud->hostname, cloud->port, cloud->secure, &myHeader, fullRequest, contentLength, &response);
//Scan the response and act if there are egress messages.
  handleResponse(&response);

//Clean up after ourselves
  free(fullRequest);
  free(url);
  cJSON_Delete(requestBody);
  return retVal;
  }

/**************************************************************************************/
/*ax_platform_send()                                                                  */
/*                                                                                    */
/*This function sends any data available in the structures directly to the cloud in   */
/*an on demand fashion.                                                               */
/*                                                                                    */
/*                                                                                    */
/*cloud(required) : a pointer to a structure that contains the cloud service info     */
/*device(required) : a pointer to a structure that contains device information        */
/*dataItems(optional) : a pointer to an array of ax_dataItem pointers that will be sent*/
/*alarms(optional) : a pointer to an array of ax_alarm pointers that will be sent      */
/*events(optional) : a pointer to an array of ax_event pointers that will be sent      */
/*locations(optional) : a pointer to an array of ax_location pointers that will be sent*/
/*                                                                                     */
/*Returns: an integer value indicating whether or not it successfully sent the data    */
/**************************************************************************************/
int ax_platform_send(ax_platform *cloud, ax_deviceID *device, ax_dataSet *dataItems[], int numDataSets, ax_alarm *alarms[], int numAlarms, ax_event *events[], int numEvents, ax_location *locations[], int numLocations) {
  
  int retVal=AX_UNKNOWN;
  HTTP_Headers myHeader;
  char *url=NULL;
  
  char *fullRequest=NULL;
  cJSON *rootNode=NULL;
  rootNode=cJSON_CreateObject();
  HTTP_Transmission response;
  zeroOutHTTPXmission(&response);
  //add the data in the DataItems queue if passed
  if(dataItems){
      cJSON_AddItemToObject(rootNode, buffer_keywords[BUFF_DATA], dataSet2JSON((ax_dataSet **)dataItems, numDataSets, terse_enable));
      }
  //add all alarms to the transmission if passed
  if(alarms){
    cJSON_AddItemToObject(rootNode, buffer_keywords[BUFF_ALARMS], AlarmsToJSON((ax_alarm **)alarms, numAlarms, terse_enable));
    }
  if(events){
    cJSON_AddItemToObject(rootNode, buffer_keywords[BUFF_EVENTS], eventsToJSON((ax_event **)events, numEvents, terse_enable));
  }
  if(locations){
    cJSON_AddItemToObject(rootNode, buffer_keywords[BUFF_LOCATIONS], locationsToJSON((ax_location **)locations, numLocations, terse_enable));
  }

  myHeader.contentType=getGeneralType(myHeader.contentType);
  url = getDataResource(url, device);
  fullRequest=cJSON_PrintUnformatted(rootNode);

  retVal= http_send_post(url, cloud->hostname, cloud->port, cloud->secure, &myHeader, fullRequest, strlen(fullRequest), &response);
//Scan the response and act if there are egress messages.
  handleResponse(&response);

  if(fullRequest) {
  free(fullRequest);
  }
  free(url);
  cJSON_Delete(rootNode);

return retVal;
  }

/**************************************************************************************/
/*ax_platform_sendData()                                                              */
/*                                                                                    */
/*This function immedately sends any data included in the parameter to the platform   */
/*listed. It makes use of the ax_platform_send() function as a special case.          */
/*                                                                                    */
/*cloud(required) : a pointer to a structure that contains the cloud service info     */
/*device(required) : a pointer to a structure that contains device information        */
/*dataItems(required) : pointer to an array of ax_dataItem pointers that will be sent */
/*                                                                                     */
/*Returns: an integer value indicating whether or not it successfully sent the data    */
/**************************************************************************************/
int ax_platform_sendData(ax_platform *cloud, ax_deviceID *device, ax_dataSet *dataItems[], int numDataSets) {

return ax_platform_send(cloud, device, dataItems, numDataSets, NULL, 0, NULL, 0, NULL, 0);

}
/**************************************************************************************/
/*ax_platform_sendAlarms()                                                            */
/*                                                                                    */
/*This function immedately sends any alarms included in the parameter to the platform */
/*listed. It makes use of the ax_platform_send() function as a special case.          */
/*                                                                                    */
/*cloud(required) : a pointer to a structure that contains the cloud service info     */
/*device(required) : a pointer to a structure that contains device information        */
/*alarms(required) : a pointer to an array of ax_alarm pointers that will be sent     */
/*                                                                                     */
/*Returns: an integer value indicating whether or not it successfully sent the data    */
/**************************************************************************************/
int ax_platform_sendAlarms(ax_platform *cloud, ax_deviceID *device, ax_alarm *alarms[], int numAlarms) {

return ax_platform_send(cloud, device, NULL, 0, alarms, numAlarms, NULL, 0, NULL, 0);

}
/**************************************************************************************/
/*ax_platform_sendEvents()                                                            */
/*                                                                                    */
/*This function immedately sends any events included in the parameter to the platform */
/*listed. It makes use of the ax_platform_send() function as a special case.          */
/*                                                                                    */
/*cloud(required) : a pointer to a structure that contains the cloud service info     */
/*device(required) : a pointer to a structure that contains device information        */
/*events(required) : a pointer to an array of ax_event pointers that will be sent     */
/*                                                                                     */
/*Returns: an integer value indicating whether or not it successfully sent the data    */
/**************************************************************************************/
int ax_platform_sendEvents(ax_platform *cloud, ax_deviceID *device, ax_event *events[], int numEvents) {

return ax_platform_send(cloud, device, NULL, 0, NULL, 0, events, numEvents, NULL, 0);

}
/**************************************************************************************/
/*ax_platform_sendLocations()                                                         */
/*                                                                                    */
/*This function immedately sends any events included in the parameter to the platform */
/*listed. It makes use of the ax_platform_send() function as a special case.          */
/*                                                                                    */
/*cloud(required) : a pointer to a structure that contains the cloud service info     */
/*device(required) : a pointer to a structure that contains device information        */
/*locations(required) : a pointer to an array of ax_location poitners that will be sent*/
/*                                                                                     */
/*Returns: an integer value indicating whether or not it successfully sent the data    */
/**************************************************************************************/
int ax_platform_sendLocations(ax_platform *cloud, ax_deviceID *device, ax_location *locations[], int numLocations) {

return ax_platform_send(cloud, device, NULL, 0, NULL, 0, NULL, 0, locations, numLocations);

}

/**************************************************************************************/
/*ax_platform_setPkgStatus()                                                          */
/*                                                                                    */
/*Tells the platform what state the package is currently in. This is necessary for the*/
/*lifecycle of the packages in the Axeda System.                                      */
/*                                                                                    */
/**************************************************************************************/
int ax_platform_setPkgStatus(ax_platform *cloud, ax_deviceID *device, char *pkgID, int status, char *errorMsg) {
  int retVal=AX_UNKNOWN;
  char *url=NULL;
  char *fullRequest=NULL;
  cJSON *requestBody=NULL; 
  HTTP_Headers myHeader;
  HTTP_Transmission response;
  zeroOutHTTPXmission(&response);
 
  requestBody= getPKGStatusJSON(status, errorMsg, AX_NO_PRIORITY, 0, terse_enable);  

  myHeader.contentType=getGeneralType(myHeader.contentType);
  url=getPackageUpdateResource(url, device, pkgID);
  int urlLength=strlen(url);
  url[urlLength]='\0'; 
 
  fullRequest=cJSON_PrintUnformatted(requestBody);
  int contentLength=strlen(fullRequest);
//Send the status
  retVal=http_send_put(url, cloud->hostname, cloud->port, cloud->secure, &myHeader, fullRequest, contentLength, &response);
//Scan the response and act if there are egress messages.
  handleResponse(&response);

//Clean up after ourselves
  free(fullRequest);
  free(url);
  cJSON_Delete(requestBody); 

  return retVal;  
  }
/**************************************************************************************/
/*ax_platform_setPkgStatus()                                                          */
/*                                                                                    */
/*Tells the platform what state the package is currently in. This is necessary for the*/
/*lifecycle of the packages in the Axeda System.                                      */
/*                                                                                    */
/**************************************************************************************/
int ax_platform_setPkgStatusStarted(ax_platform *cloud, ax_deviceID *device, char *pkgID) {
  return ax_platform_setPkgStatus(cloud, device, pkgID, AX_PKG_STARTED, NULL);
  }
/**************************************************************************************/
/*ax_platform_setPkgStatus()                                                          */
/*                                                                                    */
/*Tells the platform what state the package is currently in. This is necessary for the*/
/*lifecycle of the packages in the Axeda System.                                      */
/*                                                                                    */
/**************************************************************************************/
int ax_platform_setPkgStatusQueued(ax_platform *cloud, ax_deviceID *device, char *pkgID) {
  return ax_platform_setPkgStatus(cloud, device, pkgID, AX_PKG_QUEUED, NULL);
  }
/**************************************************************************************/
/*ax_platform_setPkgStatus()                                                          */
/*                                                                                    */
/*Tells the platform what state the package is currently in. This is necessary for the*/
/*lifecycle of the packages in the Axeda System.                                      */
/*                                                                                    */
/**************************************************************************************/
int ax_platform_setPkgStatusSuccess(ax_platform *cloud, ax_deviceID *device, char *pkgID) {
  return ax_platform_setPkgStatus(cloud, device, pkgID, AX_PKG_SUCCESS, NULL);
  }
/**************************************************************************************/
/*ax_platform_setPkgStatus()                                                          */
/*                                                                                    */
/*Tells the platform what state the package is currently in. This is necessary for the*/
/*lifecycle of the packages in the Axeda System.                                      */
/*                                                                                    */
/**************************************************************************************/
int ax_platform_setPkgStatusFailed(ax_platform *cloud, ax_deviceID *device, char *pkgID, char *errorMsg) {
  return ax_platform_setPkgStatus(cloud, device, pkgID, AX_PKG_FAILURE, errorMsg);
  }

/***************************************************************************************************************************************************************/
/***************************************************************************************************************************************************************/
/*The code in the following sections should never need to be called as it will be called from the preceeding functions.                                        */
/***************************************************************************************************************************************************************/
/***************************************************************************************************************************************************************/

/************************************************************************************/
/* The following methods construct references to endpoints on the platform where the */
/*respective data will be sent. For the sake of convenience they all return a pointer*/
/*that is equal in value to that which was passed in.                                */
/* They all take the same arguments:                                                 */
/*                                                                                   */
/* endPointBuff = The pointer to where the endpoint will be stored. This pointer    */
/*                will be  allocated and populated by the function                   */
/* ax_deviceID = A structure that contains the model and serial number of the current*/
/*               device. This structure should be the same as the one constructed at */
/*               startup based on the arguments.                                     */
/************************************************************************************/
char *getDataResource(char *endPointBuff, ax_deviceID *device)
   {
   return getResource(endPointBuff, device, END_DATA);
   }

char *getAgentResource(char *endPointBuff, ax_deviceID *device)
   {
   return getResource(endPointBuff, device, END_AGENTS);
   }

char *getFileResource(char *endPointBuff, ax_deviceID *device)
   {
   return getResource(endPointBuff, device, END_FILES);
   }

char *getRegistrationResource(char *endPointBuff, ax_deviceID *device)
   {
   return getResource(endPointBuff, device, END_REG);
   }
char *getFileDownloadResource(char *endPointBuff, ax_deviceID *device, char *fileID) {
    //since this url is slightly different from all the others we need to override the standard passing.
    char *tempBuff=NULL;
    tempBuff=encodeAgentID(device, tempBuff);
    int len=strlen(endpoints[END_BASE])+strlen(endpoints[END_PACKAGES])+6+strlen(tempBuff)+strlen(fileID)+strlen(endpoints[END_FILES])+1+strlen(PROTOCOL_VERSION)+1;
    endPointBuff = (char *)calloc(len,sizeof(char));
    // /ammp/packages/1/files/test_model!test_serial/12345
    // , URL_SEP, endpoints[END_BASE], URL_SEP, endpoints[END_FILED], URL_SEP, PROTOCOL_VERSION, URL_SEP, endpoints[END_FILES], URL_SEP, tempBuff=encodeAgentID(device, tempBuff), URL_SEP, fileID
    // %c%s%c%s%c%s%c%s%c%s%c%s
    
    snprintf(endPointBuff, len, "%c%s%c%s%c%s%c%s%c%s%c%s", URL_SEP, endpoints[END_BASE], URL_SEP, endpoints[END_PACKAGES], URL_SEP, PROTOCOL_VERSION, URL_SEP, endpoints[END_FILES], URL_SEP, tempBuff, URL_SEP, fileID );
    free(tempBuff);

    return endPointBuff;
}

char *getPackageUpdateResource(char *endPointBuff, ax_deviceID *device, char *packageID){
    //since this url is slightly different from all the others we need to override the standard passing.
    // "/ammp/packages/1/12345/status/test_model!test_serial"
    char *tempBuff=NULL;
    tempBuff=encodeAgentID(device, tempBuff);
    int len=6+strlen(endpoints[END_BASE])+strlen(endpoints[END_PACKAGES])+strlen(PROTOCOL_VERSION)+strlen(packageID)+strlen(endpoints[END_STATUS])+strlen(tempBuff)+1;
        endPointBuff = (char *)calloc(len, sizeof(char));
    
        snprintf(endPointBuff, len, "%c%s%c%s%c%s%c%s%c%s%c%s", URL_SEP, endpoints[END_BASE], URL_SEP, endpoints[END_PACKAGES], URL_SEP, PROTOCOL_VERSION, URL_SEP, packageID, URL_SEP, endpoints[END_STATUS], URL_SEP, tempBuff);
        free(tempBuff);

        return endPointBuff;
    }

char *getResource(char *endPointBuff, ax_deviceID *device, int resourceType)
  {
//Check for bounds on the endpoints array. END_REG is currently the highest, if it's OOB return the agent default URL
  int resType=END_AGENTS;
  if((resourceType<0)||(resourceType>END_REG)) { resType=END_AGENTS; }
  else { resType=resourceType; }
  int len = strlen(endpoints[END_BASE])+strlen(endpoints[resType])+6+strlen(device->model)+strlen(device->serial);
       endPointBuff = (char *)calloc(len+1, sizeof(char));
        char *tempBuff=NULL;
         switch(resType) {
            case END_REG:
              snprintf(endPointBuff, len+1, "%c%s%c%s%c%s", URL_SEP, endpoints[END_BASE], URL_SEP, endpoints[END_AGENTS], URL_SEP, PROTOCOL_VERSION);
            break;
            case END_FILED:
            
            break;
            default:
             snprintf(endPointBuff, len+1, "%c%s%c%s%c%s%c%s", URL_SEP, endpoints[END_BASE], URL_SEP, endpoints[resType], URL_SEP, PROTOCOL_VERSION, URL_SEP, tempBuff=encodeAgentID(device, tempBuff));
             free(tempBuff); //only used for storing the deviceID it's work is done now.
            break;
         }

        return endPointBuff;
  }


/**************************************************************************************/
/*encodeAgentID()                                                                     */
/*                                                                                    */
/*A utility method to convert the ax_deviceID structure into a protocol compliant     */
/*identifier string. Used mostly by the registration message                          */
/*                                                                                    */
/*device(required) : a pointer to a structure that contains the model, serial, tenant*/
/*buff(required) : a pointer to a char array where the output will be stored.         */
/*                                                                                    */
/*Returns: a pointer to the char array, same as *buff                                 */
/**************************************************************************************/
char* encodeAgentID(ax_deviceID *device, char *buff)
 {
    //TODO: Add logic to URL Encode output string if special characters are encountered...
 int len=0;
if(strlen(device->tenant)>0)
    {
    len=strlen(device->model)+strlen(device->serial)+strlen(device->tenant)+4;
    buff = (char *)calloc(len, sizeof(char));
    //buff[len]='\0';
    snprintf(buff, len, "%s@%s!%s", device->model, device->tenant, device->serial );
    }
 else
    {
    len=strlen(device->model)+strlen(device->serial)+3;
    buff = (char *)calloc(len, sizeof(char));
    //buff[len]='\0';
    snprintf(buff,len, "%s!%s", device->model, device->serial);
    }

    printDebug(buff);

 return buff;
 }

/**************************************************************************************/
/*getContentType()                                                                    */
/*                                                                                    */
/*A convenience method to allow different messages to have different media types. The */
/*media types are set forth in the protocol specification. The function will return a */
/*a pointer to a declared string, for which you do not need to free.                   */
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/**************************************************************************************/

char *getContentType(char *contentBuff, int type) {
    switch(type) {
        case 0:
          contentBuff=(char *)contentTypes[MIME_JSON];
          break;
        default:
          contentBuff=(char *)contentTypes[MIME_JSON];
          break;
        }
    return contentBuff;
}

char *getGeneralType(char *contentBuff) {
    return getContentType(contentBuff, TRANS_TYPE_JSON);
    }

/**************************************************************************************/
/*int handleResponse()                                                                */
/*                                                                                    */
/*A catch-all method that will handle any egress messages sent from the platform back */
/*to the device. If the JSON returned is valid it will dispatch the requests as needed*/
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/**************************************************************************************/
//Possible returns:
// AX_EGR_JSON_PARSE_FAIL -- A failure to parse the JSON that was returned

int handleResponse(HTTP_Transmission *response){
    cJSON *resp_int, *temp, *temp_child, *instructions, *instruction_child;
    int retVal=AX_OK;
    if(response->body==NULL) {return AX_OK;} //if there's no body, there's nothing to do here.

    resp_int=cJSON_Parse(response->body);
    if(resp_int==NULL) {
        return AX_GEN_PARSE_ERR;
        }
  printDebug("Creating software packages\n");
    temp=cJSON_GetObjectItem(resp_int, "packages");
    if(temp!=NULL) {
        //Handle a software package here
        int ctr=0, pkg_ctr2=0;
        int sz=cJSON_GetArraySize(temp);
        int instructionCt=0;
        ax_package *temp_package;

        for(ctr=0; ctr<sz; ctr++)
            {
            printDebug("Parsing package[]...\n");
            temp_child=cJSON_GetArrayItem(temp, ctr);
			//Create an ax_package for this
            temp_package=(ax_package *)malloc(sizeof(ax_package));
			char *pkgID=cJSON_GetObjectItem(temp_child, "id")->valuestring;
			retVal=ax_pkg_createPackage(temp_package, pkgID, 0, AX_NO_PRIORITY);         
            temp_package->priority=cJSON_GetObjectItem(temp_child, "priority")->valueint;
            temp_package->time=cJSON_GetObjectItem(temp_child, "time")->valueint;
			//add Instructions to the package
            instructions=cJSON_GetObjectItem(temp_child, "instructions");
            instructionCt=cJSON_GetArraySize(instructions);
                for(pkg_ctr2=0; pkg_ctr2<instructionCt; pkg_ctr2++)
                  {
		  		  //int instrType=-1;
                  printDebug("Parsing instruction\n");
                  instruction_child=cJSON_GetArrayItem(instructions, pkg_ctr2);
				                    
                  if(strcmp("down", cJSON_GetObjectItem(instruction_child, "@type")->valuestring)==0) {
				      cJSON *id=cJSON_GetObjectItem(instruction_child, "id");
				      char *s_id = NULL;
				      if(id != NULL){
						s_id=id->valuestring;
					  }
					  char *s_path = NULL;
					  //path is optional so we need to make sure it is here before trying to get the valuestring
					  cJSON *path = cJSON_GetObjectItem(instruction_child, "fp");
					  if(path != NULL){
		  				s_path=path->valuestring;
					  }
					  else{
						  path = cJSON_GetObjectItem(instruction_child, "path");
						  if(path != NULL){
		  					s_path=path->valuestring;
						  }
					  }
					  char *s_filename = NULL;
					  cJSON *fn = cJSON_GetObjectItem(instruction_child, "fn");
					  if(fn != NULL){
		       				s_filename=fn->valuestring;
					  }
					  else{
						  path = cJSON_GetObjectItem(instruction_child, "filename");
						  if(path != NULL){
		  					s_path=path->valuestring;
						  }
					  }
                      retVal=ax_pkg_addDLInstruction(temp_package, s_id, s_path, s_filename); 
                      }
				  //if it's not a download instruction, we don't care; down was the only one available in AMMP1.0
                  }
			//Now we tell someone that we've got a software package
			scm_download_req(temp_package); 
            }
        }
    int dictr1=0;
    //Set Data Item Commands will occur here.
     temp=NULL;
     temp_child=NULL;
     instructions=NULL;
     instruction_child=NULL;

     printDebug("Setting Data Item Commands\n");
    temp=cJSON_GetObjectItem(resp_int, "set");
    if(temp!=NULL){
        int disz=cJSON_GetArraySize(temp);
        for(dictr1=0; dictr1<disz; dictr1++)
             {
             temp_child=cJSON_GetArrayItem(temp, dictr1);
             instructions=cJSON_GetObjectItem(temp_child, "dataItems");
             instruction_child=instructions->child;
             while(instruction_child!=NULL){
                 if(instruction_child->type==cJSON_String) {
                     data_item_write(instruction_child->string, instruction_child->valuestring, 0, AX_STRING);
                     }
                 else if(instruction_child->type==cJSON_False) {
                     data_item_write(instruction_child->string, NULL, AX_FALSE, AX_DIGITAL);
                     }
                 else if(instruction_child->type==cJSON_True) {
                     data_item_write(instruction_child->string, NULL, AX_TRUE, AX_DIGITAL);
                     }
                 else {
                     data_item_write(instruction_child->string, NULL, instruction_child->valuedouble, AX_ANALOG);
                     }
                 instruction_child=instruction_child->next;
                 }

             }
         }
     //Data Item Poll requests here.
    printDebug("Setting Data Item Poll requests\n");
    int dictr2=0;
    temp=NULL;
    temp_child=NULL;
    instructions=NULL;
    instruction_child=NULL;
     temp=cJSON_GetObjectItem(resp_int, "send");
     if(temp!=NULL){
        int dissz=cJSON_GetArraySize(temp);
        for(dictr2=0; dictr2<dissz; dictr2++) {
            temp_child=cJSON_GetArrayItem(temp, dictr2);
            instructions=cJSON_GetObjectItem(temp_child, "dataItems");
            instruction_child=instructions->child;
            while(instruction_child!=NULL){
                data_item_request(instruction_child->valuestring);
                instruction_child=instruction_child->next;
                }
            }
        }

    cJSON_Delete(resp_int);//dispose of the cJSON object
    free(response->body);


  return retVal;
  }