
/************************************************************
*版权所有 （C）2020，公司（或个人）名称
*
*文件名称： midware.c
*内容摘要： 数据中转中心，上对云端，下对网关，承上启下
*其他说明： 
*当前版本：  
*************************************************************/


#include<stdio.h>
#include"com_api.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include "cJSON.h"
#include "kk_product.h"
#include "kk_tsl_common.h"
#include "kk_tsl_api.h"
#include "kk_dm_api.h"
#include "kk_dm_msg.h"
#include "kk_dm_mng.h"
#include "kk_log.h"
#include "kk_dm_queue.h"
#include "kk_property_db.h"
#include "sqlite3.h"
#include "kk_linkkit.h"
#include "kk_dm_heartbeat.h"
#include "kk_sub_db.h"
#include "kk_hal.h"
#include "kk_history_db.h"
#include "kk_scene_handle.h"
#include "dm_ota.h"
#include "ccu_ver.h"
#include "kk_area_handle.h"

int g_timezone = 8;
char * g_filerToPlatTable[] = 
{
	(char *){KK_REGISTER_TOPIC_REPLY},
	(char *){KK_ADD_TOPIC_REPLY},
	(char *){KK_LOGIN_TOPIC_REPLY},	
	(char *){KK_THING_SERVICE_PROPERTY_GET},	
	(char *){KK_THING_CLOUDSTATE_MSG}, 	
	(char *){KK_THING_SERVICE_ADDSCENC},
	(char *){KK_THING_SERVICE_UPDATESCENC},	
	(char *){KK_THING_SERVICE_DELETESCENC},	
	(char *){KK_THING_SERVICE_NEGATIVE},
	(char *){KK_THING_SERVICE_SYNCINFO},
	(char *){KK_THING_SERVICE_BINDSCENE},	
	(char *){KK_THING_SERVICE_UNBINDSBUTTTON},
	(char *){KK_THING_SERVICE_ACTIVEBUTTON},
	(char *){KK_THING_SERVICE_HISTORYALARM},
	(char *){KK_THING_SERVICE_DEL_HISTORYALARM},	
};
static char s_ccuid[DEVICE_CODE_LEN] = {0};
static char s_Version[VERSION_MAXLEN] = {0};
static void HAL_Ccuid_version(void)
{
	FILE *fp;

	if(!(fp =  fopen(KK_VERSION_FILE_PATH,"r")))
	{
		ERROR_PRINT("can't open the file tslPath:%s\n",KK_VERSION_FILE_PATH);
		return ;
	}
	fread(s_Version, 1, VERSION_MAXLEN, fp);
	if(strlen(s_Version) == 0){
		strncpy(s_Version, KK_CCU_VERSION, strlen(KK_CCU_VERSION));
	}
	INFO_PRINT("HAL_Ccuid_version version:%s!!!\n",s_Version);
	fclose(fp);
	return;
}
int HAL_GetVersion(_OU_ char *version)
{
	strncpy(version, s_Version, strlen(s_Version));
	version[strlen(s_Version)] = '\0';
	return strlen(s_Version);
}

