Axeda Ready Demo for Freescale FRDM-KL46Z as accident alert system

Dependencies:   FRDM_MMA8451Q KL46Z-USBHost MAG3110 SocketModem TSI mbed FATFileSystem

Fork of AxedaGo-Freescal_FRDM-KL46Z by Axeda Corp

Revision:
0:65004368569c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMPC/axPlatform.c	Tue Jul 01 21:31:54 2014 +0000
@@ -0,0 +1,670 @@
+/************************************************************************************/
+/* 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;
+  }
+
+
+