#if 1
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include "azure_roche_common.h"
#include "mosquitto.h"

/* Paste in the your iothub device connection string  */
//static const char* connectionString = "HostName=LNXALLIoT.azure-devices.net;DeviceId=987654321;SharedAccessKey=re0oGuRIvVl6vpc/3i/hSbR9KWGab/2eG6jzaKXzdh8=";
static const char* connectionString = "HostName=lnxall.azure-devices.net;DeviceId=device_test;SharedAccessKey=fjGDOINKdCgi098nk5EwSC9kBLIMsrApPJt+jZxJ46Q=";
#define DOWORK_LOOP_NUM     3

azure_var_t gazure_var = {0};

typedef struct MAKER_TAG
{
    char* makerName;
    char* style;
    int year;
} Maker;

typedef struct GEO_TAG
{
    double longitude;
    double latitude;
} Geo;

typedef struct CAR_STATE_TAG
{
    int32_t softwareVersion;        // reported property
    uint8_t reported_maxSpeed;      // reported property
    char* vanityPlate;              // reported property
} CarState;

typedef struct CAR_SETTINGS_TAG
{
    uint8_t desired_maxSpeed;       // desired property
    Geo location;                   // desired property
} CarSettings;

typedef struct CAR_TAG
{
    char* lastOilChangeDate;        // reported property
    char* changeOilReminder;        // desired property
    Maker maker;                    // reported property
    CarState state;                 // reported property
    CarSettings settings;           // desired property
} Car;


//  Converts the Car object into a JSON blob with reported properties that is ready to be sent across the wire as a twin.
static char* serializeToJson(Car* car)
{
    char* result;

    JSON_Value* root_value = json_value_init_object();
    JSON_Object* root_object = json_value_get_object(root_value);

    // Only reported properties:
    (void)json_object_set_string(root_object, "lastOilChangeDate", car->lastOilChangeDate);
    (void)json_object_dotset_string(root_object, "maker.makerName", car->maker.makerName);
    (void)json_object_dotset_string(root_object, "maker.style", car->maker.style);
    (void)json_object_dotset_number(root_object, "maker.year", car->maker.year);
    (void)json_object_dotset_number(root_object, "state.reported_maxSpeed", car->state.reported_maxSpeed);
    (void)json_object_dotset_number(root_object, "state.softwareVersion", car->state.softwareVersion);
    (void)json_object_dotset_string(root_object, "state.vanityPlate", car->state.vanityPlate);

	(void)json_object_dotset_number(root_object, "temperature", 28.8);
	(void)json_object_dotset_number(root_object, "humidity", 68.1);

    result = json_serialize_to_string(root_value);

    json_value_free(root_value);

    return result;
}

//  Converts the desired properties of the Device Twin JSON blob received from IoT Hub into a Car object.
static Car* parseFromJson(const char* json, DEVICE_TWIN_UPDATE_STATE update_state)
{
    Car* car = malloc(sizeof(Car));
    JSON_Value* root_value = NULL;
    JSON_Object* root_object = NULL;

    if (NULL == car)
    {
        dy_syslog(LOG_ERR, "ERROR: Failed to allocate memory");
    }

    else
    {
        (void)memset(car, 0, sizeof(Car));

        root_value = json_parse_string(json);
        root_object = json_value_get_object(root_value);

        // Only desired properties:
        JSON_Value* changeOilReminder;
        JSON_Value* desired_maxSpeed;
        JSON_Value* latitude;
        JSON_Value* longitude;

        if (update_state == DEVICE_TWIN_UPDATE_COMPLETE)
        {
            changeOilReminder = json_object_dotget_value(root_object, "desired.changeOilReminder");
            desired_maxSpeed = json_object_dotget_value(root_object, "desired.settings.desired_maxSpeed");
            latitude = json_object_dotget_value(root_object, "desired.settings.location.latitude");
            longitude = json_object_dotget_value(root_object, "desired.settings.location.longitude");
        }
        else
        {
            changeOilReminder = json_object_dotget_value(root_object, "changeOilReminder");
            desired_maxSpeed = json_object_dotget_value(root_object, "settings.desired_maxSpeed");
            latitude = json_object_dotget_value(root_object, "settings.location.latitude");
            longitude = json_object_dotget_value(root_object, "settings.location.longitude");
        }

        if (changeOilReminder != NULL)
        {
            const char* data = json_value_get_string(changeOilReminder);

            if (data != NULL)
            {
                car->changeOilReminder = malloc(strlen(data) + 1);
                if (NULL != car->changeOilReminder)
                {
                    (void)strcpy(car->changeOilReminder, data);
                }
            }
        }

        if (desired_maxSpeed != NULL)
        {
            car->settings.desired_maxSpeed = (uint8_t)json_value_get_number(desired_maxSpeed);
        }

        if (latitude != NULL)
        {
            car->settings.location.latitude = json_value_get_number(latitude);
        }

        if (longitude != NULL)
        {
            car->settings.location.longitude = json_value_get_number(longitude);
        }
        json_value_free(root_value);
    }

    return car;
}

static int deviceMethodCallback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* response_size, void* userContextCallback)
{
    (void)userContextCallback;
    (void)payload;
    (void)size;

    int result;

    if (strcmp("getCarVIN", method_name) == 0)
    {
        const char deviceMethodResponse[] = "{ \"Response\": \"1HGCM82633A004352\" }";
        *response_size = sizeof(deviceMethodResponse)-1;
        *response = malloc(*response_size);
        (void)memcpy(*response, deviceMethodResponse, *response_size);
        result = 200;
    }
    else
    {
        // All other entries are ignored.
        const char deviceMethodResponse[] = "{ }";
        *response_size = sizeof(deviceMethodResponse)-1;
        *response = malloc(*response_size);
        (void)memcpy(*response, deviceMethodResponse, *response_size);
        result = -1;
    }

    return result;
}
//#define DY_TEST
#define INSTRUMENT_DATA_Alarms "{\"Alarms\":[{\"Timestamp\":\"\",\"EventCode\":\"\",\"EventSubcode\":\"\",\"AlarmseverityCode\":\"\"}]}"
#define INSTRUMENT_DATA_TestResults "{\"TestResults\":[{\"ModuleNo\":\"1\",\"SubmoduleNo\":\"1\",\"TimeCreated\":\"\",\"SampleDrawingTime\":\"\",\"SampleOrderingTime\":\"\",\"SampleArrivalTime\":\"\",\"SampleClass\":\"\",\"SampleSequenceNo\":\"\",\"tST_AppID\":\"\",\"tST_RgtLotID\":\"\",\"ReagentContainerID\":\"\",\"SignalValue\":\"\",\"ResultValueCust\":\"\",\"TargetValueCust\":\"\",\"InstrumentFactorID\":\"\",\"SamplingDateTime\":\"\",\"ReportingDateTime\":\"\",\"IsValid\":\"\"}]}"
#define INSTRUMENT_DATA_TestCalibration "{\"TestCalibration\":{\"ImmunoTestCalib\":[{\"ModuleNo\":\"1\",\"SubmoduleNo\":\"1\",\"TestId\":\"\",\"TestId_LOINC\":\"\",\"RackpackId\":\"\",\"LotNumber\":\"\",\"CalibLotNo\":\"\",\"CalibLotId\":\"\",\"CalibExpirationTime\":\"\",\"Conc1\":\"\",\"Conc2\":\"\",\"Conc3\":\"\",\"Conc4\":\"\",\"Conc5\":\"\",\"TimeReceived\":\"\",\"TimeCreated\":\"\",\"CalibMode_LorC\":\"\",\"ValidityMode_LotOrRack\":\"\",\"IsValid\":\"\",\"Criteria\":\"\",\"UsedCalibrator\":\"\",\"MultiNum\":\"\",\"IsQualitative\":\"\",\"BlockRelease\":\"\"}]}}"
#define INSTRUMENT_DATA_TraceInstrument "{\"TraceInstrument\":{\"ModuleNo\":\"1\",\"SubmoduleNo\":\"1\",\"TimeReceived\":\"\",\"ProcessCounter\":\"\",\"SampleCounter\":\"\",\"StatusdurationPUCounter\":\"\",\"StatusdurationOPCounter\":\"\"}}"
#define INSTRUMENT_DATA_InstrumentConfiguration "{\"InstrumentConfiguration\":{\"modE_InstFactor\":[{\"ModuleNo\":\"1\",\"SubmoduleNo\":\"1\",\"TimeReceived\":\"\",\"AppCode\":\"\",\"InstFactorAData\":\"\",\"InstFactorADecimal\":\"\",\"InstFactorBData\":\"\",\"InstFactorBDecimal\":\"\"}]}}"

#ifdef DY_TEST
#define test_result "{\"IoTHubConnString\":\"HostName=lnxall-test.azure-devices.net;DeviceId=REF_LNX123_89860436101891923504;SharedAccessKey=hq2dQZKQex78/K2mRJVjbybsM+a27UTzxrNAN70J0oY=\",\"Instruments\":[{\"SerialNumber\":\"1111-22\"},{\"SerialNumber\":\"8888-99\"}]}"
#define test_desired "{\"desired\":{\"Config\":{\"HeartbeatInterval\":300,\"SensorTelemetryInterval\":300,\"InstrumentTelemetryInterval\":300,\"InstrumentType\":\"cobasLink\",\"EnableE411DataConnection\":\"1\",\"E411RealtimeDataInterval\":5,\"E411ScheduleDataInterval\":3600,\"EnableAxedaDataUpload\":\"1\",\"AutoRebootTime\":\"00:00\"},\"$version\":22},\"reported\":{\"Config\":{\"HeartbeatInterval\":300,\"SensorTelemetryInterval\":300,\"InstrumentTelemetryInterval\":300,\"InstrumentType\":\"E411\",\"EnableE411DataConnection\":\"1\",\"E411RealtimeDataInterval\":5,\"E411ScheduleDataInterval\":3600,\"EnableAxedaDataUpload\":\"1\"},\"Device\":{\"DeviceState\":\"Normal\",\"CreatedTime\":\"2017-10-16T08:09:18.007645Z\",\"StartupTime\":\"2018-03-27T07:48:04.0723834Z\",\"ShutdownTime\":\"2017-12-05T02:24:40.0777575Z\",\"ShutdownState\":\"Poweroff\",\"Carrier\":\"CHN-CT\",\"ICCID\":\"8986031749203107004\",\"IsSimulatedDevice\":false,\"DeviceID\":\"REF_KNT535_862815030014672\"},\"System\":{\"IMEI\":\"862815030014672\",\"Manufacturer\":\"cleidon\",\"ModelNumber\":\"1.1.33\",\"SerialNumber\":\"862815030014672\",\"FirmwareVersion\":\"1.1.33\",\"Platform\":\"x86\",\"Processor\":\"Intel Celeron\",\"InstalledRAM\":\"1024M\"},\"$version\":2195}}"
#else
#define test_result "{\"IoTHubConnString\":\"HostName=test-ih-iothub.azure-devices.cn;DeviceId=REF_KNT535_862815030014672;SharedAccessKey=NKV78FWd/WyTW+n1v+AS62DSVRjqdh8OBLCkmzNUrDo=\",\"Instruments\":[{\"SerialNumber\":\"2085-32\"},{\"SerialNumber\":\"SCL66464\"}]}"
#endif


static void getCompleteDeviceTwinOnDemandCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
{
    (void)update_state;
    (void)userContextCallback;
	dy_syslog(LOG_DEBUG, "GetTwinAsync result:\%d", (int)size);
    dy_syslog(LOG_DEBUG, "GetTwinAsync result:\r\n%.*s", (int)size, payLoad);

	char *tmp = calloc(4096,1);

	snprintf(tmp, 4096, "echo \"%s\"", payLoad);
	printf("payLoad====%s===\n",payLoad);

	system(tmp);
	free(tmp);
	
	azure_dev_info_t *azure_dev = (azure_dev_info_t *)userContextCallback;
#ifdef DY_TEST
	cJSON *root = cJSON_Parse(test_desired);
#else
	cJSON *root = cJSON_Parse(payLoad);
#endif
	if(root)
	{
		cJSON *desired = cJSON_GetObjectItem(root, "desired");
		dy_syslog(LOG_DEBUG, "--desired:%p", desired);
		if(desired)
		{
			cJSON *Config = cJSON_GetObjectItem(desired, "Config");
			dy_syslog(LOG_DEBUG, "--Config:%p", Config);
			if(Config)
			{
				if(azure_dev->desired_config)
				{
					free(azure_dev->desired_config);
					azure_dev->desired_config = NULL;
				}
				azure_dev->desired_config = calloc(1, sizeof(desired_config_t));

				GET_JSON_VALUE_INT(Config, "HeartbeatInterval", azure_dev->desired_config->HeartbeatInterval);
				GET_JSON_VALUE_INT(Config, "SensorTelemetryInterval", azure_dev->desired_config->SensorTelemetryInterval);
				GET_JSON_VALUE_INT(Config, "InstrumentTelemetryInterval", azure_dev->desired_config->InstrumentTelemetryInterval);
				GET_JSON_VALUE_STRING(Config, "InstrumentType", azure_dev->desired_config->InstrumentType);
				GET_JSON_VALUE_INT(Config, "EnableE411DataConnection", azure_dev->desired_config->EnableE411DataConnection);
				GET_JSON_VALUE_INT(Config, "E411RealtimeDataInterval", azure_dev->desired_config->E411RealtimeDataInterval);
				GET_JSON_VALUE_INT(Config, "E411ScheduleDataInterval", azure_dev->desired_config->E411ScheduleDataInterval);
				GET_JSON_VALUE_STRING(Config, "EnableAxedaDataUpload", azure_dev->desired_config->EnableAxedaDataUpload);
				GET_JSON_VALUE_STRING(Config, "AutoRebootEnabled", azure_dev->desired_config->AutoRebootEnabled);
				GET_JSON_VALUE_INT(Config, "AutoRebootInterval", azure_dev->desired_config->AutoRebootInterval);
				GET_JSON_VALUE_STRING(Config, "AutoRebootTime", azure_dev->desired_config->AutoRebootTime);

				dy_syslog(LOG_DEBUG, "=====HeartbeatInterval %d SensorTelemetryInterval %d InstrumentTelemetryInterval %d InstrumentType %s EnableE411DataConnection %d E411RealtimeDataInterval %d E411ScheduleDataInterval %d EnableAxedaDataUpload %s AutoRebootEnabled %s AutoRebootInterval %d AutoRebootTime %s", 
					azure_dev->desired_config->HeartbeatInterval,azure_dev->desired_config->SensorTelemetryInterval,azure_dev->desired_config->InstrumentTelemetryInterval,
					azure_dev->desired_config->InstrumentType,azure_dev->desired_config->EnableE411DataConnection,azure_dev->desired_config->E411RealtimeDataInterval,
					azure_dev->desired_config->E411ScheduleDataInterval,azure_dev->desired_config->EnableAxedaDataUpload,azure_dev->desired_config->AutoRebootEnabled,
					azure_dev->desired_config->AutoRebootInterval,azure_dev->desired_config->AutoRebootTime);
			}
		}
	}
}

static void deviceTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
{
    (void)update_state;
    (void)size;

	azure_dev_info_t *azure_dev = (azure_dev_info_t *)userContextCallback;

	dy_syslog(LOG_DEBUG, "payLoad:%s update_state:%d", payLoad, update_state);
#if 0
    Car* oldCar = (Car*)userContextCallback;
    Car* newCar = parseFromJson((const char*)payLoad, update_state);

    if (NULL == newCar)
    {
        dy_syslog(LOG_ERR, "ERROR: parseFromJson returned NULL");
    }
    else
    {
        if (newCar->changeOilReminder != NULL)
        {
            if ((oldCar->changeOilReminder != NULL) && (strcmp(oldCar->changeOilReminder, newCar->changeOilReminder) != 0))
            {
                free(oldCar->changeOilReminder);
            }
            
            if (oldCar->changeOilReminder == NULL)
            {
                dy_syslog(LOG_DEBUG, "Received a new changeOilReminder = %s", newCar->changeOilReminder);
                if ( NULL != (oldCar->changeOilReminder = malloc(strlen(newCar->changeOilReminder) + 1)))
                {
                    (void)strcpy(oldCar->changeOilReminder, newCar->changeOilReminder);
                    free(newCar->changeOilReminder);
                }
            }
        }

        if (newCar->settings.desired_maxSpeed != 0)
        {
            if (newCar->settings.desired_maxSpeed != oldCar->settings.desired_maxSpeed)
            {
                dy_syslog(LOG_DEBUG, "Received a new desired_maxSpeed = %" PRIu8, newCar->settings.desired_maxSpeed);
                oldCar->settings.desired_maxSpeed = newCar->settings.desired_maxSpeed;
            }
        }

        if (newCar->settings.location.latitude != 0)
        {
            if (newCar->settings.location.latitude != oldCar->settings.location.latitude)
            {
                dy_syslog(LOG_DEBUG, "Received a new latitude = %f", newCar->settings.location.latitude);
                oldCar->settings.location.latitude = newCar->settings.location.latitude;
            }
        }

        if (newCar->settings.location.longitude != 0)
        {
            if (newCar->settings.location.longitude != oldCar->settings.location.longitude)
            {
                dy_syslog(LOG_DEBUG, "Received a new longitude = %f", newCar->settings.location.longitude);
                oldCar->settings.location.longitude = newCar->settings.location.longitude;
            }
        }
        
        free(newCar);
    }
#endif
}

static void reportedStateCallback(int status_code, void* userContextCallback)
{
    (void)userContextCallback;
    dy_syslog(LOG_DEBUG, "Device Twin reported properties update completed with result: %d", status_code);
}