int HAL_Get_ccuid(_OU_ char *device_code)
{    
    strncpy(device_code, s_ccuid, strlen(s_ccuid));
    printf("HAL_Get_ccuid:%s\n",s_ccuid);
    return strlen(s_ccuid);
}
static int _setDevice_Code(_IN_ char *device_code,int len)
{
    memset(s_ccuid, 0x0, DEVICE_CODE_LEN);
    printf("_setDevice_Code:%s\n",device_code);
    strncpy(s_ccuid, device_code, len);
    return len;
}
static void HAL_Ccuid_init(void)
{
    uint8_t ccuid[DEVICE_CODE_LEN] = {0};
    int ccuid_len = 0;
    HAL_Execel_cmd(GET_CCUID_CMD,(char *)ccuid,sizeof(ccuid),&ccuid_len);
    printf("GET_CCUID_CMD:%s\n",ccuid);
    if(ccuid_len > 0 && ccuid_len <= DEVICE_CODE_LEN){
        _setDevice_Code(ccuid,ccuid_len-1);
    }else{
        _setDevice_Code(KK_CCU_ID,strlen(KK_CCU_ID));
    }
}
/************************************************************
*功能描述：过滤不需要下发给网关的消息
*输入参数：msgtype：消息类型
*输出参数：无
*返 回 值：1:过滤；0：不过滤
*其他说明：
*************************************************************/
static int _kk_filter_to_plat(const char* msgtype)
{
	int i = 0,num = 0;
	num = sizeof(g_filerToPlatTable)/sizeof(char *);

	for(i =0; i < num; i++){
		if(strstr(msgtype,g_filerToPlatTable[i]))
		{
			INFO_PRINT("this msg do not send to platform!!!\n");
			return 1;
		}
	}
	return 0;
}
#define KK_PRINTF_PER_LEN 1000
void kk_print_long_data(char *data,int len)
{
	int lenTemp = len;
	int count = 0;
	char *pTmp = NULL;
	pTmp = malloc(KK_PRINTF_PER_LEN+1);
	if(pTmp == NULL){
		return;
	}	
	while(1)
	{
		memset(pTmp,0x0,KK_PRINTF_PER_LEN+1);
		if(lenTemp > KK_PRINTF_PER_LEN)
		{
			memcpy(pTmp,data + count,KK_PRINTF_PER_LEN);
			INFO_PRINT("%s \n",pTmp);
			lenTemp -= KK_PRINTF_PER_LEN;
			count += KK_PRINTF_PER_LEN;
		}else{
			memcpy(pTmp,data + count,lenTemp);
			INFO_PRINT("%s \n",pTmp);
			break;
		}
	}
	if(pTmp){
		free(pTmp);
		pTmp = NULL;
	}
}
/************************************************************
*功能描述：向网关发送信息
*输入参数：data：消息内容
          len:消息长度
     	  chalMark：消息通道，一般是网关MAC
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void kk_sendData2gw(void* data, int len, char* chalMark){
	int newLen = 0;
	if (data == NULL || chalMark== NULL || strlen(chalMark) == 0){
		ERROR_PRINT(" chalMark is null");
		return;
	}
	cJSON_Minify((char*)data);
	newLen = strlen(data);
	if (kk_is_tcp_channel(chalMark) > -1){
		kk_tcp_channel_ser_send(data, newLen, chalMark);
	}else{
		kk_ipc_send_ex(IPC_MID2PLAT, data, newLen + 1, chalMark);
	}
	INFO_PRINT("start to send data to gw srart\n");
	kk_print_long_data(data,newLen);
	INFO_PRINT("start to send data to gw end\n");
}
void split(char *src,const char *separator,char **dest,int *num) {
    char *pNext;
    int count = 0;
    if (src == NULL || strlen(src) == 0)
        return;
    if (separator == NULL || strlen(separator) == 0)
         return;    
    pNext = strtok(src,separator);
    while(pNext != NULL) {
        *dest++ = pNext;
        ++count;
        pNext = strtok(NULL,separator);  
    }  
    *num = count;
 } 
/************************************************************
*功能描述：属性参数校验
*输入参数：payload：消息内容
          deviceCode:设备devieCode
*输出参数：无
*返 回 值： 0:成功；其他：失败
*其他说明：
*************************************************************/
static int kk_property_set_data_check(cJSON * payload,const char *deviceCode){
	cJSON *params = NULL;
	dm_mgr_dev_node_t *node = NULL;	
	kk_tsl_data_t *property = NULL;	
	cJSON *propertyItem = NULL;	
	cJSON *epNum = NULL;
	int epNumInt = 1;
	int num = 0;
	int res = 0;
	int idx = 0;
	int value = 0;
	char *propertiesbuf[64] = {0};
	char propertiesTmp[64] = {0};

	res = dm_mgr_get_device_by_devicecode((char*)deviceCode,&node);
	if (res != SUCCESS_RETURN) {
		ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
		return FAIL_RETURN;
	}
	params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params != NULL){
		//传感器安防等级设置
		if(strcmp(node->productType ,"sensor") == 0){
			cJSON* sensorType =  cJSON_GetObjectItem(params, "SensorType");
			if(sensorType != NULL){
				int level = sensorType->valueint;
				res = kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,"SensorType",&level,NULL);
				if(res != SUCCESS_RETURN)
				{
					ERROR_PRINT(" error res:%d\n",res);
				}	
				char tmpValue[16] = {0};
				sprintf(tmpValue,"%d",level);
				kk_property_db_update_value(deviceCode,"SensorType",tmpValue);
				return SUCCESS_RETURN;
			}
		}
		epNum = cJSON_GetObjectItem(params, "epNum");
		if(epNum != NULL){
			epNumInt = atoi(epNum->valuestring);
		}else{
			epNumInt = 1;
		}
		//printf("----------------->epNumInt:%d\n",epNumInt);
		for(idx = 0; idx < node->dev_shadow->property_number; idx++){
			property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
			if(property == NULL){
				continue;
			}
			//printf("----------------->property->identifier:%s\n",property->identifier);
			memset(propertiesTmp,0x0,sizeof(propertiesTmp));
			memcpy(propertiesTmp,property->identifier,strlen(property->identifier));
			split(propertiesTmp,"_",propertiesbuf,&num);
			if(num == 2){
				if(atoi(propertiesbuf[1]) == epNumInt){
					//printf("----------------->propertiesbuf[0]:%s\n",propertiesbuf[0]);
					propertyItem = cJSON_GetObjectItem(params, propertiesbuf[0]);
					if(propertyItem != NULL){
						//cJSON_AddNumberToObject(params,tmpPS,PowerSwitch->valueint);
						//cJSON_DeleteItemFromObject(params, "PowerSwitch");
						//printf("----------------->property->data_value.type:%d\n",property->data_value.type);
						if(property->data_value.type == KK_TSL_DATA_TYPE_STRUCT){
								kk_tsl_data_value_complex_t *complex_struct = NULL;
								kk_tsl_data_t *current_data = NULL;
								int index;
								complex_struct = property->data_value.value;
								for (index = 0; index < complex_struct->size; index++) {
									current_data = (kk_tsl_data_t *)complex_struct->value + index;
									cJSON *propertyItem_1 = NULL;	
									propertyItem_1 = cJSON_GetObjectItem(propertyItem, current_data->identifier);
									if(propertyItem_1 == NULL){
										continue;
									}
									
									if(current_data->data_value.type != KK_TSL_DATA_TYPE_STRUCT){
										if(current_data->data_value.type == KK_TSL_DATA_TYPE_INT){
											value = propertyItem_1->valueint;
											if(value < current_data->data_value.mix ||value > current_data->data_value.max ){
												ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,current_data->data_value.mix,current_data->data_value.max);
												return INVALID_PARAMETER;
											}
										}
										else if(current_data->data_value.type == KK_TSL_DATA_TYPE_TEXT){
											if(strlen(propertyItem_1->valuestring) > current_data->data_value.length ){
												
												ERROR_PRINT("ERROR !!!strlen(propertyItem_1->valuestring):%d,current_data->data_value.length:%d\n",strlen(propertyItem_1->valuestring),current_data->data_value.length);
												return INVALID_PARAMETER;
											}
										}
									}
									else{
										kk_tsl_data_value_complex_t *complex_struct_1 = NULL;
										kk_tsl_data_t *current_data_1 = NULL;
										int index_1;
										complex_struct_1 = current_data->data_value.value;
										for(index_1 = 0; index_1 < complex_struct_1->size; index_1++){
											current_data_1 = (kk_tsl_data_t *)complex_struct_1->value + index_1;
											cJSON *propertyItem_2 = NULL;	
											propertyItem_2 = cJSON_GetObjectItem(propertyItem_1, current_data_1->identifier);
											if(propertyItem_2 == NULL){
												continue;
											}
											if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_INT){
												value = propertyItem_2->valueint;
												if(value < current_data_1->data_value.mix ||value > current_data_1->data_value.max ){
													ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,current_data_1->data_value.mix,current_data_1->data_value.max);
													return INVALID_PARAMETER;
												}
											}
											else if(current_data_1->data_value.type == KK_TSL_DATA_TYPE_TEXT){
												if(strlen(propertyItem_2->valuestring) > current_data_1->data_value.length ){
													
													ERROR_PRINT("ERROR !!!strlen(propertyItem_2->valuestring):%d,propertyItem_2->data_value.length:%d\n",strlen(propertyItem_2->valuestring),current_data_1->data_value.length);
													return INVALID_PARAMETER;
												}
											}
										}

									}
								}
								cJSON_AddItemToObject(params,property->identifier,propertyItem);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||property->data_value.type == KK_TSL_DATA_TYPE_FLOAT \
								|| property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
								value = propertyItem->valueint;
								if(value < property->data_value.mix ||value > property->data_value.max ){
									ERROR_PRINT("ERROR !!!value:%d,mix:%d,max:%d\n",value,property->data_value.mix,property->data_value.max);
									return INVALID_PARAMETER;
								}
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_INT-------------------\n");
								cJSON_AddNumberToObject(params,property->identifier,propertyItem->valueint);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}
							else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT){
								if(strlen(propertyItem->valuestring) > property->data_value.length ){
									ERROR_PRINT("ERROR !!!strlen(propertyItem->valuestring):%d,property->data_value.length:%d\n",strlen(propertyItem->valuestring),property->data_value.length );
									return INVALID_PARAMETER;
								}
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_TEXT-------------------\n");
								cJSON_AddStringToObject(params,property->identifier,propertyItem->valuestring);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}	
							else if(property->data_value.type == KK_TSL_DATA_TYPE_ENUM || property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
								INFO_PRINT("-----------------KK_TSL_DATA_TYPE_ENUM-------------------\n");
								cJSON_AddNumberToObject(params,property->identifier,propertyItem->valueint);
								cJSON_DeleteItemFromObject(params, propertiesbuf[0]);
							}					
					}
				}
			}
			//propertyItem = cJSON_GetObjectItem(params, property->identifier);
			//if(propertyItem != NULL){
				//if(strcmp(property->accessMode,"rw") != 0){
					//ERROR_PRINT("ERROR !!!property->accessMode:%s\n",property->accessMode);
					//return INVALID_PARAMETER;
				//}
	
			//}

		}
	}
	return SUCCESS_RETURN;

}

