Axeda demo software for u-blox C027 (GSM)

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
AxedaCorp
Date:
Mon Aug 11 19:02:42 2014 +0000
Child:
1:ff6d8adaf6b9
Commit message:
1st commit

Changed in this revision

AMMP/axConstants.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axDomain.c Show annotated file Show diff for this revision Revisions of this file
AMMP/axDomain.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axHTTP.c Show annotated file Show diff for this revision Revisions of this file
AMMP/axHTTP.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axPlatform.c Show annotated file Show diff for this revision Revisions of this file
AMMP/axPlatform.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axSerializer.c Show annotated file Show diff for this revision Revisions of this file
AMMP/axSerializer.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axSettings.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axStatusCodes.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axToolkit.c Show annotated file Show diff for this revision Revisions of this file
AMMP/axToolkit.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axTransport.cpp Show annotated file Show diff for this revision Revisions of this file
AMMP/axTransport.h Show annotated file Show diff for this revision Revisions of this file
AMMP/axTypes.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/GPS.cpp Show annotated file Show diff for this revision Revisions of this file
C027_Support/GPS.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/MDM.cpp Show annotated file Show diff for this revision Revisions of this file
C027_Support/MDM.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/MDMAPN.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/Pipe.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/SerialPipe.cpp Show annotated file Show diff for this revision Revisions of this file
C027_Support/SerialPipe.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/Socket/Endpoint.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/Socket/Socket.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/Socket/TCPSocketConnection.h Show annotated file Show diff for this revision Revisions of this file
C027_Support/Socket/UDPSocket.h Show annotated file Show diff for this revision Revisions of this file
cJSON/cJSON.c Show annotated file Show diff for this revision Revisions of this file
cJSON/cJSON.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axConstants.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,52 @@
+
+
+#ifndef _AXCONSTANTS_H_
+#define _AXCONSTANTS_H_
+
+#define PROTOCOL_VERSION "1"
+
+#define AX_ANALOG 1       //Used for Data Items
+#define AX_STRING 2       //Used for Data Items
+#define AX_DIGITAL 3      //Used for Data Items
+
+#define AX_TRUE 1
+#define AX_FALSE 0
+
+#define AX_SCALAR 0
+#define AX_ALARM 10
+#define AX_EVENT 2
+#define AX_FILE 3
+#define AX_LOCATION 4
+
+//used for getContentType() call, should return 'application/json'
+#define MIME_JSON       0
+#define TRANS_TYPE_JSON      0        
+
+
+#define AX_NO_PRIORITY           -1
+#define AX_LOWEST_PRIORITY       1
+#define AX_HIGHEST_PRIORITY    100
+#define AX_REGULAR_PRIORITY     50
+
+#define KEY_CDHEADER      0
+#define KEY_NAME          1
+#define KEY_HINT          2
+#define KEY_FNAME         3
+#define KEY_CTYPE         4
+#define KEY_OCTETSTR      5
+
+//The following defines are for package instruction types
+#define AX_PKG_DOWNLOAD 1
+
+//The following defines are for setting package statuses on the platform
+#define AX_PKG_QUEUED   0
+#define AX_PKG_STARTED  1
+#define AX_PKG_SUCCESS  2
+#define AX_PKG_FAILURE  3
+
+//The following defins are used for printing debug or error messages
+#define AX_DEBUG_MSG	1
+#define AX_ERROR_MSG	2
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axDomain.c	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,612 @@
+/************************************************************************************/
+/* axDomain.c                                                                       */
+/* �2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/* Defines methods for creation and interaction with Axeda domain constructs. This  */
+/* is a device independent implementation which can be applied to any device that   */
+/* supports ANSI C.                                                                 */
+/************************************************************************************/
+#include "axDomain.h"
+#include "string.h"
+#include "axSettings.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+
+
+/************************************************************************************/
+/* createAlarm()                                                                    */
+/*                                                                                  */
+/* Stores the supplied values into the structure pointed to by alm.                 */
+/*                                                                                  */
+/* alm(required) : a pointer to an empty alarm structure                            */
+/* name(required) : the name of the alarm                                           */
+/* description(required) : a more detailed account of the alarm                     */
+/* severity(required) : a numerical value from 0-1000, with 1000 being the highest  */
+/* dataItem(optional) : a pointer to a dataItem structure containing the data item  */
+/*                      that triggered this alarm. Use NULL for a generic alarm.    */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARG_NULL, AX_GEN_STR_TRUNC, AX_OK     */
+/************************************************************************************/
+int ax_data_createAlarm(ax_alarm *alm, char *alName, char *alDescription, int alSeverity, char *cause, char *reason, int timeOccured, int priority)
+  {
+  int retVal=AX_OK;
+  if((alSeverity <0)||(alSeverity>1000))
+    {
+    return AX_OUT_OF_RANGE;
+    }
+  if((!alm)||(!alName)||(!alDescription))
+    {
+    return AX_ARGNULL;
+    }
+  if(strlen(alName)<=0) {
+    return AX_ARGNULL;
+    }
+
+  snprintf(alm->alarmName, AX_ALM_NAME_S, alName);
+  if(strlen(alName)>AX_ALM_NAME_S){
+      retVal=AX_GEN_STR_TRUNC;
+      }
+
+  snprintf(alm->alarmDescription, AX_ALM_DESC_S, alDescription);
+  if(strlen(alDescription)> AX_ALM_DESC_S) {
+      retVal=AX_GEN_STR_TRUNC;
+      }
+
+  snprintf(alm->alarmCause, AX_ALM_CAUSE_S, cause);
+  if(strlen(cause)>AX_ALM_CAUSE_S) {
+     retVal=AX_GEN_STR_TRUNC;
+     }
+
+  snprintf(alm->alarmReason, AX_ALM_REAS_S, reason);
+  if(strlen(reason)>AX_ALM_REAS_S){
+     retVal=AX_GEN_STR_TRUNC;
+     }
+
+  alm->alarmSeverity=alSeverity;
+  alm->dateAcquired=timeOccured;
+  alm->priority=priority;
+  
+  return retVal;
+  }
+
+/*************************************************************************************/
+/* createDataItem()                                                                  */
+/*                                                                                   */
+/* This function will store information about a dataItem into a structure supplied   */
+/* by the calling method. There are traditionally 3 types of data Items, analog,     */
+/* string and digital.                                                               */
+/*                                                                                   */
+/* destDI(required) : A pointer to the structure where the data will be stored       */
+/* diName(required) : A character array containing the name of the data item         */
+/* diType(required) : A integer value indicating the data Item type. Can be          */
+/*                    AX_STRING, AX_DIGITAL, AX_ANALOG                               */
+/* stringValue(optional): If the type is AX_STRING, this value MUST be populated or  */
+/*                        an error will be returned. This is the value of the        */
+/*                        dataItem. If it is a String use zero for the numericValue  */
+/* numericValue(optional): If the type is AX_ANALOG or AX_DIGITAL this value MUST be */
+/*                         provided or an error will be returned. For AX_ANALOG di's */
+/*                         this value can be any numeric value within language       */
+/*                         constraints. For AX_DIGITAL, this value must be 1 or 0.   */
+/*                         1 will be considered true and 0 will be considered false. */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK       */
+/*                        AX_DI_UNKNOWN_TYPE, AX_UNKNOWN                             */
+/************************************************************************************/
+int ax_data_createDataItem(ax_dataSet *destDI, char *diName, int diType, char *stringValue, double numericValue, int timeAcquired, int priority) {
+  int retVal=AX_UNKNOWN;
+  if(!destDI) { return AX_ARGNULL; }
+  if(!diName) {return AX_ARGNULL; }
+  if((diType>3)&&(diType<1)) {return AX_ARGNULL; }
+  if(timeAcquired<0) {return AX_OUT_OF_RANGE; }
+  if((priority<-1)||(priority>100)) { return AX_OUT_OF_RANGE; }
+  if(destDI->created!=AX_TRUE) {
+      retVal=ax_data_createSet(destDI, timeAcquired, priority);
+      if(retVal!=AX_OK) { return retVal; }
+      }
+  
+  retVal=ax_data_addToSet(destDI, diName, diType, stringValue, numericValue);
+  
+  return retVal;
+  }
+/*************************************************************************************/
+/* createAnalogDataItem()                                                            */
+/*                                                                                   */
+/* This function will store information about a dataItem into a structure supplied   */
+/* by the calling method. This is a special case of the ax_data_createDataItem() call*/
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK       */
+/*                        AX_DI_UNKNOWN_TYPE, AX_UNKNOWN                             */
+/*************************************************************************************/
+int ax_data_createAnalogDataItem(ax_dataSet *destDI, char *diName, double value, int timeAcquired, int priority) {
+  return ax_data_createDataItem(destDI, diName, AX_ANALOG, NULL, value, timeAcquired, priority);
+  }
+
+/*************************************************************************************/
+/* createDigitalDataItem()                                                           */
+/*                                                                                   */
+/* This function will store information about a dataItem into a structure supplied   */
+/* by the calling method. There are traditionally 3 types of data Items, analog,     */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK       */
+/*                        AX_DI_UNKNOWN_TYPE, AX_UNKNOWN                             */
+/*************************************************************************************/
+int ax_data_createDigitalDataItem(ax_dataSet *destDI, char *diName, double value, int timeAcquired, int priority) {
+  return ax_data_createDataItem(destDI, diName, AX_DIGITAL, NULL, value, timeAcquired, priority);
+  }
+
+/*************************************************************************************/
+/* createDataItem()                                                                  */
+/*                                                                                   */
+/* This function will store information about a dataItem into a structure supplied   */
+/* by the calling method. There are traditionally 3 types of data Items, analog,     */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK       */
+/*                        AX_DI_UNKNOWN_TYPE, AX_UNKNOWN                             */
+/*************************************************************************************/
+int ax_data_createStringDataItem(ax_dataSet *destDI, char *diName, char *value, int timeAcquired, int priority) {
+  return ax_data_createDataItem(destDI, diName, AX_STRING, value, -1, timeAcquired, priority);
+  }
+
+/************************************************************************************/
+/*ax_data_createSet()                                                               */
+/*                                                                                  */
+/*Creates and populates a dataSet struct pointed to by the *set parameter. A dataSet*/
+/*can have multiple data items added by the ax_data_addToSet() method.              */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK      */
+/************************************************************************************/
+int ax_data_createSet(ax_dataSet *set, int acquisitionTime, int priority) {
+
+  if(!set) { return AX_ARGNULL; }
+  if((priority<-1)||(priority>100)) { return AX_OUT_OF_RANGE; }
+  if(acquisitionTime<0) {return AX_OUT_OF_RANGE;  }
+    set->dataNode_ct=0;
+    set->data_first=NULL;
+    set->data_last=NULL;
+
+    if(acquisitionTime >=0) {
+        set->acquisitionTime=acquisitionTime;
+        }
+    else {
+        set->acquisitionTime=-1;
+    }
+    if((priority >=1)&&(priority<=100)) {
+        set->priority=priority;
+        }
+    else {
+        set->priority=AX_NO_PRIORITY;
+        }
+
+    set->created=AX_TRUE;
+    return AX_OK;
+    }
+/************************************************************************************/
+/*ax_data_addToSet()                                                                */
+/*                                                                                  */
+/*Adds data to a preExisting data set. Data is represented as a linked list and     */
+/*pointed to by a dataSet structure. Adding data to with this method will cause the */
+/*memory to be malloc'd for each data item you set. To remove all data correctly use*/
+/*the ax_data_destroySet() function call. You will get memory leaks if you do not.  */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK      */
+/*                        AX_DI_UNKNOWN_TYPE                                        */
+/************************************************************************************/
+int ax_data_addToSet(ax_dataSet *set, char *diName, int diType, char *stringValue, double numericValue){
+    ax_dataNode *newNode, *temp=NULL;
+    int retVal=AX_UNKNOWN;
+
+    if((diType<1)||(diType>3)){
+            return AX_DI_UNKNOWN_TYPE;
+            }
+
+      if((!set)||(!diName)){
+          return AX_ARGNULL;
+            }
+
+      if((diType==AX_STRING)&&(!stringValue)){
+          return AX_ARGNULL;
+           }
+      if((diType==AX_DIGITAL)&&((numericValue<0)||(numericValue>1))){
+        return AX_OUT_OF_RANGE;
+        }
+    //if you didn't create the data set with the function this will make sure the linked list values are set. It MAY overwrite the time and priority if they are already set.
+    if(set->created!=AX_TRUE) { ax_data_createSet(set, 0, AX_NO_PRIORITY); }  
+
+    newNode=(ax_dataNode*)malloc(sizeof(ax_dataNode));
+
+    retVal=AX_OK;
+    snprintf(newNode->name, AX_DN_NAME_S, diName);
+    if(strlen(diName)>AX_DN_NAME_S) {
+        retVal=AX_GEN_STR_TRUNC;
+        }
+
+    newNode->next=NULL;
+    newNode->type=diType;
+    if(diType==AX_STRING) {
+	snprintf(newNode->sValue, AX_DN_SV_S, stringValue);
+        if(strlen(stringValue)>AX_DN_SV_S) {
+            retVal=AX_GEN_STR_TRUNC; // if the requested value was too large, set a warning to let us know it was truncated
+            }
+        }
+    else {
+        newNode->dValue=numericValue;
+        }
+
+    if(set->data_first==NULL) {
+        set->data_first=newNode;
+        }
+
+    if(set->data_last!=NULL) {
+        temp=set->data_last;
+        temp->next=(ax_dataNode *)newNode;
+        }
+
+
+    set->data_last=newNode;
+    int nodect=set->dataNode_ct;
+    nodect++;
+    set->dataNode_ct=nodect;
+
+    return retVal;
+    }
+/************************************************************************************/
+/*ax_data_addStringToSet()                                                          */
+/*                                                                                  */
+/*Adds data to a preExisting data set. Data is represented as a linked list and     */
+/*pointed to by a dataSet structure. Adding data to with this method will cause the */
+/*memory to be malloc'd for each data item you set. To remove all data correctly use*/
+/*the ax_data_destroySet() function call. You will get memory leaks if you do not.  */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK      */
+/************************************************************************************/
+int ax_data_addStringToSet(ax_dataSet *set, char *diName, char *value) {
+   return ax_data_addToSet(set, diName, AX_STRING, value, -1);
+}
+/************************************************************************************/
+/*ax_data_addAnalogToSet()                                                          */
+/*                                                                                  */
+/*Adds data to a preExisting data set. Data is represented as a linked list and     */
+/*pointed to by a dataSet structure. Adding data to with this method will cause the */
+/*memory to be malloc'd for each data item you set. To remove all data correctly use*/
+/*the ax_data_destroySet() function call. You will get memory leaks if you do not.  */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_OK                        */
+/************************************************************************************/
+int ax_data_addAnalogToSet(ax_dataSet *set, char *diName, double value){
+  return ax_data_addToSet(set, diName, AX_ANALOG, NULL, value);
+}
+/************************************************************************************/
+/*ax_data_addDigitalToSet()                                                         */
+/*                                                                                  */
+/*Adds data to a preExisting data set. Data is represented as a linked list and     */
+/*pointed to by a dataSet structure. Adding data to with this method will cause the */
+/*memory to be malloc'd for each data item you set. To remove all data correctly use*/
+/*the ax_data_destroySet() function call. You will get memory leaks if you do not.  */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_OK                        */
+/************************************************************************************/
+int ax_data_addDigitalToSet(ax_dataSet *set, char *diName, double value) {
+  return ax_data_addToSet(set, diName, AX_DIGITAL, NULL, value);
+  }    
+    
+    
+/************************************************************************************/
+/*ax_data_destroySet()                                                              */
+/*                                                                                  */
+/*Iterates through all data items in a dataset and frees them. This assumes all nodes*/
+/*have been allocated by malloc.If the addToSet() function was being used then that */
+/*will be true.                                                                     */
+/*Possible Return Codes: AX_OK  AX_ARGNULL                                          */
+/************************************************************************************/
+int ax_data_destroySet(ax_dataSet *set) {
+
+    if(set!=NULL) {
+    ax_dataNode *curr=set->data_first, *next;
+    int ctr;
+    for(ctr=0; ctr<set->dataNode_ct; ctr++)
+        {
+        next=(ax_dataNode *)curr->next;
+        free(curr);
+        curr=next;
+        next=NULL; // CYA'ing here
+        }
+    set->data_first=NULL;
+    set->data_last=NULL;
+    }
+    else {
+	return AX_ARGNULL;
+	}
+
+    return AX_OK;
+    }
+
+
+/*************************************************************************************/
+/* createEvent()                                                                     */
+/*                                                                                   */
+/* This function will populate an event structure and check the values to ensure they*/
+/* are within protocol limit                                                         */
+/* Possible Return Codes: AX_ARGNULL, AX_GEN_STR_TRUNC                               */
+/************************************************************************************/
+int ax_data_createEvent(ax_event *evt, char *name, char *description, int timeOccured, int priority)
+  {
+  int retVal=AX_OK;
+  if((!evt)||(!name)||(!description)){
+    return AX_ARGNULL;
+    }
+  if((priority<-1)||(priority>100)) {return AX_OUT_OF_RANGE; }
+
+  snprintf(evt->name,AX_EVT_NAME_S, name);
+  if(strlen(name)>AX_EVT_NAME_S) {
+      retVal= AX_GEN_STR_TRUNC;
+      }
+ 
+  snprintf(evt->description, AX_EVT_DESC_S, description);
+  if(strlen(description)>AX_EVT_DESC_S) {
+      retVal=AX_GEN_STR_TRUNC;
+      }
+
+  evt->dateAcquired=timeOccured;
+  evt->priority=priority;
+  return retVal;
+  }
+  
+
+
+
+/************************************************************************************/
+/* createLocation()                                                                 */
+/*                                                                                  */
+/* This function will populate a location structure storing the current location    */
+/*                                                                                  */
+/* loc (required) : A structure that will be populated with the data                */
+/* lat (required) : A number between 90 and -90 representing the degrees latitude.  */
+/* lon (required) : A number between 180 and -180 representing the degrees longitude*/
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARGNULL, AX_OK                        */
+/************************************************************************************/
+int ax_data_createLocation(ax_location *loc, double lat, double lon, double alt, int timeAcquired, int priority){
+  if(!loc){
+    return AX_ARGNULL;
+    }
+  
+  if((lat>90)||(lat<-90)){
+    return AX_OUT_OF_RANGE;
+    }
+  
+  if((lon>180)||(lon<-180)){
+    return AX_OUT_OF_RANGE;
+    }
+  
+  
+  loc->latitude=lat;  
+  loc->longitude=lon;
+  loc->altitude=alt;
+
+  loc->dateAcquired=timeAcquired;
+  loc->priority=priority;
+  return AX_OK;
+  }
+
+/************************************************************************************/
+/* createModelSerialDeviceId()                                                      */
+/*                                                                                  */
+/* This function will populate a structure that stores data about the device's iden-*/
+/* tification. The Axeda platform allows for multiple ways of identifying a device. */
+/*                                                                                  */
+/* device(required) : a pointer to a structure where the data will be stored        */
+/* model (required) : A model number that describes a particular family of device.  */
+/*                    If this were describing a car it could be a Ford_Mustang      */
+/* serial (required) : A unique Identifier for the device. If it was a car it would */
+/*                    be analagous to the VIN number.                               */
+/* tenant (optional) : The identifier of the Axeda tenant instance. Not currently   */
+/*                      used and should always default to zero.                     */
+/* Possible Return Codes: AX_ARGNULL, AX_GEN_STR_TRUNC, AX_OK                       */
+/************************************************************************************/
+
+int ax_data_createModelSerialDeviceId(ax_deviceID *device, char *model, char *serial, char *tenant) {
+  int retVal=AX_OK;
+    if((!device)||(!model)||(!serial)){
+    return AX_ARGNULL;
+    }
+  snprintf(device->model, AX_MSID_MDL_S, model);
+  if(strlen(model)> AX_MSID_MDL_S) {
+      retVal=AX_GEN_STR_TRUNC;
+      }
+
+  snprintf(device->serial, AX_MSID_SER_S, serial);
+  if(strlen(serial)>AX_MSID_SER_S) {
+      retVal=AX_GEN_STR_TRUNC;
+      }
+
+  memset(device->tenant, '\0', AX_MSID_TEN_S);
+  if(tenant!=NULL) {
+  	snprintf(device->tenant, AX_MSID_TEN_S, "%s", tenant);
+  	if(strlen(tenant)>AX_MSID_TEN_S) { retVal=AX_GEN_STR_TRUNC; }
+      	}
+
+  return retVal;
+  }
+/************************************************************************************/
+/*ax_createPlatform()                                                               */
+/*                                                                                  */
+/*Populates the ax_platform struct pointed to by axedaCloud It will add the hostname*/
+/*ip and port. Other parts of the ax_platform structure can be populated at will    */
+/*                                                                                  */
+/*                                                                                  */
+/* Possible Return Codes: AX_OUT_OF_RANGE, AX_ARG_NULL, AX_GEN_STR_TRUNC, AX_OK     */
+/************************************************************************************/
+int ax_createPlatform(ax_platform *axedaCloud, const char *hostname, int ip[], int port)
+  {
+  int retVal=AX_OK;
+//Check that there's an IP or Hostname.
+  if((!ip)&&(!hostname))
+    { return AX_ARGNULL; } 
+  if(!axedaCloud) {return AX_ARGNULL; }
+//Check the port is in bounds of known ports
+  if((port<0)||(port>65536)) {
+	return AX_OUT_OF_RANGE;
+	}
+  if((hostname)&&(strlen(hostname)>0))
+    {
+    snprintf(axedaCloud->hostname, AX_PLAT_HOST_S, hostname);
+    if(strlen(hostname)>AX_PLAT_HOST_S) {
+        retVal=AX_GEN_STR_TRUNC;
+        }
+    }
+   else {
+    return AX_ARG_EMPTY;
+    }
+
+ if(ip)
+    {
+     int i=0;
+    for(i=0; i<4; i++) { if((ip[i]>255)||(ip[i]<0)) return AX_OUT_OF_RANGE; }
+    axedaCloud->ip[0]=ip[0];
+    axedaCloud->ip[1]=ip[1];
+    axedaCloud->ip[2]=ip[2];
+    axedaCloud->ip[3]=ip[3];
+
+    }
+  axedaCloud->port=port;
+  return retVal;
+  }
+/************************************************************************************/
+/* ax_createFile()                                                                  */
+/*                                                                                  */
+/* Populates a file structure with the necessary info and checks the arguments to   */
+/* ensure compliance with the protocol                                              */
+/* Possible Return Codes: AX_UNKNOWN, AX_GEN_STR_TRUNC, AX_OK, AX_ARGNULL           */
+/*                                                                                  */
+/*file (required): A pointer to an already existing ax_file structure to store data */
+/*name (required): A name for the file, this can be any arbitrary string. It will   */
+/*                 appear on the platform after upload                              */
+/*hint (optional): A string that allows for easy retrieval on the platform          */
+/*size (required): The size of the file to send. The end of the file would occur at */
+/*                 data+size                                                       */
+/*data (required): A pointer to the starting address of data to send, it can be the */
+/*                 first cell in an array or any location in memory.                */
+/************************************************************************************/
+int ax_createFile(ax_file *file, char *name, char *hint, int size, unsigned char *data)
+    {
+    int retVal=AX_OK;
+//ARG Checks
+    if(size<=0) { return AX_OUT_OF_RANGE; }
+	if(file==NULL) { return AX_ARGNULL; }
+	if(name==NULL) { return AX_ARGNULL; }
+	if(data==NULL) { return AX_ARGNULL; }
+//Store the data into the structure
+    snprintf(file->name, AX_FILE_NAME_S, name);
+    if(strlen(name)>AX_FILE_NAME_S){
+        retVal=AX_GEN_STR_TRUNC;
+        }
+
+    if(hint!=NULL) {
+	    snprintf(file->hint, AX_FILE_HINT_S, hint);
+	    if(strlen(hint)>AX_FILE_HINT_S) {
+	        retVal=AX_GEN_STR_TRUNC;
+	        }
+	}
+
+    file->size=size;
+    file->data=data;
+
+    return retVal;
+    }
+
+/************************************************************************************/
+/*ax_createPackageInstruction()                                                     */
+/*                                                                                  */
+/*populates an ax_package_instruction structre passed in. This should never need to */
+/*be called by a library implementor. It will only be used for egress notifications */
+/*                                                                                  */
+/*                                                                                  */
+/************************************************************************************/
+int ax_pkg_createPackageInstruction(ax_package_instruction *inst, int instruction_type, char *file_id, char *path, char *filename){
+	int retVal=AX_OK;
+
+	inst->instruction_type=instruction_type;
+	int fdSZ=snprintf(inst->file_id, AX_PKGI_FID_S, file_id);
+	if(strlen(file_id)>fdSZ) {
+       retVal=AX_GEN_STR_TRUNC;
+                      }
+                  
+    int pathSZ=snprintf(inst->path, AX_PKGI_PATH_S, path);
+	if(strlen(path)>pathSZ) {
+       retVal=AX_GEN_STR_TRUNC;
+       }
+
+                  
+    int fnSZ=snprintf(inst->filename, AX_PKGI_FNAME_S, filename);
+	if(strlen(filename)>fnSZ) {
+       retVal=AX_GEN_STR_TRUNC;
+       }
+	inst->next=NULL;
+
+  return retVal;
+  }
+
+/************************************************************************************/
+/*ax_createPackage()                                                                */
+/*                                                                                  */
+/*populates an ax_package structre passed in. This should never need to be called by*/ 
+/*a library implementor. It will only be used for egress notifications              */
+/*                                                                                  */
+/*                                                                                  */
+/************************************************************************************/
+int ax_pkg_createPackage(ax_package *package, char *pkgID, int time, int priority) {
+  int retVal=AX_OK;
+
+  int nmsz=snprintf(package->packageID, AX_PKG_ID_S, pkgID);
+  if(strlen(pkgID)> nmsz) {
+    retVal=AX_GEN_STR_TRUNC;
+	}
+  package->time=time;
+  package->priority=priority;
+  package->instructions=NULL;
+  
+
+return retVal;
+} 
+/************************************************************************************/
+/*ax_pkg_addDLInstruction()                                                          */
+/*                                                                                   */
+/*Adds a file download package to an already existing package. This function will    */ 
+/*dynamically allocate memory for each instruction. That memory will need to be freed*/
+/*When the status is complete                                                        */
+/*                                                                                   */
+/************************************************************************************/
+int ax_pkg_addDLInstruction(ax_package *pkg, char *file_id, char *path, char *filename) {
+  int retVal=AX_UNKNOWN;
+  ax_package_instruction *curr=NULL;
+  ax_package_instruction *newInst=NULL;
+
+  newInst=(ax_package_instruction *)calloc(1, sizeof(ax_package_instruction));
+  retVal=ax_pkg_createPackageInstruction(newInst, AX_PKG_DOWNLOAD, file_id, path, filename);
+
+  if(pkg->instructions!=NULL) {
+	curr=pkg->instructions;
+	//Go to the end of the list
+  	while(curr->next!=NULL) {
+		curr=curr->next;
+		}
+	curr->next=newInst;
+ 	}
+
+  else {
+	pkg->instructions=newInst;
+	}  
+
+
+return retVal;
+}
+/*************************************************************************************/
+/*ax_pkg_destroyPackage()                                                            */
+/*                                                                                   */
+/*Free's lined package Instructions when created by the ax_pkg_add*() function. Be   */
+/*careful not to use this on a package with instructions that were manually declared */
+/*This does not attempt to free the package itself as it may have been declared and  */
+/*not dynamically allocated.                                                         */
+/************************************************************************************/
+int ax_pkg_destroyPackage(ax_package *pkg) {
+  ax_package_instruction *curr=NULL;
+  ax_package_instruction *target=NULL;
+  curr=pkg->instructions;
+  while(curr!=NULL) {
+	target=curr;       //We'll aim at the current node   
+	curr=curr->next;   //store the value for the next node
+    free(target);	   //kill the target node
+   }
+return AX_OK;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axDomain.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,53 @@
+/************************************************************************************/
+/* axDomain.h                                                                       */
+/* �2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/* Defines methods for creation and interaction with Axeda domain constructs. This  */
+/* is a device independent implementation which can be applied to any device that   */
+/* supports ANSI C.                                                                 */
+/************************************************************************************/
+
+#ifndef AXDOMAIN_H
+#define AXDOMAIN_H
+
+#include "axTypes.h"
+#include "axConstants.h"
+#include "axStatusCodes.h"
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+
+int ax_data_createAlarm(ax_alarm *alm, char *alName, char *alDescription, int alSeverity, char *cause, char *reason, int timeOccured, int priority);
+int ax_data_createEvent(ax_event *evt, char *name, char *description, int timeOccured, int priority);
+int ax_data_createRegistration();
+int ax_data_createLocation(ax_location *loc, double lat, double lon, double alt, int timeAcquired, int priority);
+int ax_data_createModelSerialDeviceId(ax_deviceID *device, char *model, char *serial, char *tenant);
+int ax_createFile(ax_file *file, char *name, char *hint, int size, unsigned char *data);
+
+int ax_createPlatform(ax_platform *axedaCloud, const char *hostname, int ip[], int port);
+
+
+int ax_data_createDataItem(ax_dataSet *destDI, char *diName, int diType, char *stringValue, double numericValue, int timeAcquired, int priority);
+int ax_data_createAnalogDataItem(ax_dataSet *destDI, char *diName, double value, int timeAcquired, int priority);
+int ax_data_createDigitalDataItem(ax_dataSet *destDI, char *diName, double value, int timeAcquired, int priority);
+int ax_data_createStringDataItem(ax_dataSet *destDI, char *diName, char *value, int timeAcquired, int priority);
+
+int ax_data_createSet(ax_dataSet *set, int acquisitionTime, int priority);
+
+int ax_data_addToSet(ax_dataSet *set, char *diName, int diType, char *stringValue, double numericValue);
+int ax_data_addStringToSet(ax_dataSet *set, char *diName, char *value);
+int ax_data_addAnalogToSet(ax_dataSet *set, char *diName, double value);
+int ax_data_addDigitalToSet(ax_dataSet *set, char *diName, double value);
+int ax_data_destroySet(ax_dataSet *set);
+
+int ax_pkg_createPackageInstruction(ax_package_instruction *package, int instruction_type, char *file_id, char *path, char *filename);
+int ax_pkg_createPackage(ax_package *package, char *pkgID, int time, int priority);
+int ax_pkg_addDLInstruction(ax_package *pkg, char *file_id, char *path, char *filename);
+int ax_pkg_destroyPackage(ax_package *pkg);
+
+#ifdef __cplusplus
+  }
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axHTTP.c	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,460 @@
+#include "axHTTP.h"
+#include "axStatusCodes.h"
+#include "axConstants.h"
+#include "ctype.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "axSettings.h"
+#include "axTransport.h"
+
+#define AX_HTTP_OK                  200
+#define AX_HTTP_SYNTAX_INVALID      400     //The Request syntax is incorrect
+#define AX_HTTP_UNAUTHORIZED        401     //You need permission to access that resource. Agent Authentication failure
+#define AX_HTTP_FORBIDDEN           403     //You need permission to access that resource.
+#define AX_HTTP_NOT_FOUND           404     //The resource was not found
+#define AX_HTTP_REQ_INVALID         405     //Content type is invalid, should be application/json most of the time
+#define AX_HTTP_CONTENT_INVALID     422     //The Request is valid syntactically but the content is invalid e.g. wrong instruction
+#define AX_HTTP_SERVER_ERROR        500     //The server attempted to handle your request but a failure occurred; check the server logs.
+
+#define HTTPKEY_GET         0
+#define HTTPKEY_POST        1
+#define HTTPKEY_PUT         2
+#define HTTPKEY_PROTOCOL    3
+#define HTTPKEY_CRLF        4
+
+
+#define HTTPH_HOST          0
+#define HTTPH_TYPE          1
+#define HTTPH_LENGTH        2
+#define HTTPH_CONNECTION    3
+#define HTTPH_XCOUNT        4
+#define HTTPH_CONTENTDIS    5
+#define HTTPH_MULTIPART     6
+#define HTTPH_FORMDATA      7
+#define HTTPH_ACCEPT        8
+
+#define HTTPR_TYPE          0
+#define HTTPR_LENGTH        1
+#define HTTPR_BODY_SEP      2
+#define HTTPR_DELIMS        3
+
+int http_debug=AX_FALSE;
+int x_count=0;
+
+int http_getResponse(HTTP_Transmission *response, ax_socket *source);
+
+char *HTTP_KEY[]= {"GET", "POST", "PUT", "HTTP/1.1", "\r\n"};
+char *HTTP_HEADER[] = { "Host: ", "Content-Type: ", "Content-Length: ", "Connection: close", "x-count: ", "Content-Disposition: ","multipart/form-data; boundary=", "form-data;", "Accept: */*"};
+char *HTTP_RESP[] = { "Content-Type:", "Content-Length:", "\r\n\r\n", " \r\n"}; 
+
+int http_send(HTTP_Transmission *request, char *host, int port, int secure, HTTP_Transmission *response){
+  int retVal=AX_UNKNOWN;
+
+  switch(request->operation) {
+      case AX_HTTP_GET:
+        retVal=http_send_get(request->resource, host, port, secure, response);
+      break;
+      case AX_HTTP_POST:
+        retVal=http_send_post(request->resource, host, port, secure, &request->headers, request->body, request->body_length, response);
+      break;
+      case AX_HTTP_PUT:
+              retVal=http_send_put(request->resource, host, port, secure, &request->headers, request->body, request->body_length, response);
+      break;
+      case AX_HTTP_MPOST:
+        retVal=http_send_mpost(request->resource, host, port, secure, &request->headers, request->body, request->body_length, request->mpData, 1, response);
+      break;
+      }
+
+  return retVal;
+  }
+
+int http_send_get(char *resource, char *host, int port, int secure, HTTP_Transmission *response) {
+  int retVal=AX_UNKNOWN;
+
+  if(!resource||!host||!response) { return AX_ARGNULL; }
+  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
+  int sz=strlen(HTTP_KEY[HTTPKEY_GET])+strlen(resource)+strlen(HTTP_KEY[HTTPKEY_PROTOCOL])+strlen(HTTP_HEADER[HTTPH_HOST])+strlen(host)+13+6+strlen(HTTP_HEADER[HTTPH_CONNECTION])+strlen(HTTP_HEADER[HTTPH_ACCEPT]); //+6 adds space for extra CRLFs, spaces, and null terminator
+
+  ax_socket sock;
+
+  retVal=net_socketInit(&sock);
+  retVal=net_socketOpen(&sock, host, port, secure);
+  if(retVal!=AX_OK){
+      return retVal;
+      }
+
+  char *buff=(char *)malloc(sizeof(char)*sz);
+  int wrtSz=snprintf(buff, sz, "%s %s %s%s%s%s:%d%s%s%s%s", HTTP_KEY[HTTPKEY_GET], resource, HTTP_KEY[HTTPKEY_PROTOCOL], HTTP_KEY[HTTPKEY_CRLF], HTTP_HEADER[HTTPH_HOST], host, port, HTTP_KEY[HTTPKEY_CRLF], HTTP_HEADER[HTTPH_CONNECTION], HTTP_KEY[HTTPKEY_CRLF], HTTP_KEY[HTTPKEY_CRLF]);
+
+  if(wrtSz>sz) { printDebug("http_send_get(): Buffer allocated for header was too small, truncated"); } 
+  retVal=net_socketWrite(&sock, buff, sz);
+  retVal=net_socketFlush(&sock);
+
+  retVal=http_getResponse(response, &sock);
+  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }
+
+  net_socketClose(&sock);
+  free(buff);
+  return retVal;
+  }
+
+int http_send_put(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response) {
+  int retVal=AX_UNKNOWN;
+
+  if(!resource||!host||!response) { return AX_ARGNULL; }
+  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
+  if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }
+
+  ax_socket sock;
+
+  retVal=net_socketInit(&sock);
+  retVal=net_socketOpen(&sock, host, port, secure);
+  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
+    return retVal;
+    }
+  printDebug("Attempting to create headers");
+   char *header=NULL;
+   header=createHeaders(header, HTTPKEY_PUT, resource, HTTPKEY_PROTOCOL, host, headers->contentType, data_sz, x_count); //returns a malloc'd string with the headers
+
+  retVal=net_socketWrite(&sock, header, strlen(header));
+  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
+      goto cleanup;
+      }
+  retVal=net_socketWrite(&sock, data, data_sz);
+  net_socketFlush(&sock);
+  if(retVal!=AX_OK) {
+     retVal=AX_NET_ERR_DATA_WRITE;
+     goto cleanup;
+     }
+
+  retVal=http_getResponse(response, &sock);
+  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }
+
+  x_count++;
+   goto cleanup;
+
+
+cleanup:
+  net_socketClose(&sock);
+  free(header);
+  return retVal;
+}
+
+
+
+int http_send_post(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response){
+  int retVal=AX_UNKNOWN;
+
+  if(!resource||!host||!response) { return AX_ARGNULL; }
+  if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
+  if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }
+
+  ax_socket sock;
+
+  retVal=net_socketInit(&sock);
+  retVal=net_socketOpen(&sock, host, port, secure);
+  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
+    return retVal;
+    }
+  printDebug("Attempting to create headers");
+   char *header=NULL;
+   header=createHeaders(header, HTTPKEY_POST, resource, HTTPKEY_PROTOCOL, host, headers->contentType, data_sz, x_count); //returns a malloc'd string with the headers
+
+  retVal=net_socketWrite(&sock, header, strlen(header));
+  if(retVal!=AX_OK){ //if a failure occurred bail out. failures here would be that a port is not free
+      goto cleanup;
+      }
+  retVal=net_socketWrite(&sock, data, data_sz);
+  net_socketFlush(&sock);
+  x_count++;
+  printDebug("Transmission sent, Waiting for response\n");
+
+
+  retVal=http_getResponse(response, &sock);
+  if(retVal==AX_HTTP_OK) { retVal=AX_OK; }
+
+   goto cleanup;
+
+cleanup:
+  net_socketClose(&sock);
+  free(header);
+  return retVal;
+  }
+
+int http_send_mpost(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Part *files, int part_ct, HTTP_Transmission *response) {
+    int retVal=AX_UNKNOWN;
+ //   char xcount_tmp[10];
+//    char clength_tmp[10];
+    int boundary_sz=10;
+    int body_sz=0;
+    int hint_sz=0;
+    char *hint=NULL;
+	char *header=NULL;
+    ax_socket sock;
+
+      if(!resource||!host||!response) { return AX_ARGNULL; }
+    if((port < 0)||(port>65536)) { return AX_NET_PORT_INVALID; }
+    if((!data)&&(data_sz!=0)) { return AX_CONFLICTING_ARG; }
+ //Assemble body Parts
+    char *fileargs=NULL;
+    int file_arg_len=strlen(files->file_name)+51;
+    fileargs=(char *)malloc(sizeof(char)*file_arg_len);
+    int wrtfarg=snprintf(fileargs, file_arg_len, "name=\"file\"; filename=\"%s\"\r\nContent-Type: text/plain", files->file_name);
+    if(wrtfarg>file_arg_len) { printDebug("http_send_mpost(): Buffer allocated for file arguments was too small, truncated"); }
+    if(files->hint!=NULL)
+        {
+        hint_sz=strlen(files->hint)+18;//+1 for terminating char
+        hint=(char *)malloc(sizeof(char)*hint_sz);
+        int wrthint=snprintf(hint, hint_sz, "name=\"hint\"\r\n\r\n%s\r\n", files->hint);
+        if(wrthint>hint_sz) { printDebug("http_send_mpost(): Buffer allocated for hint was too small, truncated"); }
+        }
+//body size calculation here
+  //Boundary: --<boundary>
+    body_sz=body_sz+2+boundary_sz;   
+  //adding body ---for mparts
+    if(data_sz>0){
+      body_sz=body_sz+36+data_sz+boundary_sz;  
+      }
+  //Add Hint     Content-Disposition: form-data;name="<hint>"\r\n--<boundary>\r\n
+    if(files->hint!=NULL){
+      body_sz=body_sz+38+strlen(hint)+boundary_sz;  
+      }
+    if(files->data_sz>0) {
+      body_sz=body_sz+38+strlen(fileargs)+files->data_sz;
+      }
+    body_sz=body_sz+8+boundary_sz;
+
+//get a boundary for the multipart
+    char *boundary=(char *)malloc(sizeof(char)*boundary_sz);
+    http_getBoundary(boundary, boundary_sz);
+//convert the data size integer into a string
+ //  int wrtCLen=snprintf(clength_tmp, 10, "%d", body_sz);
+ //   if(wrtCLen>10) { printDebug("http_send_mpost(): Buffer allocated for clength_tmp was too small, truncated"); }
+    //Add operation line
+
+    printDebug("Attempting to create headers");
+
+//Create Content Type 
+	 int cTypeSz=0;
+	 cTypeSz=strlen(HTTP_HEADER[HTTPH_MULTIPART])+strlen(boundary)+1;
+	 char *contentType=(char *)calloc(cTypeSz, sizeof(char));       
+	 int wrt_ctype=snprintf(contentType, cTypeSz, "%s%s", HTTP_HEADER[HTTPH_MULTIPART], boundary);
+	 if(wrt_ctype>cTypeSz) { printDebug("http_send_mpost(): Buffer allocated for contentType was too small, truncated");}
+//Get the headers
+     header=createHeaders(header, HTTPKEY_POST, resource, HTTPKEY_PROTOCOL, host, contentType, body_sz, x_count); //returns a malloc'd string with the headers
+	 free(contentType); //we're done with the string we used to cat the values
+//Start to send the data
+	retVal=net_socketInit(&sock);
+    retVal=net_socketOpen(&sock, host, port, secure);
+    if(retVal!=AX_OK){ //if a failure occurred, bail out. A failure here would indicate that a port is closed, or the network is not available.
+      return retVal;
+      }
+//Write the headers
+    retVal=net_socketWrite(&sock, header, strlen(header));
+      if(retVal!=AX_OK){ goto cleanup; }
+
+   //write the body...
+   //start boundary
+      retVal=net_socketWrite(&sock, "--", 2);
+      retVal=net_socketWrite(&sock, boundary, boundary_sz);
+      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+   //1st section -uses the data in body if specified
+    if(data_sz>0){
+      retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
+      retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
+      retVal=net_socketWrite(&sock, data, data_sz); //Write body data, the fields and values
+      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+      retVal=net_socketWrite(&sock, "--", 2);
+      retVal=net_socketWrite(&sock, boundary, boundary_sz);
+      }
+    if(files->hint!=NULL){
+       retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
+       retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
+       retVal=net_socketWrite(&sock, hint, hint_sz); //Write body data, the fields and values
+       retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+       retVal=net_socketWrite(&sock, "--", 2);
+       retVal=net_socketWrite(&sock, boundary, boundary_sz);
+       retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+       }
+    if(files->data_sz>0) {
+        retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_CONTENTDIS], 21);
+        retVal=net_socketWrite(&sock, HTTP_HEADER[HTTPH_FORMDATA], 11);
+        retVal=net_socketWrite(&sock, fileargs, file_arg_len);
+        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+        retVal=net_socketWrite(&sock, (char *)files->data, files->data_sz);
+        retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+        }
+      retVal=net_socketWrite(&sock, "--", 2);
+      retVal=net_socketWrite(&sock, boundary, boundary_sz);
+      retVal=net_socketWrite(&sock, "--", 2);
+      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+      retVal=net_socketWrite(&sock, HTTP_KEY[HTTPKEY_CRLF], 2);
+
+
+    net_socketFlush(&sock);
+    x_count++;
+    retVal=http_getResponse(response, &sock);
+    if(retVal==AX_HTTP_OK) { retVal=AX_OK; }
+
+  cleanup:
+   net_socketClose(&sock);
+   free(header);
+   free(hint);
+   free(fileargs);
+   free(boundary);
+   return retVal;
+  }
+
+void http_add_mpart(HTTP_Transmission *request, char *file_name, unsigned char *data, int file_sz) {
+ //For future expansion.
+}
+
+//Return Handling
+HTTP_Transmission *http_parse(HTTP_Transmission *response, char *data){
+printDebug("Starting parse of ");
+printDebug(data);
+
+    char clength[7];
+    int reqSize=0;
+    char *temp=NULL;
+    char *bodyStart=NULL;
+    response->body_length=0;
+    response->response_code=-1; //indicate that no response code has been recieved(yet)
+
+    reqSize=strlen(data);
+    if(reqSize<=12) { printDebug("No Body included"); }
+    else { printDebug("body present" );
+    bodyStart=strstr(data, HTTP_RESP[HTTPR_BODY_SEP]);
+    if(bodyStart==NULL) { printDebug("D'oh! Couldn't parse for body\n"); }
+    else {
+	 int body_length=strlen(bodyStart)-4; //don't count the extra \r\n\r\n
+         response->body_length=body_length;
+         response->body=(char *)calloc(body_length+1, sizeof(char));
+         snprintf(response->body, body_length+1, "%s", bodyStart+4); //the +4 gets rid of the preceeding \r\n\r\n
+         }
+    }
+
+    temp = strtok(data, HTTP_RESP[HTTPR_DELIMS]);
+    while (temp!=NULL) {
+
+    if((strlen(temp)==3)&&(isdigit((int)temp[0]))&&(isdigit((int)temp[1]))&&(isdigit((int)temp[2]))) {
+        response->response_code=atoi(temp); //convert the text response code to an int.
+        }
+
+    if(strcmp(temp, HTTP_RESP[HTTPR_TYPE])==0) {
+        response->headers.contentType=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
+        }
+    if(strcmp(temp, HTTP_RESP[HTTPR_LENGTH])==0){
+        temp=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
+        strcpy(clength, temp);
+    response->body_length=atoi(clength);
+    if(response->body_length<=0) {
+         response->body_length=strlen(bodyStart+4);
+          }
+        }
+
+    temp=strtok(NULL, HTTP_RESP[HTTPR_DELIMS]);
+    }
+
+    return response;
+    }
+
+int http_getResponse(HTTP_Transmission *response, ax_socket *source){
+    int retVal=AX_UNKNOWN;
+    char *responseTxt=NULL;
+     responseTxt=(char *)calloc(AX_NET_BUFF_S, sizeof(char));
+     int length=0;
+     response->response_code=0;
+     retVal=net_socketRead(source, 300, (unsigned char *)responseTxt, AX_NET_BUFF_S, &length);
+     if(retVal==AX_OK) { printDebug("response received"); }
+     else { printDebug("Response Timeout"); return AX_NET_ERR_TIMEOUT;}
+     http_parse(response, (char *)responseTxt); 
+
+     free(responseTxt);
+    return response->response_code;
+    }
+
+
+//Supporting Methods
+/***************************************************************************************************/
+/*http_getBoundary()                                                                               */
+/*                                                                                                 */
+/*This method creates a unique string token that is used when creating mulitpart form transmissions*/
+/*in HTTP. It will return a random sequence of letters and numbers.                                */
+/***************************************************************************************************/
+char *http_getBoundary(char *buff, int length){
+    int ctr=0;
+    if(buff==NULL) { return NULL; } //if no pointer was given to us give a nothing back.
+    if(length<=0) {return NULL;} 
+       int randNum=0;
+       for(ctr=0; ctr<length; ctr++) {
+       randNum=abs(randInt()%62);
+           if(randNum<=10) {
+		if(randNum==0) { randNum++; } //avoid using slashes in boundary, char 47
+               buff[ctr]=randNum+47;
+               }
+           else if((randNum>10)&&(randNum<=36)) {
+               buff[ctr]=(randNum-10)+64;
+               }
+           else {
+               buff[ctr]=(randNum-37)+97;
+               }
+           if(buff[ctr]==32) {buff[ctr]=97; }
+       }
+
+    return buff;
+    }
+
+void zeroOutHTTPXmission(HTTP_Transmission *tgt){
+
+	    tgt->operation=-1;
+	    tgt->resource=NULL;
+	    tgt->headers.contentType=NULL;
+	    tgt->body=NULL;
+	    tgt->body_length=0;
+	    tgt->mpData=NULL;
+	    tgt->response_code=-1;
+	    tgt->secure=-1;
+}
+
+char *createHeaders(char *tgtBuff, int http_operation, char *resource, int httpver, char *hostname, char *contentType, int contentLength, int xCount) {
+  int headerSz=4;  //we account for the closing CRLF CRLF here
+  char clength_tmp[10];
+  char xCount_tmp[10];
+  int wrthdr=0;  
+//convert the ints to strings so we can get an strlen on them
+  snprintf(clength_tmp, 10, "%d", contentLength);
+  snprintf(xCount_tmp, 10, "%d", xCount);
+
+//String Size Calculations
+  headerSz=headerSz+strlen(resource)+strlen(HTTP_KEY[http_operation])+strlen(HTTP_KEY[httpver])+5; //"POST  HTTP/1.1" there are 2 spaces and a CRLF in there as well., 1 for the null
+  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_HOST])+strlen(hostname)+2;  //Host: <hostname>
+  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_TYPE])+strlen(contentType)+2;  //Content-Type: <contentType>
+  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_LENGTH])+strlen(clength_tmp)+2;  //Content-Length: <contentLength>
+  headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_CONNECTION])+2; 		      //Connection: Close
+  if(xCount>0) {
+    headerSz=headerSz+strlen(HTTP_HEADER[HTTPH_XCOUNT])+strlen(xCount_tmp)+2;	
+   }
+
+//String buffer creation  
+  tgtBuff=(char *)calloc(headerSz, sizeof(char));
+//Stuffin the buffer
+  if((xCount>0)&&(http_debug==AX_TRUE)) {
+     wrthdr=snprintf(tgtBuff, headerSz, "%s %s %s\r\n%s%s\r\n%s%s\r\n%s%s\r\n%s\r\n%s%s\r\n\r\n", HTTP_KEY[http_operation], resource, HTTP_KEY[httpver], HTTP_HEADER[HTTPH_HOST], hostname, HTTP_HEADER[HTTPH_TYPE], contentType, HTTP_HEADER[HTTPH_LENGTH], clength_tmp, HTTP_HEADER[HTTPH_CONNECTION], HTTP_HEADER[HTTPH_XCOUNT], xCount_tmp);
+	}
+  else {
+     wrthdr=snprintf(tgtBuff, headerSz, "%s %s %s\r\n%s%s\r\n%s%s\r\n%s%s\r\n%s\r\n\r\n", HTTP_KEY[http_operation], resource, HTTP_KEY[httpver], HTTP_HEADER[HTTPH_HOST], hostname, HTTP_HEADER[HTTPH_TYPE], contentType, HTTP_HEADER[HTTPH_LENGTH], clength_tmp, HTTP_HEADER[HTTPH_CONNECTION]);   
+
+     }
+  if(wrthdr>headerSz) { printDebug("http_send_post(): Buffer allocated for header was too small, truncated"); }
+
+return tgtBuff;
+}
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axHTTP.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,76 @@
+/************************************************************************************/
+/* axHTTP.h                                                                         */
+/* �2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/*Provides a basic, bare bones implementation of the HTTP 1.1 protocol spec to allow*/
+/*this library to be more platform independent. The function calls in this file     */
+/*depend on the socket calls provided in axTransport                                */
+/*                                                                                  */
+/************************************************************************************/
+#ifndef AXHTTP_H
+#define AXHTTP_H
+
+#include "axTransport.h"
+
+#define AX_HTTP_GET    0  //Standard GET Operation
+#define AX_HTTP_POST   1  //Standard HTTP Post operation
+#define AX_HTTP_MPOST  2  //Multipart form data operation, POST
+#define AX_HTTP_PUT    3
+
+
+
+typedef struct {
+ // char *host; //..Host is passed in when sending to the
+  char *contentType;
+}HTTP_Headers;
+
+typedef struct HTTP_Part{
+   char *file_name;
+   unsigned char *data;
+   int data_sz;
+   char *hint;
+   struct HTTP_Part *next;
+}HTTP_Part;
+
+typedef struct {
+    int operation;          //POST, GET, MPOST.
+    char *resource;         //A pointer to a string that the resource is identified by
+    HTTP_Headers headers;   //a structure of headers for the request
+    char *body;             //the body of the request, used only for post and mpost
+    int body_length;        //the length of the main body, used only for post and mpost
+    HTTP_Part *mpData;      //the first link in a chain of data to be uploaded as part of a multipart post request
+    int response_code;      //For responses only, this field will be populated after calling http_parse
+    int secure;             //use SSL or TLS
+}HTTP_Transmission;
+
+//Flag used to turn on debug x-count header.
+extern int http_debug;
+
+//struct ax_socket; //incomplete declaration, see axTransport.h for full declaration
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+
+
+//Operations
+int http_send(HTTP_Transmission *request, char *host, int port, int secure, HTTP_Transmission *response);
+int http_send_get(char *resource, char *host, int port, int secure, HTTP_Transmission *response);
+int http_send_put(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response);
+int http_send_post(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Transmission *response);
+int http_send_mpost(char *resource, char *host, int port, int secure, HTTP_Headers *headers, char *data, int data_sz, HTTP_Part *files, int part_ct, HTTP_Transmission *response);
+void http_add_mpart(HTTP_Transmission *request, char *file_name, unsigned char *data, int file_sz); //For Future expansion, do not use.
+
+//Return Handling
+HTTP_Transmission *http_parse(HTTP_Transmission *response, char *data);
+
+//Supporting Methods
+char *http_getBoundary(char *buff, int length);
+void zeroOutHTTPXmission(HTTP_Transmission *tgt);
+char *createHeaders(char *tgtBuff, int http_operation, char *resource, int httpver, char *hostname, char *contentType, int contentLength, int xCount);
+
+#ifdef __cplusplus
+  }
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axPlatform.c	Mon Aug 11 19:02:42 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;
+  }
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axPlatform.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,77 @@
+/************************************************************************************/
+/* axPlatform.h                                                                    */
+/* 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.                                                                 */
+/************************************************************************************/
+
+#ifndef AXPLATFORM_H
+#define AXPLATFORM_H
+
+#include "axTypes.h"
+#include <stdio.h>
+
+
+#define END_BASE     0
+#define END_DATA     1
+#define END_AGENTS   2
+#define END_FILES    3
+#define END_FILED    4
+#define END_PACKAGES 5
+#define END_STATUS   6
+#define END_REG	     7
+
+#define BUFF_ALARMS     0
+#define BUFF_EVENTS     1
+#define BUFF_DATA       2
+#define BUFF_LOCATIONS  3
+
+#define PKG_QUEUED      0
+#define PKG_STARTED     1
+#define PKG_SUCCESS     2
+#define PKG_FAILURE     3
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+
+
+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 ax_platform_sendData(ax_platform *cloud, ax_deviceID *device, ax_dataSet *dataItems[], int numDataSets);
+int ax_platform_sendAlarms(ax_platform *cloud, ax_deviceID *device, ax_alarm *alarms[], int numAlarms);
+int ax_platform_sendEvents(ax_platform *cloud, ax_deviceID *device, ax_event *events[], int numEvents);
+int ax_platform_sendLocations(ax_platform *cloud, ax_deviceID *device, ax_location *locations[], int numLocations);
+
+int ax_platform_register(ax_platform *cloud, ax_deviceID *device);
+int ax_platform_ping(ax_platform *cloud, ax_deviceID *device);
+int ax_platform_upload(ax_platform *cloud, ax_deviceID *device, ax_file *file);
+int ax_platform_download(ax_platform *cloud, ax_deviceID *device, ax_package_instruction *instr);
+
+int ax_platform_setPkgStatus(ax_platform *cloud, ax_deviceID *device, char *pkgID, int status, char *errorMsg);
+int ax_platform_setPkgStatusStarted(ax_platform *cloud, ax_deviceID *device, char *pkgID);
+int ax_platform_setPkgStatusQueued(ax_platform *cloud, ax_deviceID *device, char *pkgID);
+int ax_platform_setPkgStatusSuccess(ax_platform *cloud, ax_deviceID *device, char *pkgID);
+int ax_platform_setPkgStatusFailed(ax_platform *cloud, ax_deviceID *device, char *pkgID, char *errorMsg);
+/*******************************************************************************************************/
+/*The following functions are internal only and should never need to be called outside of this library*/
+/*****************************************************************************************************/
+char *encodeAgentID(ax_deviceID *device, char *buff);
+char *getResource(char *endPointBuff, ax_deviceID *device, int resourceType);
+char *getDataResource(char *endPointBuff, ax_deviceID *device);
+char *getAgentResource(char *endPointBuff, ax_deviceID *device);
+char *getFileResource(char *endPointBuff, ax_deviceID *device);
+char *getRegistrationResource(char *endPointBuff, ax_deviceID *device);
+char *getFileDownloadResource(char *endPointBuff, ax_deviceID *device, char *fileID);
+char *getPackageUpdateResource(char *endPointBuff, ax_deviceID *device, char *packageID);
+
+char *getContentType(char *contentBuff, int type);
+char *getGeneralType(char *contentBuff);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axSerializer.c	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,374 @@
+/************************************************************************************/
+/* axSerializer.c                                                                   */
+/* �2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/* Defines methods for transposing the data in domain objects into a serialized     */
+/* encoding for transmission to the Platform Endpoint. This is a platform independent*/
+/* implementation that can be applied to any device that supports ANSI C.           */
+/*                                                                                  */
+/************************************************************************************/
+#include "axSerializer.h"
+
+#define REG_ID              0
+#define REG_MODEL_NUMBER    1
+#define REG_SERIAL_NUMBER   2
+#define REG_TENANT          3
+#define REG_PING            4
+#define REG_KEY             5
+
+#define DATA_ALERTS 0
+#define DATA_EVENTS 1
+#define DATA_DATA 2
+#define DATA_LOCATIONS 3
+#define DATA_ITEMS 4
+
+#define PKG_STATUS  0
+#define PKG_ERROR   1
+
+#define ALERT_SEV 0
+#define ALERT_CAUSE 1
+#define ALERT_REASON 2
+
+#define COM_TIME 0
+#define COM_PRIORITY 1
+#define COM_NAME 2
+#define COM_DESCRIPTION 3
+
+//#define EVENT_NAME 1
+//#define EVENT_DESC 0
+
+#define LOC_LAT 0
+#define LOC_LON 1
+#define LOC_ALT 2
+
+int terse_enable=AX_TRUE;
+
+const char *commonKW[]= {"time", "priority", "name", "description" };
+const char *dataKW[]={ "alerts", "events", "data", "locations", "dataItems"};
+const char *registrationKW[]=  {"id", "mn", "sn", "tn", "pingRate", "key"};
+const char *alertKW[]= {"severity","cause", "reason" };
+const char *locationKW[]= {"latitude", "longitude", "altitude"};
+const char *pkgStatusKW[]={"status", "error"};
+
+const char *terse_commonKW[]= {"t", "dp", "n", "d"};
+const char *terse_dataKW[]={ "alerts", "events", "data", "locations", "di"};
+const char *terse_registrationKW[]=  {"id", "mn", "sn", "tn", "pr", "k"};
+const char *terse_alertKW[]= {"sv", "cn", "cr" };
+const char *terse_locationKW[]= {"lat", "lon", "alt"};
+const char *terse_pkgStatusKW[]={"st", "err"};
+/*************************************************************************************************/
+/*dataSet2JSON()                                                                                 */
+/*                                                                                               */
+/*Takes an array of ax_dataItem structs and creates JSON to represent them in the AMMP-json      */
+/*protocol. The return type will be a CJSON pointer which can then be rendered into an actual    */
+/*JSON string. The JSON pointer will need to be free'd when you're done. If there are zero data  */
+/*items in the array then this method will return an empty JSON array pointer.                   */
+/*                                                                                               */
+/*NOTE: If any array spots are left empty they will only be ignored if theyre are NULL. Junk     */
+/*      values from left over data will cause seg faults. NULL your empty pointers!!!            */
+/*************************************************************************************************/
+//takes data item set, not longer just data item structs.
+cJSON *dataSet2JSON(ax_dataSet *di[], int len, int terse_on)
+ {
+ cJSON *root, *child_obj, *dis=NULL;
+  int ctr=0;
+
+  ax_dataSet *curr=NULL;
+  ax_dataNode *currNode;
+  root=cJSON_CreateArray();
+  
+  for(ctr=0; ctr<len; ctr++)
+      {
+      curr=di[ctr];
+      if((curr!=NULL)&&(curr->dataNode_ct>0)) //If this set doesn't have any data in it, don't include it.
+          {
+          cJSON_AddItemToArray(root, child_obj=cJSON_CreateObject());
+	if(terse_on==AX_TRUE) {
+	      cJSON_AddItemToObject(child_obj, terse_dataKW[DATA_ITEMS], dis=cJSON_CreateObject());  }
+	else {
+	     cJSON_AddItemToObject(child_obj, dataKW[DATA_ITEMS], dis=cJSON_CreateObject());  
+	     }
+	if((curr->acquisitionTime>=0)&&(curr->acquisitionTime)){
+             if(terse_on==AX_TRUE){
+                 cJSON_AddNumberToObject(child_obj, terse_commonKW[COM_TIME], curr->acquisitionTime);
+                 }
+             else {
+                  cJSON_AddNumberToObject(child_obj, commonKW[COM_TIME], curr->acquisitionTime);
+                  }
+             }
+          if((curr->priority>=1)&&(curr->priority<=100)) {
+                 if(terse_on==AX_TRUE){
+                     cJSON_AddNumberToObject(child_obj, terse_commonKW[COM_PRIORITY], curr->priority);
+                     }
+                 else {
+                     cJSON_AddNumberToObject(child_obj, commonKW[COM_PRIORITY], curr->priority);
+                     }
+             }
+          currNode=curr->data_first;
+          while(currNode!=NULL)
+              {
+              if(currNode->type==AX_DIGITAL)    {
+                  if(currNode->dValue==1)        {
+                      cJSON_AddTrueToObject(dis, currNode->name);
+                      }
+                  else {
+                      cJSON_AddFalseToObject(dis, currNode->name);
+                      }
+                  }
+                  else if(currNode->type==AX_ANALOG)  {
+                      cJSON_AddNumberToObject(dis, currNode->name, currNode->dValue);
+                      }
+                  else    {
+                      cJSON_AddStringToObject(dis, currNode->name, currNode->sValue);
+                      }
+              //advance to the next data item
+              currNode=currNode->next;
+              }
+          }
+      }
+ return root;
+ }
+/*************************************************************************************************/
+/* eventsToJSON()                                                                                */
+/*                                                                                               */
+/*Takes an array of ax_event struct pointers and creates JSON to represent them in the AMMP-json */
+/*protocol. The return type will be a CJSON pointer which can then be rendered into an actual    */
+/*JSON string. The JSON pointer will need to be free'd when you're done. If there are zero data  */
+/*items in the array then this method will return an empty JSON array pointer.                   */
+/*                                                                                               */
+/*NOTE: If any array spots are left empty they will only be ignored if theyre are NULL. Junk     */
+/*      values from left over data will cause seg faults. NULL your empty pointers!!!            */
+/*************************************************************************************************/
+cJSON *eventsToJSON(ax_event *events[], int len, int terse_on) {
+    cJSON *root, *dis;
+    ax_event *curr;
+    int ctr=0;
+    root=cJSON_CreateArray();
+    curr=events[0];
+     for(ctr=0; ctr<len; ctr++)
+          {
+		  curr=events[ctr];
+          if(curr!=NULL)
+            {
+                cJSON_AddItemToArray(root, dis=cJSON_CreateObject());
+				if(terse_on==AX_TRUE){
+	                cJSON_AddStringToObject(dis, terse_commonKW[COM_NAME], curr->name);
+					cJSON_AddStringToObject(dis, terse_commonKW[COM_DESCRIPTION], curr->description);
+					}
+				else {
+					cJSON_AddStringToObject(dis, commonKW[COM_NAME], curr->name);
+					cJSON_AddStringToObject(dis, commonKW[COM_DESCRIPTION], curr->description); 
+					}
+                
+                if((curr->dateAcquired>=0)&&(curr->dateAcquired)){
+                    if(terse_on==AX_TRUE){
+                         cJSON_AddNumberToObject(dis, terse_commonKW[COM_TIME], curr->dateAcquired);
+                         }
+                    else {
+                         cJSON_AddNumberToObject(dis, commonKW[COM_TIME], curr->dateAcquired);
+                         }
+                     }
+                if((curr->priority>=1)&&(curr->priority<=100)&&(curr->priority)) {
+                     if(terse_on==AX_TRUE){
+                         cJSON_AddNumberToObject(dis, terse_commonKW[COM_PRIORITY], curr->priority);
+                         }
+                     else {
+                          cJSON_AddNumberToObject(dis, commonKW[COM_PRIORITY], curr->priority);
+                          }
+                   }
+                }
+          }
+
+    return root;
+}
+/*************************************************************************************************/
+/* locationsToJSON()                                                                             */
+/*                                                                                               */
+/*Takes an array of ax_location struct pointers and creates JSON to represent them in the AMMP   */
+/*protocol. The return type will be a CJSON pointer which can then be rendered into an actual    */
+/*JSON string. The JSON pointer will need to be free'd when you're done. If there are zero data  */
+/*items in the array then this method will return an empty JSON array pointer.                   */
+/*                                                                                               */
+/*NOTE: If any array spots are left empty they will only be ignored if theyre are NULL. Junk     */
+/*      values from left over data will cause seg faults. NULL your empty pointers!!!            */
+/*************************************************************************************************/
+cJSON *locationsToJSON(ax_location *locations[], int len, int terse_on) {
+    cJSON *root, *dis;
+    ax_location *curr;
+    int ctr=0;
+    root=cJSON_CreateArray();
+        for(ctr=0; ctr<len; ctr++)
+              {
+              curr=locations[ctr];
+                  if(curr)
+                    {
+                    cJSON_AddItemToArray(root, dis=cJSON_CreateObject());
+                    if(terse_on==AX_TRUE){
+                        cJSON_AddNumberToObject(dis, terse_locationKW[LOC_LAT], curr->latitude);
+                        cJSON_AddNumberToObject(dis, terse_locationKW[LOC_LON], curr->longitude);
+                        cJSON_AddNumberToObject(dis, terse_locationKW[LOC_ALT], curr->altitude);
+                        }
+                    else {
+                        cJSON_AddNumberToObject(dis, locationKW[LOC_LAT], curr->latitude);
+                        cJSON_AddNumberToObject(dis, locationKW[LOC_LON], curr->longitude);
+                        cJSON_AddNumberToObject(dis, locationKW[LOC_ALT], curr->altitude);
+                        }
+                    if((curr->dateAcquired)&&(curr->dateAcquired>=0)){
+                        if(terse_on==AX_TRUE){
+                            cJSON_AddNumberToObject(dis, terse_commonKW[COM_TIME], curr->dateAcquired);
+                            }
+                        else {
+                            cJSON_AddNumberToObject(dis, commonKW[COM_TIME], curr->dateAcquired);
+                            }
+                        }
+                    if((curr->priority>=1)&&(curr->priority<=100)&&(curr->priority)) {
+                        if(terse_on==AX_TRUE){
+                            cJSON_AddNumberToObject(dis, terse_commonKW[COM_PRIORITY], curr->priority);
+                            }
+                        else {
+                            cJSON_AddNumberToObject(dis, commonKW[COM_PRIORITY], curr->priority);
+                            }
+                        }
+                    }
+              }
+
+    return root;
+}
+
+/*************************************************************************************************/
+/* alarmsToJSON()                                                                                */
+/*                                                                                               */
+/*Takes an array of ax_alarm struct pointers and creates JSON to represent them in the AMMP-json */
+/*protocol. The return type will be a CJSON pointer which can then be rendered into an actual    */
+/*JSON string. The JSON pointer will need to be free'd when you're done. If there are zero data  */
+/*items in the array then this method will return an empty JSON array pointer.                   */
+/*                                                                                               */
+/*NOTE: If any array spots are left empty they will only be ignored if theyre are NULL. Junk     */
+/*      values from left over data will cause seg faults. NULL your empty pointers!!!            */
+/*************************************************************************************************/
+cJSON *AlarmsToJSON(ax_alarm *alarms[], int len, int terse_on)
+  {
+  cJSON *root, *dis;
+     int ctr=0;
+     ax_alarm *curr;
+    root=cJSON_CreateArray();
+	curr=alarms[0];
+     for(ctr=0; ctr<len; ctr++) {
+      curr=alarms[ctr];
+      if(curr!=NULL)
+      {
+      cJSON_AddItemToArray(root, dis=cJSON_CreateObject());
+      if(terse_on==AX_TRUE){
+          cJSON_AddStringToObject(dis, terse_commonKW[COM_NAME], curr->alarmName);
+          cJSON_AddStringToObject(dis, terse_commonKW[COM_DESCRIPTION], curr->alarmDescription);
+          cJSON_AddNumberToObject(dis, terse_alertKW[ALERT_SEV], curr->alarmSeverity);
+          cJSON_AddStringToObject(dis, terse_alertKW[ALERT_CAUSE], curr->alarmCause);
+          cJSON_AddStringToObject(dis, terse_alertKW[ALERT_REASON], curr->alarmReason);
+          }
+      else {
+          cJSON_AddStringToObject(dis, commonKW[COM_NAME], curr->alarmName);
+          cJSON_AddStringToObject(dis, commonKW[COM_DESCRIPTION], curr->alarmDescription);
+          cJSON_AddNumberToObject(dis, alertKW[ALERT_SEV], curr->alarmSeverity);
+          cJSON_AddStringToObject(dis, alertKW[ALERT_CAUSE], curr->alarmCause);
+          cJSON_AddStringToObject(dis, alertKW[ALERT_REASON], curr->alarmReason);
+          }
+
+      if((curr->dateAcquired)&&(curr->dateAcquired>=0)){
+            if(terse_on==AX_TRUE){
+               cJSON_AddNumberToObject(dis, terse_commonKW[COM_TIME], curr->dateAcquired);
+               }
+            else {
+               cJSON_AddNumberToObject(dis, commonKW[COM_TIME], curr->dateAcquired);
+               }
+            }
+       if((curr->priority>=1)&&(curr->priority<=100)&&(curr->priority)) {
+            if(terse_on==AX_TRUE){
+               cJSON_AddNumberToObject(dis, terse_commonKW[COM_PRIORITY], curr->priority);
+               }
+            else {
+               cJSON_AddNumberToObject(dis, commonKW[COM_PRIORITY], curr->priority);
+               }
+           }
+        }
+     }
+
+    return root;
+  }
+/*************************************************************************************************/
+/* getRegistrationJSON()                                                                         */
+/*                                                                                               */
+/*Takes a device and ping rate and will return a cJSON structure that represents a registration  */
+/*message in the AMMP protocol.  								 */
+/*                                                                                               */
+/*************************************************************************************************/
+cJSON *getRegistrationJSON(ax_deviceID *device, int pingRate)
+  {
+   cJSON *root, *child;
+
+   root=cJSON_CreateObject();
+
+   cJSON_AddItemToObject(root, registrationKW[REG_ID], child=cJSON_CreateObject());
+   if(device->model) {
+	   cJSON_AddStringToObject(child, registrationKW[REG_MODEL_NUMBER], device->model);
+   	   }
+   if(device->serial) {
+	   cJSON_AddStringToObject(child, registrationKW[REG_SERIAL_NUMBER], device->serial);
+   	   }
+   if(strlen(device->tenant)>=1)
+    {
+    cJSON_AddStringToObject(child, registrationKW[REG_TENANT], device->tenant);
+    }
+   cJSON_AddNumberToObject(root, registrationKW[REG_PING], pingRate);
+
+
+  return root;
+  }
+
+//TODO: Fill out this description
+/*************************************************************************************************/
+/*getPKGStatusJSON()                                                                             */
+/*                                                                                               */
+/*                                                                                               */
+/*                                                                                               */
+/*************************************************************************************************/
+cJSON *getPKGStatusJSON(int status, char *error, int priority, int time, int terse_on){
+  cJSON *root;
+  root=cJSON_CreateObject();
+//STATUS
+  if(terse_on==AX_TRUE) {
+    cJSON_AddNumberToObject(root, pkgStatusKW[PKG_STATUS], status);
+	}
+  else {
+	cJSON_AddNumberToObject(root, pkgStatusKW[PKG_STATUS], status);
+	}
+//TIME
+   if(time>=0) {
+     if(terse_on==AX_TRUE) {
+		cJSON_AddNumberToObject(root, terse_commonKW[COM_TIME], time);
+		}
+	  else {
+		cJSON_AddNumberToObject(root, commonKW[COM_TIME], time);
+		}
+	  }
+//PRIORITY
+	if((priority>0)&&(priority<=100)) {
+	   if(terse_on==AX_TRUE) {
+		cJSON_AddNumberToObject(root, terse_commonKW[COM_PRIORITY], priority);
+		}
+	 else {
+		cJSON_AddNumberToObject(root, commonKW[COM_PRIORITY], priority);
+		}
+	  }
+//ERROR
+	if(error!=NULL) {
+	  if(terse_on==AX_TRUE) {
+		cJSON_AddStringToObject(root, terse_pkgStatusKW[PKG_ERROR], error);
+		}
+	  else {
+		cJSON_AddStringToObject(root, pkgStatusKW[PKG_ERROR], error);
+		}
+	}
+return root;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axSerializer.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,37 @@
+/************************************************************************************/
+/* axSerializer.c                                                                   */
+/* ©2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/* Defines methods for transposing the data in domain objects into a serialized     */
+/* encoding for transmission to the Platform Endpoint. This is a platform independent*/
+/* implementation that can be applied to any device that supports ANSI C.           */
+/*                                                                                  */
+/************************************************************************************/
+
+#ifndef AXSERIALIZER_H
+#define AXSERIALIZER_H
+
+#include "cJSON.h"
+#include "axTypes.h"
+#include "axConstants.h"
+
+extern int terse_enable;
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+
+
+cJSON *dataSet2JSON(ax_dataSet *di[], int len, int terse_on);
+cJSON *getRegistrationJSON(ax_deviceID *device, int pingRate);
+cJSON *getPKGStatusJSON(int status, char *error, int priority, int time, int terse_on);
+cJSON *AlarmsToJSON(ax_alarm *alarms[], int len, int terse_on);
+cJSON *eventsToJSON(ax_event *events[], int len, int terse_on);
+cJSON *locationsToJSON(ax_location *locations[], int len, int terse_on);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axSettings.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,47 @@
+#ifndef _AXSETTINGS_H_
+#define _AXSETTINGS_H_
+
+/************************************************************************************/
+/* axSettings.h                                                                     */
+/* �2013 Axeda Corporation                                                          */
+/*                                                                                  */
+/*This file defines default settings for the domain objects. Most of the time they  */
+/*define how many characters will be allocated to a particular field. The library   */
+/*automatically truncate strings that are too long and will return an error code.   */
+/************************************************************************************/
+
+//define max string sizes for certain structs
+#define AX_ALM_NAME_S 50				//Defines how many characters are allocated for an alarm name           (ax_alarm.alarmName)
+#define AX_ALM_DESC_S 50        //Defines how many characters are allocated for an alarm description    (ax_alarm.alarmDescription)
+#define AX_ALM_CAUSE_S 50       //Defines how many characters are allocated for an alarm cause          (ax_alarm.alarmCause)
+#define AX_ALM_REAS_S 50        //Defines how many characters are allocated for an alarm reason         (ax_alarm.alarmReason)
+
+#define AX_DN_NAME_S  50        //Defines how many characters are allocated for a dataNode name         (ax_dataNode.name)
+#define AX_DN_SV_S    50        //Defines how many characters are allocated for a dataNode string       (ax_datanode.sValue)
+
+#define AX_EVT_NAME_S 50        //Defines how many characters are allocated for an event name           (ax_event.name)
+#define AX_EVT_DESC_S 50        //Defines how many characters are allocated for an devent description   (ax_event.description)
+
+#define AX_MSID_DID_S 50         //Defines how many characters are allocated for a device ID             (ax_deviceID.deviceId)
+#define AX_MSID_MDL_S 50        //Defines how many characters are allocated for a model number          (ax_deviceID.model)
+#define AX_MSID_SER_S 50        //Defines how many characters are allocated for a serial number         (ax_deviceID.serial)
+#define AX_MSID_TEN_S 50        //Defines how many characters are allocated for a tenant ID             (ax_deviceID.tenant)
+
+#define AX_FILE_NAME_S 50      //Defines how many characters are allocated for a file name              (ax_file.name)
+#define AX_FILE_HINT_S 50      //Defines how many characters are allocated for a file hint              (ax_file.hint)
+#define AX_FILE_ID_S   50      //Defines how many characters are allocated for a file ID                (ax_file.fileID)
+                                                                                                       
+#define AX_PLAT_HOST_S 50      //Defines how many characters are allocated for a platform hostname      (ax_platform.hostname)
+
+#define AX_PKGI_FID_S   50     //Defines how many characters are allocated for a package file ID        (ax_package_instruction.file_id)
+#define AX_PKGI_PATH_S  50     //Defines how many characters are allocated for a package path           (ax_package_instruction.path)
+#define AX_PKGI_FNAME_S 50     //Defines how many characters are allocated for a package file name      (ax_package_instruction.filename)
+
+#define AX_PKG_ID_S   50       //Defines how many characters are allocated for a package ID             (ax_package.packageID)
+
+#define AX_NET_BUFF_S 1024     //Defines how many characters are allocated for an HTTP response         (ax_alarm.alarmReason)
+
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axStatusCodes.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,37 @@
+
+#ifndef _AXSTATUSCODES_H_
+#define _AXSTATUSCODES_H_
+
+#define AX_ERROR -1                         //A General Error has occurred
+#define AX_OK 0                             //Operation Success
+#define AX_UNKNOWN -42                      //An unknown error has occurred. Functions are normally initialized to return this value. The function should change it before returning it.
+#define AX_ARGNULL -999                     //An argument passed to the function was left null
+#define AX_OUT_OF_RANGE -998                //An argument passed to the function was out of range
+#define AX_DI_UNKNOWN_TYPE -997             //An argument passed to the function indicating the Data Item type was incorrect
+#define AX_CONFLICTING_ARG -996             //Two arguments passed to a function describing the same object have conflicting values e.g. arg1(string)=="fubar"; arg2(strlength)==0, The string fubar is obviously longer than 0
+#define AX_ARG_EMPTY  -995		    //An argument passed to the function was a string but it was empty eg mystring="". This will be thrown when a value is required. 
+
+#define AX_NET_ERR_UNABLE_TO_CONNECT  700       //Call to open the TCP port to IP or hostname has failed. Is the port open? IP contactable?
+#define AX_NET_ERR_PORT_WRITE         701       //The program was unable to write data onto the socket.
+#define AX_NET_ERR_HEADER_WRITE       702       //a write error occurred while writing the HTTP headers
+#define AX_NET_ERR_DATA_WRITE         703       //a write error occurred while writing the HTTP data/body
+#define AX_NET_ERR_TIMEOUT            704       //A timeout occurred while waiting for a response.
+#define AX_NET_PORT_INVALID           705       //The port that was specified is larger than 65536 or less than 0
+#define AX_NET_DNS_ERROR	      706	//There was an error resolving the name of the platform server
+#define AX_NET_MORE_WAITING	      707	//Thrown when the data written to the port does not equal the amount of data that was requested to be written.
+
+#define AX_GEN_STR_TRUNC                604     //the string to be stored was too long and has been truncated, This is a warning only.
+#define AX_EGR_JSON_PARSE_FAIL          800     //The egress message that was returned did not have the necessary fields
+#define AX_GEN_PARSE_ERR                603     //A general parsing failure has occured. Invalid JSON will cause this error. 
+
+
+//The following codes are used for an optional Queueing implementation example. 
+#define AX_GEN_QUEUE_FULL               600     //The queue is full and cannot accept more items. Item was not added. Enable overwrite or empty the queue
+#define AX_GEN_QUEUE_ITEM_EXISTS        601     //The item you tried to enqueue already exists in the queue.
+#define AX_GEN_QUEUE_EMPTY              602     //The queue is empty, thrown on a dequeue operation
+
+
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axToolkit.c	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,23 @@
+#pragma once
+#include "axToolkit.h"
+#include "axTransport.h"
+
+int debugEnabled=AX_TRUE;
+
+void printDebug(char *msg) {
+    if(debugEnabled==AX_TRUE){
+    	ax_print(AX_DEBUG_MSG, msg);
+        }
+    }
+
+void printError(char *msg) {
+   ax_print(AX_ERROR_MSG, msg);
+   }
+
+int ax_debugEnabled() {
+    if(debugEnabled==1) { return AX_TRUE; }
+    else {return AX_FALSE; }
+    }
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axToolkit.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,50 @@
+#pragma once
+/* ========================================================================== */
+/*                                                                            */
+/*   axToolkit.h                                                              */
+/*   �2013 Axeda Corporation                                                  */
+/*                                                                            */
+/*   This file will include all necessary libraries and functions to use the  */
+/*   AMMP C Toolkit in your project.                                          */
+/* ========================================================================== */
+
+#ifndef AXTOOLKIT_H
+#define AXTOOLKIT_H
+
+#include "axTypes.h"
+#include "axConstants.h"
+#include "axStatusCodes.h"
+#include "axDomain.h"
+#include "axPlatform.h"
+#include "axTransport.h"
+#include "axHTTP.h"
+
+
+typedef struct
+{
+    ax_deviceID thisDevice;         //A struct containing the device serial and model numbers  -- How the device identifies itself
+    ax_platform platform;           //A struct containing the target platform URL, port number etc. -- Where to send the data
+    int     conf_ping_rate;         //ping rate of the device in SECONDS
+    int     first_run;              //a flag to indicate if this is a first run of the agent
+    int     conf_recv_timeout;      //how long we wait to receive a response from the server
+    int     conf_queue_size;        //the size of the queues used to store data items/locations/events/alarms while operating
+    int     debug_mode;             //prints out extra messages to the standard out. Also adds HTTP header with a sequential value to all packets.
+    int     print_mem;              //prints out heap memory statistics to the standard out.
+} axToolkitConfig;
+
+extern int debugEnabled;
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+
+int ax_debugEnabled();
+void printDebug(char *msg);
+void printError(char *msg); 
+
+
+#ifdef __cplusplus
+  }
+#endif
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axTransport.cpp	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,301 @@
+
+#include "axTransport.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "MDM.h"
+#include "axStatusCodes.h"
+#include "axConstants.h"
+#include <math.h>
+
+
+MDMSerial* mdm;
+int socket;
+char *temp_buff;
+int buff_size;
+
+
+/************************************************************************************************/
+/*getEpoch()                                                                                    */
+/*                                                                                              */
+/*This method should return the number of seconds since January 1st 1970.                       */
+/*                                                                                              */
+/*returns long value in seconds                                                                 */
+/************************************************************************************************/
+
+long getEpoch()
+{
+    return (long)0;
+}
+
+
+/**************************************************************************************************/
+/*ax_print()                                                                                     */
+/*                                                                                               */
+/*A wrapper method that will allow you to direct the output to a particular stream. Most of the  */
+/*time the output will just go to printf/std. out. This is called by the axAgent library to print*/
+/*error and debug messages. It is reccomended to include processing for the integers AX_DEBUG_MSG*/
+/*and AX_ERROR_MSG as the library will frequently use these options if configured.               */
+/*                                                                                               */
+/* msgType: allows for an integer value to control how the data is displayed or written          */
+/* msg: a pointer to a string containing the data to be printed                                  */
+/************************************************************************************************/
+void ax_print(int msgType, char *msg)
+{
+    switch(msgType) {
+        case AX_DEBUG_MSG:
+            printf("DEBUG: %s\r\n", msg);
+            break;
+        case AX_ERROR_MSG:
+            printf("ERR: %s\r\n", msg);
+            break;
+    }
+
+}
+/************************************************************************************************/
+/*sys_delay()                                                                                   */
+/*                                                                                              */
+/*A wrapper method that is meant to induce a delay on the system that it running it. Used mostly*/
+/*to implement timeouts.                                                                        */
+/*                                                                                              */
+/*                                                                                              */
+/*                                                                                              */
+/************************************************************************************************/
+void sys_delay(int seconds)
+{
+    wait_ms(seconds*1000);
+}
+
+/************************************************************************************************/
+/*randInt()											*/
+/*												*/
+/*This function is an abstraction function and should be populated with a call to the host's    */
+/*equivalent of the random function. 								*/
+/************************************************************************************************/
+int randInt()
+{
+    //call to the local create random method.
+    return rand();
+}
+
+/************************************************************************************************/
+/*seedRand()                                                                                     */
+/*                                                                                              */
+/*This function is an abstraction function and should be populated with a call to the host's    */
+/*equivalent of the function that seeds the random number generator                             */
+/************************************************************************************************/
+
+int seedRand()
+{
+    srand(12345);
+    return AX_OK;
+}
+
+/*************************************************************************************************/
+/*net_socketInit()                                                                               */
+/*                                                                                               */
+/*This method provides a convenient way to call code that initializes the socket before it is    */
+/*actually called to open. For example, it could initialize a holder object that you code or set */
+/*options on the socket itself. The return will be a code that could be passed up through the    */
+/*HTTP library and to the error stream.                                                          */
+/*************************************************************************************************/
+int net_socketInit(ax_socket *sock)
+{
+    int retVal=AX_UNKNOWN;
+    buff_size=0;
+    temp_buff=NULL;
+    return retVal;
+}
+
+/*************************************************************************************************/
+/*net_socketOpen()                                                                               */
+/*                                                                                               */
+/*This function opens a network port and connects to it. The connection point is defined by server*/
+/*and port in the arguments. A reference to the port should be stored in the sock structure. If  */
+/*the secure flag is set to AX_TRUE your code should enable TLS or SSL at this stage.            */
+/*                                                                                               */
+/*************************************************************************************************/
+int net_socketOpen(ax_socket *sock, char *server, int port, int secure)
+{
+    int retVal=AX_UNKNOWN;
+    const char* host = server;
+    mdm = MDMSerial::getMDMInstance();
+    socket = mdm->socketSocket(MDMParser::IPPROTO_TCP);
+    if (socket >= 0) {
+        mdm->socketSetBlocking(socket, 5000);
+        mdm->socketConnect(socket, host, port);
+        retVal=AX_OK;
+    } else {
+        retVal=AX_NET_ERR_UNABLE_TO_CONNECT;
+    }
+
+    return retVal;
+}
+/*************************************************************************************************/
+/*net_socketWrite()                                                                             */
+/*                                                                                               */
+/*This function is used to write the data to a network port that has already been open and is    */
+/*connected. As usual the ax_socket struct should contain a reference to your port that you wish */
+/*to write to. Data contains the data to be written and size describes how long the data is.     */
+/*                                                                                               */
+/*************************************************************************************************/
+int net_socketWrite(ax_socket *sock, char *data, int size)
+{
+    int retVal=AX_OK;
+    int fullsz=size+1;
+    if(buff_size==0) {
+        temp_buff=(char *)calloc(fullsz, sizeof(char));
+        int wrt=snprintf(temp_buff, fullsz, "%s", data);
+        buff_size++;
+    } else {
+        int total=strlen(temp_buff)+fullsz;
+        char *temp=(char *)calloc(total, sizeof(char));
+        snprintf(temp, total, "%s%s", temp_buff, data);
+        free(temp_buff);
+        temp_buff=temp;
+        buff_size++;
+    }
+    return retVal;
+}
+
+
+/*************************************************************************************************/
+/*net_socketFlush()                                                                              */
+/*                                                                                               */
+/*This function will be called to handle writing all the data out to a network port. This function*/
+/*may not be needed depending on your system. The single argument is a pointer to a struct that  */
+/*should contain the necessary references to the port on your local system.                      */
+/*                                                                                               */
+/*************************************************************************************************/
+int net_socketFlush(ax_socket *sock)
+{
+    int retVal=AX_UNKNOWN;
+    int size=strlen(temp_buff);
+    retVal = mdm->socketSend(socket, temp_buff, size); //Wr
+    free(temp_buff);
+    buff_size=0;
+    return retVal;
+}
+/*************************************************************************************************/
+/*net_socketClose()                                                                              */
+/*                                                                                               */
+/*This function will be called to handle a socket close operation. It is used primarily by the   */
+/*axHTTP part of the library. The single argument is pointer to a structure that should contain  */
+/*the necessary references to the port on your local system.                                     */
+/*Override the source in this function to close a network port                                   */
+/*************************************************************************************************/
+int net_socketClose(ax_socket *sock)
+{
+
+    mdm->socketClose(socket);
+    mdm->socketFree(socket);
+
+    return AX_OK;
+}
+
+/*************************************************************************************************/
+/*net_socketRead()                                                                               */
+/*                                                                                               */
+/*This function is a wrapper function that will read returned data from a previous web call. It  */
+/*is assumed that any connection related to ax_socket will have already been established. The    */
+/*function should read the data and store it into the *data pointer, then populate the number of */
+/*bytes read in the size variable. The axHTTP library will handle parsing and making sense of the*/
+/*data that it is provided. The timeout will be passed as a parameter but is not implemented by  */
+/*any of the calling libraries, implement it here or pass to another local function if available.*/
+/*************************************************************************************************/
+int net_socketRead(ax_socket *sock, int timeout, unsigned char *buffer, int bufferSz, int *readSz)
+{
+    int retVal=AX_UNKNOWN;
+    retVal = mdm->socketRecv(socket, (char*)buffer, bufferSz);
+    readSz = &retVal;
+    retVal=AX_OK;
+    return retVal;
+}
+
+/*************************************************************************************************/
+/*scm_download_req()                                                                              */
+/*                                                                                                */
+/*This function will be called whenever an egress message is recieved with a file download command*/
+/*You can write the code in the function to handle the file immediately OR store the structure for*/
+/*later processing. The latter is preferable as this request may prevent the network port from    */
+/*being closed in a timely fashion.                                                              */
+/*                                                                                               */
+/*************************************************************************************************/
+int scm_download_req(ax_package *request)
+{
+
+    return AX_OK;
+}
+
+
+/*************************************************************************************************/
+/*scm_file_write()                                                                               */
+/*                                                                                               */
+/*This function will be called whenever a file download is requested from the system. Override the*/
+/*function to direct the output to serial or a file system or other storage device of your choice*/
+/*The parameters to the function will be filled in when it's called by the toolkit               */
+/*                                                                                               */
+/*char *filename: Just what it sounds like, the file name of the file                            */
+/*char *data: The actual data of the file.                                                       */
+/*int length: The number of bytes received                                                       */
+/*ax_package_instruction *downloadInfo: a struct containing filename/path etc.                   */
+/*************************************************************************************************/
+int scm_file_write(char *filename, char *data, int length, ax_package_instruction *downloadInfo)
+{
+
+    return AX_OK;
+}
+
+/*************************************************************************************************/
+/*data_item_write()                                                                              */
+/*                                                                                               */
+/*If a set data item command is recieved from the platform server this function will be called to*/
+/*handle it each time. The function is here to allow for external data to be modified as needed. */
+/*It could toggle a pin and light up an led or set a global variable in another thread.          */
+/*                                                                                               */
+/*char *name: The name of the data item on the platform                                          */
+/*int ax_type: {AX_STRING|AX_ANALoG|AX_DIGITAL} indicates whether the sValue or dValue parameter */
+/*             will have the intended data.                                                      */
+/*char *sValue: if ax_type==AX_STRING then this will be a pointer to a valid cstring             */
+/*int dValue: if ax_type==AX_ANLOG|AX_DIGITAL this value will be populated. It should be not be  */
+/*            checked if the type is AX_STRING                                                   */
+/*************************************************************************************************/
+int data_item_write(char *name, char *sValue, int dValue, int ax_type)
+{
+/*
+//these variables are declared in main.cpp
+    extern int oil_level;
+    extern int oil_level2;
+
+    if (ax_type==AX_ANALOG) {
+        if (strstr(name, "oil_level2"))
+            printf("STATUS: Received data item from platform: OL1");
+        oil_level2=dValue;
+        return AX_OK;
+    } else if (strstr(name, "oil_level")) {
+        printf("STATUS: Received data item from platform: OL2");
+        oil_level=dValue;
+    }
+*/
+return AX_OK;
+}
+
+/*************************************************************************************************/
+/*data_item_request()                                                                            */
+/*                                                                                               */
+/*This function is called whenever the platform requests a data item's current value. Since this */
+/*library is designed to run as it's own thread it does not maintain a list of data items and    */
+/*values. The implementation of this function should call an appropriate library or check an input*/
+/*then create a dataItem set and send it immediately or on the next ping.                        */
+/*                                                                                               */
+/*char *name, the name of the data item being requested                                          */
+/*                                                                                               */
+/*************************************************************************************************/
+int data_item_request(char *name)
+{
+
+    return AX_OK;
+}
+
+/***************************************************************************************************/
+/***********************************************{Custom helper methods}****************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axTransport.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifndef _AXTRANSPORT_H_
+#define _AXTRANSPORT_H_
+
+#include "axTypes.h"
+
+/************************************************************************************/
+/*Struct ax_socket                                                                  */
+/*                                                                                  */
+/*The following structure is meant as a mechanism to pass information from a network*/
+/*function to the next. It can be overridden with machine specific code, provided   */
+/* that all of the functions in this file prefixed with net_ can handle it correctly*/
+/************************************************************************************/
+
+
+#ifdef __cplusplus 
+  extern "C" {
+#endif
+typedef struct {
+
+    
+}ax_socket;
+
+
+long getEpoch();
+void ax_print(int msgType, char *msg);
+int randInt();
+int seedRand();
+
+void sys_delay(int seconds);
+
+int net_socketInit(ax_socket *sock);
+int net_socketOpen(ax_socket *sock, char *server, int port, int secure);
+int net_socketWrite(ax_socket *sock, char *data, int size);
+int net_socketClose(ax_socket *sock);
+int net_socketFlush(ax_socket *sock);
+int net_socketRead(ax_socket *sock, int timeout, unsigned char *buffer, int bufferSz, int *readSz);
+
+int scm_download_req(ax_package *request);
+int scm_file_write(char *filename, char *data, int length, ax_package_instruction *downloadInfo);
+int data_item_write(char *name, char *sValue, int dValue, int ax_type);
+int data_item_request(char *name);
+
+
+#ifdef __cplusplus 
+ }
+#endif
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AMMP/axTypes.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,100 @@
+#ifndef _AXTYPES_H_
+#define _AXTYPES_H_
+
+#include "axSettings.h"
+
+
+typedef struct ax_dataNode {
+    char name[AX_DN_NAME_S];   
+    char sValue[AX_DN_SV_S];
+    double  dValue;
+    int type;
+    struct ax_dataNode* next;
+}ax_dataNode;
+
+typedef struct ax_dataNode axDataNode;
+
+typedef struct {
+    int acquisitionTime;
+    int priority;
+    int created;
+    ax_dataNode *data_first;  
+    ax_dataNode *data_last;
+    int dataNode_ct;
+}ax_dataSet;
+
+typedef struct {
+  char alarmName[AX_ALM_NAME_S];
+  char alarmDescription[AX_ALM_DESC_S];
+  int alarmSeverity;
+  char alarmCause[AX_ALM_CAUSE_S];
+  char alarmReason[AX_ALM_REAS_S];
+  int dateAcquired;
+  int priority;
+}ax_alarm;   
+
+typedef struct {
+  char name[AX_EVT_NAME_S];
+  char description[AX_EVT_DESC_S];
+  int dateAcquired;
+  int priority;
+}ax_event;
+
+typedef struct {
+  double latitude;
+  double longitude;
+  double altitude;
+  int dateAcquired;
+  int priority;
+}ax_location;
+
+typedef struct { 
+    char deviceId[AX_MSID_DID_S]; //Future expansion
+    char model[AX_MSID_MDL_S];
+    char serial[AX_MSID_SER_S];
+    char tenant[AX_MSID_TEN_S];
+}ax_deviceID;
+
+//TODO: Possibly deprecate the ax_registration domain object which is just a ping rate and deviceID. Enforce it in the method.
+typedef struct {
+    ax_deviceID *device;
+    int pingRate;
+}ax_registration;
+
+typedef struct { 
+  char name[AX_FILE_NAME_S];
+  char hint[AX_FILE_HINT_S];
+  int size;
+  char fileID[AX_FILE_ID_S];
+  unsigned char *data; //array of bytes/ints/whatever
+  //int priority;
+}ax_file;
+
+typedef struct {
+    char hostname[AX_PLAT_HOST_S];
+    int ip[4];
+    int online;
+    int port;
+    int secure;         //Use SSL/TLS when talking to the platform.
+    int ping_rate;
+    int verify;         //a flag to verify the SSL/TLS certificate of the platform. The certificate MUST be stored locally and match otherwise the TLS handshake will fail.
+}ax_platform;
+
+typedef struct pkg_inst{
+   int instruction_type; //mapped to the @type
+   char file_id[AX_PKGI_FID_S];
+   char path[AX_PKGI_PATH_S];
+   char filename[AX_PKGI_FNAME_S];
+   struct pkg_inst *next;
+}ax_package_instruction;
+
+typedef struct {
+  char packageID[AX_PKG_ID_S];
+  ax_package_instruction *instructions;
+  int time;
+  int priority;
+}ax_package;
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/GPS.cpp	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,390 @@
+#include "mbed.h"
+#include <ctype.h>
+#include "GPS.h"
+#ifdef TARGET_UBLOX_C027
+ #include "C027_api.h"
+#endif
+
+void GPSParser::powerOff(void)
+{
+    // set the gps into backup mode using the command RMX-LPREQ
+    struct { unsigned long dur; unsigned long flags; } msg = {0/*endless*/,0/*backup*/};
+    sendUbx(0x02, 0x41, &msg, sizeof(msg));
+}
+
+int GPSParser::_getMessage(Pipe<char>* pipe, char* buf, int len)
+{
+    int unkn = 0;
+    int sz = pipe->size();
+    int fr = pipe->free();
+    if (len > sz)
+        len = sz;
+    while (len > 0)
+    {
+        // NMEA protocol
+        pipe->set(unkn);
+        int nmea = _parseNmea(pipe,len);
+        if ((nmea != NOT_FOUND) && (unkn > 0))  
+            return UNKNOWN | pipe->get(buf,unkn);
+        if (nmea == WAIT && fr)                       
+            return WAIT;
+        if (nmea > 0)                           
+            return NMEA | pipe->get(buf,nmea);
+        // UBX protocol
+        
+        pipe->set(unkn);
+        int ubx = _parseUbx(pipe,len);
+        if ((ubx != NOT_FOUND) && (unkn > 0))   
+            return UNKNOWN | pipe->get(buf,unkn);
+        if (ubx == WAIT && fr)                        
+            return WAIT;
+        if (ubx > 0)                            
+            return UBX | pipe->get(buf,ubx);
+        
+        // UNKNOWN
+        unkn ++;
+        len--;
+    }
+    if (unkn > 0)                      
+        return UNKNOWN | pipe->get(buf,unkn); 
+    return WAIT;
+}
+
+int GPSParser::_parseNmea(Pipe<char>* pipe, int len)
+{
+    int o = 0;
+    int c = 0;
+    char ch;
+    if (++o > len)                      return WAIT;
+    if ('$' != pipe->next())            return NOT_FOUND;
+    // this needs to be extended by crc checking 
+    for (;;)
+    {
+        if (++o > len)                  return WAIT;
+        ch = pipe->next();
+        if ('*' == ch)                  break; // crc delimiter 
+        if (!isprint(ch))               return NOT_FOUND; 
+        c ^= ch;
+    }
+    if (++o > len)                      return WAIT;
+    ch = toHex[(c >> 4) & 0xF]; // high nibble
+    if (ch != pipe->next())             return NOT_FOUND;
+    if (++o > len)                      return WAIT;
+    ch = toHex[(c >> 0) & 0xF]; // low nibble
+    if (ch != pipe->next())             return NOT_FOUND;
+    if (++o > len)                      return WAIT;
+    if ('\r' != pipe->next())           return NOT_FOUND;
+    if (++o > len)                      return WAIT;
+    if ('\n' != pipe->next())           return NOT_FOUND;
+    return o;
+}
+
+int GPSParser::_parseUbx(Pipe<char>* pipe, int l)
+{
+    int o = 0;
+    if (++o > l)                return WAIT;
+    if ('\xB5' != pipe->next()) return NOT_FOUND;   
+    if (++o > l)                return WAIT;
+    if ('\x62' != pipe->next()) return NOT_FOUND;
+    o += 4;
+    if (o > l)                  return WAIT;
+    int i,j,ca,cb;
+    i = pipe->next(); ca  = i; cb  = ca; // cls
+    i = pipe->next(); ca += i; cb += ca; // id
+    i = pipe->next(); ca += i; cb += ca; // len_lsb
+    j = pipe->next(); ca += j; cb += ca; // len_msb 
+    j = i + (j << 8);
+    while (j--)
+    {
+        if (++o > l)            return WAIT;
+        i = pipe->next(); 
+        ca += i; 
+        cb += ca;
+    }
+    ca &= 0xFF; cb &= 0xFF;
+    if (++o > l)                return WAIT;
+    if (ca != pipe->next())     return NOT_FOUND;
+    if (++o > l)                return WAIT;
+    if (cb != pipe->next())     return NOT_FOUND;
+    return o;
+}
+
+int GPSParser::send(const char* buf, int len)
+{
+    return _send(buf, len);
+}
+
+int GPSParser::sendNmea(const char* buf, int len)
+{
+    char head[1] = { '$' };
+    char tail[5] = { '*', 0x00/*crc_high*/, 0x00/*crc_low*/, '\r', '\n' };
+    int i;
+    int crc = 0;
+    for (i = 0; i < len; i ++)
+        crc ^= *buf++;
+    i  = _send(head, sizeof(head));
+    i += _send(buf, len);
+    tail[1] = toHex[(crc > 4) & 0xF0];
+    tail[2] = toHex[(crc > 0) & 0x0F];
+    i += _send(tail, sizeof(tail));
+    return i;
+}
+
+int GPSParser::sendUbx(unsigned char cls, unsigned char id, const void* buf /*= NULL*/, int len /*= 0*/)
+{
+    char head[6] = { 0xB5, 0x62, cls, id, len >> 0, len >> 8 };
+    char crc[2];
+    int i;
+    int ca = 0;
+    int cb = 0;
+    for (i = 2; i < 6; i ++)
+    {
+        ca += head[i];
+        cb += ca;
+    }
+    for (i = 0; i < len; i ++)
+    {
+        ca += ((char*)buf)[i];
+        cb += ca; 
+    }
+    i  = _send(head, sizeof(head));
+    i += _send(buf, len);
+    crc[0] = ca & 0xFF;
+    crc[1] = cb & 0xFF;
+    i += _send(crc,  sizeof(crc));
+    return i;
+}
+
+const char* GPSParser::findNmeaItemPos(int ix, const char* start, const char* end)
+{
+    // find the start
+    for (; (start < end) && (ix > 0); start ++)
+    {
+        if (*start == ',')
+            ix --;
+    }
+    // found and check bounds
+    if ((ix == 0) && (start < end) && 
+        (*start != ',') && (*start != '*') && (*start != '\r') && (*start != '\n'))
+        return start;
+    else 
+        return NULL;
+}
+
+bool GPSParser::getNmeaItem(int ix, char* buf, int len, double& val)
+{
+    char* end = &buf[len];
+    const char* pos = findNmeaItemPos(ix, buf, end);
+    // find the start
+    if (!pos)
+        return false;
+    val = strtod(pos, &end);
+    // restore the last character
+    return (end > pos);
+}
+
+bool GPSParser::getNmeaItem(int ix, char* buf, int len, int& val, int base /*=10*/)
+{
+    char* end = &buf[len];
+    const char* pos = findNmeaItemPos(ix, buf, end);
+    // find the start
+    if (!pos)
+        return false;
+    val = (int)strtol(pos, &end, base);
+    return (end > pos);
+}
+
+bool GPSParser::getNmeaItem(int ix, char* buf, int len, char& val)
+{
+    const char* end = &buf[len];
+    const char* pos = findNmeaItemPos(ix, buf, end);
+    // find the start
+    if (!pos)
+        return false;
+    // skip leading spaces
+    while ((pos < end) && isspace(*pos))
+        pos++;
+    // check bound
+    if ((pos < end) && 
+        (*pos != ',') && (*pos != '*') && (*pos != '\r') && (*pos != '\n'))
+    {
+        val = *pos;
+        return true;
+    }
+    return false;
+}
+
+bool GPSParser::getNmeaAngle(int ix, char* buf, int len, double& val)
+{
+    char ch;
+    if (getNmeaItem(ix,buf,len,val) && getNmeaItem(ix+1,buf,len,ch) && 
+        ((ch == 'S') || (ch == 'N') || (ch == 'E') || (ch == 'W')))
+    {
+        val *= 0.01;
+        int i = (int)val;
+        val = (val - i) / 0.6 + i;
+        if (ch == 'S' || ch == 'W')
+            val = -val;
+        return true;
+    }
+    return false;
+}
+                
+const char GPSParser::toHex[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
+
+// ----------------------------------------------------------------
+// Serial Implementation 
+// ----------------------------------------------------------------
+
+GPSSerial::GPSSerial(PinName tx /*= GPSTXD*/, PinName rx /*= GPSRXD*/, int baudrate /*= GPSBAUD*/,
+            int rxSize /*= 256*/, int txSize /*= 128*/) : 
+            SerialPipe(tx, rx, rxSize, txSize)
+{
+    baud(baudrate);
+#ifdef TARGET_UBLOX_C027
+    _onboard = (tx == GPSTXD) || (rx == GPSRXD);
+    if (_onboard)
+        c027_gps_powerOn(); 
+#endif
+}
+
+GPSSerial::~GPSSerial(void)
+{
+    powerOff();
+#ifdef TARGET_UBLOX_C027
+    if (_onboard)
+         c027_gps_powerOff();
+#endif
+}
+
+bool GPSSerial::init(PinName pn)
+{
+    // send a byte to wakup the device again
+    putc(0xFF);
+    // wait until we get some bytes
+    int size = _pipeRx.size();
+    Timer timer;
+    timer.start();
+    while ((100 > timer.read_ms()) && (size == _pipeRx.size()))
+        /* nothing / just wait */;
+    return (size != _pipeRx.size());
+}
+
+int GPSSerial::getMessage(char* buf, int len)
+{
+    return _getMessage(&_pipeRx, buf, len);   
+}
+
+int GPSSerial::_send(const void* buf, int len)   
+{ 
+    return put((const char*)buf, len, true/*=blocking*/); 
+}
+
+// ----------------------------------------------------------------
+// I2C Implementation 
+// ----------------------------------------------------------------
+
+GPSI2C::GPSI2C(PinName sda /*= GPSSDA*/, PinName scl /*= GPSSCL*/,
+            unsigned char i2cAdr /*=GPSADR*/, int rxSize /*= 256*/) : 
+            I2C(sda,scl),
+            _pipe(rxSize),
+            _i2cAdr(i2cAdr)
+{
+    frequency(100000);
+#ifdef TARGET_UBLOX_C027
+    _onboard = (sda == GPSSDA) && (scl == GPSSCL);
+    if (_onboard)
+        c027_gps_powerOn(); 
+#endif
+}
+
+GPSI2C::~GPSI2C(void)
+{
+    powerOff();
+#ifdef TARGET_UBLOX_C027
+    if (_onboard)
+         c027_gps_powerOff();
+#endif
+}
+
+bool GPSI2C::init(PinName pn)
+{
+    if (pn != NC) {
+        DigitalOut pin(pn, 0);
+        ::wait_us(1);
+        pin = 1;
+        ::wait_ms(100);
+    }
+    return !I2C::write(_i2cAdr,&REGSTREAM,sizeof(REGSTREAM));
+}
+
+int GPSI2C::getMessage(char* buf, int len)
+{
+    // fill the pipe
+    int sz = _pipe.free();
+    if (sz) 
+        sz = _get(buf, sz);
+    if (sz) 
+        _pipe.put(buf, sz);
+    // now parse it
+    return _getMessage(&_pipe, buf, len);   
+}
+
+int GPSI2C::send(const char* buf, int len)
+{
+    int sent = 0;
+    if (len) 
+    {
+        if (!I2C::write(_i2cAdr,&REGSTREAM,sizeof(REGSTREAM),true))
+            sent = send(buf, len);
+        stop();
+    }
+    return sent;
+}
+
+int GPSI2C::sendNmea(const char* buf, int len)
+{ 
+    int sent = 0;
+    if (!I2C::write(_i2cAdr,&REGSTREAM,sizeof(REGSTREAM),true))
+        sent = GPSParser::sendNmea(buf, len);
+    stop();
+    return sent;
+}
+
+int GPSI2C::sendUbx(unsigned char cls, unsigned char id, const void* buf, int len)
+{ 
+    int sent = 0;
+    if (!I2C::write(_i2cAdr,&REGSTREAM,sizeof(REGSTREAM),true))
+        sent = GPSParser::sendUbx(cls, id, buf, len);
+    I2C::stop();
+    return sent;
+}
+
+int GPSI2C::_get(char* buf, int len)
+{
+    int read = 0;
+    unsigned char sz[2] = {0,0};
+    if (!I2C::write(_i2cAdr,&REGLEN,sizeof(REGLEN),true) && 
+        !I2C::read(_i2cAdr,(char*)sz,sizeof(sz)))
+    {
+        int size = 256 * (int)sz[0] + sz[1];
+        if (size > len)
+            size = len;
+        if (size > 0) 
+        {
+            if (!I2C::write(_i2cAdr,&REGSTREAM,sizeof(REGSTREAM),true) &&
+                !I2C::read(_i2cAdr,buf,size)) {
+                read = size;
+            }
+        }
+    }
+    return read;
+}
+
+int GPSI2C::_send(const void* buf, int len)
+{ 
+    return !I2C::write(_i2cAdr,(const char*)buf,len,true) ? len : 0; 
+}
+
+const char GPSI2C::REGLEN    = 0xFD;
+const char GPSI2C::REGSTREAM = 0xFF;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/GPS.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,294 @@
+#pragma once 
+
+#include "mbed.h"
+#include "Pipe.h"
+#include "SerialPipe.h"
+
+#ifdef TARGET_UBLOX_C027
+ #define GPS_IF(onboard, shield) onboard
+#else
+ #define GPS_IF(onboard, shield) shield
+#endif
+
+/** basic gps parser class 
+*/
+class GPSParser
+{
+public:
+    /** Power on / Wake up the gps 
+    */
+    virtual bool init(PinName pn) = 0;
+    
+    enum { 
+        // getLine Responses
+        WAIT      = -1, //!< wait for more incoming data (the start of a message was found, or no data available)
+        NOT_FOUND =  0, //!< a parser concluded the the current offset of the pipe doe not contain a valid message
+    
+        #define LENGTH(x)   (x & 0x00FFFF)  //!< extract/mask the length
+        #define PROTOCOL(x) (x & 0xFF0000)  //!< extract/mask the type
+
+        UNKNOWN   = 0x000000,       //!< message type is unknown 
+        UBX       = 0x100000,       //!< message if of protocol NMEA
+        NMEA      = 0x200000        //!< message if of protocol UBX
+    };
+    
+    /** Get a line from the physical interface. This fucntion 
+        needs to be implemented in the inherited class.
+        \param buf the buffer to store it
+        \param len size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    virtual int getMessage(char* buf, int len) = 0;
+    
+    /** send a buffer
+        \param buf the buffer to write
+        \param len size of the buffer to write
+        \return bytes written
+    */
+    virtual int send(const char* buf, int len);
+    
+    /** send a NMEA message, this function just takes the 
+        payload and calculates and adds checksum. ($ and *XX\r\n will be added)
+        \param buf the message payload to write
+        \param len size of the message payload to write
+        \return total bytes written
+    */
+    virtual int sendNmea(const char* buf, int len);
+    
+    /** send a UBX message, this function just takes the 
+        payload and calculates and adds checksum.
+        \param cls the UBX class id 
+        \param id the UBX message id
+        \param buf the message payload to write
+        \param len size of the message payload to write
+        \return total bytes written
+    */
+    virtual int sendUbx(unsigned char cls, unsigned char id, 
+                        const void* buf = NULL, int len = 0);
+    
+    /** Power off the gps, it can be again woken up by an 
+        edge on the serial port on the external interrupt pin. 
+    */
+    void powerOff(void);
+    
+    /** get the first character of a NMEA field
+        \param ix the index of the field to find
+        \param start the start of the buffer
+        \param end the end of the buffer
+        \return the pointer to the first character of the field. 
+    */
+    static const char* findNmeaItemPos(int ix, const char* start, const char* end);
+    
+    /** extract a double value from a buffer containing a NMEA message
+        \param ix the index of the field to extract
+        \param buf the NMEA message
+        \param len the size of the NMEA message
+        \param val the extracted value
+        \return true if successful, false otherwise
+    */
+    static bool getNmeaItem(int ix, char* buf, int len, double& val);
+    
+    /** extract a interger value from a buffer containing a NMEA message
+        \param ix the index of the field to extract
+        \param buf the NMEA message
+        \param len the size of the NMEA message
+        \param val the extracted value
+        \param base the numeric base to be used (e.g. 8, 10 or 16)
+        \return true if successful, false otherwise
+    */
+    static bool getNmeaItem(int ix, char* buf, int len, int& val, int base/*=10*/);
+    
+    /** extract a char value from a buffer containing a NMEA message
+        \param ix the index of the field to extract
+        \param buf the NMEA message
+        \param len the size of the NMEA message
+        \param val the extracted value
+        \return true if successful, false otherwise
+    */
+    static bool getNmeaItem(int ix, char* buf, int len, char& val);
+    
+    /** extract a latitude/longitude value from a buffer containing a NMEA message
+        \param ix the index of the field to extract (will extract ix and ix + 1)
+        \param buf the NMEA message
+        \param len the size of the NMEA message
+        \param val the extracted latitude or longitude
+        \return true if successful, false otherwise
+    */
+    static bool getNmeaAngle(int ix, char* buf, int len, double& val);
+    
+protected:
+    /** Get a line from the physical interface. 
+        \param pipe the receiveing pipe to parse messages 
+        \param buf the buffer to store it
+        \param len size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    static int _getMessage(Pipe<char>* pipe, char* buf, int len);
+    
+    /** Check if the current offset of the pipe contains a NMEA message.
+        \param pipe the receiveing pipe to parse messages 
+        \param len numer of bytes to parse at maximum
+        \return length if something was found (including the NMEA frame) 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    static int _parseNmea(Pipe<char>* pipe, int len);
+    
+    /** Check if the current offset of the pipe contains a UBX message.
+        \param pipe the receiveing pipe to parse messages 
+        \param len numer of bytes to parse at maximum
+        \return length if something was found (including the UBX frame)
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    static int _parseUbx(Pipe<char>* pipe, int len);
+    
+    /** Write bytes to the physical interface. This function 
+        needs to be implemented by the inherited class. 
+        \param buf the buffer to write
+        \param len size of the buffer to write
+        \return bytes written
+    */
+    virtual int _send(const void* buf, int len) = 0;
+    
+    static const char toHex[16]; //!< num to hex conversion
+#ifdef TARGET_UBLOX_C027
+    bool _onboard;
+#endif
+};
+
+/** gps class which uses a serial port 
+    as physical interface. 
+*/
+class GPSSerial : public SerialPipe, public GPSParser
+{
+public:
+    /** Constructor
+        \param tx is the serial ports transmit pin (gps to CPU)
+        \param rx is the serial ports receive pin (CPU to gps)
+        \param baudrate the baudrate of the gps use 9600
+        \param rxSize the size of the serial rx buffer
+        \param txSize the size of the serial tx buffer
+    */
+    GPSSerial(PinName tx    GPS_IF( = GPSTXD, /* = D8 */), // resistor on shield not populated 
+              PinName rx    GPS_IF( = GPSRXD, /* = D9 */), // resistor on shield not populated 
+              int baudrate  GPS_IF( = GPSBAUD, = 9600 ),
+              int rxSize    = 256 , 
+              int txSize    = 128 );
+              
+    //! Destructor
+    virtual ~GPSSerial(void);
+    
+    virtual bool init(PinName pn = NC);
+    
+    /** Get a line from the physical interface. 
+        \param buf the buffer to store it
+        \param len size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    virtual int getMessage(char* buf, int len);
+    
+protected:
+    /** Write bytes to the physical interface.
+        \param buf the buffer to write
+        \param len size of the buffer to write
+        \return bytes written
+    */
+    virtual int _send(const void* buf, int len);
+};
+
+/** gps class which uses a i2c as physical interface. 
+*/
+class GPSI2C : public I2C, public GPSParser
+{
+public: 
+    /** Constructor
+        \param sda is the I2C SDA pin (between CPU and GPS)
+        \param scl is the I2C SCL pin (CPU to GPS) 
+        \param adr the I2C address of the GPS set to (66<<1)
+        \param rxSize the size of the serial rx buffer
+    */
+    GPSI2C(PinName sda          GPS_IF( = GPSSDA, = D14 ), 
+           PinName scl          GPS_IF( = GPSSCL, = D15 ),
+           unsigned char i2cAdr GPS_IF( = GPSADR, = (66<<1) ), 
+           int rxSize           = 256 );
+    //! Destructor
+    virtual ~GPSI2C(void);
+    
+    /** helper function to probe the i2c device
+        \return true if successfully detected the gps. 
+    */ 
+    virtual bool init(PinName pn = GPS_IF( GPSINT, NC /* D7 resistor R67 on shield not mounted */));
+    
+    /** Get a line from the physical interface. 
+        \param buf the buffer to store it
+        \param len size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    virtual int getMessage(char* buf, int len);
+    
+    /** send a buffer
+        \param buf the buffer to write
+        \param len size of the buffer to write
+        \return bytes written
+    */
+    virtual int send(const char* buf, int len);
+    
+    /** send a NMEA message, this function just takes the 
+        payload and calculates and adds checksum. ($ and *XX\r\n will be added)
+        \param buf the message payload to write
+        \param len size of the message payload to write
+        \return total bytes written
+    */
+    virtual int sendNmea(const char* buf, int len);
+    
+    /** send a UBX message, this function just takes the 
+        payload and calculates and adds checksum.
+        \param cls the UBX class id 
+        \param id the UBX message id
+        \param buf the message payload to write
+        \param len size of the message payload to write
+        \return total bytes written
+    */
+    virtual int sendUbx(unsigned char cls, unsigned char id, 
+                        const void* buf = NULL, int len = 0);
+                        
+protected:
+    /** check if the port is writeable (like SerialPipe)
+        \return true if writeable        
+    */
+    bool writeable(void) { return true; }
+    
+    /** Write a character (like SerialPipe)
+        \param c  the character to write
+        \return true if succesffully written 
+    */
+    bool putc(int c)     { char ch = c; return send(&ch, 1); }
+    
+    /** Write bytes to the physical interface.
+        \param buf the buffer to write
+        \param len size of the buffer to write
+        \return bytes written
+    */
+    virtual int _send(const void* buf, int len);
+    
+    /** read bytes from the physical interface.
+        \param buf the buffer to read into
+        \param len size of the read buffer 
+        \return bytes read
+    */
+    int _get(char* buf, int len);
+    
+    Pipe<char> _pipe;           //!< the rx pipe
+    unsigned char _i2cAdr;      //!< the i2c address
+    static const char REGLEN;   //!< the length i2c register address
+    static const char REGSTREAM;//!< the stream i2c register address
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/MDM.cpp	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,1671 @@
+#include "mbed.h"
+#include "MDM.h"
+#ifdef TARGET_UBLOX_C027
+ #include "C027_api.h"
+#endif
+#include "MDMAPN.h"
+                
+#define PROFILE         "0"   //!< this is the psd profile used
+#define MAX_SIZE        128   //!< max expected messages
+// num sockets
+#define NUMSOCKETS      (sizeof(_sockets)/sizeof(*_sockets))
+//! test if it is a socket is ok to use
+#define ISSOCKET(s)     (((s) >= 0) && ((s) < NUMSOCKETS) && (_sockets[s].handle != SOCKET_ERROR))
+//! check for timeout
+#define TIMEOUT(t, ms)  ((ms != TIMEOUT_BLOCKING) && (ms < t.read_ms())) 
+//! registration ok check helper
+#define REG_OK(r)       ((r == REG_HOME) || (r == REG_ROAMING)) 
+//! registration done check helper (no need to poll further)
+#define REG_DONE(r)     ((r == REG_HOME) || (r == REG_ROAMING) || (r == REG_DENIED)) 
+//! helper to make sure that lock unlock pair is always balaced 
+#define LOCK()         { lock() 
+//! helper to make sure that lock unlock pair is always balaced 
+#define UNLOCK()       } unlock()
+
+#ifdef MDM_DEBUG
+ #if 1 // colored terminal output using ANSI escape sequences
+  #define COL(c) "\033[" c
+ #else
+  #define COL(c) 
+ #endif
+ #define DEF COL("39m")
+ #define BLA COL("30m")
+ #define RED COL("31m")
+ #define GRE COL("32m")
+ #define YEL COL("33m")
+ #define BLU COL("34m")
+ #define MAG COL("35m")
+ #define CYA COL("36m")
+ #define WHY COL("37m")
+ 
+void dumpAtCmd(const char* buf, int len)
+{
+    ::printf(" %3d \"", len);
+    while (len --) {
+        char ch = *buf++;
+        if ((ch > 0x1F) && (ch != 0x7F)) { // is printable
+            if      (ch == '%')  ::printf("%%");
+            else if (ch == '"')  ::printf("\\\"");
+            else if (ch == '\\') ::printf("\\\\");
+            else putchar(ch);
+        } else {
+            if      (ch == '\a') ::printf("\\a"); // BEL (0x07)
+            else if (ch == '\b') ::printf("\\b"); // Backspace (0x08)
+            else if (ch == '\t') ::printf("\\t"); // Horizontal Tab (0x09)
+            else if (ch == '\n') ::printf("\\n"); // Linefeed (0x0A)
+            else if (ch == '\v') ::printf("\\v"); // Vertical Tab (0x0B)
+            else if (ch == '\f') ::printf("\\f"); // Formfeed (0x0C)
+            else if (ch == '\r') ::printf("\\r"); // Carriage Return (0x0D)
+            else                 ::printf("\\x%02x", (unsigned char)ch);
+        }
+    }
+    ::printf("\"\r\n");
+}
+ 
+ #define ERROR(...)     (_debugLevel < 0) ? : ::printf(RED), ::printf(__VA_ARGS__), ::printf(DEF) 
+ #define TEST(...)                            ::printf(CYA), ::printf(__VA_ARGS__), ::printf(DEF)  
+ #define INFO(...)      (_debugLevel < 1) ? : ::printf(GRE), ::printf(__VA_ARGS__), ::printf(DEF) 
+ #define TRACE(...)     (_debugLevel < 2) ? : ::printf(__VA_ARGS__)
+ 
+#else
+ 
+ #define ERROR(...) (void)0 // no tracing
+ #define TEST(...)  (void)0 // no tracing
+ #define INFO(...)  (void)0 // no tracing
+ #define TRACE(...) (void)0 // no tracing
+
+#endif
+
+MDMParser* MDMParser::inst;
+
+MDMParser::MDMParser(void)
+{
+    inst = this;
+    memset(&_dev, 0, sizeof(_dev));
+    memset(&_net, 0, sizeof(_net));
+    _net.lac = 0xFFFF;
+    _net.ci = 0xFFFFFFFF;
+    _ip        = NOIP;
+    _init      = false;
+    memset(_sockets, 0, sizeof(_sockets));
+    for (int socket = 0; socket < NUMSOCKETS; socket ++)
+        _sockets[socket].handle = SOCKET_ERROR;
+#ifdef MDM_DEBUG
+    _debugLevel = 1;
+    _debugTime.start();
+#endif
+}
+
+int MDMParser::send(const char* buf, int len)
+{
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 3) {
+        ::printf("%10.3f AT send    ", _debugTime.read_ms()*0.001);
+        dumpAtCmd(buf,len);
+    }
+#endif
+    return _send(buf, len);
+}
+
+int MDMParser::sendFormated(const char* format, ...) {
+    char buf[MAX_SIZE];
+    va_list args;
+    va_start(args, format);
+    int len = vsnprintf(buf,sizeof(buf), format, args);
+    va_end(args);
+    return send(buf, len);
+}
+
+int MDMParser::waitFinalResp(_CALLBACKPTR cb /* = NULL*/, 
+                             void* param /* = NULL*/, 
+                             int timeout_ms /*= 5000*/)
+{
+    char buf[MAX_SIZE + 64 /* add some more space for framing */]; 
+    Timer timer;
+    timer.start();
+    do {
+        int ret = getLine(buf, sizeof(buf));
+#ifdef MDM_DEBUG
+        if ((_debugLevel >= 3) && (ret != WAIT) && (ret != NOT_FOUND))
+        {
+            int len = LENGTH(ret);
+            int type = TYPE(ret);
+            const char* s = (type == TYPE_UNKNOWN)? YEL "UNK" DEF : 
+                            (type == TYPE_TEXT)   ? MAG "TXT" DEF : 
+                            (type == TYPE_OK   )  ? GRE "OK " DEF : 
+                            (type == TYPE_ERROR)  ? RED "ERR" DEF : 
+                            (type == TYPE_PLUS)   ? CYA " + " DEF : 
+                            (type == TYPE_PROMPT) ? BLU " > " DEF : 
+                                                        "..." ;
+            ::printf("%10.3f AT read %s", _debugTime.read_ms()*0.001, s);
+            dumpAtCmd(buf, len);
+        }
+#endif        
+        if ((ret != WAIT) && (ret != NOT_FOUND))
+        {
+            int type = TYPE(ret);
+            // handle unsolicited commands here
+            if (type == TYPE_PLUS) {
+                const char* cmd = buf+3;
+                int a, b, c, d, r;
+                char s[32];
+
+                // SMS Command ---------------------------------
+                // +CNMI: <mem>,<index>
+                if (sscanf(cmd, "CMTI: \"%*[^\"]\",%d", &a) == 1) { 
+                    TRACE("New SMS at index %d\r\n", a);
+                // Socket Specific Command ---------------------------------
+                // +UUSORD: <socket>,<length>
+                } else if ((sscanf(cmd, "UUSORD: %d,%d", &a, &b) == 2)) {
+                    int socket = _findSocket(a);
+                    TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
+                    if (socket != SOCKET_ERROR)
+                        _sockets[socket].pending = b;
+                // +UUSORF: <socket>,<length>
+                } else if ((sscanf(cmd, "UUSORF: %d,%d", &a, &b) == 2)) {
+                    int socket = _findSocket(a);
+                    TRACE("Socket %d: handle %d has %d bytes pending\r\n", socket, a, b);
+                    if (socket != SOCKET_ERROR)
+                        _sockets[socket].pending = b;
+                // +UUSOCL: <socket>
+                } else if ((sscanf(cmd, "UUSOCL: %d", &a) == 1)) {
+                    int socket = _findSocket(a);
+                    TRACE("Socket %d: handle %d closed by remote host\r\n", socket, a);
+                    if ((socket != SOCKET_ERROR) && _sockets[socket].connected)
+                        _sockets[socket].connected = false;
+                }
+                if (_dev.dev == DEV_LISA_C200) {
+                    // CDMA Specific -------------------------------------------
+                    // +CREG: <n><SID>,<NID>,<stat>
+                    if (sscanf(cmd, "CREG: %*d,%d,%d,%d",&a,&b,&c) == 3) {
+                        // _net.sid = a;
+                        // _net.nid = b;
+                        if      (c == 0) _net.csd = REG_NONE;     // not registered, home network
+                        else if (c == 1) _net.csd = REG_HOME;     // registered, home network
+                        else if (c == 2) _net.csd = REG_NONE;     // not registered, but MT is currently searching a new operator to register to
+                        else if (c == 3) _net.csd = REG_DENIED;   // registration denied
+                        else if (c == 5) _net.csd = REG_ROAMING;  // registered, roaming
+                        _net.psd = _net.csd; // fake PSD registration (CDMA is always registered)
+                        _net.act = ACT_CDMA;
+                        // +CSS: <mode>[,<format>,<oper>[,<AcT>]]
+                    } else if (sscanf(cmd, "CSS %*c,%2s,%*d",s) == 1) {
+                        //_net.reg = (strcmp("Z", s) == 0) ? REG_UNKNOWN : REG_HOME;
+                    }
+                } else {
+                    // GSM/UMTS Specific -------------------------------------------
+                    // +UUPSDD: <profile_id> 
+                    if (sscanf(cmd, "UUPSDD: %d",&a) == 1) {
+                        if (*PROFILE == a) _ip = NOIP;
+                    } else {
+                        // +CREG|CGREG: <n>,<stat>[,<lac>,<ci>[,AcT[,<rac>]]] // reply to AT+CREG|AT+CGREG
+                        // +CREG|CGREG: <stat>[,<lac>,<ci>[,AcT[,<rac>]]]     // URC
+                        b = 0xFFFF; c = 0xFFFFFFFF; d = -1;
+                        r = sscanf(cmd, "%s %*d,%d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
+                        if (r <= 1)
+                            r = sscanf(cmd, "%s %d,\"%X\",\"%X\",%d",s,&a,&b,&c,&d);
+                        if (r >= 2) {
+                            Reg *reg = !strcmp(s, "CREG:")  ? &_net.csd : 
+                                       !strcmp(s, "CGREG:") ? &_net.psd : NULL;
+                            if (reg) {
+                                // network status
+                                if      (a == 0) *reg = REG_NONE;     // 0: not registered, home network
+                                else if (a == 1) *reg = REG_HOME;     // 1: registered, home network
+                                else if (a == 2) *reg = REG_NONE;     // 2: not registered, but MT is currently searching a new operator to register to
+                                else if (a == 3) *reg = REG_DENIED;   // 3: registration denied
+                                else if (a == 4) *reg = REG_UNKNOWN;  // 4: unknown
+                                else if (a == 5) *reg = REG_ROAMING;  // 5: registered, roaming
+                                if ((r >= 3) && (b != 0xFFFF))      _net.lac = b; // location area code
+                                if ((r >= 4) && (c != 0xFFFFFFFF))  _net.ci  = c; // cell ID
+                                // access technology
+                                if (r >= 5) {
+                                    if      (d == 0) _net.act = ACT_GSM;      // 0: GSM
+                                    else if (d == 1) _net.act = ACT_GSM;      // 1: GSM COMPACT
+                                    else if (d == 2) _net.act = ACT_UTRAN;    // 2: UTRAN
+                                    else if (d == 3) _net.act = ACT_EDGE;     // 3: GSM with EDGE availability
+                                    else if (d == 4) _net.act = ACT_UTRAN;    // 4: UTRAN with HSDPA availability
+                                    else if (d == 5) _net.act = ACT_UTRAN;    // 5: UTRAN with HSUPA availability
+                                    else if (d == 6) _net.act = ACT_UTRAN;    // 6: UTRAN with HSDPA and HSUPA availability
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (cb) {
+                int len = LENGTH(ret);
+                int ret = cb(type, buf, len, param);
+                if (WAIT != ret)
+                    return ret; 
+            }
+            if (type == TYPE_OK)
+                return RESP_OK;
+            if (type == TYPE_ERROR)
+                return RESP_ERROR;
+            if (type == TYPE_PROMPT)    
+                return RESP_PROMPT;
+        }
+        // relax a bit
+        wait_ms(10); 
+    }
+    while (!TIMEOUT(timer, timeout_ms));
+    return WAIT;
+}
+
+int MDMParser::_cbString(int type, const char* buf, int len, char* str)
+{
+    if (str && (type == TYPE_UNKNOWN)) {
+        if (sscanf(buf, "\r\n%s\r\n", str) == 1)
+            /*nothing*/;
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbInt(int type, const char* buf, int len, int* val)
+{
+    if (val && (type == TYPE_UNKNOWN)) {
+        if (sscanf(buf, "\r\n%d\r\n", val) == 1)
+            /*nothing*/;
+    }
+    return WAIT;
+}
+
+// ----------------------------------------------------------------
+
+bool MDMParser::connect(
+            const char* simpin, 
+            const char* apn, const char* username, 
+            const char* password, Auth auth,
+            PinName pn)
+{
+    bool ok = init(simpin, NULL, pn);  
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpDevStatus(&_dev);
+#endif
+    if (!ok)
+        return false;
+    ok = registerNet();
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpNetStatus(&_net);
+#endif
+    if (!ok)
+        return false;
+    IP ip = join(apn,username,password,auth);
+#ifdef MDM_DEBUG
+    if (_debugLevel >= 1) dumpIp(ip);
+#endif
+    if (ip == NOIP)
+        return false; 
+    return true;
+}
+
+bool MDMParser::init(const char* simpin, DevStatus* status, PinName pn)
+{
+    int i = 10;
+    LOCK();
+    memset(&_dev, 0, sizeof(_dev));
+    if (pn != NC) {
+        INFO("Modem::wakeup\r\n");
+        DigitalOut pin(pn, 1);
+        while (i--) {
+            // SARA-U2/LISA-U2 50..80us
+            pin = 0; ::wait_us(50);
+            pin = 1; ::wait_ms(10); 
+            
+            // SARA-G35 >5ms, LISA-C2 > 150ms, LEON-G2 >5ms
+            pin = 0; ::wait_ms(150);
+            pin = 1; ::wait_ms(100);
+            
+            // purge any messages 
+            purge();
+            
+            // check interface
+            sendFormated("AT\r\n");
+            int r = waitFinalResp(NULL,NULL,1000);
+            if(RESP_OK == r) break;
+        }
+        if (i < 0) {
+            ERROR("No Reply from Modem\r\n");
+            goto failure;
+        }
+    }
+    _init = true;
+    
+    INFO("Modem::init\r\n");
+    // echo off
+    sendFormated("AT E0\r\n");
+    if(RESP_OK != waitFinalResp())
+        goto failure; 
+    // enable verbose error messages
+    sendFormated("AT+CMEE=2\r\n");
+    if(RESP_OK != waitFinalResp())
+        goto failure;
+    // set baud rate
+    sendFormated("AT+IPR=115200\r\n");
+    if (RESP_OK != waitFinalResp())
+        goto failure;
+    wait_ms(40);
+    // identify the module 
+    sendFormated("ATI\r\n");
+    if (RESP_OK != waitFinalResp(_cbATI, &_dev.dev))
+        goto failure;
+    if (_dev.dev == DEV_UNKNOWN)
+        goto failure;
+    // device specific init
+    if (_dev.dev == DEV_LISA_C200) {
+        // get the manufacturer
+        sendFormated("AT+GMI\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
+            goto failure;
+        // get the model identification
+        sendFormated("AT+GMM\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.model))
+            goto failure;
+        // get the sw version
+        sendFormated("AT+GMR\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
+            goto failure;
+        // get the pseudo ESN or MEID
+        sendFormated("AT+GSN\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.meid))
+            goto failure;
+#if 0
+        // enable power saving
+        if (_dev.lpm != LPM_DISABLED) {
+             // enable power saving (requires flow control, cts at least)
+            sendFormated("AT+UPSV=1,1280\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;  
+            _dev.lpm = LPM_ACTIVE;
+        }
+#endif
+    } else {
+        if ((_dev.dev == DEV_LISA_U200) || (_dev.dev == DEV_LEON_G200)) {
+            // enable the network identification feature 
+            sendFormated("AT+UGPIOC=20,2\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;
+        } else if ((_dev.dev == DEV_SARA_U260) || (_dev.dev == DEV_SARA_U270) || 
+                   (_dev.dev == DEV_SARA_G350)) {
+            // enable the network identification feature 
+            sendFormated("AT+UGPIOC=16,2\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;
+        }
+        // check the sim card
+        for (int i = 0; (i < 5) && (_dev.sim != SIM_READY); i++) {
+            sendFormated("AT+CPIN?\r\n");
+            int ret = waitFinalResp(_cbCPIN, &_dev.sim);
+            // having an error here is ok (sim may still be initializing)
+            if ((RESP_OK != ret) && (RESP_ERROR != ret))
+                goto failure;
+            // Enter PIN if needed
+            if (_dev.sim == SIM_PIN) {
+                if (!simpin) {
+                    ERROR("SIM PIN not available\r\n");
+                    goto failure;
+                }
+                sendFormated("AT+CPIN=%s\r\n", simpin);
+                if (RESP_OK != waitFinalResp(_cbCPIN, &_dev.sim))
+                    goto failure;
+            } else if (_dev.sim != SIM_READY) {
+                wait_ms(1000);
+            }
+        }
+        if (_dev.sim != SIM_READY) {
+            if (_dev.sim == SIM_MISSING)
+                ERROR("SIM not inserted\r\n");
+            goto failure;
+        }
+        // get the manufacturer
+        sendFormated("AT+CGMI\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.manu))
+            goto failure;
+        // get the model identification
+        sendFormated("AT+CGMM\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.model))
+            goto failure;
+        // get the 
+        sendFormated("AT+CGMR\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.ver))
+            goto failure;            
+        // Returns the ICCID (Integrated Circuit Card ID) of the SIM-card. 
+        // ICCID is a serial number identifying the SIM.
+        sendFormated("AT+CCID\r\n");
+        if (RESP_OK != waitFinalResp(_cbCCID, _dev.ccid))
+            goto failure;
+        // Returns the product serial number, IMEI (International Mobile Equipment Identity)
+        sendFormated("AT+CGSN\r\n");
+        if (RESP_OK != waitFinalResp(_cbString, _dev.imei))
+            goto failure;
+        // enable power saving
+        if (_dev.lpm != LPM_DISABLED) {
+             // enable power saving (requires flow control, cts at least)
+            sendFormated("AT+UPSV=1\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;  
+            _dev.lpm = LPM_ACTIVE;
+        }
+        // enable the psd registration unsolicited result code
+        sendFormated("AT+CGREG=2\r\n");
+        if (RESP_OK != waitFinalResp())
+            goto failure;
+    } 
+    // enable the network registration unsolicited result code
+    sendFormated("AT+CREG=%d\r\n", (_dev.dev == DEV_LISA_C200) ? 1 : 2);
+    if (RESP_OK != waitFinalResp())
+        goto failure;
+    // Setup SMS in text mode 
+    sendFormated("AT+CMGF=1\r\n");
+    if (RESP_OK != waitFinalResp())
+        goto failure;
+    // setup new message indication
+    sendFormated("AT+CNMI=2,1\r\n");
+    if (RESP_OK != waitFinalResp())
+        goto failure;
+    // Request IMSI (International Mobile Subscriber Identification)
+    sendFormated("AT+CIMI\r\n");
+    if (RESP_OK != waitFinalResp(_cbString, _dev.imsi))
+        goto failure;
+    if (status)
+        memcpy(status, &_dev, sizeof(DevStatus));
+    UNLOCK();
+    return true; 
+failure:
+    unlock();
+    return false; 
+}
+
+bool MDMParser::powerOff(void)
+{
+    bool ok = false;
+    if (_init) {
+        LOCK();
+        INFO("Modem::powerOff\r\n");
+        sendFormated("AT+CPWROFF\r\n");
+        if (RESP_OK == waitFinalResp(NULL,NULL,120*1000)) {
+            _init = false;
+            ok = true;
+        }
+        UNLOCK();
+    }
+    return ok;
+}
+
+int MDMParser::_cbATI(int type, const char* buf, int len, Dev* dev)
+{
+    if ((type == TYPE_UNKNOWN) && dev) {
+        if      (strstr(buf, "SARA-G350")) *dev = DEV_SARA_G350;
+        else if (strstr(buf, "LISA-U200")) *dev = DEV_LISA_U200;
+        else if (strstr(buf, "LISA-C200")) *dev = DEV_LISA_C200;
+        else if (strstr(buf, "SARA-U260")) *dev = DEV_SARA_U260;
+        else if (strstr(buf, "SARA-U270")) *dev = DEV_SARA_U270;
+        else if (strstr(buf, "LEON-G200")) *dev = DEV_LEON_G200;
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCPIN(int type, const char* buf, int len, Sim* sim)
+{
+    if (sim) {
+        if (type == TYPE_PLUS){
+            char s[16];
+            if (sscanf(buf, "\r\n+CPIN: %[^\r]\r\n", s) >= 1)
+                *sim = (0 == strcmp("READY", s)) ? SIM_READY : SIM_PIN;
+        } else if (type == TYPE_ERROR) {
+            if (strstr(buf, "+CME ERROR: SIM not inserted"))
+                *sim = SIM_MISSING;
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCCID(int type, const char* buf, int len, char* ccid)
+{
+    if ((type == TYPE_PLUS) && ccid){
+        if (sscanf(buf, "\r\n+CCID: %[^\r]\r\n", ccid) == 1)
+            /*TRACE("Got CCID: %s\r\n", ccid)*/;
+    }
+    return WAIT;
+}
+
+bool MDMParser::registerNet(NetStatus* status /*= NULL*/, int timeout_ms /*= 180000*/) 
+{
+    Timer timer;
+    timer.start();
+    INFO("Modem::register\r\n");
+    while (!checkNetStatus(status) && !TIMEOUT(timer, timeout_ms))
+        wait_ms(1000);
+    if (_net.csd == REG_DENIED) ERROR("CSD Registration Denied\r\n");
+    if (_net.psd == REG_DENIED) ERROR("PSD Registration Denied\r\n");
+    return REG_OK(_net.csd) || REG_OK(_net.psd);
+}
+
+bool MDMParser::checkNetStatus(NetStatus* status /*= NULL*/)
+{
+    bool ok = false;
+    LOCK();
+    memset(&_net, 0, sizeof(_net));
+    _net.lac = 0xFFFF;
+    _net.ci = 0xFFFFFFFF;
+    // check registration
+    sendFormated("AT+CREG?\r\n");
+    waitFinalResp();     // don't fail as service could be not subscribed 
+    if (_dev.dev != DEV_LISA_C200) {
+        // check PSD registration
+        sendFormated("AT+CGREG?\r\n");
+        waitFinalResp(); // don't fail as service could be not subscribed 
+    }
+    if (REG_OK(_net.csd) || REG_OK(_net.psd))
+    {
+        // check modem specific status messages 
+        if (_dev.dev == DEV_LISA_C200) {
+            sendFormated("AT+CSS?\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;
+            while (1) {
+                // get the Telephone number
+                sendFormated("AT$MDN?\r\n");
+                if (RESP_OK != waitFinalResp(_cbString, _net.num))
+                    goto failure;
+                // check if we have a Mobile Directory Number
+                if (*_net.num && (memcmp(_net.num, "000000", 6) != 0))
+                    break;
+                    
+                INFO("Device not yet activated\r\n");
+                INFO("Make sure you have a valid contract with the network operator for this device.\r\n");
+                // Check if the the version contains a V for Verizon 
+                // Verizon: E0.V.xx.00.xxR, 
+                // Sprint E0.S.xx.00.xxR
+                if (_dev.ver[3] == 'V') { 
+                    int i;
+                    INFO("Start device over-the-air activation (this can take a few minutes)\r\n");
+                    sendFormated("AT+CDV=*22899\r\n");
+                    i = 1;
+                    if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
+                        ERROR("Device over-the-air activation failed\r\n");
+                        goto failure;
+                    }
+                    INFO("Device over-the-air activation successful\r\n");
+                    
+                    INFO("Start PRL over-the-air update (this can take a few minutes)\r\n");
+                    sendFormated("AT+CDV=*22891\r\n");
+                    i = 1;
+                    if ((RESP_OK != waitFinalResp(_cbUACTIND, &i, 120*1000)) || (i == 1)) {
+                        ERROR("PRL over-the-air update failed\r\n");
+                        goto failure;
+                    }
+                    INFO("PRL over-the-air update successful\r\n");
+                    
+                } else { 
+                    // Sprint or Aeris 
+                    INFO("Wait for OMA-DM over-the-air activation (this can take a few minutes)\r\n");
+                    wait_ms(120*1000);
+                }
+            }
+            // get the the Network access identifier string
+            char nai[64];
+            sendFormated("AT$QCMIPNAI?\r\n");
+            if (RESP_OK != waitFinalResp(_cbString, nai))
+                goto failure;
+        } else {
+            sendFormated("AT+COPS?\r\n");
+            if (RESP_OK != waitFinalResp(_cbCOPS, &_net))
+                goto failure;
+            // get the MSISDNs related to this subscriber
+            sendFormated("AT+CNUM\r\n");
+            if (RESP_OK != waitFinalResp(_cbCNUM, _net.num))
+                goto failure;
+        }  
+        // get the signal strength indication
+        sendFormated("AT+CSQ\r\n");
+        if (RESP_OK != waitFinalResp(_cbCSQ, &_net))
+            goto failure;
+    }
+    if (status) {
+        memcpy(status, &_net, sizeof(NetStatus));
+    }
+    ok = REG_DONE(_net.csd) && REG_DONE(_net.psd);
+    UNLOCK();
+    return ok;
+failure:
+    unlock();
+    return false;
+}
+
+int MDMParser::_cbCOPS(int type, const char* buf, int len, NetStatus* status)
+{
+    if ((type == TYPE_PLUS) && status){
+        int act = 99;
+        // +COPS: <mode>[,<format>,<oper>[,<AcT>]]
+        if (sscanf(buf, "\r\n+COPS: %*d,%*d,\"%[^\"]\",%d",status->opr,&act) >= 1) {
+            if      (act == 0) status->act = ACT_GSM;      // 0: GSM, 
+            else if (act == 2) status->act = ACT_UTRAN;    // 2: UTRAN
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCNUM(int type, const char* buf, int len, char* num)
+{
+    if ((type == TYPE_PLUS) && num){
+        int a;
+        if ((sscanf(buf, "\r\n+CNUM: \"My Number\",\"%31[^\"]\",%d", num, &a) == 2) && 
+            ((a == 129) || (a == 145))) {
+        }
+    }
+    return WAIT;
+}
+                    
+int MDMParser::_cbCSQ(int type, const char* buf, int len, NetStatus* status)
+{
+    if ((type == TYPE_PLUS) && status){
+        int a,b;
+        char _ber[] = { 49, 43, 37, 25, 19, 13, 7, 0 }; // see 3GPP TS 45.008 [20] subclause 8.2.4
+        // +CSQ: <rssi>,<qual>
+        if (sscanf(buf, "\r\n+CSQ: %d,%d",&a,&b) == 2) {
+            if (a != 99) status->rssi = -113 + 2*a;  // 0: -113 1: -111 ... 30: -53 dBm with 2 dBm steps
+            if ((b != 99) && (b < sizeof(_ber))) status->ber = _ber[b];  // 
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbUACTIND(int type, const char* buf, int len, int* i)
+{
+    if ((type == TYPE_PLUS) && i){
+        int a;
+        if (sscanf(buf, "\r\n+UACTIND: %d", &a) == 1) {
+            *i = a;
+        }
+    }
+    return WAIT;
+}
+
+// ----------------------------------------------------------------
+// internet connection 
+
+MDMParser::IP MDMParser::join(const char* apn /*= NULL*/, const char* username /*= NULL*/, 
+                              const char* password /*= NULL*/, Auth auth /*= AUTH_DETECT*/)
+{
+    LOCK();
+    INFO("Modem::join\r\n");
+    _ip = NOIP;
+    if (_dev.dev == DEV_LISA_C200) {
+        // make a dumy dns lookup (which will fail, so ignore the result) 
+        sendFormated("AT+UDNSRN=0,\"u-blox.com\"\r\n");
+        waitFinalResp(); 
+        // This fake lookup will enable the IP connection and we 
+        // should have an IP after this, so we check it
+        
+        //Get local IP address
+        sendFormated("AT+CMIP?\r\n");
+        if (RESP_OK != waitFinalResp(_cbCMIP, &_ip))
+            goto failure;
+    } else { 
+        // check gprs attach status 
+        sendFormated("AT+CGATT=1\r\n");
+        if (RESP_OK != waitFinalResp(NULL,NULL,3*60*1000)) 
+            goto failure;
+        
+        // Check the profile
+        int a = 0;
+        bool force = true;
+        sendFormated("AT+UPSND=" PROFILE ",8\r\n");
+        if (RESP_OK != waitFinalResp(_cbUPSND, &a))
+            goto failure;
+        if (a == 1 && force) {
+            // disconnect the profile already if it is connected 
+            sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
+            if (RESP_OK != waitFinalResp(NULL,NULL,40*1000))
+                goto failure;
+            a = 0;
+        }
+        if (a == 0) {
+            bool ok = false;
+            // try to lookup the apn settings from our local database by mccmnc
+            const char* config = NULL;
+            if (!apn && !username && !password)
+                config = apnconfig(_dev.imsi);
+            
+            // Set up the dynamic IP address assignment.
+            sendFormated("AT+UPSD=" PROFILE ",7,\"0.0.0.0\"\r\n");
+            if (RESP_OK != waitFinalResp())
+                goto failure;
+ 
+            do {
+                if (config) {
+                    apn      = _APN_GET(config);
+                    username = _APN_GET(config);
+                    password = _APN_GET(config);
+                    TRACE("Testing APN Settings(\"%s\",\"%s\",\"%s\")\r\n", apn, username, password);
+                }
+                // Set up the APN
+                if (apn && *apn) {
+                    sendFormated("AT+UPSD=" PROFILE ",1,\"%s\"\r\n", apn);
+                    if (RESP_OK != waitFinalResp())
+                        goto failure;
+                }
+                if (username && *username) {
+                    sendFormated("AT+UPSD=" PROFILE ",2,\"%s\"\r\n", username);
+                    if (RESP_OK != waitFinalResp())
+                        goto failure;
+                }
+                if (password && *password) {
+                    sendFormated("AT+UPSD=" PROFILE ",3,\"%s\"\r\n", password);
+                    if (RESP_OK != waitFinalResp())
+                        goto failure;
+                }
+                // try different Authentication Protocols
+                // 0 = none 
+                // 1 = PAP (Password Authentication Protocol)
+                // 2 = CHAP (Challenge Handshake Authentication Protocol)
+                for (int i = AUTH_NONE; i <= AUTH_CHAP && !ok; i ++) {
+                    if ((auth == AUTH_DETECT) || (auth == i)) {
+                        // Set up the Authentication Protocol
+                        sendFormated("AT+UPSD=" PROFILE ",6,%d\r\n", i);
+                        if (RESP_OK != waitFinalResp())
+                            goto failure;
+                        // Activate the profile and make connection
+                        sendFormated("AT+UPSDA=" PROFILE ",3\r\n");
+                        if (RESP_OK == waitFinalResp(NULL,NULL,150*1000))
+                            ok = true;
+                    }
+                }
+            } while (!ok && config && *config); // maybe use next setting ? 
+            if (!ok) {
+                ERROR("Your modem APN/password/username may be wrong\r\n");
+                goto failure;
+            }
+        }
+        //Get local IP address
+        sendFormated("AT+UPSND=" PROFILE ",0\r\n");
+        if (RESP_OK != waitFinalResp(_cbUPSND, &_ip))
+            goto failure;
+    }
+    UNLOCK();
+    return _ip;
+failure: 
+    unlock();
+    return NOIP;
+}
+
+int MDMParser::_cbUDOPN(int type, const char* buf, int len, char* mccmnc)
+{
+    if ((type == TYPE_PLUS) && mccmnc) {
+        if (sscanf(buf, "\r\n+UDOPN: 0,\"%[^\"]\"", mccmnc) == 1)
+            ;
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbCMIP(int type, const char* buf, int len, IP* ip)
+{
+    if ((type == TYPE_UNKNOWN) && ip) {
+        int a,b,c,d;
+        if (sscanf(buf, "\r\n" IPSTR, &a,&b,&c,&d) == 4)
+            *ip = IPADR(a,b,c,d);
+    }
+    return WAIT;
+}
+        
+int MDMParser::_cbUPSND(int type, const char* buf, int len, int* act)
+{
+    if ((type == TYPE_PLUS) && act) {
+        if (sscanf(buf, "\r\n+UPSND: %*d,%*d,%d", act) == 1)
+            /*nothing*/;
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbUPSND(int type, const char* buf, int len, IP* ip)
+{
+    if ((type == TYPE_PLUS) && ip) {
+        int a,b,c,d;
+        // +UPSND=<profile_id>,<param_tag>[,<dynamic_param_val>]
+        if (sscanf(buf, "\r\n+UPSND: " PROFILE ",0,\"" IPSTR "\"", &a,&b,&c,&d) == 4)
+            *ip = IPADR(a,b,c,d);
+    }
+    return WAIT;
+}
+
+int MDMParser::_cbUDNSRN(int type, const char* buf, int len, IP* ip)
+{
+    if ((type == TYPE_PLUS) && ip) {
+        int a,b,c,d;
+        if (sscanf(buf, "\r\n+UDNSRN: \"" IPSTR "\"", &a,&b,&c,&d) == 4)
+            *ip = IPADR(a,b,c,d);
+    }
+    return WAIT;
+}
+
+bool MDMParser::disconnect(void)
+{
+    bool ok = false;
+    LOCK();
+    INFO("Modem::disconnect\r\n");
+    if (_ip != NOIP) {
+        if (_dev.dev == DEV_LISA_C200) {
+            // There something to do here
+            _ip = NOIP;
+            ok = true;
+        } else { 
+            sendFormated("AT+UPSDA=" PROFILE ",4\r\n");
+            if (RESP_OK != waitFinalResp()) {
+                _ip = NOIP;
+                ok = true;
+            }
+        }
+    }
+    UNLOCK();
+    return ok;
+}
+
+MDMParser::IP MDMParser::gethostbyname(const char* host)
+{
+    IP ip = NOIP; 
+    int a,b,c,d;
+    if (sscanf(host, IPSTR, &a,&b,&c,&d) == 4)
+        ip = IPADR(a,b,c,d);
+    else {
+        LOCK();
+        sendFormated("AT+UDNSRN=0,\"%s\"\r\n", host);
+        if (RESP_OK != waitFinalResp(_cbUDNSRN, &ip))
+            ip = NOIP;
+        UNLOCK();
+    }
+    return ip;
+}
+
+// ----------------------------------------------------------------
+// sockets
+
+int MDMParser::_cbUSOCR(int type, const char* buf, int len, int* handle)
+{
+    if ((type == TYPE_PLUS) && handle) {
+        const char* p = strstr(buf,"+USOCR: "); 
+        if (p)
+            *handle = atoi(p+8);
+    }
+    return WAIT;
+}
+
+int MDMParser::socketSocket(IpProtocol ipproto, int port)
+{
+    int socket;
+    LOCK();
+    // find an free socket
+    socket = _findSocket();
+    TRACE("socketSocket(%d)\r\n", ipproto);
+    if (socket != SOCKET_ERROR) {
+        if ((ipproto == IPPROTO_UDP) && (port == -1)){
+            sendFormated("AT+USOCR=17\r\n");
+        } else if (ipproto == IPPROTO_UDP){
+            sendFormated("AT+USOCR=17,%d\r\n", port);
+        } else /*(ipproto == IPPROTO_TCP)*/ {
+            sendFormated("AT+USOCR=6\r\n");
+        } 
+        int handle = SOCKET_ERROR;
+        if ((RESP_OK == waitFinalResp(_cbUSOCR, &handle)) && 
+            (handle != SOCKET_ERROR)) {
+            TRACE("Socket %d: handle %d was created\r\n", socket, handle);
+            _sockets[socket].handle     = handle;
+            _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
+            _sockets[socket].connected  = false;
+            _sockets[socket].pending    = 0;
+        }
+        else
+            socket = SOCKET_ERROR;
+    }
+    UNLOCK();
+    return socket;
+}
+
+bool MDMParser::socketConnect(int socket, const char * host, int port)
+{
+    IP ip = gethostbyname(host);
+    if (ip == NOIP)
+        return false;
+    // connect to socket
+    bool ok = false; 
+    LOCK();
+    if (ISSOCKET(socket) && (!_sockets[socket].connected)) {
+        TRACE("socketConnect(%d,%s,%d)\r\n", socket,host,port);
+        sendFormated("AT+USOCO=%d,\"" IPSTR "\",%d\r\n", _sockets[socket].handle, IPNUM(ip), port);
+        if (RESP_OK == waitFinalResp())
+            ok = _sockets[socket].connected = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::socketIsConnected(int socket)
+{
+    bool ok = false;
+    LOCK();
+    TRACE("socketIsConnected(%d)\r\n", socket);
+    ok = ISSOCKET(socket) && _sockets[socket].connected;
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::socketSetBlocking(int socket, int timeout_ms)
+{
+    bool ok = false;
+    LOCK();
+    TRACE("socketSetBlocking(%d,%d)\r\n", socket,timeout_ms);
+    if (ISSOCKET(socket)) {
+        _sockets[socket].timeout_ms = timeout_ms;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool  MDMParser::socketClose(int socket)
+{
+    bool ok = false;
+    LOCK();
+    if (ISSOCKET(socket) && _sockets[socket].connected) {
+        TRACE("socketClose(%d)\r\n", socket);
+        sendFormated("AT+USOCL=%d\r\n", _sockets[socket].handle);
+        if (RESP_OK == waitFinalResp()) {
+            _sockets[socket].connected = false;
+            ok = true;
+        }
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool  MDMParser::socketFree(int socket)
+{
+    // make sure it is closed
+    socketClose(socket);
+    bool ok = true;
+    LOCK();
+    if (ISSOCKET(socket)) {
+        TRACE("socketFree(%d)\r\n",  socket);
+        _sockets[socket].handle     = SOCKET_ERROR;
+        _sockets[socket].timeout_ms = TIMEOUT_BLOCKING;
+        _sockets[socket].connected  = false;
+        _sockets[socket].pending    = 0;
+        ok = true;
+    }
+    UNLOCK();
+    return ok;
+}
+
+#define USO_MAX_WRITE 1024 //!< maximum number of bytes to write to socket
+
+int MDMParser::socketSend(int socket, const char * buf, int len)
+{
+    TRACE("socketSend(%d,%s,%d)\r\n", socket,buf,len);
+    int cnt = len;
+    while (cnt > 0) {
+        int blk = USO_MAX_WRITE;
+        if (cnt < blk) 
+            blk = cnt;
+        bool ok = false;
+        LOCK();
+        if (ISSOCKET(socket)) {
+            sendFormated("AT+USOWR=%d,%d\r\n",_sockets[socket].handle,blk);
+            if (RESP_PROMPT == waitFinalResp()) {
+                wait_ms(50);
+                TRACE("SENT: %s", buf);
+                send(buf, blk);
+                if (RESP_OK == waitFinalResp()) 
+                    ok = true;
+            }
+        }
+        UNLOCK();
+        if (!ok) 
+            return SOCKET_ERROR;
+        buf += blk;
+        cnt -= blk;
+    }
+    return (len - cnt);
+}
+
+int MDMParser::socketSendTo(int socket, IP ip, int port, const char * buf, int len)
+{
+    TRACE("socketSendTo(%d," IPSTR ",%d,,%d)\r\n", socket,IPNUM(ip),port,len);
+    int cnt = len;
+    while (cnt > 0) {
+        int blk = USO_MAX_WRITE;
+        if (cnt < blk) 
+            blk = cnt;
+        bool ok = false;
+        LOCK();
+        if (ISSOCKET(socket)) {
+            sendFormated("AT+USOST=%d,\"" IPSTR "\",%d,%d\r\n",_sockets[socket].handle,IPNUM(ip),port,blk);
+            if (RESP_PROMPT == waitFinalResp()) {
+                wait_ms(50);
+                send(buf, blk);
+                if (RESP_OK == waitFinalResp())
+                    ok = true;
+            }
+        }
+        UNLOCK();
+        if (!ok)
+            return SOCKET_ERROR;
+        buf += blk;
+        cnt -= blk;
+    }
+    return (len - cnt);
+}
+
+int MDMParser::socketReadable(int socket)
+{
+    int pending = SOCKET_ERROR;
+    LOCK();
+    if (ISSOCKET(socket) && _sockets[socket].connected) {
+        TRACE("socketReadable(%d)\r\n", socket);
+        // allow to receive unsolicited commands 
+        waitFinalResp(NULL, NULL, 0);
+        if (_sockets[socket].connected)
+           pending = _sockets[socket].pending; 
+    }
+    UNLOCK();
+    return pending;
+}
+
+int MDMParser::_cbUSORD(int type, const char* buf, int len, char* out)
+{
+    if ((type == TYPE_PLUS) && out) {
+        int sz, sk;
+        if ((sscanf(buf, "\r\n+USORD: %d,%d,", &sk, &sz) == 2) && 
+            (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
+            memcpy(out, &buf[len-1-sz], sz);
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::socketRecv(int socket, char* buf, int len)
+{
+    int cnt = 0;
+    TRACE("socketRecv(%d,,%d)\r\n", socket, len);
+#ifdef MDM_DEBUG
+    memset(buf, '\0', len);
+#endif
+    Timer timer;
+    timer.start();
+    while (len) {
+        int blk = MAX_SIZE; // still need space for headers and unsolicited  commands 
+        if (len < blk) blk = len;
+        bool ok = false;        
+        LOCK();
+        if (ISSOCKET(socket)) {
+            if (_sockets[socket].connected) {
+                if (_sockets[socket].pending < blk)
+                    blk = _sockets[socket].pending;
+                if (blk > 0) {
+                    sendFormated("AT+USORD=%d,%d\r\n",_sockets[socket].handle, blk);
+                    if (RESP_OK == waitFinalResp(_cbUSORD, buf)) {
+                        _sockets[socket].pending -= blk;
+                        len -= blk;
+                        cnt += blk;
+                        buf += blk;
+                        ok = true;
+                    }
+                } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
+                    ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
+                } else {
+                    len = 0;
+                    ok = true;
+                }
+            } else {
+                len = 0;
+                ok = true;
+            }
+        }
+        UNLOCK();
+        if (!ok)
+            return SOCKET_ERROR;
+    }
+    return cnt;
+}
+
+int MDMParser::_cbUSORF(int type, const char* buf, int len, USORFparam* param)
+{
+    if ((type == TYPE_PLUS) && param) {
+        int sz, sk, p, a,b,c,d;
+        int r = sscanf(buf, "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,", 
+            &sk,&a,&b,&c,&d,&p,&sz);
+        if ((r == 7) && (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
+            memcpy(param->buf, &buf[len-1-sz], sz);
+            param->ip = IPADR(a,b,c,d);
+            param->port = p;
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len)
+{
+    int cnt = 0;
+    TRACE("socketRecvFrom(%d,,%d)\r\n", socket, len);
+#ifdef MDM_DEBUG
+    memset(buf, '\0', len);
+#endif
+    Timer timer;
+    timer.start();
+    while (len) {
+        int blk = MAX_SIZE; // still need space for headers and unsolicited commands 
+        if (len < blk) blk = len;
+        bool ok = false;        
+        LOCK();
+        if (ISSOCKET(socket)) {
+            if (_sockets[socket].pending < blk)
+                blk = _sockets[socket].pending;
+            if (blk > 0) {
+                sendFormated("AT+USORF=%d,%d\r\n",_sockets[socket].handle, blk);
+                USORFparam param;
+                param.buf = buf;
+                if (RESP_OK == waitFinalResp(_cbUSORF, &param)) {
+                    _sockets[socket].pending -= blk;
+                    *ip = param.ip;
+                    *port = param.port;
+                    len -= blk;
+                    cnt += blk;
+                    buf += blk;
+                    len = 0; // done 
+                    ok = true;
+                }
+            } else if (!TIMEOUT(timer, _sockets[socket].timeout_ms)) {
+                ok = (WAIT == waitFinalResp(NULL,NULL,0)); // wait for URCs
+            } else {
+                len = 0; // no more data and socket closed or timed-out
+                ok = true;
+            }
+        }
+        UNLOCK();
+        if (!ok)
+            return SOCKET_ERROR;
+    }
+    timer.stop();
+    timer.reset();
+    return cnt;
+}
+
+int MDMParser::_findSocket(int handle) {
+    for (int socket = 0; socket < NUMSOCKETS; socket ++) {
+        if (_sockets[socket].handle == handle)
+            return socket;
+    }
+    return SOCKET_ERROR;
+}
+
+// ----------------------------------------------------------------
+
+int MDMParser::_cbCMGL(int type, const char* buf, int len, CMGLparam* param)
+{ 
+    if ((type == TYPE_PLUS) && param && param->num) {
+        // +CMGL: <ix>,...
+        int ix;
+        if (sscanf(buf, "\r\n+CMGL: %d,", &ix) == 1)
+        {
+            *param->ix++ = ix;
+            param->num--;
+        }
+    }
+    return WAIT;
+}
+
+int MDMParser::smsList(const char* stat /*= "ALL"*/, int* ix /*=NULL*/, int num /*= 0*/) {
+    int ret = -1;
+    LOCK();
+    sendFormated("AT+CMGL=\"%s\"\r\n", stat);
+    CMGLparam param;
+    param.ix = ix;
+    param.num = num;
+    if (RESP_OK == waitFinalResp(_cbCMGL, &param))
+        ret = num - param.num;
+    UNLOCK();
+    return ret;
+}
+
+bool MDMParser::smsSend(const char* num, const char* buf)
+{
+    bool ok = false;
+    LOCK();
+    sendFormated("AT+CMGS=\"%s\"\r\n",num);
+    if (RESP_PROMPT == waitFinalResp(NULL,NULL,150*1000)) {
+        send(buf, strlen(buf));
+        const char ctrlZ = 0x1A;
+        send(&ctrlZ, sizeof(ctrlZ));
+        ok = (RESP_OK == waitFinalResp());
+    }
+    UNLOCK();
+    return ok;
+}
+
+bool MDMParser::smsDelete(int ix)
+{
+    bool ok = false;
+    LOCK();
+    sendFormated("AT+CMGD=%d\r\n",ix);
+    ok = (RESP_OK == waitFinalResp());
+    UNLOCK();
+    return ok;
+}
+
+int MDMParser::_cbCMGR(int type, const char* buf, int len, CMGRparam* param)
+{
+    if (param) {
+        if (type == TYPE_PLUS) {
+            if (sscanf(buf, "\r\n+CMGR: \"%*[^\"]\",\"%[^\"]", param->num) == 1) {
+            }
+        } else if ((type == TYPE_UNKNOWN) && (buf[len-2] == '\r') && (buf[len-1] == '\n')) {
+            memcpy(param->buf, buf, len-2);
+            param->buf[len-2] = '\0';
+        }
+    }
+    return WAIT;
+}
+
+bool MDMParser::smsRead(int ix, char* num, char* buf, int len)
+{
+    bool ok = false;
+    LOCK();
+    CMGRparam param;
+    param.num = num;
+    param.buf = buf;
+    sendFormated("AT+CMGR=%d\r\n",ix);
+    ok = (RESP_OK == waitFinalResp(_cbCMGR, &param));
+    UNLOCK();
+    return ok;
+}
+   
+// ----------------------------------------------------------------
+  
+int MDMParser::_cbCUSD(int type, const char* buf, int len, char* resp)
+{
+    if ((type == TYPE_PLUS) && resp) {
+        // +USD: \"%*[^\"]\",\"%[^\"]\",,\"%*[^\"]\",%d,%d,%d,%d,\"*[^\"]\",%d,%d"..);
+        if (sscanf(buf, "\r\n+CUSD: %*d,\"%[^\"]\",%*d", resp) == 1) {
+            /*nothing*/            
+        }
+    }
+    return WAIT;
+}  
+
+bool MDMParser::ussdCommand(const char* cmd, char* buf)
+{
+    bool ok = false;
+    LOCK();
+    *buf = '\0';
+    if (_dev.dev != DEV_LISA_C200) {
+        sendFormated("AT+CUSD=1,\"%s\"\r\n",cmd);
+        ok = (RESP_OK == waitFinalResp(_cbCUSD, buf));
+    }
+    UNLOCK();
+    return ok;
+}
+
+// ----------------------------------------------------------------
+   
+bool MDMParser::delFile(const char* filename)
+{
+    bool ok = false;
+    LOCK();
+    sendFormated("AT+UDELFILE=\"%s\"\r\n", filename);
+    ok = (RESP_OK == waitFinalResp());
+    UNLOCK();
+    return ok;
+}
+
+int MDMParser::writeFile(const char* filename, const char* buf, int len)
+{
+    bool ok = false;
+    LOCK();
+    sendFormated("AT+UDWNFILE=\"%s\",%d\r\n", filename, len);
+    if (RESP_PROMPT == waitFinalResp()) {
+        send(buf, len);
+        ok = (RESP_OK == waitFinalResp());
+    }
+    UNLOCK();
+    return ok ? len : -1;
+}
+
+int MDMParser::readFile(const char* filename, char* buf, int len)
+{
+    URDFILEparam param;
+    param.filename = filename;
+    param.buf = buf; 
+    param.sz = len; 
+    param.len = 0;
+    LOCK();
+    sendFormated("AT+URDFILE=\"%s\"\r\n", filename, len);
+    if (RESP_OK != waitFinalResp(_cbURDFILE, &param))
+        param.len = -1;
+    UNLOCK();
+    return param.len;
+}
+
+int MDMParser::_cbURDFILE(int type, const char* buf, int len, URDFILEparam* param)
+{
+    if ((type == TYPE_PLUS) && param && param->filename && param->buf) {
+        char filename[48];
+        int sz;
+        if ((sscanf(buf, "\r\n+URDFILE: \"%[^\"]\",%d,", filename, &sz) == 2) && 
+            (0 == strcmp(param->filename, filename)) &&
+            (buf[len-sz-2] == '\"') && (buf[len-1] == '\"')) {
+            param->len = (sz < param->sz) ? sz : param->sz;
+            memcpy(param->buf, &buf[len-1-sz], param->len);
+        }
+    }
+    return WAIT;
+}
+  
+// ----------------------------------------------------------------
+bool MDMParser::setDebug(int level) 
+{
+#ifdef MDM_DEBUG
+    if ((_debugLevel >= 0) && (level >= 0)) {
+        _debugLevel = level;
+        return true;
+    }
+#endif
+    return false;
+}
+
+void MDMParser::dumpDevStatus(MDMParser::DevStatus* status, 
+            _DPRINT dprint, void* param) 
+{
+    dprint(param, "Modem::devStatus\r\n");
+    const char* txtDev[] = { "Unknown", "SARA-G350", "LISA-U200", "LISA-C200", "SARA-U260", "SARA-U270", "LEON-G200" };
+    if (status->dev < sizeof(txtDev)/sizeof(*txtDev) && (status->dev != DEV_UNKNOWN))
+        dprint(param, "  Device:       %s\r\n", txtDev[status->dev]);
+    const char* txtLpm[] = { "Disabled", "Enabled", "Active" };
+    if (status->lpm < sizeof(txtLpm)/sizeof(*txtLpm))
+        dprint(param, "  Power Save:   %s\r\n", txtLpm[status->lpm]);
+    const char* txtSim[] = { "Unknown", "Missing", "Pin", "Ready" };
+    if (status->sim < sizeof(txtSim)/sizeof(*txtSim) && (status->sim != SIM_UNKNOWN))
+        dprint(param, "  SIM:          %s\r\n", txtSim[status->sim]);
+    if (*status->ccid)  
+        dprint(param, "  CCID:         %s\r\n", status->ccid);
+    if (*status->imei) 
+        dprint(param, "  IMEI:         %s\r\n", status->imei);
+    if (*status->imsi)  
+        dprint(param, "  IMSI:         %s\r\n", status->imsi);
+    if (*status->meid) 
+        dprint(param, "  MEID:         %s\r\n", status->meid); // LISA-C
+    if (*status->manu) 
+        dprint(param, "  Manufacturer: %s\r\n", status->manu);
+    if (*status->model)  
+        dprint(param, "  Model:        %s\r\n", status->model);
+    if (*status->ver)  
+        dprint(param, "  Version:      %s\r\n", status->ver);
+}
+
+void MDMParser::dumpNetStatus(MDMParser::NetStatus *status,
+            _DPRINT dprint, void* param)
+{
+    dprint(param, "Modem::netStatus\r\n");
+    const char* txtReg[] = { "Unknown", "Denied", "None", "Home", "Roaming" };
+    if (status->csd < sizeof(txtReg)/sizeof(*txtReg) && (status->csd != REG_UNKNOWN))
+        dprint(param, "  CSD Registration:   %s\r\n", txtReg[status->csd]);
+    if (status->psd < sizeof(txtReg)/sizeof(*txtReg) && (status->psd != REG_UNKNOWN))
+        dprint(param, "  PSD Registration:   %s\r\n", txtReg[status->psd]);
+    const char* txtAct[] = { "Unknown", "GSM", "Edge", "3G", "CDMA" };
+    if (status->act < sizeof(txtAct)/sizeof(*txtAct) && (status->act != ACT_UNKNOWN))
+        dprint(param, "  Access Technology:  %s\r\n", txtAct[status->act]);
+    if (status->rssi) 
+        dprint(param, "  Signal Strength:    %d dBm\r\n", status->rssi);
+    if (status->ber) 
+        dprint(param, "  Bit Error Rate:     %d\r\n", status->ber);
+    if (*status->opr)  
+        dprint(param, "  Operator:           %s\r\n", status->opr);
+    if (status->lac != 0xFFFF)  
+        dprint(param, "  Location Area Code: %04X\r\n", status->lac);
+    if (status->ci != 0xFFFFFFFF)  
+        dprint(param, "  Cell ID:            %08X\r\n", status->ci);
+    if (*status->num)  
+        dprint(param, "  Phone Number:       %s\r\n", status->num);
+}
+
+void MDMParser::dumpIp(MDMParser::IP ip,
+            _DPRINT dprint, void* param) 
+{
+    if (ip != NOIP)
+        dprint(param, "Modem:IP " IPSTR "\r\n", IPNUM(ip));
+}
+    
+// ----------------------------------------------------------------
+int MDMParser::_parseMatch(Pipe<char>* pipe, int len, const char* sta, const char* end)
+{
+    int o = 0;
+    if (sta) {
+        while (*sta) {
+            if (++o > len)                  return WAIT;
+            char ch = pipe->next();
+            if (*sta++ != ch)               return NOT_FOUND;
+        }
+    }
+    if (!end)                               return o; // no termination
+    // at least any char
+    if (++o > len)                      return WAIT;
+    pipe->next();
+    // check the end     
+    int x = 0;
+    while (end[x]) {
+        if (++o > len)                      return WAIT;
+        char ch = pipe->next();
+        x = (end[x] == ch) ? x + 1 : 
+            (end[0] == ch) ? 1 : 
+                            0;
+    }
+    return o;
+}
+
+int MDMParser::_parseFormated(Pipe<char>* pipe, int len, const char* fmt)
+{
+    int o = 0;
+    int num = 0;
+    if (fmt) {
+        while (*fmt) {
+            if (++o > len)                  return WAIT;
+            char ch = pipe->next();
+            if (*fmt == '%') {
+                fmt++;
+                if (*fmt == 'd') { // numeric
+                    fmt ++;
+                    num = 0;
+                    while (ch >= '0' && ch <= '9') {
+                        num = num * 10 + (ch - '0'); 
+                        if (++o > len)      return WAIT;
+                        ch = pipe->next();
+                    }
+                }   
+                else if (*fmt == 'c') { // char buffer (takes last numeric as length)
+                    fmt ++;
+                    while (num --) {
+                        if (++o > len)      return WAIT;
+                        ch = pipe->next();
+                    }   
+                }
+                else if (*fmt == 's') {
+                    fmt ++;
+                    if (ch != '\"')         return NOT_FOUND;
+                    do {
+                        if (++o > len)      return WAIT;
+                        ch = pipe->next();
+                    } while (ch != '\"');
+                    if (++o > len)          return WAIT;
+                    ch = pipe->next();
+                }
+            }
+            if (*fmt++ != ch)               return NOT_FOUND;
+        }
+    }
+    return o; 
+}
+
+int MDMParser::_getLine(Pipe<char>* pipe, char* buf, int len)
+{
+    int unkn = 0;
+    int sz = pipe->size();
+    int fr = pipe->free();
+    if (len > sz)
+        len = sz;
+    while (len > 0)
+    {
+        static struct { 
+              const char* fmt;                              int type; 
+        } lutF[] = {
+            { "\r\n+USORD: %d,%d,\"%c\"",                   TYPE_PLUS       },
+            { "\r\n+USORF: %d,\"" IPSTR "\",%d,%d,\"%c\"",  TYPE_PLUS       },
+            { "\r\n+URDFILE: %s,%d,\"%c\"",                 TYPE_PLUS       },
+        };
+        static struct { 
+              const char* sta;          const char* end;    int type; 
+        } lut[] = {
+            { "\r\nOK\r\n",             NULL,               TYPE_OK         },
+            { "\r\nERROR\r\n",          NULL,               TYPE_ERROR      },
+            { "\r\n+CME ERROR:",        "\r\n",             TYPE_ERROR      }, 
+            { "\r\n+CMS ERROR:",        "\r\n",             TYPE_ERROR      },
+            { "\r\nRING\r\n",           NULL,               TYPE_RING       },
+            { "\r\nCONNECT\r\n",        NULL,               TYPE_CONNECT    },
+            { "\r\nNO CARRIER\r\n",     NULL,               TYPE_NOCARRIER  },
+            { "\r\nNO DIALTONE\r\n",    NULL,               TYPE_NODIALTONE },
+            { "\r\nBUSY\r\n",           NULL,               TYPE_BUSY       },
+            { "\r\nNO ANSWER\r\n",      NULL,               TYPE_NOANSWER   },
+            { "\r\n+",                  "\r\n",             TYPE_PLUS       },
+            { "\r\n@",                  NULL,               TYPE_PROMPT     }, // Sockets
+            { "\r\n>",                  NULL,               TYPE_PROMPT     }, // SMS
+            { "\n>",                    NULL,               TYPE_PROMPT     }, // File
+        };
+        for (int i = 0; i < sizeof(lutF)/sizeof(*lutF); i ++) {
+            pipe->set(unkn);
+            int ln = _parseFormated(pipe, len, lutF[i].fmt);
+            if (ln == WAIT && fr)                       
+                return WAIT;
+            if ((ln != NOT_FOUND) && (unkn > 0))  
+                return TYPE_UNKNOWN | pipe->get(buf, unkn);
+            if (ln > 0)
+                return lutF[i].type  | pipe->get(buf, ln);
+        }
+        for (int i = 0; i < sizeof(lut)/sizeof(*lut); i ++) {
+            pipe->set(unkn);
+            int ln = _parseMatch(pipe, len, lut[i].sta, lut[i].end);
+            if (ln == WAIT && fr)                       
+                return WAIT;
+            if ((ln != NOT_FOUND) && (unkn > 0))  
+                return TYPE_UNKNOWN | pipe->get(buf, unkn);
+            if (ln > 0)
+                return lut[i].type | pipe->get(buf, ln);
+        }
+        // UNKNOWN
+        unkn ++;
+        len--;
+    }
+    return WAIT;
+}
+
+// ----------------------------------------------------------------
+// Serial Implementation 
+// ----------------------------------------------------------------
+
+/*! Helper Dev Null Device 
+    Small helper class used to shut off stderr/stdout. Sometimes stdin/stdout
+    is shared with the serial port of the modem. Having printfs inbetween the 
+    AT commands you cause a failure of the modem.
+*/
+class DevNull : public Stream {
+public: 
+    DevNull() : Stream(_name+1) { }             //!< Constructor
+    void claim(const char* mode, FILE* file) 
+        { freopen(_name, mode, file); }         //!< claim a stream
+protected:
+    virtual int _getc()         { return EOF; } //!< Nothing
+    virtual int _putc(int c)    { return c; }   //!< Discard
+    static const char* _name;                   //!< File name
+};
+const char* DevNull::_name = "/null";  //!< the null device name
+static      DevNull null;              //!< the null device
+MDMSerial* MDMSerial::mdmInst;
+
+MDMSerial::MDMSerial(PinName tx /*= MDMTXD*/, PinName rx /*= MDMRXD*/, 
+            int baudrate /*= MDMBAUD*/,
+#if DEVICE_SERIAL_FC
+            PinName rts /*= MDMRTS*/, PinName cts /*= MDMCTS*/, 
+#endif
+            int rxSize /*= 256*/, int txSize /*= 128*/) : 
+            SerialPipe(tx, rx, rxSize, txSize) 
+{   mdmInst=this;
+    if (rx == USBRX) 
+        null.claim("r", stdin);
+    if (tx == USBTX) {
+        null.claim("w", stdout);
+        null.claim("w", stderr);
+#ifdef MDM_DEBUG
+        _debugLevel = -1;
+#endif
+    }
+#ifdef TARGET_UBLOX_C027
+    _onboard = (tx == MDMTXD) && (rx == MDMRXD);
+    if (_onboard)
+       c027_mdm_powerOn(false);
+#endif
+    baud(baudrate);
+#if DEVICE_SERIAL_FC
+    if ((rts != NC) || (cts != NC))
+    {
+        Flow flow = (cts == NC) ? RTS :
+                    (rts == NC) ? CTS : RTSCTS ;
+        set_flow_control(flow, rts, cts);
+        if (cts != NC) _dev.lpm = LPM_ENABLED;
+    }
+#endif
+}
+
+MDMSerial::~MDMSerial(void)
+{
+    powerOff();
+#ifdef TARGET_UBLOX_C027
+    if (_onboard)
+        c027_mdm_powerOff();
+#endif
+}
+
+int MDMSerial::_send(const void* buf, int len)   
+{ 
+    return put((const char*)buf, len, true/*=blocking*/);
+}
+
+int MDMSerial::getLine(char* buffer, int length)
+{
+    return _getLine(&_pipeRx, buffer, length);
+}
+
+// ----------------------------------------------------------------
+// USB Implementation 
+// ----------------------------------------------------------------
+
+#ifdef HAVE_MDMUSB
+MDMUsb::MDMUsb(void)                             
+{ 
+#ifdef MDM_DEBUG
+    _debugLevel = 1;
+#endif    
+#ifdef TARGET_UBLOX_C027
+    _onboard = true;
+    c027_mdm_powerOn(true);
+#endif
+}
+
+MDMUsb::~MDMUsb(void)
+{
+    powerOff();
+#ifdef TARGET_UBLOX_C027
+    if (_onboard)
+        c027_mdm_powerOff();
+#endif
+}
+
+int MDMUsb::_send(const void* buf, int len)      { return 0; }
+
+int MDMUsb::getLine(char* buffer, int length)    { return NOT_FOUND; }
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/MDM.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,664 @@
+#pragma once 
+
+#include "mbed.h"
+#include <stdarg.h>
+
+#include "Pipe.h"
+#include "SerialPipe.h"
+
+#ifdef TARGET_UBLOX_C027
+ #define MDM_IF(onboard,shield) onboard
+#else
+ #define MDM_IF(onboard,shield) shield
+#endif
+
+//! include debug capabilty on more powerful targets with a dedicated debug port 
+#if defined(TARGET_LPC1768) || defined(TARGET_LPC4088) || defined(TARGET_K64F)
+ #define MDM_DEBUG 
+#endif 
+
+/** basic modem parser class 
+*/
+class MDMParser
+{
+public:
+    //! Constructor 
+    MDMParser(void);
+    //! get static instance
+    static MDMParser* getInstance() { return inst; };
+    
+    // ----------------------------------------------------------------
+    // Types 
+    // ----------------------------------------------------------------
+    //! MT Device Types 
+    typedef enum { DEV_UNKNOWN, DEV_SARA_G350, DEV_LISA_U200, DEV_LISA_C200, 
+                   DEV_SARA_U260, DEV_SARA_U270, DEV_LEON_G200 } Dev; 
+    //! SIM Status
+    typedef enum { SIM_UNKNOWN, SIM_MISSING, SIM_PIN, SIM_READY } Sim;
+    //! SIM Status
+    typedef enum { LPM_DISABLED, LPM_ENABLED, LPM_ACTIVE } Lpm; 
+    //! Device status
+    typedef struct { 
+        Dev dev;            //!< Device Type
+        Lpm lpm;            //!< Power Saving 
+        Sim sim;            //!< SIM Card Status
+        char ccid[20+1];    //!< Integrated Circuit Card ID
+        char imsi[15+1];    //!< International Mobile Station Identity
+        char imei[15+1];    //!< International Mobile Equipment Identity
+        char meid[18+1];    //!< Mobile Equipment IDentifier
+        char manu[16];      //!< Manufacturer (u-blox)
+        char model[16];     //!< Model Name (LISA-U200, LISA-C200 or SARA-G350)
+        char ver[16];       //!< Software Version
+    } DevStatus;
+    //! Registration Status
+    typedef enum { REG_UNKNOWN, REG_DENIED, REG_NONE, REG_HOME, REG_ROAMING } Reg; 
+    //! Access Technology
+    typedef enum { ACT_UNKNOWN, ACT_GSM, ACT_EDGE, ACT_UTRAN, ACT_CDMA } AcT; 
+    //! Network Status
+    typedef struct { 
+        Reg csd;        //!< CSD Registration Status (Circuit Switched Data)
+        Reg psd;        //!< PSD Registration status (Packet Switched Data)
+        AcT act;        //!< Access Technology
+        int rssi;       //!< Received Signal Strength Indication (in dBm, range -113..-53)
+        int ber;        //!< Bit Error Rate (BER), see 3GPP TS 45.008 [20] subclause 8.2.4
+        char opr[16+1]; //!< Operator Name
+        char num[32];   //!< Mobile Directory Number
+        unsigned short lac;  //!< location area code in hexadecimal format (2 bytes in hex)
+        unsigned int ci;     //!< Cell ID in hexadecimal format (2 to 4 bytes in hex)
+    } NetStatus;
+    //! An IP v4 address
+    typedef uint32_t IP;
+    #define NOIP ((MDMParser::IP)0) //!< No IP address
+    // ip number formating and conversion
+    #define IPSTR           "%d.%d.%d.%d"
+    #define IPNUM(ip)       ((ip)>>24)&0xff, \
+                            ((ip)>>16)&0xff, \
+                            ((ip)>> 8)&0xff, \
+                            ((ip)>> 0)&0xff
+    #define IPADR(a,b,c,d) ((((IP)(a))<<24) | \
+                            (((IP)(b))<<16) | \
+                            (((IP)(c))<< 8) | \
+                            (((IP)(d))<< 0))
+
+    
+    // ----------------------------------------------------------------
+    // Device 
+    // ----------------------------------------------------------------
+    
+    typedef enum { AUTH_NONE, AUTH_PAP, AUTH_CHAP, AUTH_DETECT } Auth; 
+    
+    /** Combined Init, checkNetStatus, join suitable for simple applications
+        \param simpin a optional pin of the SIM card
+        \param apn  the of the network provider e.g. "internet" or "apn.provider.com"
+        \param username is the user name text string for the authentication phase
+        \param password is the password text string for the authentication phase
+        \param auth is the authentication mode (CHAP,PAP,NONE or DETECT)
+        \return true if successful, false otherwise
+    */
+    bool connect(const char* simpin = NULL, 
+            const char* apn = NULL, const char* username = NULL, 
+            const char* password = NULL, Auth auth = AUTH_DETECT,
+            PinName pn MDM_IF( = MDMPWRON, = D4));    
+
+    /** register (Attach) the MT to the GPRS service. 
+        \param simpin a optional pin of the SIM card
+        \param status an optional struture to with device information 
+        \return true if successful, false otherwise
+    */
+    bool init(const char* simpin = NULL, DevStatus* status = NULL, 
+                PinName pn MDM_IF( = MDMPWRON, = D4));
+    
+    /** register to the network 
+        \param status an optional structure to with network information 
+        \param timeout_ms -1 blocking, else non blocking timeout in ms
+        \return true if successful and connected to network, false otherwise
+    */
+    bool registerNet(NetStatus* status = NULL, int timeout_ms = 180000);
+    
+    /** check if the network is available 
+        \param status an optional structure to with network information 
+        \return true if successful and connected to network, false otherwise
+    */
+    bool checkNetStatus(NetStatus* status = NULL);
+    
+    /** Power off the MT, This function has to be called prior to 
+        switching off the supply. 
+        \return true if successfully, false otherwise
+    */ 
+    bool powerOff(void);
+    
+    // ----------------------------------------------------------------
+    // Data Connection (GPRS)
+    // ----------------------------------------------------------------
+    
+    /** register (Attach) the MT to the GPRS service. 
+        \param apn  the of the network provider e.g. "internet" or "apn.provider.com"
+        \param username is the user name text string for the authentication phase
+        \param password is the password text string for the authentication phase
+        \param auth is the authentication mode (CHAP,PAP,NONE or DETECT)
+        \return the ip that is assigned 
+    */
+    MDMParser::IP join(const char* apn = NULL, const char* username = NULL, 
+                       const char* password = NULL, Auth auth = AUTH_DETECT);
+    
+    /** deregister (detach) the MT from the GPRS service.
+        \return true if successful, false otherwise
+    */
+    bool disconnect(void);
+    
+    /** Translates a domain name to an IP address
+        \param host the domain name to translate e.g. "u-blox.com"
+        \return the IP if successful, 0 otherwise
+    */
+    MDMParser::IP gethostbyname(const char* host);
+    
+    // ----------------------------------------------------------------
+    // Sockets
+    // ----------------------------------------------------------------
+    
+    //! Type of IP protocol 
+    typedef enum { IPPROTO_TCP, IPPROTO_UDP } IpProtocol; 
+    
+    //! Socket error return codes
+    #define SOCKET_ERROR -1
+    
+    /** Create a socket for a ip protocol (and optionaly bind)
+        \param ipproto the protocol (UDP or TCP) 
+        \param port in case of UDP, this optional port where it is bind
+        \return the socket handle if successful or SOCKET_ERROR on failure 
+    */
+    int socketSocket(IpProtocol ipproto, int port = -1);
+    
+    /** make a socket connection
+        \param socket the socket handle
+        \param host the domain name to connect e.g. "u-blox.com"
+        \param port the port to connect
+        \return true if successfully, false otherwise
+    */
+    bool socketConnect(int socket, const char* host, int port);
+        
+    /** make a socket connection
+        \param socket the socket handle
+        \return true if connected, false otherwise
+    */
+    bool socketIsConnected(int socket);
+     
+    /** Get the number of bytes pending for reading for this socket
+        \param socket the socket handle
+        \param timeout_ms -1 blocking, else non blocking timeout in ms
+        \return 0 if successful or SOCKET_ERROR on failure 
+    */
+    bool socketSetBlocking(int socket, int timeout_ms);
+    
+    /** Write socket data 
+        \param socket the socket handle
+        \param buf the buffer to write
+        \param len the size of the buffer to write
+        \return the size written or SOCKET_ERROR on failure 
+    */
+    int socketSend(int socket, const char * buf, int len);
+    
+    /** Write socket data to a IP
+        \param socket the socket handle
+        \param ip the ip to send to
+        \param port the port to send to
+        \param buf the buffer to write
+        \param len the size of the buffer to write
+        \return the size written or SOCKET_ERROR on failure 
+    */
+    int socketSendTo(int socket, IP ip, int port, const char * buf, int len);
+    
+    /** Get the number of bytes pending for reading for this socket
+        \param socket the socket handle
+        \return the number of bytes pending or SOCKET_ERROR on failure 
+    */
+    int socketReadable(int socket);
+    
+    /** Read this socket
+        \param socket the socket handle
+        \param buf the buffer to read into
+        \param len the size of the buffer to read into
+        \return the number of bytes read or SOCKET_ERROR on failure 
+    */
+    int socketRecv(int socket, char* buf, int len);
+    
+    /** Read from this socket
+        \param socket the socket handle
+        \param ip the ip of host where the data originates from
+        \param port the port where the data originates from
+        \param buf the buffer to read into
+        \param len the size of the buffer to read into
+        \return the number of bytes read or SOCKET_ERROR on failure 
+    */
+    int socketRecvFrom(int socket, IP* ip, int* port, char* buf, int len);
+    
+    /** Close a connectied socket (that was connected with #socketConnect)
+        \param socket the socket handle
+        \return true if successfully, false otherwise
+    */    
+    bool socketClose(int socket);
+    
+    /** Free the socket (that was allocated before by #socketSocket)
+        \param socket the socket handle
+        \return true if successfully, false otherwise
+    */    
+    bool socketFree(int socket);
+        
+    // ----------------------------------------------------------------
+    // SMS Short Message Service
+    // ----------------------------------------------------------------
+    
+    /** count the number of sms in the device and optionally return a 
+        list with indexes from the storage locations in the device.
+        \param stat what type of messages you can use use 
+                    "REC UNREAD", "REC READ", "STO UNSENT", "STO SENT", "ALL"
+        \param ix   list where to save the storage positions
+        \param num  number of elements in the list 
+        \return the number of messages, this can be bigger than num, -1 on failure
+    */
+    int smsList(const char* stat = "ALL", int* ix = NULL, int num = 0);
+    
+    /** Read a Message from a storage position
+        \param ix the storage position to read
+        \param num the originator address (~16 chars)
+        \param buf a buffer where to save the sm
+        \param len the length of the sm
+        \return true if successful, false otherwise
+    */
+    bool smsRead(int ix, char* num, char* buf, int len);
+    
+    /** Send a message to a recipient 
+        \param ix the storage position to delete
+        \return true if successful, false otherwise
+    */
+    bool smsDelete(int ix);
+    
+    /** Send a message to a recipient 
+        \param num the phone number of the recipient
+        \param buf the content of the message to sent
+        \return true if successful, false otherwise
+    */
+    bool smsSend(const char* num, const char* buf);
+    
+    // ----------------------------------------------------------------
+    // USSD Unstructured Supplementary Service Data
+    // ----------------------------------------------------------------
+    
+    /** Read a Message from a storage position
+        \param cmd the ussd command to send e.g "*#06#"
+        \param buf a buffer where to save the reply
+        \return true if successful, false otherwise
+    */
+    bool ussdCommand(const char* cmd, char* buf);
+    
+    // ----------------------------------------------------------------
+    // FILE 
+    // ----------------------------------------------------------------
+    
+    /** Delete a file in the local file system
+        \param filename the name of the file 
+        \return true if successful, false otherwise
+    */
+    bool delFile(const char* filename);
+    
+    /** Write some data to a file in the local file system
+        \param filename the name of the file 
+        \param buf the data to write 
+        \param len the size of the data to write
+        \return the number of bytes written
+    */
+    int writeFile(const char* filename, const char* buf, int len);
+    
+    /** REad a file from the local file system
+        \param filename the name of the file 
+        \param buf a buffer to hold the data 
+        \param len the size to read
+        \return the number of bytes read
+    */
+    int readFile(const char* filename, char* buf, int len);
+    
+    // ----------------------------------------------------------------
+    // DEBUG/DUMP status to standard out (printf)
+    // ----------------------------------------------------------------
+    
+    /*! Set the debug level 
+        \param level 0 = OFF, 1 = INFO(default), 2 = TRACE, 3 = ATCMD
+        \return true if successful, false not possible
+    */ 
+    bool setDebug(int level);
+
+    //! helper type for DPRINT
+    typedef int (*_DPRINT)(void* param, char const * format, ...);
+    
+    //! helper to declate templates and void versions
+#define _DUMP_TEMPLATE(func, type, arg) \
+    template<class T> \
+    inline void func(type arg, \
+                int (*dprint)( T* param, char const * format, ...), \
+                T* param) { func(arg, (_DPRINT)dprint, (void*)param); } \
+    static void func(type arg, \
+                _DPRINT dprint = (_DPRINT)fprintf, \
+                void* param = (void*)stdout);
+
+    /** dump the device status to stdout using printf
+        \param status the status to convert to textual form, 
+               unavailable fields are ommited (not printed)
+        \param dprint a function pointer
+        \param param  the irst argument passed to dprint
+    */
+    _DUMP_TEMPLATE(dumpDevStatus, MDMParser::DevStatus*, status)
+
+    /** dump the network status to stdout using printf
+        \param status the status to convert to textual form, 
+               unavailable fields are ommited (not printed)
+        \param dprint a function pointer
+        \param param  the irst argument passed to dprint
+    */
+    _DUMP_TEMPLATE(dumpNetStatus, MDMParser::NetStatus*, status)
+    
+    /** dump the ip address to stdout using printf
+        \param ip the ip to convert to textual form, 
+               unavailable fields are ommited (not printed)
+        \param dprint a function pointer
+        \param param  the irst argument passed to dprint
+    */
+    _DUMP_TEMPLATE(dumpIp, MDMParser::IP, ip)
+   
+    // ----------------------------------------------------------------
+    // Parseing
+    // ----------------------------------------------------------------
+    
+    enum { 
+        // waitFinalResp Responses
+        NOT_FOUND     =  0,
+        WAIT          = -1, // TIMEOUT
+        RESP_OK       = -2, 
+        RESP_ERROR    = -3,
+        RESP_PROMPT   = -4,
+    
+        // getLine Responses
+        #define LENGTH(x)  (x & 0x00FFFF) //!< extract/mask the length
+        #define TYPE(x)    (x & 0xFF0000) //!< extract/mask the type
+        
+        TYPE_UNKNOWN    = 0x000000,
+        TYPE_OK         = 0x110000,
+        TYPE_ERROR      = 0x120000,
+        TYPE_RING       = 0x210000,
+        TYPE_CONNECT    = 0x220000,
+        TYPE_NOCARRIER  = 0x230000,
+        TYPE_NODIALTONE = 0x240000,
+        TYPE_BUSY       = 0x250000,
+        TYPE_NOANSWER   = 0x260000,
+        TYPE_PROMPT     = 0x300000,
+        TYPE_PLUS       = 0x400000,
+        TYPE_TEXT       = 0x500000,
+        
+        // special timout constant
+        TIMEOUT_BLOCKING = -1
+    };
+    
+    /** Get a line from the physical interface. This function need 
+        to be implemented in a inherited class. Usually just calls 
+        #_getLine on the rx buffer pipe. 
+            
+        \param buf the buffer to store it
+        \param buf size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    virtual int getLine(char* buf, int len) = 0; 
+    
+    /* clear the pending input data
+    */
+    virtual void purge(void) = 0;
+    
+    /** Write data to the device 
+        \param buf the buffer to write
+        \param buf size of the buffer to write
+        \return bytes written
+    */
+    virtual int send(const char* buf, int len);
+    
+    /** Write formated date to the physical interface (printf style)
+        \param fmt the format string
+        \param .. variable arguments to be formated
+        \return bytes written
+    */
+    int sendFormated(const char* format, ...);
+    
+    /** callback function for #waitFinalResp with void* as argument
+        \param type the #getLine response
+        \param buf the parsed line
+        \param len the size of the parsed line
+        \param param the optional argument passed to #waitFinalResp
+        \return WAIT if processing should continue, 
+                any other value aborts #waitFinalResp and this retunr value retuned
+    */
+    typedef int (*_CALLBACKPTR)(int type, const char* buf, int len, void* param);
+    
+    /** Wait for a final respons
+        \param cb the optional callback function
+        \param param the optional callback function parameter
+        \param timeout_ms the timeout to wait (See Estimated command 
+               response time of AT manual)
+    */
+    int waitFinalResp(_CALLBACKPTR cb = NULL, 
+                      void* param = NULL, 
+                      int timeout_ms = 10000);
+
+    /** template version of #waitFinalResp when using callbacks, 
+        This template will allow the compiler to do type cheking but 
+        internally symply casts the arguments and call the (void*) 
+        version of #waitFinalResp.
+        \sa waitFinalResp
+    */ 
+    template<class T>
+    inline int waitFinalResp(int (*cb)(int type, const char* buf, int len, T* param), 
+                    T* param, 
+                    int timeout_ms = 10000) 
+    {
+        return waitFinalResp((_CALLBACKPTR)cb, (void*)param, timeout_ms);
+    }
+    
+protected:
+    /** Write bytes to the physical interface. This function should be 
+        implemented in a inherited class.
+        \param buf the buffer to write
+        \param buf size of the buffer to write
+        \return bytes written
+    */
+    virtual int _send(const void* buf, int len) = 0;
+
+    /** Helper: Parse a line from the receiving buffered pipe
+        \param pipe the receiving buffer pipe 
+        \param buf the parsed line
+        \param len the size of the parsed line
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */
+    static int _getLine(Pipe<char>* pipe, char* buffer, int length);
+    
+    /** Helper: Parse a match from the pipe
+        \param pipe the buffered pipe
+        \param number of bytes to parse at maximum, 
+        \param sta the starting string, NULL if none
+        \param end the terminating string, NULL if none
+        \return size of parsed match 
+    */   
+    static int _parseMatch(Pipe<char>* pipe, int len, const char* sta, const char* end);
+    
+    /** Helper: Parse a match from the pipe
+        \param pipe the buffered pipe
+        \param number of bytes to parse at maximum, 
+        \param fmt the formating string (%d any number, %c any char of last %d len)
+        \return size of parsed match
+    */   
+    static int _parseFormated(Pipe<char>* pipe, int len, const char* fmt);
+
+protected:
+    // for rtos over riding by useing Rtos<MDMxx> 
+    /** override in a rtos system, you us the wait function of a Thread
+        \param ms the number of milliseconds to wait
+    */
+    virtual void wait_ms(int ms)   { if (ms) ::wait_ms(ms); }
+    //! override the lock in a rtos system
+    virtual void lock(void)        { } 
+    //! override the unlock in a rtos system
+    virtual void unlock(void)      { } 
+protected:
+    // parsing callbacks for different AT commands and their parameter arguments
+    static int _cbString(int type, const char* buf, int len, char* str);
+    static int _cbInt(int type, const char* buf, int len, int* val);
+    // device
+    static int _cbATI(int type, const char* buf, int len, Dev* dev);
+    static int _cbCPIN(int type, const char* buf, int len, Sim* sim);
+    static int _cbCCID(int type, const char* buf, int len, char* ccid);
+    // network 
+    static int _cbCSQ(int type, const char* buf, int len, NetStatus* status);
+    static int _cbCOPS(int type, const char* buf, int len, NetStatus* status);
+    static int _cbCNUM(int type, const char* buf, int len, char* num);
+    static int _cbUACTIND(int type, const char* buf, int len, int* i);
+    static int _cbUDOPN(int type, const char* buf, int len, char* mccmnc);
+    // sockets
+    static int _cbCMIP(int type, const char* buf, int len, IP* ip);
+    static int _cbUPSND(int type, const char* buf, int len, int* act);
+    static int _cbUPSND(int type, const char* buf, int len, IP* ip);
+    static int _cbUDNSRN(int type, const char* buf, int len, IP* ip);
+    static int _cbUSOCR(int type, const char* buf, int len, int* handle);
+    static int _cbUSORD(int type, const char* buf, int len, char* out);
+    typedef struct { char* buf; IP ip; int port; } USORFparam;
+    static int _cbUSORF(int type, const char* buf, int len, USORFparam* param);
+    typedef struct { char* buf; char* num; } CMGRparam;
+    static int _cbCUSD(int type, const char* buf, int len, char* buf);
+    // sms
+    typedef struct { int* ix; int num; } CMGLparam;
+    static int _cbCMGL(int type, const char* buf, int len, CMGLparam* param);
+    static int _cbCMGR(int type, const char* buf, int len, CMGRparam* param);
+    // file
+    typedef struct { const char* filename; char* buf; int sz; int len; } URDFILEparam;
+    static int _cbURDFILE(int type, const char* buf, int len, URDFILEparam* param);
+    // variables
+    DevStatus   _dev; //!< collected device information
+    NetStatus   _net; //!< collected network information 
+    IP          _ip;  //!< assigned ip address
+    // management struture for sockets
+    typedef struct { int handle; int timeout_ms; volatile bool connected; volatile int pending; } SockCtrl;
+    // LISA-C has 6 TCP and 6 UDP sockets 
+    // LISA-U and SARA-G have 7 sockets
+    SockCtrl _sockets[12];
+    int _findSocket(int handle = SOCKET_ERROR/* = CREATE*/);
+    static MDMParser* inst;
+    bool _init;
+#ifdef TARGET_UBLOX_C027
+    bool _onboard;
+#endif
+#ifdef MDM_DEBUG
+    int _debugLevel;
+    Timer _debugTime;
+#endif
+};
+
+// -----------------------------------------------------------------------
+
+/** modem class which uses a serial port 
+    as physical interface. 
+*/
+class MDMSerial :  public SerialPipe, public MDMParser
+{
+public: 
+    /** Constructor
+    
+        \param tx is the serial ports transmit pin (modem to CPU)
+        \param rx is the serial ports receive pin (CPU to modem)
+        \param baudrate the baudrate of the modem use 115200
+        \param rts is the serial ports ready to send pin (CPU to modem) 
+               this pin is optional 
+        \param cts is the serial ports clear to send pin (modem to CPU) 
+               this pin is optional, but required for power saving to be enabled
+        \param rxSize the size of the serial rx buffer
+        \param txSize the size of the serial tx buffer
+    */
+    MDMSerial(PinName tx    MDM_IF( = MDMTXD,  = D1 ), 
+              PinName rx    MDM_IF( = MDMRXD,  = D0 ), 
+              int baudrate  MDM_IF( = MDMBAUD, = 115200 ),
+ #if DEVICE_SERIAL_FC
+              PinName rts   MDM_IF( = MDMRTS,  = NC /* D2 resistor R62 on shield not mounted */ ), 
+              PinName cts   MDM_IF( = MDMCTS,  = NC /* D3 resistor R63 on shield not mounted */ ),
+ #endif
+              int rxSize    = 256 , 
+              int txSize    = 128 );
+ static MDMSerial* getMDMInstance() { return mdmInst; };
+ 
+    //! Destructor          
+    virtual ~MDMSerial(void);
+    
+    /** Get a line from the physical interface. 
+        \param buf the buffer to store it
+        \param buf size of the buffer
+        \return type and length if something was found, 
+                WAIT if not enough data is available
+                NOT_FOUND if nothing was found
+    */ 
+    virtual int getLine(char* buffer, int length);
+    
+    /* clear the pending input data */
+    virtual void purge(void) 
+    { 
+        while (readable())
+            getc();
+    }
+protected:
+   static MDMSerial* mdmInst;
+   int oil_level;
+    /** Write bytes to the physical interface.
+        \param buf the buffer to write
+        \param buf size of the buffer to write
+        \return bytes written
+    */
+    virtual int _send(const void* buf, int len);
+};
+
+// -----------------------------------------------------------------------
+
+//#define HAVE_MDMUSB
+#ifdef HAVE_MDMUSB
+class MDMUsb :  /*public UsbSerial,*/ public MDMParser
+{
+public: 
+    //! Constructor          
+    MDMUsb(void);
+    //! Destructor          
+    virtual ~MDMUsb(void);
+    virtual int getLine(char* buffer, int length);
+    virtual void purge(void) { }
+protected:
+    virtual int _send(const void* buf, int len);
+};
+#endif
+
+// -----------------------------------------------------------------------
+
+#ifdef RTOS_H
+/** Use this template to override the lock and wait functions of the 
+    modem driver in a Rtos system. For example declare it the modem 
+    object as MDMRtos<MDMSerial> instead of MDMSerial.
+*/
+template <class T>
+class MDMRtos :  public T
+{
+protected:
+    //! we assume that the modem runs in a thread so we yield when waiting
+    virtual void wait_ms(int ms)   {
+        if (ms) Thread::wait(ms);
+        else    Thread::yield();
+    }
+    //! lock a mutex when accessing the modem
+    virtual void lock(void)     { _mtx.lock(); }  
+    //! unlock the modem when done accessing it
+    virtual void unlock(void)   { _mtx.unlock(); }
+    // the mutex resource
+    Mutex _mtx;
+};
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/MDMAPN.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,129 @@
+#pragma once 
+
+/* ----------------------------------------------------------------
+   APN stands for Access Point Name, a setting on your modem or phone
+   that identifies an external network your phone can access for data 
+   (e.g. 3G or 4G Internet service on your phone). 
+   
+   The APN settings can be forced when calling the join function.
+   Below is a list of known APNs that us used if no apn config 
+   is forced. This list could be extended by other settings.
+   
+   For further reading:
+   wiki apn: http://en.wikipedia.org/wiki/Access_Point_Name
+   wiki mcc/mnc: http://en.wikipedia.org/wiki/Mobile_country_code
+   google: https://www.google.de/search?q=APN+list   
+---------------------------------------------------------------- */
+
+//! helper to generate the APN string
+#define _APN(apn,username,password) apn "\0" username "\0" password "\0"
+
+//! helper to extract a field from the config string 
+#define _APN_GET(cfg) \
+    *cfg ? cfg : ""; \
+    cfg  += strlen(cfg) + 1
+                    
+//! APN lookup struct
+typedef struct { 
+    const char* mccmnc; //!< mobile country code (MCC) and mobile network code MNC  
+    const char* cfg;    //!< APN configuartion string, use _APN macro to generate
+} APN_t;
+
+//! default APN settings used by many networks
+static const char* apndef = _APN(,,)
+                            _APN("internet",,);
+
+/*! this is a list of special APNs for different network operators 
+    There is no need to enter the default apn internet in the table; 
+    apndef will be used if no entry matches.
+    
+    The APN without username/password have to be listed first.
+*/
+static const APN_t apnlut[] = {
+// MCC Country
+//  { /* Operator */ "MCC-MNC[,MNC]" _APN(APN,USERNAME,PASSWORD) },
+// MCC must be 3 digits
+// MNC must be either 2 or 3 digits
+// MCC must be separated by '-' from MNC, multiple MNC can be separated by ','
+
+// 460 China - CN
+    { /* CN Mobile */"460-00",  _APN("cmnet",,)
+                                _APN("cmwap",,) },
+    { /* Unicom */   "460-01",  _APN("3gnet",,)
+                                _APN("uninet","uninet","uninet") },
+                                
+// 262 Germany - DE
+    { /* T-Mobile */ "262-01",  _APN("internet.t-mobile","t-mobile","tm") },
+
+// 222 Italy - IT
+    { /* TIM */      "222-01",  _APN("ibox.tim.it",,) },
+    { /* Vodafone */ "222-10",  _APN("web.omnitel.it",,) },
+    { /* Wind */     "222-88",  _APN("internet.wind.biz",,) },
+
+// 440 Japan - JP
+    { /* Softbank */ "440-04,06,20,40,41,42,43,44,45,46,47,48,90,91,92,93,94,95"
+                         ",96,97,98"
+                                _APN("open.softbank.ne.jp","opensoftbank","ebMNuX1FIHg9d3DA")
+                                _APN("smile.world","dna1trop","so2t3k3m2a") },
+    { /* NTTDoCoMo */"440-09,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,"
+                         "28,29,30,31,32,33,34,35,36,37,38,39,58,59,60,61,62,63,"
+                         "64,65,66,67,68,69,87,99",
+                                _APN("bmobilewap",,) /*BMobile*/
+                                _APN("mpr2.bizho.net","Mopera U",) /* DoCoMo */
+                                _APN("bmobile.ne.jp","bmobile@wifi2","bmobile") /*BMobile*/ },
+
+// 293 Slovenia - SI
+    { /* Si.mobil */ "293-40",  _APN("internet.simobil.si",,) },
+    { /* Tusmobil */ "293-70",  _APN("internet.tusmobil.si",,) },
+
+// 228 Switzerland - CH
+    { /* Swisscom */ "228-01",  _APN("gprs.swisscom.ch",,) },
+    { /* Orange */   "228-03",  _APN("internet",,) /* contract */
+                                _APN("click",,)    /* pre-pay */ },
+
+// 234 United Kingdom - GB
+    { /* O2 */       "234-02,10,11",
+                                _APN("mobile.o2.co.uk","faster","web") /* contract */
+                                _APN("mobile.o2.co.uk","bypass","web") /* pre-pay */
+                                _APN("payandgo.o2.co.uk","payandgo","payandgo") },
+    { /* Vodafone */ "234-15",  _APN("internet","web","web")          /* contract */
+                                _APN("pp.vodafone.co.uk","wap","wap")  /* pre-pay */ },
+
+// 310 United States of America - US
+    { /* T-Mobile */ "310-026,260,490",
+                                _APN("epc.tmobile.com",,)
+                                _APN("fast.tmobile.com",,) /* LTE */ },
+    { /* AT&T */     "310-030,150,170,260,410,560,680",
+                                _APN("phone",,)
+                                _APN("wap.cingular","WAP@CINGULARGPRS.COM","CINGULAR1")
+                                _APN("isp.cingular","ISP@CINGULARGPRS.COM","CINGULAR1") },
+};
+
+inline const char* apnconfig(const char* imsi)
+{
+    const char* config = NULL;
+    if (imsi && *imsi) {
+        // many carriers use internet without username and password, os use this as default
+        // now try to lookup the setting for our table
+        for (int i = 0; i < sizeof(apnlut)/sizeof(*apnlut) && !config; i ++) {
+            const char* p = apnlut[i].mccmnc;
+            // check the MCC
+            if ((0 == memcmp(imsi, p, 3))) {
+                p += 3;
+                // check all the MNC, MNC length can be 2 or 3 digits
+                while (((p[0] == '-') || (p[0] == ',')) && 
+                        (p[1] >= '0') && (p[1] <= '9') && 
+                        (p[2] >= '0') && (p[2] <= '9') && !config) {
+                    int l = ((p[3] >= '0') && (p[3] <= '9')) ? 3 : 2;
+                    if (0 == memcmp(imsi+3,p+1,l))
+                        config = apnlut[i].cfg;
+                    p += 1 + l;
+                } 
+            }
+        }
+    }
+    // use default if not found
+    if (!config)
+        config = apndef;
+    return config;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/Pipe.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,242 @@
+#pragma once 
+
+/** pipe, this class implements a buffered pipe that can be savely 
+    written and read between two context. E.g. Written from a task 
+    and read from a interrupt.
+*/
+template <class T>
+class Pipe
+{
+public:
+    /* Constructor
+        \param n size of the pipe/buffer
+        \param b optional buffer that should be used. 
+                 if NULL the constructor will allocate a buffer of size n. 
+    */
+    Pipe(int n, T* b = NULL)
+    {
+        _a = b ? NULL : n ? new T[n] : NULL;
+        _r = 0;
+        _w = 0;
+        _b = b ? b : _a;
+        _s = n;
+    }    
+    /** Destructor 
+        frees a allocated buffer.
+    */
+    ~Pipe(void)
+    {
+        if (_a) 
+            delete [] _a;
+    }
+    
+    /* This function can be used during debugging to hexdump the 
+       content of a buffer to the stdout. 
+    */
+    void dump(void)
+    {
+        int o = _r;
+        printf("pipe: %d/%d ", size(), _s);
+        while (o != _w) {
+            T t = _b[o]; 
+            printf("%0*X", sizeof(T)*2, t);
+            o = _inc(o); 
+        }
+        printf("\n");
+    }
+    
+    // writing thread/context API
+    //------------------------------------------------------------- 
+    
+    /** Check if buffer is writeable (=not full)
+        \return true if writeable
+    */
+    bool writeable(void)
+    {
+        return free() > 0;
+    }
+    
+    /** Return the number of free elements in the buffer 
+        \return the number of free elements
+    */
+    int free(void)
+    {
+        int s = _r - _w;
+        if (s <= 0)
+            s += _s;
+        return s - 1;
+    }
+    
+    /* Add a single element to the buffer. (blocking)
+        \param c the element to add.
+        \return c
+    */
+    T putc(T c)
+    {
+        int i = _w;
+        int j = i;
+        i = _inc(i);
+        while (i == _r) // = !writeable() 
+            /* nothing / just wait */;
+        _b[j] = c;
+        _w = i; 
+        return c;
+    }
+    
+    /* Add a buffer of elements to the buffer.
+        \param p the elements to add
+        \param n the number elements to add from p
+        \param t set to true if blocking, false otherwise
+        \return number elements added 
+    */
+    int put(const T* p, int n, bool t = false)
+    {
+        int c = n;
+        while (c)
+        {
+            int f;
+            for (;;) // wait for space
+            {
+                f = free();
+                if (f > 0) break;     // data avail
+                if (!t) return n - c; // no more space and not blocking
+                /* nothing / just wait */;
+            }
+            // check free space
+            if (c < f) f = c;
+            int w = _w;
+            int m = _s - w; 
+            // check wrap
+            if (f > m) f = m;
+            memcpy(&_b[w], p, f);
+            _w = _inc(w, f);
+            c -= f;
+            p += f;
+        }
+        return n - c;
+    }
+    
+    // reading thread/context API
+    // --------------------------------------------------------
+    
+    /** Check if there are any emelemnt available (readble / not empty)
+        \return true if readable/not empty
+    */
+    bool readable(void)
+    {
+        return (_r != _w);
+    }
+    
+    /** Get the number of values available in the buffer
+        return the number of element available
+    */
+    int size(void)
+    {
+        int s = _w - _r;
+        if (s < 0)
+            s += _s;
+        return s;
+    }
+    
+    /** get a single value from buffered pipe (this function will block if no values available)
+        \return the element extracted
+    */
+    T getc(void)
+    {
+        int r = _r;
+        while (r == _w) // = !readable()
+            /* nothing / just wait */;
+        T t = _b[r];
+        _r = _inc(r);
+        return t;
+    }
+    
+    /*! get elements from the buffered pipe
+        \param p the elements extracted
+        \param n the maximum number elements to extract
+        \param t set to true if blocking, false otherwise
+        \return number elements extracted
+    */
+    int get(T* p, int n, bool t = false)
+    {
+        int c = n;
+        while (c)
+        {
+            int f;
+            for (;;) // wait for data
+            {
+                f = size();
+                if (f)  break;        // free space
+                if (!t) return n - c; // no space and not blocking
+                /* nothing / just wait */;
+            }
+            // check available data
+            if (c < f) f = c;
+            int r = _r;
+            int m = _s - r; 
+            // check wrap
+            if (f > m) f = m;
+            memcpy(p, &_b[r], f);
+            _r = _inc(r, f);
+            c -= f;
+            p += f;
+        }
+        return n - c;
+    }
+    
+    // the following functions are useful if you like to inspect 
+    // or parse the buffer in the reading thread/context
+    // --------------------------------------------------------
+    
+    /** set the parsing index and return the number of available 
+        elments starting this position.
+        \param ix the index to set.
+        \return the number of elements starting at this position 
+    */
+    int set(int ix) 
+    {
+        int sz = size();
+        ix = (ix > sz) ? sz : ix;
+        _o = _inc(_r, ix); 
+        return sz - ix;
+    }
+    
+    /** get the next element from parsing position and increment parsing index
+        \return the extracted element.
+    */
+    T next(void)
+    {
+        int o = _o;
+        T t = _b[o]; 
+        _o = _inc(o); 
+        return t; 
+    }
+    
+    /** commit the index, mark the current parsing index as consumed data.
+    */
+    void done(void) 
+    {
+        _r = _o; 
+    } 
+
+private:
+    /** increment the index
+        \param i index to increment
+        \param n the step to increment
+        \return the incremented index.
+    */
+    inline int _inc(int i, int n = 1)
+    {
+        i += n;
+        if (i >= _s)
+            i -= _s;
+        return i;
+    }
+
+    T*            _b; //!< buffer
+    T*            _a; //!< allocated buffer
+    int           _s; //!< size of buffer (s - 1) elements can be stored
+    volatile int  _w; //!< write index 
+    volatile int  _r; //!< read index 
+    int           _o; //!< offest index used by parsing functions  
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/SerialPipe.cpp	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,112 @@
+#pragma once 
+
+#include "SerialPipe.h"
+
+SerialPipe::SerialPipe(PinName tx, PinName rx, int rxSize, int txSize) : 
+            _SerialPipeBase(tx,rx), 
+            _pipeRx( (rx!=NC) ? rxSize : 0), 
+            _pipeTx( (tx!=NC) ? txSize : 0)
+{
+    if (rx!=NC)
+        attach(this, &SerialPipe::rxIrqBuf, RxIrq);
+}
+
+SerialPipe::~SerialPipe(void)
+{
+    attach(NULL, RxIrq);
+    attach(NULL, TxIrq);
+}
+
+// tx channel
+int SerialPipe::writeable(void)    
+{
+    return _pipeTx.free();
+}
+
+int SerialPipe::putc(int c)    
+{
+    c = _pipeTx.putc(c);
+    txStart();
+    return c;
+}
+
+int SerialPipe::put(const void* buffer, int length, bool blocking)    
+{ 
+    int count = length;
+    const char* ptr = (const char*)buffer;
+    if (count)
+    {
+        do
+        {
+            int written = _pipeTx.put(ptr, count, false);
+            if (written) {
+                ptr += written;
+                count -= written;
+                txStart();
+            }
+            else if (!blocking)
+                break;
+            /* nothing / just wait */;
+        }
+        while (count);
+    }
+    return (length - count);
+}
+
+void SerialPipe::txCopy(void)
+{
+    while (_SerialPipeBase::writeable() && _pipeTx.readable())
+    {
+        char c = _pipeTx.getc();
+        _SerialPipeBase::_base_putc(c);
+    }
+}
+
+void SerialPipe::txIrqBuf(void)
+{
+    txCopy();
+    // detach tx isr if we are done 
+    if (!_pipeTx.readable())
+        attach(NULL, TxIrq);
+}
+
+void SerialPipe::txStart(void)
+{
+    // disable the tx isr to avoid interruption
+    attach(NULL, TxIrq);
+    txCopy();
+    // attach the tx isr to handle the remaining data
+    if (_pipeTx.readable())
+        attach(this, &SerialPipe::txIrqBuf, TxIrq);
+}
+
+// rx channel
+int SerialPipe::readable(void)                      
+{ 
+    return _pipeRx.readable(); 
+} 
+
+int SerialPipe::getc(void)                          
+{ 
+    if (!_pipeRx.readable())
+        return EOF;
+    return _pipeRx.getc(); 
+} 
+
+int SerialPipe::get(void* buffer, int length, bool blocking) 
+{ 
+    return _pipeRx.get((char*)buffer,length,blocking); 
+}
+
+void SerialPipe::rxIrqBuf(void)
+{
+    while (_SerialPipeBase::readable())
+    {
+        char c = _SerialPipeBase::_base_getc();
+        if (_pipeRx.writeable())
+            _pipeRx.putc(c);
+        else 
+            /* overflow */;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/SerialPipe.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,80 @@
+#pragma once 
+
+#include "mbed.h"
+#include "Pipe.h"
+
+#define _SerialPipeBase SerialBase //!< base class used by this class
+
+/** Buffered serial interface (rtos capable/interrupt driven)
+*/
+class SerialPipe : public _SerialPipeBase
+{
+public:
+    /** Constructor
+        \param tx the trasmitting pin
+        \param rx the receiving pin
+        \param rxSize the size of the receiving buffer
+        \param txSize the size of the transmitting buffer
+    */
+    SerialPipe(PinName tx, PinName rx, int rxSize = 128, int txSize = 128);
+    
+    /** Destructor
+    */
+    virtual ~SerialPipe(void);
+    
+    // tx channel
+    //----------------------------------------------------
+    
+    /** check if writable 
+        return the number of free bytes
+    */
+    int writeable(void);
+    
+    /** send a character (blocking)
+        \param c the character to send
+        \return c
+    */
+    int putc(int c);
+    
+    /** send a buffer
+        \param buffer the buffer to send
+        \param length the size of the buffer to send
+        \param blocking, if true this function will block 
+               until all bytes placed in the buffer. 
+        \return the number of bytes written 
+    */
+    int put(const void* buffer, int length, bool blocking);
+    
+    // rx channel
+    //----------------------------------------------------
+    
+    /** check if readable
+        \return the size available in the buffer.
+    */
+    int readable(void);
+    
+    /** receive one character from the serial port (blocking)
+        \param the character received 
+    */
+    int getc(void);
+    
+    /** read a buffer from the serial port
+        \param pointer to the buffer to read.
+        \param length number of bytes to read 
+        \param blocking true if all bytes shall be read. false if only the available bytes.
+        \return the number of bytes read.
+    */
+    int get(void* buffer, int length, bool blocking);
+    
+protected:
+    //! receive interrupt routine
+    void rxIrqBuf(void);
+    //! transmit interrupt woutine 
+    void txIrqBuf(void);
+    //! start transmission helper
+    void txStart(void);
+    //! move bytes to hardware
+    void txCopy(void);
+    Pipe<char> _pipeRx; //!< receive pipe
+    Pipe<char> _pipeTx; //!< transmit pipe
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/Socket/Endpoint.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,65 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef ENDPOINT_H
+#define ENDPOINT_H
+
+#include "MDM.h"
+
+class UDPSocket;
+
+class Endpoint {
+    friend class UDPSocket;
+public:
+    Endpoint(void)  { 
+        _ip[0] = '\0'; 
+        _port = 0; 
+        _mdm = NULL; 
+    }
+    
+    void reset_address(void) { 
+        _ip[0] = '\0'; 
+        _port = 0; 
+    }
+    
+    int  set_address(const char* host, const int port) {
+        _ip[0] = '\0';
+        _port = 0;
+        if (_mdm == NULL)
+            _mdm = MDMParser::getInstance();
+        if (_mdm == NULL)
+            return -1;
+        // resove the host name (eventually does a dns lookup)
+        MDMParser::IP ip = _mdm->gethostbyname(host);
+        if (ip == NOIP)
+            return -1;
+        sprintf(_ip, IPSTR, IPNUM(ip));
+        _port = port;
+        return 0;
+    }
+    
+    char* get_address(void)     {   return _ip; }
+    
+    int get_port(void)          {   return _port; }
+    
+protected:
+    MDMParser* _mdm;
+    char _ip[17];
+    int _port;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/Socket/Socket.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,44 @@
+#ifndef SOCKET_H_
+#define SOCKET_H_
+
+#include "MDM.h"
+
+/** Socket file descriptor and select wrapper
+  */
+class Socket {
+public:
+    Socket() {
+        _socket  = -1;
+        _timeout_ms = MDMParser::TIMEOUT_BLOCKING;
+        _mdm     = NULL;
+    }
+    
+    void set_blocking(bool blocking, unsigned int timeout = 1500) {
+        _timeout_ms = blocking ? MDMParser::TIMEOUT_BLOCKING : (int)timeout;
+        if (_socket >= 0) {
+            _mdm->socketSetBlocking(_socket, _timeout_ms); 
+        }
+    }
+    
+    int close() {
+        bool ret = false;
+        if (_socket >= 0)
+        {
+            ret = _mdm->socketClose(_socket);
+            _mdm->socketFree(_socket);
+            _socket = -1;
+            _timeout_ms = MDMParser::TIMEOUT_BLOCKING;
+        }
+        return ret ? 0 : -1;
+    }
+    
+    ~Socket() { close(); }
+    
+protected:
+    int _socket;
+    int _timeout_ms;
+    MDMParser* _mdm;
+};
+
+
+#endif /* SOCKET_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/Socket/TCPSocketConnection.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,77 @@
+#ifndef TCPSOCKET_H
+#define TCPSOCKET_H
+
+#include "Socket.h"
+
+/** TCP socket connection
+ */
+class TCPSocketConnection: public Socket
+{
+    friend class TCPSocketServer;
+
+public:
+    /** TCP socket connection
+    */
+    TCPSocketConnection() {}
+
+    /** Connects this TCP socket to the server
+    \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS.
+    \param port The host's port to connect to.
+    \return 0 on success, -1 on failure.
+    */
+    int connect(const char* host, const int port)
+    {
+        if (_mdm == NULL)
+            _mdm = MDMParser::getInstance();
+        if (_mdm == NULL)
+            return -1;
+            
+        if (_socket < 0) {
+            _socket = _mdm->socketSocket(MDMParser::IPPROTO_TCP);
+            if (_socket < 0) {
+                return -1;
+            }
+        }
+    
+        _mdm->socketSetBlocking(_socket, _timeout_ms); 
+        if (!_mdm->socketConnect(_socket, host, port)) {
+            return -1;
+        }
+        return 0;
+    }
+    /** Check if the socket is connected
+    \return true if connected, false otherwise.
+    */
+    bool is_connected(void)                 { return _mdm->socketIsConnected(_socket); }
+
+    /** Send data to the remote host.
+    \param data The buffer to send to the host.
+    \param length The length of the buffer to send.
+    \return the number of written bytes on success (>=0) or -1 on failure
+     */
+    int send(char* data, int length)        { return _mdm->socketSend(_socket, data, length); }
+
+    /** Send all the data to the remote host.
+    \param data The buffer to send to the host.
+    \param length The length of the buffer to send.
+    \return the number of written bytes on success (>=0) or -1 on failure
+    */
+    int send_all(char* data, int length)    { return send(data,length); }
+
+    /** Receive data from the remote host.
+    \param data The buffer in which to store the data received from the host.
+    \param length The maximum length of the buffer.
+    \return the number of received bytes on success (>=0) or -1 on failure
+     */
+    int receive(char* data, int length)     { return _mdm->socketRecv(_socket, data, length); }
+
+    /** Receive all the data from the remote host.
+    \param data The buffer in which to store the data received from the host.
+    \param length The maximum length of the buffer.
+    \return the number of received bytes on success (>=0) or -1 on failure
+    */
+    int receive_all(char* data, int length) { return receive(data,length); }
+    
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support/Socket/UDPSocket.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,79 @@
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef UDPSOCKET_H
+#define UDPSOCKET_H
+
+#include "Socket/Socket.h"
+#include "Socket/Endpoint.h"
+
+/**
+UDP Socket
+*/
+class UDPSocket : public Socket {
+
+public:
+    int init(void) 
+    {
+        if (_mdm == NULL)
+            _mdm = MDMParser::getInstance();
+        if (_mdm == NULL)
+            return -1;
+        return 0;
+    }
+    
+    int bind(int port) {
+        if (_socket < 0) {
+            _socket = _mdm->socketSocket(MDMParser::IPPROTO_UDP, port);
+            if (_socket < 0) {
+                return -1;
+            }
+        }
+        _mdm->socketSetBlocking(_socket, _timeout_ms); 
+        return 0;
+    }
+    
+    int join_multicast_group(const char* address)   { return -1; }
+    
+    int set_broadcasting(bool broadcast=true)       { return -1; }
+    
+    int sendTo(Endpoint &remote, char *packet, int length)
+    {
+        char* str = remote.get_address();
+        int port = remote.get_port();
+        MDMParser::IP ip = _mdm->gethostbyname(str);
+        if (ip == NOIP)
+            return -1;
+        return _mdm->socketSendTo(_socket, ip, port, packet, length); 
+    }
+    
+    int receiveFrom(Endpoint &remote, char *buffer, int length)
+    { 
+        MDMParser::IP ip;
+        int port;
+        int ret = _mdm->socketRecvFrom(_socket, &ip, &port, buffer, length); 
+        if (ret >= 0) {
+            char str[17];
+            sprintf(str, IPSTR, IPNUM(ip));
+            remote.set_address(str, port);
+        }
+        return ret;
+    }
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cJSON/cJSON.c	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,847 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+#include "cJSON.h"
+
+static const char *ep;
+
+const char *cJSON_GetErrorPtr()
+{
+    return ep;
+}
+
+static int cJSON_strcasecmp(const char *s1,const char *s2)
+{
+    if (!s1) return (s1==s2)?0:1;
+    if (!s2) return 1;
+    for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)    if(*s1 == 0)    return 0;
+    return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+}
+
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
+
+static char* cJSON_strdup(const char* str)
+{
+    size_t len;
+    char* copy;
+
+    len = strlen(str) + 1;
+    if (!(copy = (char*)cJSON_malloc(len))) return 0;
+    memcpy(copy,str,len);
+    return copy;
+}
+
+void cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
+
+    cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+    cJSON_free     = (hooks->free_fn)?hooks->free_fn:free;
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item()
+{
+    cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+    if (node) memset(node,0,sizeof(cJSON));
+    return node;
+}
+
+/* Delete a cJSON structure. */
+void cJSON_Delete(cJSON *c)
+{
+    cJSON *next;
+    while (c) {
+        next=c->next;
+        if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+        if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+        if (c->string) cJSON_free(c->string);
+        cJSON_free(c);
+        c=next;
+    }
+}
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+    double n=0,sign=1,scale=0;
+    int subscale=0,signsubscale=1;
+
+    /* Could use sscanf for this? */
+    if (*num=='-') sign=-1,num++;    /* Has sign? */
+    if (*num=='0') num++;            /* is zero */
+    if (*num>='1' && *num<='9')    do    n=(n*10.0)+(*num++ -'0');
+        while (*num>='0' && *num<='9');    /* Number? */
+    if (*num=='.' && num[1]>='0' && num[1]<='9') {
+        num++;           /* Fractional part? */
+        do    n=(n*10.0)+(*num++ -'0'),scale--;
+        while (*num>='0' && *num<='9');
+    }
+    if (*num=='e' || *num=='E') {      /* Exponent? */
+        num++;
+        if (*num=='+') num++;
+        else if (*num=='-') signsubscale=-1,num++;        /* With sign? */
+        while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');    /* Number? */
+    }
+
+    n=sign*n*pow(10.0,(scale+subscale*signsubscale));    /* number = +/- number.fraction * 10^+/- exponent */
+
+    item->valuedouble=n;
+    item->valueint=(int)n;
+    item->type=cJSON_Number;
+    return num;
+}
+
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item)
+{
+    char *str;
+    double d=item->valuedouble;
+    if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) {
+        str=(char*)cJSON_malloc(21);    /* 2^64+1 can be represented in 21 chars. */
+        if (str) sprintf(str,"%d",item->valueint);
+    } else {
+        str=(char*)cJSON_malloc(64);    /* This is a nice tradeoff. */
+        if (str) {
+            if (fabs(floor(d)-d)<=DBL_EPSILON)            sprintf(str,"%.0f",d);
+            else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)    sprintf(str,"%e",d);
+            else                                        sprintf(str,"%f",d);
+        }
+    }
+    return str;
+}
+
+/* Parse the input text into an unescaped cstring, and populate item. */
+static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+    const char *ptr=str+1;
+    char *ptr2;
+    char *out;
+    int len=0;
+    unsigned uc,uc2;
+    if (*str!='\"') {
+        ep=str;    /* not a string! */
+        return 0;
+    }
+
+    while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++;    /* Skip escaped quotes. */
+
+    out=(char*)cJSON_malloc(len+1);    /* This is how long we need for the string, roughly. */
+    if (!out) return 0;
+
+    ptr=str+1;
+    ptr2=out;
+    while (*ptr!='\"' && *ptr) {
+        if (*ptr!='\\') *ptr2++=*ptr++;
+        else {
+            ptr++;
+            switch (*ptr) {
+                case 'b':
+                    *ptr2++='\b';
+                    break;
+                case 'f':
+                    *ptr2++='\f';
+                    break;
+                case 'n':
+                    *ptr2++='\n';
+                    break;
+                case 'r':
+                    *ptr2++='\r';
+                    break;
+                case 't':
+                    *ptr2++='\t';
+                    break;
+                case 'u':     /* transcode utf16 to utf8. */
+                    sscanf(ptr+1,"%4x",&uc);
+                    ptr+=4;    /* get the unicode char. */
+
+                    if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)    break;    // check for invalid.
+
+                    if (uc>=0xD800 && uc<=0xDBFF) {  // UTF16 surrogate pairs.
+                        if (ptr[1]!='\\' || ptr[2]!='u')    break;    // missing second-half of surrogate.
+                        sscanf(ptr+3,"%4x",&uc2);
+                        ptr+=6;
+                        if (uc2<0xDC00 || uc2>0xDFFF)        break;    // invalid second-half of surrogate.
+                        uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
+                    }
+
+                    len=4;
+                    if (uc<0x80) len=1;
+                    else if (uc<0x800) len=2;
+                    else if (uc<0x10000) len=3;
+                    ptr2+=len;
+
+                    switch (len) {
+                        case 4:
+                            *--ptr2 =((uc | 0x80) & 0xBF);
+                            uc >>= 6;
+                        case 3:
+                            *--ptr2 =((uc | 0x80) & 0xBF);
+                            uc >>= 6;
+                        case 2:
+                            *--ptr2 =((uc | 0x80) & 0xBF);
+                            uc >>= 6;
+                        case 1:
+                            *--ptr2 =(uc | firstByteMark[len]);
+                    }
+                    ptr2+=len;
+                    break;
+                default:
+                    *ptr2++=*ptr;
+                    break;
+            }
+            ptr++;
+        }
+    }
+    *ptr2=0;
+    if (*ptr=='\"') ptr++;
+    item->valuestring=out;
+    item->type=cJSON_String;
+    return ptr;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static char *print_string_ptr(const char *str)
+{
+    const char *ptr;
+    char *ptr2,*out;
+    int len=0;
+    unsigned char token;
+
+    if (!str) return cJSON_strdup("");
+    ptr=str;
+    while ((token=*ptr) && ++len) {
+        if (strchr("\"\\\b\f\n\r\t",token)) len++;
+        else if (token<32) len+=5;
+        ptr++;
+    }
+
+    out=(char*)cJSON_malloc(len+3);
+    if (!out) return 0;
+
+    ptr2=out;
+    ptr=str;
+    *ptr2++='\"';
+    while (*ptr) {
+        if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+        else {
+            *ptr2++='\\';
+            switch (token=*ptr++) {
+                case '\\':
+                    *ptr2++='\\';
+                    break;
+                case '\"':
+                    *ptr2++='\"';
+                    break;
+                case '\b':
+                    *ptr2++='b';
+                    break;
+                case '\f':
+                    *ptr2++='f';
+                    break;
+                case '\n':
+                    *ptr2++='n';
+                    break;
+                case '\r':
+                    *ptr2++='r';
+                    break;
+                case '\t':
+                    *ptr2++='t';
+                    break;
+                default:
+                    sprintf(ptr2,"u%04x",token);
+                    ptr2+=5;
+                    break;    /* escape and print */
+            }
+        }
+    }
+    *ptr2++='\"';
+    *ptr2++=0;
+    return out;
+}
+/* Invote print_string_ptr (which is useful) on an item. */
+static char *print_string(cJSON *item)
+{
+    return print_string_ptr(item->valuestring);
+}
+
+/* Predeclare these prototypes. */
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth,int fmt);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth,int fmt);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth,int fmt);
+
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in)
+{
+    while (in && *in && (unsigned char)*in<=32) in++;
+    return in;
+}
+
+/* Parse an object - create a new root, and populate. */
+cJSON *cJSON_Parse(const char *value)
+{
+    cJSON *c=cJSON_New_Item();
+    ep=0;
+    if (!c) return 0;       /* memory fail */
+
+    if (!parse_value(c,skip(value))) {
+        cJSON_Delete(c);
+        return 0;
+    }
+    return c;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+char *cJSON_Print(cJSON *item)
+{
+    return print_value(item,0,1);
+}
+char *cJSON_PrintUnformatted(cJSON *item)
+{
+    return print_value(item,0,0);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static const char *parse_value(cJSON *item,const char *value)
+{
+    if (!value)                        return 0;    /* Fail on null. */
+    if (!strncmp(value,"null",4))    {
+        item->type=cJSON_NULL;
+        return value+4;
+    }
+    if (!strncmp(value,"false",5))    {
+        item->type=cJSON_False;
+        return value+5;
+    }
+    if (!strncmp(value,"true",4))    {
+        item->type=cJSON_True;
+        item->valueint=1;
+        return value+4;
+    }
+    if (*value=='\"')                {
+        return parse_string(item,value);
+    }
+    if (*value=='-' || (*value>='0' && *value<='9'))    {
+        return parse_number(item,value);
+    }
+    if (*value=='[')                {
+        return parse_array(item,value);
+    }
+    if (*value=='{')                {
+        return parse_object(item,value);
+    }
+
+    ep=value;
+    return 0;    /* failure. */
+}
+
+/* Render a value to text. */
+static char *print_value(cJSON *item,int depth,int fmt)
+{
+    char *out=0;
+    if (!item) return 0;
+    switch ((item->type)&255) {
+        case cJSON_NULL:
+            out=cJSON_strdup("null");
+            break;
+        case cJSON_False:
+            out=cJSON_strdup("false");
+            break;
+        case cJSON_True:
+            out=cJSON_strdup("true");
+            break;
+        case cJSON_Number:
+            out=print_number(item);
+            break;
+        case cJSON_String:
+            out=print_string(item);
+            break;
+        case cJSON_Array:
+            out=print_array(item,depth,fmt);
+            break;
+        case cJSON_Object:
+            out=print_object(item,depth,fmt);
+            break;
+    }
+    return out;
+}
+
+/* Build an array from input text. */
+static const char *parse_array(cJSON *item,const char *value)
+{
+    cJSON *child;
+    if (*value!='[')    {
+        ep=value;    /* not an array! */
+        return 0;
+    }
+
+    item->type=cJSON_Array;
+    value=skip(value+1);
+    if (*value==']') return value+1;    /* empty array. */
+
+    item->child=child=cJSON_New_Item();
+    if (!item->child) return 0;         /* memory fail */
+    value=skip(parse_value(child,skip(value)));    /* skip any spacing, get the value. */
+    if (!value) return 0;
+
+    while (*value==',') {
+        cJSON *new_item;
+        if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */
+        child->next=new_item;
+        new_item->prev=child;
+        child=new_item;
+        value=skip(parse_value(child,skip(value+1)));
+        if (!value) return 0;    /* memory fail */
+    }
+
+    if (*value==']') return value+1;    /* end of array */
+    ep=value;
+    return 0;    /* malformed. */
+}
+
+/* Render an array to text */
+static char *print_array(cJSON *item,int depth,int fmt)
+{
+    char **entries;
+    char *out=0,*ptr,*ret;
+    int len=5;
+    cJSON *child=item->child;
+    int numentries=0,i=0,fail=0;
+
+    /* How many entries in the array? */
+    while (child) numentries++,child=child->next;
+    /* Allocate an array to hold the values for each */
+    entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+    if (!entries) return 0;
+    memset(entries,0,numentries*sizeof(char*));
+    /* Retrieve all the results: */
+    child=item->child;
+    while (child && !fail) {
+        ret=print_value(child,depth+1,fmt);
+        entries[i++]=ret;
+        if (ret) len+=strlen(ret)+2+(fmt?1:0);
+        else fail=1;
+        child=child->next;
+    }
+
+    /* If we didn't fail, try to malloc the output string */
+    if (!fail) out=(char*)cJSON_malloc(len);
+    /* If that fails, we fail. */
+    if (!out) fail=1;
+
+    /* Handle failure. */
+    if (fail) {
+        for (i=0; i<numentries; i++) if (entries[i]) cJSON_free(entries[i]);
+        cJSON_free(entries);
+        return 0;
+    }
+
+    /* Compose the output array. */
+    *out='[';
+    ptr=out+1;
+    *ptr=0;
+    for (i=0; i<numentries; i++) {
+        strcpy(ptr,entries[i]);
+        ptr+=strlen(entries[i]);
+        if (i!=numentries-1) {
+            *ptr++=',';
+            if(fmt)*ptr++=' ';
+            *ptr=0;
+        }
+        cJSON_free(entries[i]);
+    }
+    cJSON_free(entries);
+    *ptr++=']';
+    *ptr++=0;
+    return out;
+}
+
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value)
+{
+    cJSON *child;
+    if (*value!='{')    {
+        ep=value;    /* not an object! */
+        return 0;
+    }
+
+    item->type=cJSON_Object;
+    value=skip(value+1);
+    if (*value=='}') return value+1;    /* empty array. */
+
+    item->child=child=cJSON_New_Item();
+    if (!item->child) return 0;
+    value=skip(parse_string(child,skip(value)));
+    if (!value) return 0;
+    child->string=child->valuestring;
+    child->valuestring=0;
+    if (*value!=':') {
+        ep=value;    /* fail! */
+        return 0;
+    }
+    value=skip(parse_value(child,skip(value+1)));    /* skip any spacing, get the value. */
+    if (!value) return 0;
+
+    while (*value==',') {
+        cJSON *new_item;
+        if (!(new_item=cJSON_New_Item()))    return 0; /* memory fail */
+        child->next=new_item;
+        new_item->prev=child;
+        child=new_item;
+        value=skip(parse_string(child,skip(value+1)));
+        if (!value) return 0;
+        child->string=child->valuestring;
+        child->valuestring=0;
+        if (*value!=':') {
+            ep=value;    /* fail! */
+            return 0;
+        }
+        value=skip(parse_value(child,skip(value+1)));    /* skip any spacing, get the value. */
+        if (!value) return 0;
+    }
+
+    if (*value=='}') return value+1;    /* end of array */
+    ep=value;
+    return 0;    /* malformed. */
+}
+
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt)
+{
+    char **entries=0,**names=0;
+    char *out=0,*ptr,*ret,*str;
+    int len=7,i=0,j;
+    cJSON *child=item->child;
+    int numentries=0,fail=0;
+    /* Count the number of entries. */
+    while (child) numentries++,child=child->next;
+    /* Allocate space for the names and the objects */
+    entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+    if (!entries) return 0;
+    names=(char**)cJSON_malloc(numentries*sizeof(char*));
+    if (!names) {
+        cJSON_free(entries);
+        return 0;
+    }
+    memset(entries,0,sizeof(char*)*numentries);
+    memset(names,0,sizeof(char*)*numentries);
+
+    /* Collect all the results into our arrays: */
+    child=item->child;
+    depth++;
+    if (fmt) len+=depth;
+    while (child) {
+        names[i]=str=print_string_ptr(child->string);
+        entries[i++]=ret=print_value(child,depth,fmt);
+        if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0);
+        else fail=1;
+        child=child->next;
+    }
+
+    /* Try to allocate the output string */
+    if (!fail) out=(char*)cJSON_malloc(len);
+    if (!out) fail=1;
+
+    /* Handle failure */
+    if (fail) {
+        for (i=0; i<numentries; i++) {
+            if (names[i]) cJSON_free(names[i]);
+            if (entries[i]) cJSON_free(entries[i]);
+        }
+        cJSON_free(names);
+        cJSON_free(entries);
+        return 0;
+    }
+
+    /* Compose the output: */
+    *out='{';
+    ptr=out+1;
+    if (fmt)*ptr++='\n';
+    *ptr=0;
+    for (i=0; i<numentries; i++) {
+        if (fmt) for (j=0; j<depth; j++) *ptr++='\t';
+        strcpy(ptr,names[i]);
+        ptr+=strlen(names[i]);
+        *ptr++=':';
+        if (fmt) *ptr++='\t';
+        strcpy(ptr,entries[i]);
+        ptr+=strlen(entries[i]);
+        if (i!=numentries-1) *ptr++=',';
+        if (fmt) *ptr++='\n';
+        *ptr=0;
+        cJSON_free(names[i]);
+        cJSON_free(entries[i]);
+    }
+
+    cJSON_free(names);
+    cJSON_free(entries);
+    if (fmt) for (i=0; i<depth-1; i++) *ptr++='\t';
+    *ptr++='}';
+    *ptr++=0;
+    return out;
+}
+
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)
+{
+    cJSON *c=array->child;
+    int i=0;
+    while(c)i++,c=c->next;
+    return i;
+}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)
+{
+    cJSON *c=array->child;
+    while (c && item>0) item--,c=c->next;
+    return c;
+}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)
+{
+    cJSON *c=object->child;
+    while (c && cJSON_strcasecmp(c->string,string)) c=c->next;
+    return c;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item)
+{
+    prev->next=item;
+    item->prev=prev;
+}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item)
+{
+    cJSON *ref=cJSON_New_Item();
+    if (!ref) return 0;
+    memcpy(ref,item,sizeof(cJSON));
+    ref->string=0;
+    ref->type|=cJSON_IsReference;
+    ref->next=ref->prev=0;
+    return ref;
+}
+
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+    cJSON *c=array->child;
+    if (!item) return;
+    if (!c) {
+        array->child=item;
+    } else {
+        while (c && c->next) c=c->next;
+        suffix_object(c,item);
+    }
+}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)
+{
+    if (!item) return;
+    if (item->string) cJSON_free(item->string);
+    item->string=cJSON_strdup(string);
+    cJSON_AddItemToArray(object,item);
+}
+void    cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+    cJSON_AddItemToArray(array,create_reference(item));
+}
+void    cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)
+{
+    cJSON_AddItemToObject(object,string,create_reference(item));
+}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)
+{
+    cJSON *c=array->child;
+    while (c && which>0) c=c->next,which--;
+    if (!c) return 0;
+    if (c->prev) c->prev->next=c->next;
+    if (c->next) c->next->prev=c->prev;
+    if (c==array->child) array->child=c->next;
+    c->prev=c->next=0;
+    return c;
+}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)
+{
+    cJSON_Delete(cJSON_DetachItemFromArray(array,which));
+}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string)
+{
+    int i=0;
+    cJSON *c=object->child;
+    while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;
+    if (c) return cJSON_DetachItemFromArray(object,i);
+    return 0;
+}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string)
+{
+    cJSON_Delete(cJSON_DetachItemFromObject(object,string));
+}
+
+/* Replace array/object items with new ones. */
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)
+{
+    cJSON *c=array->child;
+    while (c && which>0) c=c->next,which--;
+    if (!c) return;
+    newitem->next=c->next;
+    newitem->prev=c->prev;
+    if (newitem->next) newitem->next->prev=newitem;
+    if (c==array->child) array->child=newitem;
+    else newitem->prev->next=newitem;
+    c->next=c->prev=0;
+    cJSON_Delete(c);
+}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem)
+{
+    int i=0;
+    cJSON *c=object->child;
+    while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;
+    if(c) {
+        newitem->string=cJSON_strdup(string);
+        cJSON_ReplaceItemInArray(object,i,newitem);
+    }
+}
+
+/* Create basic types: */
+cJSON *cJSON_CreateNull()
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=cJSON_NULL;
+    return item;
+}
+cJSON *cJSON_CreateTrue()
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=cJSON_True;
+    return item;
+}
+cJSON *cJSON_CreateFalse()
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=cJSON_False;
+    return item;
+}
+cJSON *cJSON_CreateBool(int b)
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=b?cJSON_True:cJSON_False;
+    return item;
+}
+cJSON *cJSON_CreateNumber(double num)
+{
+    cJSON *item=cJSON_New_Item();
+    if(item) {
+        item->type=cJSON_Number;
+        item->valuedouble=num;
+        item->valueint=(int)num;
+    }
+    return item;
+}
+cJSON *cJSON_CreateString(const char *string)
+{
+    cJSON *item=cJSON_New_Item();
+    if(item) {
+        item->type=cJSON_String;
+        item->valuestring=cJSON_strdup(string);
+    }
+    return item;
+}
+cJSON *cJSON_CreateArray()
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=cJSON_Array;
+    return item;
+}
+cJSON *cJSON_CreateObject()
+{
+    cJSON *item=cJSON_New_Item();
+    if(item)item->type=cJSON_Object;
+    return item;
+}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(int *numbers,int count)
+{
+    int i;
+    cJSON *n=0,*p=0,*a=cJSON_CreateArray();
+    for(i=0; a && i<count; i++) {
+        n=cJSON_CreateNumber(numbers[i]);
+        if(!i)a->child=n;
+        else suffix_object(p,n);
+        p=n;
+    }
+    return a;
+}
+cJSON *cJSON_CreateFloatArray(float *numbers,int count)
+{
+    int i;
+    cJSON *n=0,*p=0,*a=cJSON_CreateArray();
+    for(i=0; a && i<count; i++) {
+        n=cJSON_CreateNumber(numbers[i]);
+        if(!i)a->child=n;
+        else suffix_object(p,n);
+        p=n;
+    }
+    return a;
+}
+cJSON *cJSON_CreateDoubleArray(double *numbers,int count)
+{
+    int i;
+    cJSON *n=0,*p=0,*a=cJSON_CreateArray();
+    for(i=0; a && i<count; i++) {
+        n=cJSON_CreateNumber(numbers[i]);
+        if(!i)a->child=n;
+        else suffix_object(p,n);
+        p=n;
+    }
+    return a;
+}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)
+{
+    int i;
+    cJSON *n=0,*p=0,*a=cJSON_CreateArray();
+    for(i=0; a && i<count; i++) {
+        n=cJSON_CreateString(strings[i]);
+        if(!i)a->child=n;
+        else suffix_object(p,n);
+        p=n;
+    }
+    return a;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cJSON/cJSON.h	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,135 @@
+/*
+  Copyright (c) 2009 Dave Gamble
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <ctype.h>
+
+/* cJSON Types: */
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+#define cJSON_IsReference 256
+
+/* The cJSON structure: */
+typedef struct cJSON {
+    struct cJSON *next,*prev;    /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+    struct cJSON *child;        /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+
+    int type;                    /* The type of the item, as above. */
+
+    char *valuestring;            /* The item's string, if type==cJSON_String */
+    int valueint;                /* The item's number, if type==cJSON_Number */
+    double valuedouble;            /* The item's number, if type==cJSON_Number */
+
+    char *string;                /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+} cJSON;
+
+typedef struct cJSON_Hooks {
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
+} cJSON_Hooks;
+
+/* Supply malloc, realloc and free functions to cJSON */
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+
+
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
+extern cJSON *cJSON_Parse(const char *value);
+/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
+extern char  *cJSON_Print(cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Delete a cJSON entity and all subentities. */
+extern void   cJSON_Delete(cJSON *c);
+
+/* Returns the number of items in an array (or object). */
+extern int      cJSON_GetArraySize(cJSON *array);
+/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+/* Get item "string" from object. Case insensitive. */
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+extern const char *cJSON_GetErrorPtr();
+
+/* These calls create a cJSON item of the appropriate type. */
+extern cJSON *cJSON_CreateNull();
+extern cJSON *cJSON_CreateTrue();
+extern cJSON *cJSON_CreateFalse();
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray();
+extern cJSON *cJSON_CreateObject();
+
+/* These utilities create an Array of count items. */
+extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+/* Append item to the specified array/object. */
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void    cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void    cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
+
+/* Remove/Detatch items from Arrays/Objects. */
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
+
+/* Update array items. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+#define cJSON_AddNullToObject(object,name)    cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)    cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)        cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddNumberToObject(object,name,n)    cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)    cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,252 @@
+#include "axTransport.h"
+#include "mbed.h"
+#include "GPS.h"
+#include "MDM.h"
+#include "axToolkit.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define SIMPIN      NULL
+#define APN         "wap.cingular"
+#define USERNAME    "wap@cingulargprs.com"
+#define PASSWORD    "cingular1"
+
+//------------------------------------------------------------------------------------
+
+#define MODEL   "nlr_ublox_c028"
+#define SERIAL_NUM  "lymes"
+#define HOST    "toolbox-stage-connect.axeda.com"
+#define PORT    (80)
+#define PING    (700)
+
+axToolkitConfig cfg;
+//Initial AMMP configuration
+axToolkitConfig *initConfig(axToolkitConfig *cfg)
+
+{
+    char *model = MODEL;
+    char *serial = SERIAL_NUM;
+    const char *host = HOST;
+    int port = PORT;
+
+    printf("STATUS: Initializing AMMP configuration\r\n");
+    ax_createPlatform(&cfg->platform, host,NULL,port);
+    cfg->platform.secure=AX_FALSE;
+    cfg->platform.verify=AX_FALSE;
+    cfg->platform.ping_rate=PING;
+
+    printf("STATUS: Initializing device ID\r\n");
+    ax_data_createModelSerialDeviceId(&cfg->thisDevice, model, serial, NULL);
+    cfg->conf_recv_timeout = 5000;
+    cfg->conf_queue_size=10;
+    cfg->first_run=AX_FALSE;
+    cfg->debug_mode=AX_TRUE;
+    cfg->print_mem=AX_FALSE;
+
+    return cfg;
+}
+//Sends event item to platform
+int sendEvent(char* name, char* desc)
+{
+    int res=0;
+
+    printf("STATUS: Beginning event send\r\n");
+    ax_event *events[1];
+    events[0] = NULL;
+    events[0]=(ax_event *)calloc(1,sizeof(ax_event));
+    res = ax_data_createEvent(events[0],name,desc,0,AX_NO_PRIORITY);
+    printf("STATUS: Event item creation result: %d\r\n",res);
+
+    ax_platform_sendEvents(&cfg.platform, &cfg.thisDevice,events,1);
+    free(events[0]);
+
+    return AX_OK;
+}
+//Sends location item to platform
+int sendLoc(double lat, double lon)
+{
+    int res=0;
+
+    printf("STATUS: Beginning location send\r\n");
+    ax_location *location[1];
+    location[0] = NULL;
+    location[0]=(ax_location *)calloc(1,sizeof(ax_location));
+    res = ax_data_createLocation(location[0],lat,lon,0,0,AX_NO_PRIORITY);
+    printf("STATUS: Location item creation result: %d\r\n",res);
+
+    printf("STATUS: Sending data items to platform\r\n");
+    ax_platform_sendLocations(&cfg.platform, &cfg.thisDevice,location,1);
+    free(location[0]);
+
+    return AX_OK;
+}
+
+//Sends data item to platform
+int sendData(char *name, double value)
+{
+    int res=0;
+
+    printf("STATUS: Beginning data send\r\n");
+    ax_dataSet *data[1];
+    data[0] = NULL;
+    data[0]=(ax_dataSet *)calloc(1,sizeof(ax_dataSet));
+    res = ax_data_createDataItem(data[0],name,AX_ANALOG,NULL,value,0,AX_NO_PRIORITY);
+    printf("STATUS: Data item creation result: %d\r\n",res);
+
+    printf("STATUS: Sending data items to platform\r\n");
+    ax_platform_sendData(&cfg.platform, &cfg.thisDevice,data,1);
+    free(data[0]);
+
+    return AX_OK;
+}
+
+//global variables for data items (server egress)
+int tank1=0;
+int tank2=0;
+
+int main(void)
+{
+////////////////////////////////////INIT///////////////////////////////////////////////////
+    bool abort=false;
+    int ret;
+    char buf[2048] = "";
+
+    // Create the GPS object
+#if 0  // use GPSI2C class
+    GPSI2C gps;
+#else   // or GPSSerial class 
+    GPSSerial gps;
+#endif
+
+    //Create modem object
+    MDMSerial mdm;
+   // mdm.setDebug(4); //Uncomment this line to get modem debug messages
+
+    //initialize the modem
+    MDMParser::DevStatus devStatus = {};
+    MDMParser::NetStatus netStatus = {};
+    bool mdmOk = mdm.init(SIMPIN, &devStatus);
+    mdm.dumpDevStatus(&devStatus);
+    if (mdmOk) {
+        //wait until we are connected
+        mdmOk = mdm.registerNet(&netStatus);
+        mdm.dumpNetStatus(&netStatus);
+    }
+    initConfig(&cfg);
+    MDMParser::IP ip = mdm.join(APN,USERNAME,PASSWORD);
+    if (ip == NOIP) {
+        printf("ERROR - Modem unable to join internet connection\r\n");
+        abort=true;
+    }
+    if ((ret = ax_platform_register(&cfg.platform, &cfg.thisDevice))!=AX_OK) {
+        printf("ERROR - Could not register with Axeda Platform\r\n");
+    }
+//////////////////////////////////////////////////////////////////////////////////////////
+    printf("SMS and GPS Loop\r\n");
+    char link[128] = "";
+    char data[128] = "";
+    unsigned int i = 0xFFFFFFFF;
+    const int wait = 2000;
+    //DigitalOut led(LED1);
+    while (!abort) {
+
+/////////////////////////////////POLL/////////////////////////////////////////////////////
+        /*   if ((ret = ax_platform_ping(&cfg.platform, &cfg.thisDevice))!=AX_OK) {
+               printf("ERROR - Lost connectivity with Axeda Platform\r\n");
+           }*/
+        sprintf(data, "Current data values: \r\nTank level 1: %d\r\nTank level 2: %d\r\n", tank1, tank2);
+//////////////////////////////////GPS/////////////////////////////////////////////////////
+        while ((ret = gps.getMessage(buf, sizeof(buf))) > 0) {
+            int len = LENGTH(ret);
+            //printf("NMEA: %.*s\r\n", len-2, msg);
+            if ((PROTOCOL(ret) == GPSParser::NMEA) && (len > 6)) {
+                if (!strncmp("$GPGLL", buf, 6)) {
+                    double la = 0, lo = 0;
+                    char ch;
+                    if (gps.getNmeaAngle(1,buf,len,la) &&
+                            gps.getNmeaAngle(3,buf,len,lo) &&
+                            gps.getNmeaItem(6,buf,len,ch) && ch == 'A') {
+                        printf("STATUS: GPS Location: %.5f %.5f\r\n", la, lo);
+                        sprintf(link, "I am here!\n"
+                          "https://maps.google.com/?q=%.5f,%.5f", la, lo);
+                        sendLoc(la, lo); 
+                    }
+                } else if (!strncmp("$GPGGA", buf, 6)) {
+                    double alt = 0;
+                    if (gps.getNmeaItem(9,buf,len,alt)) // altitude msl [m]
+                        printf("STATUS: GPS Altitude: %.1f\r\n", alt);
+
+                } else if (!strncmp("$GPVTG", buf, 6)) {
+                    double s = 0;
+                    if (gps.getNmeaItem(7,buf,len,s)) // speed [km/h]
+                        printf("STATUS: GPS Speed: %.1f\r\n", s);
+                }
+            }
+        }
+
+/////////////////////////////SMS//////////////////////////////////////////////////////////////
+        int ix[8];
+        int n = mdm.smsList("REC UNREAD", ix, 8);
+        if (8 < n) n = 8;
+        while (0 < n--) {
+            char num[32];
+            char msg[140];
+            printf("STATUS: Unread SMS at index %d\r\n", ix[n]);
+            if (mdm.smsRead(ix[n], num, msg, sizeof(msg))) {
+                printf("STATUS: Got SMS from \"%s\" with text \"%s\"\r\n", num, msg);
+                sendEvent(num, msg);
+                printf("STATUS: Delete SMS at index %d\r\n", ix[n]);
+                mdm.smsDelete(ix[n]);
+                // provide a reply
+                const char* reply = "Howdy from u-blox and Axeda!";
+                if (strstr(msg, /*w*/"here are you"))
+                    reply = *link ? link : "Don't know - no GPS data yet"; // reply wil location link
+                else if (strstr(msg, /*s*/"hutdown"))
+                    abort = true, reply = "Good night, and good luck";
+                else if (strstr(msg, /*f*/"ill1")) {
+                    reply = ("Increased fill - sending data to platform!");
+                    if (tank1<9) {
+                        tank1+=2;
+                    }
+                    sendData("oil_level", tank1);
+                } else if (strstr(msg, /*f*/"ill2")) {
+                    reply = ("Increased fill - sending data to platform!");
+                    if (tank2<9) {
+                        tank2+=2;
+                    }
+                    sendData("oil_level2", tank2);
+                } else if (strstr(msg, /*d*/"ipense1")) {
+                    reply = ("Dispensed from tank 1 - sending data to platform!");
+                    if (tank1>=2) {
+                        tank1-=2;
+                    }
+                    sendData("oil_level", tank1);
+                } else if (strstr(msg, /*d*/"ispense2")) {
+                    reply = ("Dipensed from tank 2 - sending data to platform!");
+                    if (tank2>=2) {
+                        tank2-=2;
+                    }
+                    sendData("oil_level2", tank2);
+                }
+
+                printf("Send SMS reply \"%s\" to \"%s\"\r\n", reply, num);
+                mdm.smsSend(num, reply);
+            }
+        }
+///////////////////////////////NETCHECK////////////////////////////////////////////////////////
+        if (mdmOk && (i++ == 5000/wait)) {
+            i = 0;
+            // check the network status
+            if (mdm.checkNetStatus(&netStatus)) {
+                mdm.dumpNetStatus(&netStatus, fprintf, stdout);
+            }
+        }
+        wait_ms(wait);
+    }
+//////////////////////////////CLOSE///////////////////////////////////////////////////////////////
+    gps.powerOff();
+    mdm.powerOff();
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Aug 11 19:02:42 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/6213f644d804
\ No newline at end of file