static void iothub_client_device_twin_and_methods_sample_run(void)
{
#if 0
    IOTHUB_CLIENT_TRANSPORT_PROVIDER protocol;
    IOTHUB_DEVICE_CLIENT_HANDLE iotHubClientHandle;

    // Select the Protocol to use with the connection
    protocol = MQTT_Protocol;

    if (IoTHub_Init() != 0)
    {
        (void)printf("Failed to initialize the platform.\r\n");
    }
    else
    {
        if ((iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(connectionString, protocol)) == NULL)
        {
            (void)printf("ERROR: iotHubClientHandle is NULL!\r\n");
        }
        else
        {
            // Uncomment the following lines to enable verbose logging (e.g., for debugging).
            //bool traceOn = true;
            //(void)IoTHubDeviceClient_SetOption(iotHubClientHandle, OPTION_LOG_TRACE, &traceOn);

#ifdef SET_TRUSTED_CERT_IN_SAMPLES
			(void)printf("IoTHubDeviceClient_SetOption\r\n");
            // For mbed add the certificate information
            if (IoTHubDeviceClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
            {
                (void)printf("failure to set option \"TrustedCerts\"\r\n");
            }
#endif // SET_TRUSTED_CERT_IN_SAMPLES

            Car car;
            memset(&car, 0, sizeof(Car));
            car.lastOilChangeDate = "2016";
            car.maker.makerName = "Fabrikam";
            car.maker.style = "sedan";
            car.maker.year = 2014;
            car.state.reported_maxSpeed = 100;
            car.state.softwareVersion = 1;
            car.state.vanityPlate = "1I1";

            char* reportedProperties = serializeToJson(&car);

            (void)IoTHubDeviceClient_GetTwinAsync(iotHubClientHandle, getCompleteDeviceTwinOnDemandCallback, NULL);
            (void)IoTHubDeviceClient_SendReportedState(iotHubClientHandle, (const unsigned char*)reportedProperties, strlen(reportedProperties), reportedStateCallback, NULL);
            (void)IoTHubDeviceClient_SetDeviceMethodCallback(iotHubClientHandle, deviceMethodCallback, NULL);
            (void)IoTHubDeviceClient_SetDeviceTwinCallback(iotHubClientHandle, deviceTwinCallback, &car);

            (void)getchar();

            IoTHubDeviceClient_Destroy(iotHubClientHandle);
            free(reportedProperties);
            free(car.changeOilReminder);
        }

        IoTHub_Deinit();
    }
#endif
}

void azure_message_arrive(void *pcontext, void *pclient, void *msg)
{
#if 0
    iotx_mqtt_topic_info_t     *topic_info = (iotx_mqtt_topic_info_pt) msg->msg;

    switch (msg->event_type) {
        case IOTX_MQTT_EVENT_PUBLISH_RECEIVED:
            /* print topic name and topic message */
            dy_syslog(LOG_DEBUG,"Message Arrived:");
            dy_syslog(LOG_DEBUG,"Topic  : %.*s", topic_info->topic_len, topic_info->ptopic);
            dy_syslog(LOG_DEBUG,"Payload: %.*s", topic_info->payload_len, topic_info->payload);

			if (strstr(topic_info->ptopic,"_reply"))
			{
				dy_syslog(LOG_DEBUG,"reply message!!!\n");
				break;
			}
			
			ipc_msg_t *mqtt_message = NULL;
			char cmd_identifier[64] = {0};
			char topic[TOPIC_MAX_LEN] = {0};
			char method[256] = {0};
			char* identifier = NULL;
			
			cJSON* root=cJSON_Parse(topic_info->payload);
	        if (!root)
			{
				dy_syslog(LOG_WARNING, "cJSON_Parse payload failed");
				return -1;
	        }
	        cJSON* nodes = cJSON_GetObjectItem(root,"params");
	        if (!nodes)
			{
				dy_syslog(LOG_WARNING, "cJSON_GetObjectItem params failed");
				return -1;
	        }

			GET_JSON_VALUE_STRING(root,"method",method);
			identifier = strstr(method, IDENTIFIER_FLAG);
			if(identifier)
			{
				strncpy(cmd_identifier, identifier+strlen(IDENTIFIER_FLAG), sizeof(cmd_identifier));
				cJSON_AddStringToObject(nodes,"identifier",cmd_identifier);
			}
			cJSON_AddStringToObject(nodes,"sn",pcontext);

			char *payload = cJSON_PrintUnformatted(nodes);
			snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", gazure_var.sn_str, "azure", pcontext, TOPIC_EVT_SET_RGLT);
			dy_syslog(LOG_DEBUG, "topic:%s payload %d %s", topic,strlen(payload),payload);
			ipc_session_publish(&gazure_var.session, topic, payload, strlen(payload));
            break;
        default:
            break;
    }
#endif
}

int azure_subscribe(void *handle, char* product_key, char* device_name, char* pcontext, const char *fmt)
{
    
    return 0;
}

static IOTHUBMESSAGE_DISPOSITION_RESULT receive_msg_callback(IOTHUB_MESSAGE_HANDLE message, void* user_context)
{
    (void)user_context;
    const char* messageId;
    const char* correlationId;

    // Message properties
    if ((messageId = IoTHubMessage_GetMessageId(message)) == NULL)
    {
        messageId = "<unavailable>";
    }

    if ((correlationId = IoTHubMessage_GetCorrelationId(message)) == NULL)
    {
        correlationId = "<unavailable>";
    }

    IOTHUBMESSAGE_CONTENT_TYPE content_type = IoTHubMessage_GetContentType(message);
    if (content_type == IOTHUBMESSAGE_BYTEARRAY)
    {
        const unsigned char* buff_msg;
        size_t buff_len;

        if (IoTHubMessage_GetByteArray(message, &buff_msg, &buff_len) != IOTHUB_MESSAGE_OK)
        {
            dy_syslog(LOG_DEBUG, "Failure retrieving byte array message\r\n");
        }
        else
        {
            dy_syslog(LOG_DEBUG, "Received Binary message Message ID: %s Correlation ID: %s Data: <<<%.*s>>> & Size=%d", messageId, correlationId, (int)buff_len, buff_msg, (int)buff_len);
        }
    }
    else
    {
        const char* string_msg = IoTHubMessage_GetString(message);
        if (string_msg == NULL)
        {
            dy_syslog(LOG_DEBUG, "Failure retrieving byte array message\r\n");
        }
        else
        {
            dy_syslog(LOG_DEBUG, "Received String Message\r\nMessage ID: %s\r\n Correlation ID: %s\r\n Data: <<<%s>>>\r\n", messageId, correlationId, string_msg);
        }
    }
    return IOTHUBMESSAGE_ACCEPTED;
}

static void connection_status_callback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* user_context)
{
    (void)reason;
    (void)user_context;
    // This sample DOES NOT take into consideration network outages.
    dy_syslog(LOG_DEBUG, "result %d, IOTHUB_CLIENT_CONNECTION_AUTHENTICATED %d", result, IOTHUB_CLIENT_CONNECTION_AUTHENTICATED);
    if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED)
    {
        dy_syslog(LOG_DEBUG, "The device client is connected to iothub\r\n");
    }
    else
    {
        dy_syslog(LOG_DEBUG, "The device client has been disconnected\r\n");
    }
}

static int device_method_callback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback)
{
    const char* SetTelemetryIntervalMethod = "SetTelemetryInterval";
	azure_dev_info_t *azure_dev = (azure_dev_info_t *)userContextCallback;
    char* end = NULL;
    int newInterval;

    int status = 501;
    const char* RESPONSE_STRING = "{ \"Response\": \"Unknown method requested.\" }";

    dy_syslog(LOG_DEBUG, "Device Method called for device %s", azure_dev->sn);
    dy_syslog(LOG_DEBUG, "Device Method name:    %s", method_name);
    dy_syslog(LOG_DEBUG, "Device Method payload: %.*s", (int)size, (const char*)payload);

	if(strcmp(method_name, "Reboot") == 0)
	{
		status = 200;
        RESPONSE_STRING = "{\"StatusCode\":\"0\",\"Message\":\"Reboot accepted\"}";
	}

	if(strcmp(method_name, "UpdateConfig") == 0)
	{
		if(payload && strstr(payload, "IoTHubConnString") && strstr(payload, "Version"))
		{
			status = 200;
        	RESPONSE_STRING = "{\"StatusCode\":\"0\",\"Message\":\"Update config accepted\"}";
		}
	}

    dy_syslog(LOG_DEBUG, "Response status: %d", status);
    dy_syslog(LOG_DEBUG, "Response payload: %s", RESPONSE_STRING);

    *resp_size = strlen(RESPONSE_STRING);
    if ((*response = malloc(*resp_size)) == NULL)
    {
        status = -1;
    }
    else
    {
        memcpy(*response, RESPONSE_STRING, *resp_size);
    }

	cJSON* root = NULL;
	if(strcmp(method_name, "Reboot") == 0)
		root=cJSON_CreateObject();
	else
		root=cJSON_Parse(payload);
	
    if (!root)
	{
		dy_syslog(LOG_WARNING, "cJSON_Parse payload failed");
    }
	else
	{
		char topic[TOPIC_MAX_LEN] = {0};

		cJSON_AddStringToObject(root, "sn", azure_dev->sn);
		cJSON_AddNumberToObject(root, "mi", 12345);
		cJSON_AddStringToObject(root, "identifier", method_name);
			
		char *azure_payload = cJSON_PrintUnformatted(root);
		snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/%s/device/%s/data/%s", gazure_var.sn_str, "azure", azure_dev->sn, TOPIC_EVT_SET_RGLT);
		dy_syslog(LOG_DEBUG, "topic:%s payload %d %s", topic,strlen(azure_payload),azure_payload);
		ipc_session_publish(gazure_var.session, topic, azure_payload, strlen(azure_payload));
	}
    
    return status;
}

static void send_confirm_callback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    (void)userContextCallback;
	static size_t g_message_count_send_confirmations = 0;
    // When a message is sent this callback will get invoked
    g_message_count_send_confirmations++;
    dy_syslog(LOG_DEBUG, "Confirmation callback received for message %lu with result %s", (unsigned long)g_message_count_send_confirmations, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
}

static int add_node_config(azure_var_t *var, azure_dev_info_t *azure_dev, char *file, cJSON *jroot, cJSON *jnodes,int update)
{
    cJSON* root=NULL;
    cJSON* nodes = NULL;

	if(jroot && jnodes)
	{
		root = jroot;
		nodes = jnodes;
	}
	else
	{
		root=cJSON_CreateObject();
	    if(root == NULL)           return -1;
	    nodes = cJSON_CreateArray();
	    cJSON_AddItemToObject(root,"azure_roche_cfg",nodes);
	}

	cJSON *item = cJSON_CreateObject();
    cJSON_AddItemToArray(nodes,item);
	cJSON_AddStringToObject(item, "sn", azure_dev->sn);
	cJSON_AddStringToObject(item, "connection_string", azure_dev->connectionString);
	cJSON_AddStringToObject(item, "Instruments", azure_dev->instruments);

	char *str = (cJSON_Print(root));
    cJSON_Delete(root);

	write_file_data(file, str, strlen(str));
	free(str);
	if(jroot && update == 0)
	{
		azure_info_list_t* azure = calloc(sizeof(azure_info_list_t), 1);
		memcpy(&azure->azure_dev, azure_dev, sizeof(azure_dev_info_t));
		
		dy_syslog(LOG_INFO,"==update link_node_cnt %d sn:%s connectionString:%s==",var->link_node_cnt,azure->azure_dev.sn,azure->azure_dev.connectionString);
		list_add_tail(&azure->list, &var->node_list);
	}
	
    return 0;

}

static int azure_roche_add_node_config(azure_var_t *var, char *file, azure_dev_info_t *azure_dev)
{
	char buff[128] = {0};
	int ret 	   = 0;
	int i		   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        goto __add_config;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
       goto __add_config;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "azure_roche_cfg");
    if (!nodes)
    {
        goto __add_config;
    }

	add_node_config(var, azure_dev, file, root, nodes, 0);
	return ret;

__add_config:
	add_node_config(var, azure_dev, file, NULL, NULL, 0);	
    return ret;
}