/************************************************************
*功能描述：nanomsg数据回调，app to mid
*输入参数：data：从app 层发来的数据
          len: 数据长度
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void mid_cb(void* data, int len){
	if (data != NULL){
		cJSON* payload;
		cJSON *json;
		cJSON *info_root,*type;
		cJSON*deviceCode;
		int res;

		json=cJSON_Parse(data);
		if (!json) {
			ERROR_PRINT("Error before: [%s]\n","cJSON_Parse");
		}
		else
		{
			info_root = cJSON_GetObjectItem(json, MSG_INFO_STR);
			if (info_root == NULL){
				ERROR_PRINT(" params [%s] can't find \n",MSG_INFO_STR);
				cJSON_Delete(json);
				return;
			}
			deviceCode = cJSON_GetObjectItem(info_root, MSG_DEVICE_CODE_STR);
			type = cJSON_GetObjectItem(info_root, MSG_TYPE_STR);
			if (deviceCode == NULL || type == NULL){
				ERROR_PRINT(" params [%s] or [%s] can't find \n",MSG_DEVICE_CODE_STR, MSG_TYPE_STR);
				cJSON_Delete(json);
				return;
			}
			payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
			if (payload == NULL){
				ERROR_PRINT(" params [%s] can't find \n",MSG_PAYLOAD_STR);
				cJSON_Delete(json);
				return;
			}
			/*****属性设置需要先检测设置参数是否超出物模型给定范围*******/
			if (strcmp(type->valuestring, KK_THING_SERVICE_PROPERTY_SET)==0){
				res = kk_property_set_data_check(payload,deviceCode->valuestring);
				if(res != SUCCESS_RETURN){
					cJSON_Delete(json);
					return;
				}
				
			}

			int devType = 0;
			dm_mgr_get_devicetype_by_devicecode(deviceCode->valuestring,&devType);
			//主机的device或过滤的
			if(devType == KK_DM_DEVICE_CCU ||_kk_filter_to_plat(type->valuestring)){
				void* buf = malloc(len);
				memcpy(buf, data, len);
				res = dm_queue_msg_insert((void *)buf);
				if (res != SUCCESS_RETURN) {
					free(buf);
				}
			}else if(devType == KK_DM_DEVICE_GATEWAY){
				/*手机端主动删除设备，需要删除数据库相关内容，再下发给网关*/
				if (strcmp(type->valuestring, KK_THING_TOPO_CHANGE_MSG)==0){
					kk_topo_delete_handle(payload);
				}
				kk_sendData2gw(data, strlen(data), deviceCode->valuestring);//send to gw itself
			}else if(devType == KK_DM_DEVICE_SUBDEV){
				dm_mgr_dev_node_t *gw_node = NULL;
				res = dm_mgr_get_device_by_devicecode(deviceCode->valuestring,&gw_node);
				if (res != SUCCESS_RETURN) {
					ERROR_PRINT("res:%d\n",res);
					cJSON_Delete(json);
					return;
				}
				cJSON *	rootData=cJSON_CreateObject();
				char *info_rootS=cJSON_Print(info_root);
				char *payloadS = cJSON_Print(payload);
				cJSON_AddItemToObject(rootData,MSG_INFO_STR, cJSON_Parse(info_rootS));
				cJSON_AddItemToObject(rootData,MSG_PAYLOAD_STR, cJSON_Parse(payloadS));
				char *pnewout=cJSON_Print(rootData);
				kk_sendData2gw(pnewout, strlen(pnewout), gw_node->fatherDeviceCode);//send to sub device
				free(info_rootS);
				free(payloadS);
				free(pnewout);
				cJSON_Delete(rootData);
			}
			else{
				ERROR_PRINT("wrong type\n");
			}
			cJSON_Delete(json);
		}
	}
}