static int azure_roche_update_node_config(azure_var_t *var, char *file, azure_dev_info_t *azure_dev, int delete)
{
	char buff[128] = {0};
	int ret 	   = 0;
	int i		   = 0;

	dy_syslog(LOG_DEBUG, "delete object sn:%s", azure_dev->sn);
	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        goto __add_config;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
       goto __add_config;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "azure_roche_cfg");
    if (!nodes)
    {
        goto __add_config;
    }

    int node_cnt = cJSON_GetArraySize(nodes);

    for (i = 0; i < node_cnt ; i++)
    {
        cJSON *node = cJSON_GetArrayItem(nodes, i);
        if (node)
        {
        	char sn[32] = {0};
        	GET_JSON_VALUE_STRING(node, "sn", sn);
			if(strcmp(sn, azure_dev->sn) == 0)
			{
				dy_syslog(LOG_DEBUG, "delete object sn:%s", sn);
				cJSON_DeleteItemFromArray(nodes, i);
				dy_syslog(LOG_DEBUG, "root:%s", cJSON_PrintUnformatted(root));
				break;
			}
        }
    }

	if(delete)
	{
		char *str = (cJSON_Print(root));
	    cJSON_Delete(root);

		write_file_data(file, str, strlen(str));
		free(str);
		return ret;
	}

	add_node_config(var, azure_dev, file, root, nodes, 1);
	return ret;

__add_config:
	add_node_config(var, azure_dev, file, NULL, NULL, 0);
    return ret;
}

static int azure_roche_load_node_config(azure_var_t *var, char *file)
{
	char buff[128] = {0};
	int ret 	   = -1;
	int i		   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        return -1;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
        return -1;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "azure_roche_cfg");
    if (!nodes)
    {
        ret = -1;
        goto __cleanup;
    }

    int size = cJSON_GetArraySize(nodes);

    for (i = 0; i < size ; i++)
    {
        cJSON *node = cJSON_GetArrayItem(nodes, i);
        if (!node)
        {
            ret = i + 1;
            goto __cleanup;
        }

		azure_info_list_t* azure = calloc(sizeof(azure_info_list_t), 1);

		GET_JSON_VALUE_STRING(node, "sn", azure->azure_dev.sn);
		GET_JSON_VALUE_STRING(node, "connection_string", azure->azure_dev.connectionString);
		GET_JSON_VALUE_STRING(node, "Instruments", azure->azure_dev.instruments);

		azure->azure_dev.protocol = MQTT_Protocol;

		var->link_node_cnt++;
        dy_syslog(LOG_DEBUG,"===%s %d link_node_cnt %d sn %s connectionString %s===\n",__FUNCTION__,__LINE__,var->link_node_cnt,azure->azure_dev.sn,azure->azure_dev.connectionString);
        //azure_mqtt_connect(&azure->azure_dev);
        list_add_tail(&azure->list,&var->node_list);
    }
    ret = 0;

__cleanup:
    cJSON_Delete(root);
    return ret;
}

static int exec_http_cmd(char *buff, char *result)
{
    int ret = -1;
    char *string = NULL;
   ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (!string)return 0;
		dy_syslog(LOG_DEBUG, "---string %s", string);
		if(strlen(string))
		{
			strncpy(result, string, 512);//test_result
			dy_syslog(LOG_DEBUG, "result:%s", result);
		}
        free(string);
		return 1;
    }
    return -1;
}

static int exec_imei_cmd(char *buff, char *result)
{
    int ret = -1;
    char *string = NULL;
   ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (!string)return 0;
		dy_syslog(LOG_DEBUG, "---string %s", string);
		if(strlen(string))
		{
			strncpy(result, string, 32);
			dy_syslog(LOG_DEBUG, "result:%s", result);
		}
        free(string);
		return 1;
    }
    return -1;
}


int Linux_GetTime(char *time_string)
{
	struct tm* ptm;	
	
	
	struct timeval tv;
	gettimeofday (&tv, NULL);
	//tv.tv_sec += 60*60*8;
	ptm = localtime (&tv.tv_sec);
	//time->_milliseconds = tv.tv_usec / 1000;
	
	/*time->_min._minutes = ptm->tm_min;
	time->_hour._hours = ptm->tm_hour;
	time->_day._dayofmonth = ptm->tm_mday;
	time->_day._dayofweek = ptm->tm_wday;
	time->_month._month = ptm->tm_mon+1;
	time->_year._year =ptm->tm_year-100;*/

	dy_syslog(LOG_DEBUG,"-%s- ptm->tm_zone:%s ms:%d _milliseconds %d----------", __FUNCTION__,ptm->tm_zone,tv.tv_usec/1000,tv.tv_usec/1000%1000);
	snprintf(time_string, 64, "20%d-%02d-%02dT%02d:%02d:%02d.%03dZ", ptm->tm_year-100,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec,tv.tv_usec/1000%1000);
	dy_syslog(LOG_DEBUG,"-%s- tm_year(%s) ----------", __FUNCTION__,time_string);
	//ptm->tm_year,time->_year._year,time->_month._month,time->_day._dayofmonth,
                    //time->_day._dayofweek,time->_hour._hours,time->_min._minutes,time->_milliseconds/1000);
	
    return 0;
}

//#define test_data "{\"DeviceId\":\"\",\"EventTime\":\"\",\"ObjectType\":\"DeviceInfo\",\"Version\":\"1.0\",\"Device\":{\"DeviceState\":\"\",\"CreatedTime\":\"\",\"StartupTime\":\"\",\"ShutdownTime\":\"\",\"ShutdownState\":\"\",\"Carrier\":\"\",\"ICCID\":\"\",\"IsSimulatedDevice\":\"\"},\"System\":{\"IMEI\":\"\",\"Manufacturer\":\"\",\"ModelNumber\":\"\",\"SerialNumber\":\"\",\"FirmwareVersion\":\"\",\"Platform\":\"\",\"Processor\":\"\",\"InstalledRAM\":\"\"},\"Config\":{\"HeartbeatInterval\":300,\"SensorTelemetryInterval\":300,\"InstrumentTelemetryInterval\":300,\"InstrumentType\":\"E411\",\"EnableE411DataConnection\":\"1\",\"E411RealtimeDataInterval\":300,\"E411ScheduleDataInterval\":300,\"EnableAxedaDataUpload\":\"1\",\"AutoRebootEnable\":\"1\",\"AutoRebootInterval\":7,\"AutoRebootTime\":\"5: 30\"},\"SupportCommands\":[{\"Name\":\"Reboot\",\"DeliveryType\":\"1\",\"Version\":\"1.0\",\"Description\":\"\"}],\"Telemetry\":[{\"Name\":\"\",\"DisplayName\":\"\",\"Type\":\"\"}]}"
//"{\"DeviceId\": \"\",     \"EventTime\": \"\",     \"ObjectType\": \"DeviceInfo\",     \"Version\": \"1.0\",     \"Device\": {         \"DeviceState\": \"\",         \"CreatedTime\": \"\",         \"StartupTime\": \"\",         \"ShutdownTime\": \"\",         \"ShutdownState\": \"\",         \"Carrier\": \"\",         \"ICCID\": \"\",         \"IsSimulatedDevice\": \"\"     } }"
//"{\"DeviceId\":\"888999\",\"EventTime\":\"\",\"ObjectType\":\"DeviceInfo\",\"Version\":\"1.0\",\"Device\":{\"DeviceState\":\"\",\"CreatedTime\":\"\",\"StartupTime\":\"\",\"ShutdownTime\":\"\",\"ShutdownState\":\"\",\"Carrier\":\"\",\"ICCID\":\"\",\"IsSimulatedDevice\":\"\"},\"System\":{\"IMEI\":\"\",\"Manufacturer\":\"\",\"ModelNumber\":\"\",\"SerialNumber\":\"\",\"FirmwareVersion\":\"\",\"Platform\":\"\",\"Processor\":\"\",\"InstalledRAM\":\"\"},\"Config\":{\"HeartbeatInterval\":300,\"SensorTelemetryInterval\":300,\"InstrumentTelemetryInterval\":300,\"InstrumentType\":\"E411\",\"EnableE411DataConnection\":\"1\",\"E411RealtimeDataInterval\":300,\"E411ScheduleDataInterval\":300,\"EnableAxedaDataUpload\":\"1\"“AutoRebootEnable”:\"1\"“AutoRebootInterval”:7“AutoRebootTime”:\"5:30\"},\"SupportCommands\":[{\"Name\":\"Reboot\",\"DeliveryType\":\"1\",\"Version\":\"1.0\",\"Description\":\"\"}],\"Telemetry\":[{\"Name\":\"\",\"DisplayName\":\"\",\"Type\":\"\"}]}"
int azure_publish(azure_dev_info_t *azure_dev, int type, char *params)
{
	dy_syslog(LOG_DEBUG, "type %d azure_publish:%s", type, params);
	if(type == 0)
	{
		dy_syslog(LOG_DEBUG, "State strlen(test_data) %d test_data:%s", strlen(params), params);
    	//IoTHubDeviceClient_SendReportedState(azure_dev->iotHubClientHandle, (const unsigned char*)params, strlen(params), reportedStateCallback, azure_dev);
	}
	else if(type == 1 || type == 2)
	{
		IOTHUB_MESSAGE_HANDLE message_handle;
		message_handle = IoTHubMessage_CreateFromString(params);

        // Set Message property
        IoTHubMessage_SetMessageId(message_handle, "MSG_ID");
        IoTHubMessage_SetCorrelationId(message_handle, "CORE_ID");
        IoTHubMessage_SetContentTypeSystemProperty(message_handle, "application%2fjson");
        IoTHubMessage_SetContentEncodingSystemProperty(message_handle, "utf-8");

        // Add custom properties to message
        //IoTHubMessage_SetProperty(message_handle, "property_key", "property_value");
		dy_syslog(LOG_DEBUG, "Event strlen(test_data) %d test_data:%s", strlen(params), params);
		IoTHubDeviceClient_SendEventAsync(azure_dev->iotHubClientHandle, message_handle, send_confirm_callback, azure_dev);
	}
	
    return 0;
}