/************************************************************
*功能描述：nanomsg数据回调，从gw  to mid
*输入参数：data：从gw 层发来的数据
          len: 数据长度
          chalMark:网关通道，一般用mac
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void mid2p_cb(void* data, int len, char* chalMark){
	if (data != NULL){
		//printf("mid2plat_cb: %s RECEIVED \r\n", data);
		int res = 0;
		void* buf = NULL;
		dm_queue_msg_t *queue_msg = NULL;
		queue_msg = malloc(sizeof(dm_queue_msg_t));
		if (queue_msg == NULL){
			ERROR_PRINT("mid2p_cb malloc queue_msg failed ");
			return;
		}
		buf = malloc(len);
		if (buf == NULL){
			ERROR_PRINT("mid2p_cb malloc buf failed ");
			return;
		}
		
		memcpy(buf, data, len);
		queue_msg->data = buf;
		memset(queue_msg->chalMark, 0, sizeof(queue_msg->chalMark));
		if(chalMark != NULL){
			memcpy(queue_msg->chalMark, chalMark, strlen(chalMark));
		}
		res = dm_queue_msg_insert2((void *)queue_msg);
		if (res != SUCCESS_RETURN) {
			free(queue_msg);
			free(buf);
			buf = NULL;
			return ;
		}
		
		//kk_ipc_send(IPC_MID2APP, data, len);
	}
}

/************************************************************
*功能描述：nanomsg数据回调，从gw  to mid
*输入参数：data：从gw 层发来的数据
          len: 数据长度
          chalMark:网关通道，一般用mac
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void gw2mid_cb(void* data, int len, char* chalMark){
	if (data != NULL){
		printf("gw2mid_cb chalMark=%s, data: %s [%d]RECEIVED \r\n", chalMark, (char*)data,len);
		mid2p_cb(data,len,chalMark);
	}
}
/************************************************************
*功能描述：midware收到gw数据的具体处理
*输入参数：data：从gw 层发来的数据
          chalMark:网关通道，一般用mac
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
static int kk_alarm_notify_handle(dm_mgr_dev_node_t *node,char *identifier,char *valueBuf)
{
	int currentValue = 0;
	char armingstate[16] = {0};
	int ret = 0;
	if(node == NULL || identifier == NULL){
		return -1;
	}

	kk_property_db_get_value(node->deviceCode,"SensorType",&currentValue);
	kk_property_db_get_value(s_ccuid,KK_TSL_CCU_ARMINGSTATE_IDENTIFIER,armingstate);
	cJSON *info = cJSON_CreateObject();
	cJSON_AddStringToObject(info, MSG_TYPE_STR, "/thing/event/alarmNotify");
	cJSON_AddStringToObject(info, MSG_DEVICE_CODE_STR, node->deviceCode);
	cJSON_AddStringToObject(info, MSG_PRODUCT_CODE_STR, node->productCode);
	char *infff=cJSON_Print(info);	

	cJSON *payload = cJSON_CreateObject();
	cJSON_AddStringToObject(payload, "method", "thing.event.alarmNotify");
	cJSON_AddStringToObject(payload, "version", "1.0");
	cJSON_AddStringToObject(payload, "identifier", "alarmNotify");
	char msgId[64] = {0};
	iotx_report_id(msgId);
	cJSON_AddStringToObject(payload, "msgId", msgId);	
	//char timerStr[16] = {0};
	//HAL_GetTime_s(timerStr);
	cJSON_AddNumberToObject(payload, "time", HAL_GetTime_ms());	
		
	cJSON *param = cJSON_CreateObject();
	if(strcmp(identifier,"BatteryAlarm") == 0){
		cJSON_AddStringToObject(param, "LowBatteryState", "1");
	}else if(strcmp(identifier,"DismantleState") == 0 && atoi(valueBuf) == 1){
		cJSON_AddStringToObject(param, "DismantleState", "1");
	}else if(strcmp(identifier,"SmokeSensorState") == 0 && atoi(valueBuf) == 1){
		cJSON_AddStringToObject(param, "CommonAlarmState", "1");
	}
	else{
		cJSON_AddStringToObject(param, "CommonAlarmState", "1");
	}
	cJSON_AddItemToObject(payload, "params", param);
	char *payload11=cJSON_Print(payload);

	if(currentValue == 2)//24小时警戒
	{
		kk_sendData2app(infff,payload11,0);
		kk_history_insert_sensor_info(node->deviceCode,identifier,valueBuf,HAL_GetTime());
	}
	else if(currentValue == 1 && atoi(armingstate) == 0) //离家布防
	{
		kk_sendData2app(infff,payload11,0);
		kk_history_insert_sensor_info(node->deviceCode,identifier,valueBuf,HAL_GetTime());
	}
	else if(currentValue == 0 && atoi(armingstate) == 2) //在家布防
	{
		kk_sendData2app(infff,payload11,0);
		kk_history_insert_sensor_info(node->deviceCode,identifier,valueBuf,HAL_GetTime());
	}
	else if(atoi(armingstate) == 3 && currentValue == 0 )
	{
		char roomId[16] = {0};
		ret = kk_get_roomId_by_deviceCode(node->deviceCode,"1",roomId,sizeof(roomId));
		INFO_PRINT("roomId: [%s] \n",roomId);
		if(ret == 1){
			int state = kk_get_room_armingstate(roomId);
			INFO_PRINT("state: [%d] \n",state);
			if(state){
				kk_sendData2app(infff,payload11,0);
				kk_history_insert_sensor_info(node->deviceCode,identifier,valueBuf,HAL_GetTime());
			}
		}
	}
	free(payload11);
	free(infff);
	cJSON_Delete(payload);
	cJSON_Delete(info);	
	return 0;
}
static int kk_indoorAir_property_save(cJSON *payload,char *deviceCode)
{
	dm_mgr_dev_node_t *node = NULL;
	kk_tsl_data_t *property = NULL;
	cJSON *propertyItem = NULL;	
	int res = 0;
	int idx = 0;
	int epNumInt = 0;
	cJSON *params = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
	if(params == NULL) return FAIL_RETURN;
	cJSON *eps = cJSON_GetObjectItem(params, "eps");
	if(eps == NULL || eps->type != cJSON_Array){
		return FAIL_RETURN;
	}		
	res = dm_mgr_get_device_by_devicecode(deviceCode,&node);
	if (res < SUCCESS_RETURN) {
		return FAIL_RETURN;
	}	
	cJSON *client_list  = eps->child;
	while(client_list != NULL){
		cJSON *epNum = cJSON_GetObjectItem(client_list, "epNum");
		if(epNum == NULL){
			continue;
		}
		if(epNum->type == cJSON_Number){
			epNumInt = epNum->valueint;
		}else if(epNum->type == cJSON_String){
			epNumInt = atoi(epNum->valuestring);
		}
		for(idx = 0; idx < node->dev_shadow->property_number; idx++){
			property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
			if(property == NULL){
				continue;
			}
			propertyItem = cJSON_GetObjectItem(client_list, property->identifier);
			if(propertyItem != NULL){
				if(property->data_value.type == KK_TSL_DATA_TYPE_INT ||property->data_value.type == KK_TSL_DATA_TYPE_ENUM
				||property->data_value.type == KK_TSL_DATA_TYPE_BOOL){
					char valBuf[16] = {0};
					int value = propertyItem->valueint;
					sprintf(valBuf,"%d",value);
					kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(property->data_value.type == KK_TSL_DATA_TYPE_FLOAT || property->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
					char valBuf[16] = {0};
					sprintf(valBuf,"%f",propertyItem->valuedouble);
					kk_indoorAir_db_update_value(deviceCode,property->identifier,valBuf,epNumInt);
				}else if(property->data_value.type == KK_TSL_DATA_TYPE_TEXT ){
					kk_indoorAir_db_update_value(deviceCode,property->identifier,propertyItem->valuestring,epNumInt);
				}
			}
			
		}
		client_list = client_list->next;
	}
	return 0;
}
static int kk_indoorAir_property_handle(cJSON *info,cJSON *payload,char *deviceCode)
{
	kk_indoorAir_property_save(payload,deviceCode);
	cJSON_AddStringToObject(payload, MSG_DEVICE_CODE_STR, deviceCode);
	char *payload11=cJSON_Print(payload);
	char *infff=cJSON_Print(info);
	kk_sendData2app(infff,payload11,0);
	free(payload11);
	free(infff);
	return 0;
}
static int kk_indoorAir_online_handle(dm_mgr_dev_node_t *node ,char *deviceCode,int epNum)
{
	int idx = 0;
	int gwExist = 0;
	char roomId[32] = {0};
	char roomName[256] = {0};
	char epNumStr[10] = {0};
	kk_tsl_data_t *property = NULL;
	if(node == NULL){
		return -1;
	}
	for(idx = 0; idx < node->dev_shadow->property_number; idx++){
		property = (kk_tsl_data_t *)(node->dev_shadow->properties + idx);
		if(property == NULL){
			continue;
		}
		kk_indoorAir_db_insert(deviceCode,property->identifier,property->data_value.type,epNum);
	}	
	gwExist = kk_get_device_roomInfo(deviceCode,1,roomName,roomId);//获取网关房间信息
	if(gwExist){
		char name[128] = {0};
		sprintf(name,"空调%d",epNum);
		sprintf(epNumStr,"%d",epNum);
		kk_room_dev_add(roomId,roomName,deviceCode,epNumStr,name);

	}
	return 0;
}
void kk_platMsg_handle(void* data, char* chalMark){
	int res = 0;
	cJSON *json;
	cJSON *info;
	cJSON *info_dcode;
	cJSON *jsonPay;
	cJSON *msgType;
	cJSON *proCode;
	cJSON *devCode;
	cJSON *mac;
	cJSON *payload;

	json=cJSON_Parse(data);
	if (!json) {
		WARNING_PRINT("Error before: [%s]\n","cJSON_Parse");
	}
	else{
		info = cJSON_GetObjectItem(json, MSG_INFO_STR);
		payload = cJSON_GetObjectItem(json, MSG_PAYLOAD_STR);
		if (info == NULL || payload == NULL){
			ERROR_PRINT("info or payload params error\n");
			goto error;
		}
		msgType = cJSON_GetObjectItem(info, MSG_TYPE_STR);
		info_dcode = cJSON_GetObjectItem(info, MSG_DEVICE_CODE_STR);
		if (msgType == NULL || info_dcode == NULL){
			ERROR_PRINT("msgType info_dcode or jsonPay params are error\n");
			goto error;
		}
		
		if (chalMark != NULL){
			dm_mgr_update_timestamp_by_devicecode(chalMark,HAL_Uptimes());
		}
		if(strcmp(msgType->valuestring,"/thing/service/property/get_reply") != 0){
			dm_mgr_update_timestamp_by_devicecode(info_dcode->valuestring,HAL_Uptimes());
		}
		
		if (strcmp(msgType->valuestring, KK_THING_TOPO_ADD_MSG)==0){
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			proCode = cJSON_GetObjectItem(jsonPay, MSG_PRODUCT_CODE_STR);
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			mac = cJSON_GetObjectItem(jsonPay, "mac");
			if (proCode == NULL || devCode == NULL || mac == NULL){
				ERROR_PRINT("productCode, deviceCode mac params are error\n");
				goto error;
			}
			INFO_PRINT("deviceCode productCode mac: [%s][%s] [%s] \n",devCode->valuestring, proCode->valuestring, mac->valuestring);
			//判断网关还是子设备
			if (strcmp(info_dcode->valuestring, devCode->valuestring) == 0){
				char ccu_deviceCode[DEVICE_CODE_MAXLEN] = {0};
				HAL_Get_ccuid(ccu_deviceCode);
				kk_mid_subdev_add(KK_DM_DEVICE_GATEWAY,proCode->valuestring,devCode->valuestring, mac->valuestring,ccu_deviceCode);
				cJSON * sceneSupportStr = cJSON_GetObjectItem(jsonPay, MSG_SCENE_SUPPORT);
				if(sceneSupportStr != NULL&&!strcmp(sceneSupportStr->valuestring,"1")){
					kk_subDev_update_sceneSupport(1,devCode->valuestring);
				}
			}else{
				kk_mid_subdev_add(KK_DM_DEVICE_SUBDEV,proCode->valuestring,devCode->valuestring, mac->valuestring,info_dcode->valuestring);
			}
			dm_mgr_update_timestamp_by_devicecode(devCode->valuestring,HAL_Uptimes());
		}
		else if (strstr(msgType->valuestring, KK_THING_STATUS_ONLINE) != NULL){//空调内机上报处理
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			dm_mgr_dev_node_t *search_node = NULL;
			res = dm_mgr_get_device_by_devicecode(devCode->valuestring,&search_node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}		
			if(strcmp(search_node->productType,KK_DM_AIR_GATEWAY_TYPE) == 0){
				cJSON *epNumJson = cJSON_GetObjectItem(jsonPay, "epNum");
				if(epNumJson == NULL) goto error;
				kk_indoorAir_online_handle(search_node,devCode->valuestring,epNumJson->valueint);
			}	
		}
		else if (strstr(msgType->valuestring, KK_THING_TOPO_BATCH_ADD_MSG) != NULL){
			kk_ipc_send(IPC_MID2APP,data,strlen(data));
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			if(devices == NULL) goto error;
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				char *productCode = cJSON_GetObjectItem(item,MSG_PRODUCT_CODE_STR)->valuestring;
				char *mac_s = cJSON_GetObjectItem(item,MSG_DEVICE_MAC)->valuestring;	
				char *fatherMac = cJSON_GetObjectItem(item,MSG_DEVICE_PARENTCODE)->valuestring;	
				kk_mid_subdev_batch_add(productCode,deviceCode,mac_s,fatherMac);
				item = item->next;
			}
		}else if (strstr(msgType->valuestring, KK_THING_PROPERTY_POST) != NULL){
			INFO_PRINT("save property and send to cloud \n");
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			char* outstr = cJSON_Print(payload);
			dm_mgr_dev_node_t *search_node = NULL;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&search_node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(search_node->isOffline){
				/*如果是离线状态，上报在线给云端*/
				dm_mgr_set_dev_onoffline(search_node,0);
			}
			if(strcmp(search_node->productType ,KK_DM_AIR_GATEWAY_TYPE) == 0){
				kk_indoorAir_property_handle(info,payload,info_dcode->valuestring);
			}
			else{
				/*插座类设备保存功率历史记录*/
				if(strcmp(search_node->productType ,"outlet") == 0){
					cJSON *power = cJSON_GetObjectItem(jsonPay,"Power");
					if(power != NULL){
						char buf[16] = {0};
						sprintf(buf,"%f",power->valuedouble);
						kk_history_insert_Outlet_info(info_dcode->valuestring,buf,"",HAL_GetTime());
					}
				}
				kk_tsl_property_set_by_shadow(search_node->dev_shadow, outstr, strlen(outstr)+1);
				dm_msg_thing_property_post_by_identify(info_dcode->valuestring,jsonPay);
				kk_scene_iftt_check(info_dcode->valuestring,jsonPay);
				free(outstr);
			}
		}else if(strstr(msgType->valuestring, KK_THING_TOPO_DELETE_MSG) != NULL){
			INFO_PRINT("kk_platMsg_handle data: handle delete\n");
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			devCode = cJSON_GetObjectItem(jsonPay, MSG_DEVICE_CODE_STR);
			kk_ipc_send(IPC_MID2APP,data,strlen(data)+1);
			dm_mgr_subdev_delete(devCode->valuestring);
			
		}else if(strstr(msgType->valuestring, KK_THING_EVENT_MESSAGE) != NULL && \
			strstr(msgType->valuestring, KK_THING_EVENT_POST) != NULL){
			dm_mgr_dev_node_t *node = NULL;
			int idx = 0;
			kk_tsl_event_t *eventItem =NULL;
			char tmpStr[128] = {0};
			char valueBuf[32] = {0};
			cJSON * itemStr = NULL;
			int sensorDev = 0;
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&node);
			if (res < SUCCESS_RETURN) {
				goto error;
			}
			if(node->isOffline){
				/*如果是离线状态，上报在线给云端*/
				dm_mgr_set_dev_onoffline(node,0);
			}
			/*如果是传感器类设备，事件上报的同时需要记录数据到数据库*/
			if(strcmp(node->productType ,"sensor") == 0){
				sensorDev = 1;
			}
			if(strcmp(msgType->valuestring, "/thing/event/SceneRecall/post") == 0){
				char btnId[16] = {0};
				cJSON *buttonId = cJSON_GetObjectItem(jsonPay, "SceneNum");
				if(buttonId == NULL || buttonId->type != cJSON_Number){
					ERROR_PRINT("DATA ERROR!!!\n");
					goto error;
				}	
				sprintf(btnId,"%d",buttonId->valueint);
				kk_scene_execute_quickpanel(btnId,info_dcode->valuestring);				
			}
			INFO_PRINT("-------------------kk_platMsg_handle event post enters \n");
			for(idx = 0; idx < node->dev_shadow->event_number; idx++){
				eventItem = node->dev_shadow->events + idx;
				if(eventItem != NULL){
					if(strcmp(eventItem->identifier,MSG_PROPERTY_STR) != 0 &&
						eventItem->output_data_number > 0){
						int index = 0;
						kk_tsl_data_t *itemData = NULL;
						for(index = 0; index < eventItem->output_data_number;index++){
							itemStr = cJSON_GetObjectItem(jsonPay, eventItem->identifier);
							itemData = eventItem->output_datas + index;		
							printf("------------111--------->itemData->identifier:%s\n",itemData->identifier);				
							cJSON * itemDataIdentifier = cJSON_GetObjectItem(jsonPay, itemData->identifier);
							if(itemDataIdentifier != NULL){
								memset(tmpStr,0x0,sizeof(tmpStr));
								sprintf(tmpStr,"%s.%s",eventItem->identifier,itemData->identifier);
								if(itemData->data_value.type == KK_TSL_DATA_TYPE_INT||
									itemData->data_value.type == KK_TSL_DATA_TYPE_ENUM||
									itemData->data_value.type == KK_TSL_DATA_TYPE_BOOL){
									sprintf(valueBuf,"%d",itemDataIdentifier->valueint);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,&itemDataIdentifier->valueint,NULL);	
								}
								else if(itemData->data_value.type == KK_TSL_DATA_TYPE_FLOAT ||
									itemData->data_value.type == KK_TSL_DATA_TYPE_DOUBLE){
									sprintf(valueBuf,"%f",itemDataIdentifier->valuedouble);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,&itemDataIdentifier->valuedouble,NULL);

								}
								else if(itemData->data_value.type == KK_TSL_DATA_TYPE_TEXT ||
									itemData->data_value.type == KK_TSL_DATA_TYPE_DATE){
									sprintf(valueBuf,"%s",itemDataIdentifier->valuestring);
									kk_tsl_set_value(kk_tsl_set_event_output_value,node->dev_shadow,tmpStr,NULL,itemDataIdentifier->valuestring);
								}	
								if(sensorDev){
									kk_alarm_notify_handle(node,itemData->identifier,valueBuf);//告警信息处理
								}										
								INFO_PRINT("kk_platMsg_handle data: event post\n");
								dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier,NULL);
								kk_scene_iftt_check(info_dcode->valuestring,jsonPay);

							}
						}
					}
					else if(strcmp(eventItem->identifier,MSG_PROPERTY_STR) != 0 &&
						eventItem->output_data_number == 0){
						itemStr = cJSON_GetObjectItem(jsonPay, eventItem->identifier);
						if(itemStr != NULL){
							if(sensorDev){
								//kk_history_insert_sensor_info(info_dcode->valuestring,eventItem->identifier,"",HAL_GetTime());
							}								
							//kk_tsl_set_value(kk_tsl_set_event_output_value,dev_shadow,eventItem->identifier,&itemStr->valueint,NULL);	
							dm_msg_thing_event_post(info_dcode->valuestring,eventItem->identifier,NULL);
						}

					}
				}
			}
		}
		else if(strstr(msgType->valuestring, KK_THING_TOPO_BATCH_DELETE_MSG) != NULL){
			kk_ipc_send(IPC_MID2APP,data,strlen(data));
			jsonPay = cJSON_GetObjectItem(payload, MSG_PARAMS_STR);
			if(jsonPay == NULL) goto error;		
			cJSON *devices = cJSON_GetObjectItem(jsonPay, MSG_TOPO_CHANGE_DEVICES_STR);
			cJSON * item = devices->child;
			while(item != NULL){
				char *deviceCode = cJSON_GetObjectItem(item,MSG_DEVICE_CODE_STR)->valuestring;
				dm_mgr_subdev_delete(deviceCode);
				item = item->next;
			}			
			
		}
		else if(strstr(msgType->valuestring, KK_THING_SERVICE_PROPERTY_GET_REPLY) != NULL){
			INFO_PRINT("kk_platMsg_handle data: KK_THING_SERVICE_PROPERTY_GET_REPLY\n");
			int res = 0;
			dm_mgr_dev_node_t *node = NULL;
			res = dm_mgr_get_device_by_devicecode(info_dcode->valuestring,&node);
			if (res != SUCCESS_RETURN) {
				ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
				goto error;
			}
			/*开机先获取网关属性，网关返回relay，置网关状态在线*/
			if(node->dev_type == KK_DM_DEVICE_GATEWAY){
				kk_dm_gw_status_update_online(info_dcode->valuestring);
				if(node->isOffline){
					/*如果是离线状态，上报在线给云端*/
					dm_mgr_set_dev_onoffline(node,0);
				}
			}
		}
		else{
			INFO_PRINT("kk_platMsg_handle data: don't handle it\n");
		}
	error:
		cJSON_Delete(json);
	}
}