int azure_send_msg(azure_dev_info_t *azure_dev, char *params)
{
	dy_syslog(LOG_DEBUG, "azure_publish:%s", params);
	IOTHUB_MESSAGE_HANDLE message_handle;
	message_handle = IoTHubMessage_CreateFromString(params);

    // Set Message property
    IoTHubMessage_SetMessageId(message_handle, "MSG_ID");
    IoTHubMessage_SetCorrelationId(message_handle, "CORE_ID");
    IoTHubMessage_SetContentTypeSystemProperty(message_handle, "application%2fjson");
    IoTHubMessage_SetContentEncodingSystemProperty(message_handle, "utf-8");

    // Add custom properties to message
    //IoTHubMessage_SetProperty(message_handle, "property_key", "property_value");
	dy_syslog(LOG_DEBUG, "Event strlen(test_data) %d test_data:%s", strlen(params), params);
	IoTHubDeviceClient_SendEventAsync(azure_dev->iotHubClientHandle, message_handle, send_confirm_callback, azure_dev);
	
    return 0;
}


void azure_event_handle(void *pcontext, void *pclient, void *msg)
{
    //dy_syslog(LOG_DEBUG, "msg->event_type : %d pcontext : %s", msg->event_type,pcontext);
}

int azure_mqtt_connect(azure_dev_info_t *azure_dev)
{
    int res = 0;

	if ((azure_dev->iotHubClientHandle = IoTHubDeviceClient_CreateFromConnectionString(azure_dev->connectionString, azure_dev->protocol)) == NULL)
    {
        dy_syslog(LOG_ERR, "ERROR: iotHubClientHandle is NULL");
    }
    else
    {
        IoTHubDeviceClient_GetTwinAsync(azure_dev->iotHubClientHandle, getCompleteDeviceTwinOnDemandCallback, azure_dev);
        //IoTHubDeviceClient_SendReportedState(azure_dev->iotHubClientHandle, (const unsigned char*)reportedProperties, strlen(reportedProperties), reportedStateCallback, NULL);
        IoTHubDeviceClient_SetDeviceMethodCallback(azure_dev->iotHubClientHandle, device_method_callback, azure_dev);
        IoTHubDeviceClient_SetDeviceTwinCallback(azure_dev->iotHubClientHandle, deviceTwinCallback, azure_dev);
		
		// Setting message callback to get C2D messages
        IoTHubDeviceClient_SetMessageCallback(azure_dev->iotHubClientHandle, receive_msg_callback, azure_dev);
        // Setting connection status callback to get indication of connection to iothub
        IoTHubDeviceClient_SetConnectionStatusCallback(azure_dev->iotHubClientHandle, connection_status_callback, azure_dev);
		azure_dev->connected = 1;
    }

    return 0;
}

int register_msg_check(azure_var_t* var, azure_dev_info_t *azure_dev, char *result)
{
	cJSON *root = cJSON_Parse(result);
	if(root)
	{
		//{"Error":{"Code":"BadArgument","Message":"Invalid Device Id."}}
		//{"RetryAfter":30}
		/*{
			"IoTHubConnString": "HostName=dev-ih-iothub.azure-devices.cn;DeviceId=devtest;SharedAccessKey=0nnnveE8MYHgOynWRtLFmb2C3Opo+hJnNVvGuAtyF84=",
			"Instruments": [
				{
				"SerialNumber": "0904-08"
				},
				{
				"SerialNumber": "0904-11"
				}
			]
		}*/
		char buff[512] = {0};
		dy_syslog(LOG_DEBUG,"================111111111 registered %d connected %d====================",azure_dev->registered,azure_dev->connected);
		//注册成功
		GET_JSON_VALUE_STRING(root, "IoTHubConnString", buff);
		if(strlen(buff))
		{
			//已注册
			dy_syslog(LOG_DEBUG,"===%s %d connectionString(%s %s)===\n",__FUNCTION__,__LINE__,azure_dev->connectionString,buff);
			if(strlen(azure_dev->connectionString) && strcmp(azure_dev->connectionString,buff) == 0)
			{
				dy_syslog(LOG_DEBUG,"===aaa===");
				//goto __check_out;
			}
			else
			{
				//未注册
				strncpy(azure_dev->connectionString, buff, sizeof(azure_dev->connectionString));
				cJSON *Instruments = cJSON_GetObjectItem(root, "Instruments");
				char *Instruments_data = cJSON_PrintUnformatted(Instruments);
				dy_syslog(LOG_DEBUG, "Instruments Instruments_data:%s", Instruments_data);
				strncpy(azure_dev->instruments, Instruments_data, sizeof(azure_dev->instruments));

				dy_syslog(LOG_DEBUG, "==connectionString(%s,%s) instruments(%s,%s)", azure_dev->connectionString,buff,azure_dev->instruments, Instruments_data);
				//if(strcmp(azure_dev->connectionString,buff) || strcmp(azure_dev->instruments, Instruments_data))
				{
					azure_roche_update_node_config(var, AZURE_ROCHE_CFG, azure_dev, 0);
				}
				
				azure_info_list_t *azure = NULL;
			    list_for_each_entry(azure, &var->node_list,list)
			    {
			    	//连接azure
			    	if(azure->azure_dev.connected == 0)
			    		azure_mqtt_connect(&azure->azure_dev);
					dy_syslog(LOG_DEBUG, "sn %s azure->azure_dev.registered:%d connected %d", azure->azure_dev.sn,azure->azure_dev.registered,azure->azure_dev.connected);
					//以一个设备的方式连接azure
					break;
			    }
			}		

			azure_dev->registered = 1;
			dy_syslog(LOG_DEBUG, "registered:%d", azure_dev->registered);
		}
		else
		{
			//下次注册时间
			GET_JSON_VALUE_STRING(root, "RetryAfter", buff);
			if(strlen(buff))
			{
				azure_dev->registered = 1;
			}
			//注册错误
			else
			{
				dy_syslog(LOG_WARNING, "result:%s", result);
			}
		}
		dy_syslog(LOG_DEBUG,"================22222222====================");
__check_out:
		cJSON_Delete(root);
	}
}

int azure_heartbeat_msg(azure_info_list_t *azure)
{
	cJSON *root = cJSON_CreateObject();
	if(root)
	{
		char time_string[64] = {0};
		Linux_GetTime(time_string);
		cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
		cJSON_AddStringToObject(root, "EventTime", time_string);
		cJSON_AddStringToObject(root, "ObjectType", "HeartbeatMessage");
		cJSON_AddStringToObject(root, "Version", "1.0");
		char *heartbeat = cJSON_PrintUnformatted(root);
		azure_send_msg(&azure->azure_dev, heartbeat);
		free(heartbeat);
		cJSON_Delete(root);
	}

	return 0;
}

int azure_sensor_msg(azure_info_list_t *azure)
{
	cJSON *root = cJSON_CreateObject();
	if(root)
	{
		char time_string[64] = {0};
		Linux_GetTime(time_string);
		cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
		cJSON_AddStringToObject(root, "EventTime", time_string);
		cJSON_AddStringToObject(root, "ObjectType", "SensorMessage");
		cJSON_AddStringToObject(root, "Version", "1.0");

		cJSON_AddStringToObject(root, "ICCID", azure->azure_dev.device_info->system.IMEI);//SIM ICCID
		cJSON_AddNumberToObject(root, "Humidity", 34.6);
		cJSON_AddNumberToObject(root, "Temperature", 25.3);
		cJSON_AddNumberToObject(root, "SignalStrength", 4);
		cJSON_AddStringToObject(root, "NetworkStandard", "CDMS");
		cJSON_AddStringToObject(root, "dbmValue", "-40");
		
		char *sensor = cJSON_PrintUnformatted(root);
		azure_send_msg(&azure->azure_dev, sensor);
		free(sensor);
		cJSON_Delete(root);
	}

	return 0;
}

int azure_instrument_msg(azure_info_list_t *azure)
{
	cJSON *root = cJSON_CreateObject();
	if(root)
	{
		char time_string[64] = {0};
		Linux_GetTime(time_string);
		cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
		cJSON_AddStringToObject(root, "EventTime", time_string);
		cJSON_AddStringToObject(root, "ObjectType", "InstrumentMessage");
		cJSON_AddStringToObject(root, "Version", "1.0");

		cJSON_AddStringToObject(root, "ICCID", azure->azure_dev.device_info->system.IMEI);//SIM ICCID
		cJSON_AddStringToObject(root, "InstrumentId", "RUDI");//RUDI for E411, empty for other
		cJSON_AddStringToObject(root, "MAC", "00:cc:29:0f:66:a3");
		cJSON_AddStringToObject(root, "IP", "192.168.1.8");
		cJSON_AddStringToObject(root, "InstrumentState", "Online");//Online/Offline
		
		char *instrument = cJSON_PrintUnformatted(root);
		azure_send_msg(&azure->azure_dev, instrument);
		free(instrument);
		cJSON_Delete(root);
	}

	return 0;
}

int azure_instrument_data_msg(azure_info_list_t *azure, char *XMLDataType, char *Payload)
{
	cJSON *root = cJSON_CreateObject();
	if(root)
	{
		char time_string[64] = {0};
		Linux_GetTime(time_string);
		cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
		cJSON_AddStringToObject(root, "EventTime", time_string);
		cJSON_AddStringToObject(root, "ObjectType", "InstrumentData");
		cJSON_AddStringToObject(root, "Version", "1.0");

		cJSON_AddStringToObject(root, "ICCID", azure->azure_dev.device_info->system.IMEI);//SIM ICCID
		cJSON_AddStringToObject(root, "InstrumentId", "91445");//Instrument SN
		cJSON_AddStringToObject(root, "MAC", "00:cc:29:0f:66:a3");
		cJSON_AddStringToObject(root, "IP", "192.168.1.8");
		cJSON_AddStringToObject(root, "Payload", Payload);//Custom Json Object
		cJSON_AddStringToObject(root, "XMLDataType", XMLDataType);//Alarms/TestResults/TestCalibration/TraceInstrument/InstrumentConfiguration
		cJSON_AddStringToObject(root, "XMLData", "");
		
		char *instrument_data = cJSON_PrintUnformatted(root);
		azure_send_msg(&azure->azure_dev, instrument_data);
		free(instrument_data);
		cJSON_Delete(root);
	}

	return 0;
}
int azure_init_device_info(azure_info_list_t *azure)
{
	if(!azure->azure_dev.device_info)
	{
		char imei[32] = {0};
		exec_imei_cmd("gcom -d /dev/ttyUSB0 -s /etc/gcom/geticcid.gcom", imei);
		if(!strlen(imei))
		{
			strcpy(imei, "89860436101891923504");
		}
		azure->azure_dev.device_info = calloc(1, sizeof(device_info_t)+sizeof(device_info_support_commands_t)+sizeof(device_info_telemetry_t));
		
		strcpy(azure->azure_dev.device_info->system.IMEI, imei);
		strcpy(azure->azure_dev.device_info->system.Manufacturer, "lnx");
		strcpy(azure->azure_dev.device_info->system.ModelNumber, "1.2.3");
		strcpy(azure->azure_dev.device_info->system.SerialNumber, imei);
		strcpy(azure->azure_dev.device_info->system.FirmwareVersion, "1.1.1");
		strcpy(azure->azure_dev.device_info->system.Platform, "arm");
		strcpy(azure->azure_dev.device_info->system.Processor, "MediaTek");
		strcpy(azure->azure_dev.device_info->system.InstalledRAM, "512M");

		strcpy(azure->azure_dev.device_info->device.DeviceState, "Normal");
		strcpy(azure->azure_dev.device_info->device.CreatedTime, "2020-09-02T02:52:58.493Z");
		strcpy(azure->azure_dev.device_info->device.StartupTime, "2020-09-02T07:52:58.493Z");
		strcpy(azure->azure_dev.device_info->device.ShutdownTime, "2020-09-02T04:52:58.493Z");
		strcpy(azure->azure_dev.device_info->device.ShutdownState, "Poweroff");
		strcpy(azure->azure_dev.device_info->device.Carrier, "CMCC");
		strcpy(azure->azure_dev.device_info->device.ICCID, azure->azure_dev.device_info->system.IMEI);
		azure->azure_dev.device_info->device.IsSimulatedDevice = 1;//False

		azure->azure_dev.device_info->support_commands_cnt = 1;
		//azure->azure_dev.device_info->support_commands = calloc(1, sizeof(device_info_support_commands_t));
		strcpy(azure->azure_dev.device_info->support_commands[0].Name, "Reboot");
		strcpy(azure->azure_dev.device_info->support_commands[0].DeliveryType, "1");
		strcpy(azure->azure_dev.device_info->support_commands[0].Version, "1.0");
		strcpy(azure->azure_dev.device_info->support_commands[0].Description, "Reboot Device");

		azure->azure_dev.device_info->telemetry_cnt = 1;
		//azure->azure_dev.device_info->telemetry = calloc(1, sizeof(device_info_telemetry_t));
		strcpy(azure->azure_dev.device_info->telemetry[0].Name, "E411");
		strcpy(azure->azure_dev.device_info->telemetry[0].DisplayName, "E411");
		strcpy(azure->azure_dev.device_info->telemetry[0].Type, "String");
	}

	return 0;
}
int azure_device_info_msg(azure_info_list_t *azure)
{
	cJSON *root = cJSON_CreateObject();
	if(root)
	{
		char time_string[64] = {0};
		Linux_GetTime(time_string);
		azure_init_device_info(azure);
		cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
		cJSON_AddStringToObject(root, "EventTime", time_string);
		cJSON_AddStringToObject(root, "ObjectType", "DeviceInfo");
		cJSON_AddStringToObject(root, "Version", "1.0");

		cJSON *device = cJSON_CreateObject();
    	cJSON_AddItemToObject(root, "Device", device);		
		cJSON_AddStringToObject(device, "DeviceState", azure->azure_dev.device_info->device.DeviceState);
		cJSON_AddStringToObject(device, "CreatedTime", azure->azure_dev.device_info->device.CreatedTime);
		cJSON_AddStringToObject(device, "StartupTime", azure->azure_dev.device_info->device.StartupTime);
		cJSON_AddStringToObject(device, "ShutdownTime", azure->azure_dev.device_info->device.ShutdownTime);
		cJSON_AddStringToObject(device, "ShutdownState", azure->azure_dev.device_info->device.ShutdownState);
		cJSON_AddStringToObject(device, "Carrier", azure->azure_dev.device_info->device.Carrier);
		cJSON_AddStringToObject(device, "ICCID", azure->azure_dev.device_info->device.ICCID);
		cJSON_AddBoolToObject(device, "IsSimulatedDevice", azure->azure_dev.device_info->device.IsSimulatedDevice);

		cJSON *system = cJSON_CreateObject();
    	cJSON_AddItemToObject(root, "System", system);
		cJSON_AddStringToObject(system, "IMEI", azure->azure_dev.device_info->system.IMEI);
		cJSON_AddStringToObject(system, "Manufacturer", azure->azure_dev.device_info->system.Manufacturer);
		cJSON_AddStringToObject(system, "ModelNumber", azure->azure_dev.device_info->system.ModelNumber);
		cJSON_AddStringToObject(system, "SerialNumber", azure->azure_dev.device_info->system.SerialNumber);
		cJSON_AddStringToObject(system, "FirmwareVersion", azure->azure_dev.device_info->system.FirmwareVersion);
		cJSON_AddStringToObject(system, "Platform", azure->azure_dev.device_info->system.Platform);
		cJSON_AddStringToObject(system, "Processor", azure->azure_dev.device_info->system.Processor);
		cJSON_AddStringToObject(system, "InstalledRAM", azure->azure_dev.device_info->system.InstalledRAM);

		cJSON *config = cJSON_CreateObject();
    	cJSON_AddItemToObject(root, "Config", config);
		cJSON_AddNumberToObject(config, "HeartbeatInterval", azure->azure_dev.desired_config->HeartbeatInterval);
		cJSON_AddNumberToObject(config, "SensorTelemetryInterval", azure->azure_dev.desired_config->SensorTelemetryInterval);
		cJSON_AddNumberToObject(config, "InstrumentTelemetryInterval", azure->azure_dev.desired_config->InstrumentTelemetryInterval);
		cJSON_AddStringToObject(config, "InstrumentType", azure->azure_dev.desired_config->InstrumentType);
		cJSON_AddNumberToObject(config, "EnableE411DataConnection", azure->azure_dev.desired_config->EnableE411DataConnection);
		cJSON_AddNumberToObject(config, "E411RealtimeDataInterval", azure->azure_dev.desired_config->E411RealtimeDataInterval);
		cJSON_AddNumberToObject(config, "E411ScheduleDataInterval", azure->azure_dev.desired_config->E411ScheduleDataInterval);
		cJSON_AddStringToObject(config, "EnableAxedaDataUpload", azure->azure_dev.desired_config->EnableAxedaDataUpload);
		cJSON_AddStringToObject(config, "AutoRebootEnabled", azure->azure_dev.desired_config->AutoRebootEnabled);
		cJSON_AddNumberToObject(config, "AutoRebootInterval", azure->azure_dev.desired_config->AutoRebootInterval);
		cJSON_AddStringToObject(config, "AutoRebootTime", azure->azure_dev.desired_config->AutoRebootTime);
#if 1
		cJSON *support_commands = cJSON_CreateArray();
    	cJSON_AddItemToObject(root, "SupportCommands", support_commands);
		int i;
		for(i=0; i<azure->azure_dev.device_info->support_commands_cnt; i++)
		{
			cJSON *commands = cJSON_CreateObject();
    		cJSON_AddItemToArray(support_commands, commands);
			
			cJSON_AddStringToObject(commands, "Name", azure->azure_dev.device_info->support_commands[i].Name);
			cJSON_AddStringToObject(commands, "DeliveryType", azure->azure_dev.device_info->support_commands[i].DeliveryType);
			cJSON_AddStringToObject(commands, "Version", azure->azure_dev.device_info->support_commands[i].Version);
			cJSON_AddStringToObject(commands, "Description", azure->azure_dev.device_info->support_commands[i].Description);
		}

		cJSON *telemetrys = cJSON_CreateArray();
    	cJSON_AddItemToObject(root, "Telemetry", telemetrys);
		for(i=0; i<azure->azure_dev.device_info->telemetry_cnt; i++)
		{
			cJSON *telemetry = cJSON_CreateObject();
    		cJSON_AddItemToArray(telemetrys, telemetry);
			
			cJSON_AddStringToObject(telemetry, "Name", azure->azure_dev.device_info->telemetry[i].Name);
			cJSON_AddStringToObject(telemetry, "DeliveryType", azure->azure_dev.device_info->telemetry[i].DisplayName);
			cJSON_AddStringToObject(telemetry, "Type", azure->azure_dev.device_info->telemetry[i].Type);
		}
#endif		
		char *device_info = cJSON_PrintUnformatted(root);
		//dy_syslog(LOG_DEBUG, "device_info:%s", device_info);
		azure_send_msg(&azure->azure_dev, device_info);
		free(device_info);
		cJSON_Delete(root);
	}

	return 0;
}

int azure_register_msg(azure_var_t* var, azure_info_list_t *azure)
{
	if(!azure->azure_dev.register_string)
	{
		cJSON *root = cJSON_CreateObject();
		if(root)
		{
			cJSON_AddStringToObject(root, "DeviceId", azure->azure_dev.sn);
			#if 0
			cJSON *Instruments = cJSON_CreateArray();
	    	cJSON_AddItemToObject(root, "Instruments", Instruments);
			int i;
			for(i=0; i<1; i++)
			{
				cJSON *Instrument = cJSON_CreateObject();
	    		cJSON_AddItemToArray(Instruments, Instrument);
				
				cJSON_AddStringToObject(Instrument, "MAC", "00:cc:29:0f:66:a3");
				cJSON_AddStringToObject(Instrument, "IP", "192.168.1.8");
			}
			#endif
			char *heartbeat = cJSON_PrintUnformatted(root);
			char *result = calloc(1,512);
			azure->azure_dev.register_string = calloc(1,512);
			snprintf(azure->azure_dev.register_string, 512, "curl -H \"Content-Type: application/json\" -X POST  --data '%s' https://rsp-test.roche-diagnostics.cn/api/v1/provision", heartbeat);
				dy_syslog(LOG_DEBUG, "==register_string:%s", azure->azure_dev.register_string);
			//azure_send_msg(&azure->azure_dev, heartbeat);
			exec_http_cmd(azure->azure_dev.register_string, result);
			register_msg_check(var, &azure->azure_dev, result);

			free(result);
			free(heartbeat);
			cJSON_Delete(root);
		}
	}
	else
	{
		char *result = calloc(1,512);
		exec_http_cmd(azure->azure_dev.register_string, result);
		register_msg_check(var, &azure->azure_dev, result);
		free(result);
	}

	return 0;
}