/************************************************************
*功能描述：从gw接收消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void kk_platMsg_dispatch(void)
{
	int count = 0;
	void *data = NULL;

	while (CONFIG_DISPATCH_QUEUE_MAXLEN == 0 || count++ < CONFIG_DISPATCH_QUEUE_MAXLEN) {
		if (dm_queue_msg_next2(&data) == SUCCESS_RETURN) {
			dm_queue_msg_t *msg = (dm_queue_msg_t *)data;
			//INFO_PRINT("kk_handle_platMsg_dispatch get call \n");
			kk_platMsg_handle(msg->data,(char*)msg->chalMark);
			if (msg->data != NULL){
				free(msg->data);
			}
			free(data);
			data = NULL;
		} else {
			break;
		}
	}
}


typedef struct {
    int auto_add_subdev;
    int master_devid;
    int cloud_connected;
    int master_initialized;
    int subdev_index;
    int permit_join;
	void *g_mid_dispatch_thread;
    void *g_ota_dispatch_thread;
    void *g_ccuProChg_dispatch_thread;	
	void *g_udp_dispatch_thread;
	int g_mid_dispatch_thread_running;
    int g_ota_dispatch_thread_running;
	int g_ccuProChg_dispatch_thread_running;	
	int g_udp_dispatch_thread_running;
} mid_ctx_t;
#define MID_YIELD_TIMEOUT_MS (200)


static mid_ctx_t g_mid_ctx;

static mid_ctx_t *kk_mid_get_ctx(void)
{
	return &g_mid_ctx;
}

extern void IOT_Linkkit_Yield(int timeout_ms);

/************************************************************
*功能描述：从app接收消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *mid_dispatch_yield(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();

	while (mid_ctx->g_mid_dispatch_thread_running) {
		IOT_Linkkit_Yield(MID_YIELD_TIMEOUT_MS);
	}

	return NULL;
}
/************************************************************
*功能描述：接收OTA消息任务
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *ota_dispatch_yield(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();

	while (mid_ctx->g_ota_dispatch_thread_running) {
		dm_ota_yield(MID_YIELD_TIMEOUT_MS);
	}

	return NULL;
}


#define UDP_LAN_PORT 25556
#define UDP_LAN_PORT_HOST 25555
#define test_
/************************************************************
*功能描述：网关发现server
*输入参数：args:传入参数
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *udp_dispatch_yield(void *args){
	INFO_PRINT("udp_dispatch_yield udp thread create\n");

	// 绑定地址 
	struct sockaddr_in addrto; 
	bzero(&addrto, sizeof(struct sockaddr_in)); 
	addrto.sin_family = AF_INET; 
	addrto.sin_addr.s_addr = htonl(INADDR_ANY); 
	addrto.sin_port = htons(UDP_LAN_PORT); 

	// 发送地址
	struct sockaddr_in addrto_host; 
	bzero(&addrto_host, sizeof(struct sockaddr_in)); 
	addrto_host.sin_family = AF_INET; 
	addrto_host.sin_addr.s_addr = htonl(INADDR_ANY); 
	//addrto_host.sin_port = htons(UDP_LAN_PORT); 

	// 接收到的广播地址 
	struct sockaddr_in from; 
	bzero(&from, sizeof(struct sockaddr_in)); 


	int sock = -1; 
	int sock_host = -1; 
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
	{
		ERROR_PRINT("socket error\n"); 
	}

	if ((sock_host = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 
	{
		ERROR_PRINT("socket error\n"); 
	}

	if(bind(sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1) 
	{
		ERROR_PRINT("bind error...\n"); 
	}

	socklen_t len = sizeof(struct sockaddr_in); 
	char szOut[128] = {0};
	char szDec[1024] = {0}; 
	char host_ip[32] = {0};
	char mac[32] = {0};
	char device_code[DEVICE_CODE_LEN] = {0};
	kk_prop_raw_struct_t ipList[10] = {0};
	int idx = 0;

	kk_property_db_get_rawdata("IPAddress",4, ipList, sizeof(ipList));
	for(; idx < 10; idx++){
		DEBUG_PRINT("ipList[%d][%s][%s] \n", idx, ipList[idx].deviceCode, ipList[idx].raw);
		if (strlen(ipList[idx].deviceCode)>0 && strlen(ipList[idx].raw)>0){
			kk_set_tcp_channel_by_idx(idx, ipList[idx].deviceCode, ipList[idx].raw);
		}
	}
	kk_TCP_channel_init(gw2mid_cb);

	while(1)
	{
		//从广播地址接受消息 
		memset(szDec, 0 , sizeof(szDec));
		int size=recvfrom(sock, szDec, sizeof(szDec), 0, (struct sockaddr*)&from,(socklen_t*)&len); 
		if(size<=0) 
		{
			WARNING_PRINT("read error....\n"); 
		}
		else
		{
			DEBUG_PRINT("lan recmsg: %s\n", szDec); 
			//DEBUG_PRINT("udp client ip:%s ,port is :%d htons(UDP_LAN_PORT)=%d \n",inet_ntoa(from.sin_addr),from.sin_port, htons(UDP_LAN_PORT)); 
			//"search_kk_ccu|deviceCode=1122334455667788;protocol=tcp"
			if(strstr(szDec, "search_kk_ccu|") != NULL){
				char* getConnet = szDec + strlen("search_kk_ccu|");
				char* tmp = NULL;
				char* endIdx = NULL;
				int itemLen = 0;
				int itemConnetLen = 0;
				char gwDevCode[DEVICE_CODE_LEN] = {0};
				char proto[10] = {0};
				char portStr[10] = {0};

				tmp = strstr(getConnet, "deviceCode=");
				itemLen = strlen("deviceCode=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(gwDevCode, tmp + itemLen,itemConnetLen);
				}

				tmp = strstr(getConnet, "protocol=");
				itemLen = strlen("protocol=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(proto, tmp + itemLen,itemConnetLen);
				}

				tmp = strstr(getConnet, "port=");
				itemLen = strlen("port=");
				if (tmp != NULL){
					endIdx = strstr(tmp, ";");
					if(endIdx == NULL){
						itemConnetLen = strlen(tmp) - itemLen;
					}else{
						itemConnetLen = endIdx - tmp - itemLen;
					}
					memcpy(portStr, tmp + itemLen,itemConnetLen);
				}

				DEBUG_PRINT("gwDevCode =%s proto=%s portStr=%s \n",gwDevCode,proto,portStr);
				if(strcmp(proto,"tcp") == 0){
					//
					kk_set_tcp_channel(gwDevCode,inet_ntoa(from.sin_addr));
				}

				memset(host_ip, 0, sizeof(host_ip));
				memset(mac, 0, sizeof(mac));
				memset(szOut, 0, sizeof(szOut));
				HAL_Get_IP(host_ip,NULL);
				HAL_Get_ccuid(device_code);
			//	printf("[%s][%d]inet_ntoa(from.sin_addr):%s\n",__FUNCTION__,__LINE__,inet_ntoa(from.sin_addr));
			//	printf("[%s][%d]host_ip:%s\n",__FUNCTION__,__LINE__,host_ip);
			//	if(strcmp(inet_ntoa(from.sin_addr),host_ip) == 0){

				

				sprintf(szOut,"search_kk_ccu_ack|deviceCode=%s;ip=%s;port=%d",device_code,host_ip,16565);
				DEBUG_PRINT("szOut:%s\n",szOut); 
				DEBUG_PRINT("udp client ip:%s ,port is :%d \n",inet_ntoa(from.sin_addr),from.sin_port); 
				//sendto(sock, szOut, strlen(szOut), 0, (struct sockaddr*)&from,len); 

				addrto_host.sin_addr.s_addr = inet_addr(inet_ntoa(from.sin_addr)); 
				if(strlen(portStr) > 0){
					addrto_host.sin_port = htons(atoi(portStr)); 
				}else{
					addrto_host.sin_port = htons(UDP_LAN_PORT_HOST); 
				}
				//addrto_host.sin_port = from.sin_port; 
				//if(strcmp(host_ip,inet_ntoa(from.sin_addr)) == 0)
				//{
					sendto(sock_host, szOut, strlen(szOut), 0, (struct sockaddr*)&addrto_host,sizeof(addrto_host)); 
				//}
				//else
				//{
				//    DEBUG_PRINT("udp client is not local ip  , refused send ack to it\n");
				//}
			//	}
			}
		}
		usleep(100000); 
	}

	close(sock);
	close(sock_host);
}
/************************************************************
*功能描述：主机IP后台检测任务，如IP有变化，上报消息给云端
*输入参数：无
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
void *ccu_property_monitor(void *args)
{
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();
 	char s_IP[NETWORK_ADDR_LEN];
	char s_IP_TSL[NETWORK_ADDR_LEN] = {0};
	int res = 0;
	int needReport  = 0;
	int time_second = 60;
	dm_mgr_dev_node_t *node = NULL;


	while (mid_ctx->g_ccuProChg_dispatch_thread_running) {
		if(kk_get_cloud_recv_status() == 0){
			iotx_dm_ccu_cloud_check();
			sleep(10);
			continue;
		}
		dm_mgr_search_dev_by_devid(KK_DM_DEVICE_CCU_DEVICEID,&node);
		//dm_mgr_update_timestamp_by_devicecode(node->deviceCode,HAL_GetTime());
		node->timestamp = HAL_Uptimes();
		HAL_Get_IP(s_IP,NULL);
		res = kk_tsl_get_value(kk_tsl_get_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,s_IP_TSL,NULL);
		if(res != SUCCESS_RETURN){
			ERROR_PRINT("kk_tsl_get_value Failed\n");
		}
		else{
			if(strcmp(s_IP,s_IP_TSL)){
				kk_tsl_set_value(kk_tsl_set_property_value,node->dev_shadow,KK_TSL_CCU_WANIP_IDENTIFIER,NULL,s_IP);
				INFO_PRINT("current ip:%s,before ip:%s\n",s_IP,s_IP_TSL);
				kk_property_db_update(node->deviceCode);
				needReport  = 1;
			}
		}
		
		if(needReport&&(kk_get_cloudstatus() == 1)){
			needReport = 0;
			char *postStr = kk_tsl_get_post_property_str(node->dev_shadow,NULL);
			if(postStr != NULL){
				dm_mgr_upstream_thing_property_post(node->devid, postStr, strlen(postStr),0);
				free(postStr);
				postStr = NULL;
			}
		}
		sleep(time_second);
	}
	return NULL;
}
sqlite3 *g_kk_pDb;


/************************************************************
*功能描述：主机数据库句柄创建
*输入参数：无
*输出参数：无
*返 回 值： 0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_sqlite_init(void)
{
	if (sqlite3_open_v2(KK_DB_FILE, &g_kk_pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL) != SQLITE_OK)
	{
		ERROR_PRINT("Error initialising linkage database fail!!!\n");
		return FAIL_RETURN;
	}
	return SUCCESS_RETURN;
}
/************************************************************
*功能描述：midware 主任务
*输入参数：argc：参数个数
           argv：参数内容
*输出参数：无
*返 回 值： 无
*其他说明：
*************************************************************/
int main(const int argc, const char **argv)
{
	int res = 0;
	//char *tsl_str;
	//int i;
	//kk_tsl_t *dev_shadow[30] = {NULL};
	mid_ctx_t *mid_ctx = kk_mid_get_ctx();

	open("midware",LOG_PID,LOG_USER);
	memset(mid_ctx, 0, sizeof(mid_ctx_t));
	HAL_Ccuid_version();
	HAL_Ccuid_init();
	kk_sqlite_init();
	kk_tsl_api_init();
	kk_ipc_init(IPC_MID2APP, mid_cb, NULL, NULL);
	kk_ipc_init(IPC_MID2PLAT, mid2p_cb, NULL, "*");
		
	kk_init_dmproc();
	kk_heartbeat_init();
	kk_subDb_init();
	kk_area_init();	
	kk_history_db_init();
	kk_scene_init();
	g_timezone = HAL_Get_TimeZone();

	mid_ctx->g_mid_dispatch_thread_running = 1;
	res = pthread_create(&mid_ctx->g_mid_dispatch_thread, NULL, mid_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate mid Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}
	mid_ctx->g_ota_dispatch_thread_running = 1;
	res = pthread_create(&mid_ctx->g_ota_dispatch_thread, NULL, ota_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate ota Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}

	// recv gateway add cmd and ack to gateway
	res = pthread_create(&mid_ctx->g_udp_dispatch_thread, NULL, udp_dispatch_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate udp Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return -1;
	}
		
	mid_ctx->g_ccuProChg_dispatch_thread_running = 1;
	res = pthread_create(&mid_ctx->g_ccuProChg_dispatch_thread, NULL, ccu_property_monitor, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate Failed\n");
		return -1;
	}

	//int ct = 0;
	for (;;) {
		usleep(200000);
		kk_platMsg_dispatch();
	}
}