int azure_get_message(azure_var_t* var)
{
	TIMER_CONFIRM(var->heartbeat_timer);
	time_t now = time(NULL);
	
    int ret;
	static int null_cnt = 0;
	
	azure_info_list_t *azure = NULL;
    list_for_each_entry(azure, &var->node_list,list)
    {
    	//注册
    	//if(azure->azure_dev.register_string)
    	{
    		if((azure->azure_dev.registered == 0 && now - azure->azure_dev.last_register >= 30) ||
				(azure->azure_dev.registered == 1 && now - azure->azure_dev.last_register >= 300))
    		{
    			dy_syslog(LOG_DEBUG, "sn %s registered %d now %ld last_register %ld", azure->azure_dev.sn,azure->azure_dev.registered,now,azure->azure_dev.last_register);
    			azure_register_msg(var, azure);
				azure->azure_dev.last_register = now;
    		}
    	}
		
    	if(!azure->azure_dev.connected || !azure->azure_dev.iotHubClientHandle || 
			!azure->azure_dev.desired_config || !azure->azure_dev.desired_config->HeartbeatInterval)
    	{
    		dy_syslog(LOG_DEBUG, "==sn %s connected %d iotHubClientHandle %p desired_config %p==", azure->azure_dev.sn,azure->azure_dev.connected,
				azure->azure_dev.iotHubClientHandle,azure->azure_dev.desired_config);
			continue;
		}
		//device info
		if(!azure->last_device_info)
    	{
    		dy_syslog(LOG_DEBUG, "==last_device_info %d", azure->last_device_info);
    		azure->last_device_info = now;
			azure_device_info_msg(azure);
    	}
		//心跳
    	if(now - azure->last_heartbeat >= azure->azure_dev.desired_config->HeartbeatInterval)
    	{
    		dy_syslog(LOG_DEBUG, "==now %ld last_heartbeat %ld HeartbeatInterval %d", now, azure->last_heartbeat,azure->azure_dev.desired_config->HeartbeatInterval);
    		azure->last_heartbeat = now;
			azure_heartbeat_msg(azure);
    	}
		//传感器遥测消息
		if(now - azure->last_sensor >= azure->azure_dev.desired_config->SensorTelemetryInterval)
    	{
    		dy_syslog(LOG_DEBUG, "==now %ld last_sensor %ld SensorTelemetryInterval %d", now, azure->last_sensor,azure->azure_dev.desired_config->SensorTelemetryInterval);
    		azure->last_sensor = now;
			//azure_sensor_msg(azure);
    	}
		//仪器状态消息，仪器数据
		if(now - azure->last_instrument >= azure->azure_dev.desired_config->InstrumentTelemetryInterval)
    	{
    		dy_syslog(LOG_DEBUG, "==now %ld last_instrument %ld InstrumentTelemetryInterval %d", now, azure->last_instrument,azure->azure_dev.desired_config->InstrumentTelemetryInterval);
    		azure->last_instrument = now;
			azure_instrument_msg(azure);
			azure_instrument_data_msg(azure, "Alarms", INSTRUMENT_DATA_Alarms);
			azure_instrument_data_msg(azure, "TestResults", INSTRUMENT_DATA_TestResults);
			azure_instrument_data_msg(azure, "TestCalibration", INSTRUMENT_DATA_TestCalibration);
			azure_instrument_data_msg(azure, "TraceInstrument", INSTRUMENT_DATA_TraceInstrument);
			azure_instrument_data_msg(azure, "InstrumentConfiguration", INSTRUMENT_DATA_InstrumentConfiguration);			
    	}
    }

	return 0;
}

static int azure_node_connect(azure_var_t *var)
{
	int i;

	if (IoTHub_Init() != 0)
    {
        dy_syslog(LOG_ERR, "Failed to initialize the platform..");
		return 0;
    }
	
	//var->link_node_cnt = 0;
	for(i=0; i<var->nodes_cfg_table->node_cnt; i++)
    {
    	if(strlen(var->nodes_cfg_table->node[i].connection_string))
		{
			//未注册
			dy_syslog(LOG_DEBUG,"===%s %d link_node_cnt %d ", __FUNCTION__,__LINE__,var->link_node_cnt);
			if(var->link_node_cnt == 0)
			{
				azure_info_list_t* azure = calloc(sizeof(azure_info_list_t), 1);

				strncpy(azure->azure_dev.sn, var->nodes_cfg_table->node[i].sn, sizeof(azure->azure_dev.sn));
				strncpy(azure->azure_dev.raw_connectionString, var->nodes_cfg_table->node[i].connection_string, sizeof(azure->azure_dev.connectionString));
				azure->azure_dev.protocol = MQTT_Protocol;

				var->link_node_cnt++;
		        dy_syslog(LOG_DEBUG,"===%s %d link_node_cnt %d sn %s connectionString %s)===\n",__FUNCTION__,__LINE__,var->link_node_cnt,azure->azure_dev.sn,azure->azure_dev.connectionString);
		        //azure_mqtt_connect(&azure->azure_dev);
		        list_add_tail(&azure->list,&var->node_list);
			}
			//已注册
			else
			{
				azure_info_list_t *azure = NULL;
			    list_for_each_entry(azure, &var->node_list,list)
			    {
			    	if(strcmp(azure->azure_dev.sn, var->nodes_cfg_table->node[i].sn) == 0)
			    	{
			    		//连接azure
			    		azure_mqtt_connect(&azure->azure_dev);
			    	}
			    }
			}
		}
    }
}

static int mqtt_msg_process(azure_var_t *var, int type, ipc_msg_t *mqtt_msg)
{
	int ret;
	static int null_cnt = 0;
	tag_table_t tag;

	//先检查参数
	ret = get_tag_data_from_str(&tag, mqtt_msg->payload);
    if (ret < 0)
    {
        dy_syslog(LOG_ERR, "get data structure failed");
        return -1;
    }
	
	azure_info_list_t *azure = NULL;
	list_for_each_entry(azure, &var->node_list, list)
	{
		//注册成功后,才处理相应消息
		if(azure->azure_dev.registered && strcmp(azure->azure_dev.sn, tag.sn) == 0)
		{
			char topic[256] = {0};
			char method[256] = {0};
			char *params = tag.tag_node;
			
			if (params == NULL)
			{
		        dy_syslog(LOG_WARNING,"type %d params is NULL!!!",type);
		        break;
		    }
			if(type == 0)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			else if(type == 1)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			else if(type == 2)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			break;
		}
	}
}

static int tcp_msg_process(azure_var_t *var, tcp_data_list_t* data)
{
	int ret;
	static int null_cnt = 0;
	tag_table_t tag;
#if 0
	//先检查参数
	ret = get_tag_data_from_str(&tag, mqtt_msg->payload);
    if (ret < 0)
    {
        dy_syslog(LOG_ERR, "get data structure failed");
        return -1;
    }
	
	azure_info_list_t *azure = NULL;
	list_for_each_entry(azure, &var->node_list, list)
	{
		//注册成功后,才处理相应消息
		if(azure->azure_dev.registered && strcmp(azure->azure_dev.sn, tag.sn) == 0)
		{
			char topic[256] = {0};
			char method[256] = {0};
			char *params = tag.tag_node;
			
			if (params == NULL)
			{
		        dy_syslog(LOG_WARNING,"type %d params is NULL!!!",type);
		        break;
		    }
			if(type == 0)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			else if(type == 1)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			else if(type == 2)
			{
				azure_publish(&azure->azure_dev, type, params);
			}
			break;
		}
	}
#endif
}


void msg_mqtt_recv(azure_var_t *var, int type, ipc_msg_t *mqtt_msg)
{
    int ret,i;

	data_list_t* data = calloc(1,sizeof(data_list_t)+mqtt_msg->payloadLen+1);	
	if(data)
	{
		strncpy(data->mqtt.topic, mqtt_msg->topic, sizeof(data->mqtt.topic));
		data->type = type;
		data->mqtt.payloadLen = mqtt_msg->payloadLen;
		memcpy(data->mqtt.payload, mqtt_msg->payload, data->mqtt.payloadLen);
		var->data_cnt++;
		dy_syslog(LOG_DEBUG, "++%s topic %s data_cnt %d\n",__FUNCTION__,data->mqtt.topic,var->data_cnt);
    	list_add_tail(&data->list,&var->data_list);
	}

	var->data_flag = 1;
}

static int mqtt_msg_process_loop(azure_var_t *var)
{
	data_list_t* data = NULL;	
	list_for_each_entry(data, &var->data_list, list)
	{
		dy_syslog(LOG_DEBUG, "var->data_cnt %d", var->data_cnt);
		var->data_cnt--;
		mqtt_msg_process(var, data->type, &data->mqtt);
		list_del(&data->list);
		break;
	}

	var->data_cnt = 0;
	var->data_flag = 0;
}

static int tcp_msg_process_loop(azure_var_t *var)
{
	tcp_data_list_t* data = NULL;	
	list_for_each_entry(data, &var->tcp_data_list, list)
	{
		dy_syslog(LOG_DEBUG, "var->data_cnt %d", var->data_cnt);
		var->tcp_data_cnt--;
		tcp_msg_process(var, data);
		list_del(&data->list);
		break;
	}

	var->tcp_data_cnt = 0;
	var->data_flag = 0;
}

static void azure_loop(azure_var_t *var)
{
	int ret = -1, maxfd = 0, i;
    fd_set rset;
    struct timeval timeout;
	
    while (1)
    {
    	SELECT_INIT();
        SELECT_ADD_FD(var->heartbeat_timer);

		if(var->data_flag)
        {
			timeout.tv_usec = 50000;
        	timeout.tv_sec = 0;
        }
		else
		{
			timeout.tv_usec = 0;
        	timeout.tv_sec = 2;
		}
		//Linux_GetTime();

        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            dy_syslog(LOG_INFO, "errno %d\n", errno);

            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret > 0)
        {
            if (var->heartbeat_timer > 0 && FD_ISSET(var->heartbeat_timer, &rset))
            {
                FD_CLR(var->heartbeat_timer, &rset);
                azure_get_message(var);
            }
        }

		mqtt_msg_process_loop(var);
    }
}

static void azure_subscribe_all(azure_var_t *var)
{
    ipc_session_t *ipc_session = var->session;
    char topic[TOPIC_MAX_LEN] = {0};

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/+/data_filtered/property/+", var->sn_str);
    ipc_session_subscribe(ipc_session, topic);

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/+/data_filtered/event/+", var->sn_str);
    ipc_session_subscribe(ipc_session, topic);

    snprintf(topic, TOPIC_MAX_LEN, "ipc/%s/+/device/+/data_filtered/service/+", var->sn_str);
    ipc_session_subscribe(ipc_session, topic);

	snprintf(topic, TOPIC_MAX_LEN, "ipc/+/%s/device/+/data/%s", port_enum2char(TCP_CLIENT), TOPIC_SEND_RGLT_SIGNAL_RAW_DATA);
    ipc_session_subscribe(ipc_session, topic);
}

static int azure_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{
    azure_var_t *var = (azure_var_t *)obj;
    bool matched;
    int ret;
    dy_syslog(LOG_DEBUG, " MQTT client: received MQTT topic:%s payload length:%d",
            mqtt_msg->topic, mqtt_msg->payloadLen);

	if (strstr(mqtt_msg->topic, TOPIC_SEND_RGLT_SIGNAL_RAW_DATA))
	{
		dy_syslog(LOG_DEBUG, "mqtt_msg->payload:%s", mqtt_msg->payload);
		if(strstr(mqtt_msg->payload, "Reboot"))
		{
			dy_syslog(LOG_DEBUG, "sleep 3; reboot...");
			system("sleep 3; reboot &");
		}
	}
	else
	{
	    ret = mosquitto_topic_matches_sub("ipc/+/+/device/+/data_filtered/property/+", mqtt_msg->topic, &matched);
	    if (ret == 0 && matched)
	    {
	        //实时数据
	        msg_mqtt_recv(var, 0, mqtt_msg);
	    }
	    else
	    {
	        //事件
	        ret = mosquitto_topic_matches_sub("ipc/+/+/device/+/data_filtered/event/+", mqtt_msg->topic, &matched);
	        if (ret == 0 && matched)
	        {
	            msg_mqtt_recv(var, 1, mqtt_msg);
	        }
	        else
	        {
	            ret = mosquitto_topic_matches_sub("ipc/+/+/device/+/data_filtered/service/+", mqtt_msg->topic, &matched);
	            if (ret == 0 && matched)
	            {
	                msg_mqtt_recv(var, 2, mqtt_msg);
	            }
	        }
	    }
	}
}

// 建立与内部broker之间的MQTT连接
int azure_mqtt_client_init(azure_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "INT_azure_%s", var->sn_str);
    var->session = ipc_session_new(clientId, (void*)var, IPC_DEFAULT);
    if (var->session == NULL) return -1;

    ipc_session_set_callbacks(var->session, azure_mqtt_handle_recv_msg, NULL);
    azure_subscribe_all(var);
    ipc_session_start(var->session);
}

static int socket_client_up_down(struct socket_session_s *session, int up, char *hostname, int socket_fd)
{
	azure_var_t *var = &gazure_var;	

	dy_syslog(LOG_DEBUG, "up %d hostname %s socket_fd %d", up, hostname, socket_fd);
	
	if(up)
	{
		client_info_t *client_info = calloc(1, sizeof(client_info_t));
		strncpy(client_info->hostname, hostname, 64);
		client_info->socket_fd = socket_fd;
		strcpy(client_info->sn, "test-sn");
		dy_syslog(LOG_DEBUG, "UP sn %s up %d hostname %s socket_fd %d", client_info->sn, up, hostname, socket_fd);
		list_add_tail(&client_info->list, &var->client_list);
#if 0
		int i;
		for(i=0; i<var->nodes_cfg_table->node_cnt; i++)
		{			
			if(strcmp(var->nodes_cfg_table->node[i].tcp_ip_addr, client_info->hostname) == 0)
			{
				strcpy(client_info->sn, var->nodes_cfg_table->node[i].sn);
				//dy_syslog(LOG_DEBUG, "client_info->sn %s up %d hostname %s socket_fd %d tcp_ip_addr %s", client_info->sn, up, hostname, socket_fd, var->nodes_cfg_table->node[i].tcp_ip_addr);
				break;
			}
		}

		if(i < var->nodes_cfg_table->node_cnt)
		{
			dy_syslog(LOG_DEBUG, "UP sn %s up %d hostname %s socket_fd %d tcp_ip_addr %s", var->nodes_cfg_table->node[i].sn, up, hostname, socket_fd, var->nodes_cfg_table->node[i].tcp_ip_addr);
			list_add_tail(&client_info->list, &var->client_list);
		}
#endif
	}
	else
	{
		client_info_t *client_info = NULL;
		list_for_each_entry(client_info, &var->client_list, list)
		{
			if(socket_fd == client_info->socket_fd)
			{
				dy_syslog(LOG_INFO,"DOWN hostname:%s socket_fd:%d",client_info->hostname,client_info->socket_fd);
				list_del(&client_info->list);
				break;
			}
		}
	}
}

static int handle_data_send_status(socket_server_session_t *session, int client_fd, int status, char *user_param)
{
	char topic[TOPIC_MAX_LEN] = {0};
	char cmd[64] = {0};
	azure_var_t *var = &gazure_var;	
    connect_config_t *connect_cfg = container_of(session, connect_config_t, socket_server);
	
#if 0
    client_info_t *tmp_client = NULL;
	list_for_each_entry(tmp_client, &var->client_list, list)
	{
		if(tmp_client->socket_fd == client_fd && status == 0 && strstr(user_param, "get"))
		{
			dy_syslog(LOG_DEBUG, "IP SoundBox play finished auto close...");
			dy_session_close_client(&var->socket_server, tmp_client->socket_fd);
			break;
		}
	}
#endif
}

static int socket_handle_rcv_msg(socket_server_session_t *session, int client_fd, char *buf, int len)
{
	azure_var_t *var = &gazure_var;	
    connect_config_t *connect_cfg = container_of(session, connect_config_t, socket_server);

    client_info_t *tmp_client = NULL;
	list_for_each_entry(tmp_client, &var->client_list, list)
	{
		if(tmp_client->socket_fd == client_fd)
		{
			dy_syslog(LOG_DEBUG, "data %s len %d			网关<-[%s]		", buf, len, tmp_client->hostname);
			tcp_data_list_t* data = calloc(1,sizeof(tcp_data_list_t)+len+1);	
			if(data)
			{
				data->len = len;
				memcpy(data->data, buf, len);
				var->tcp_data_cnt++;
				var->data_flag = 1;
				dy_syslog(LOG_DEBUG, "++%s tcp_data_cnt %d\n",__FUNCTION__,var->tcp_data_cnt);
				list_add_tail(&data->list,&var->tcp_data_list);
			}
			break;
		}
	}
}

int azure_init(azure_var_t *var)
{
    int i, j;
    const char *board_name = NULL;

    check_make_dir(NODES_CACHE);
    check_make_dir(NODES_CFG);
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);
	
	INIT_LIST_HEAD(&var->node_list);
	INIT_LIST_HEAD(&var->data_list);
	INIT_LIST_HEAD(&var->client_list);
	INIT_LIST_HEAD(&var->tcp_data_list);
	
    board_name = get_board_name();

    dy_syslog(LOG_INFO, "board name:%s", board_name);
    dy_syslog(LOG_INFO, "board SN:%s", var->sn_str);

    if (load_nodes_cfg(&var->nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }
	
    if (load_templates_cfg(&var->template_table, TEMPLATES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load template cfg fail");
    }

	if (access(AZURE_ROCHE_CFG, F_OK) != -1)
    {
    	//加载配置
        azure_roche_load_node_config(var, AZURE_ROCHE_CFG);
		dy_syslog(LOG_DEBUG, "link_node_cnt %d", var->link_node_cnt);
    }
	
    kv_array_init(&var->identifier_backup, 32);
    //azure_load_config(var);
	
	//if(strlen(var->response_event) == 0)
		//strncpy(var->response_event, RESPONSE_EVENT, sizeof(RESPONSE_EVENT));
	
	//dy_syslog(LOG_DEBUG,"%s response_event:%s \n", __FUNCTION__,var->response_event);
    azure_mqtt_client_init(var);

	var->socket_server.socket_server_port = 3333;
	var->socket_server.type = SOCKET_TCP;
	var->socket_server.handle_recv_msg = socket_handle_rcv_msg;
	var->socket_server.handle_client_up_down = socket_client_up_down;
	var->socket_server.handle_data_send_status = handle_data_send_status;

	dy_syslog(LOG_INFO,"==port:%d protocol_type:%d==",var->socket_server.socket_server_port,var->socket_server.type);
	//dy_socket_server_session_init(&var->socket_server);
	//配置存在，直接连接
	azure_node_connect(var);
	
	var->heartbeat_timer = my_timer_create();
    if (var->heartbeat_timer > 0)
    {
        my_timer_set(var->heartbeat_timer, 1, 5000);
    }
	
    return 0;
}


int main(int argc, char *argv[])
{
    azure_var_t *var = &gazure_var;

	dy_syslog(LOG_DEBUG, "\n\
            |********************************************|\n\
            |           azure start  X_X         |\n\
            |********************************************|\n");
    memset(var, 0, sizeof(azure_var_t));
    azure_init(var);
    azure_loop(var);

    return 0;
}
#endif
