前言

EDP协议是OneNET自主定制的协议,应用在即需要设备上传数据点到平台,又需要下发命令到设备的协议,具体关于OneNET的EDP协议的解释,请看OneNET EDP协议概述,对于协议的具体讲解,请看设备终端接入协议-EDP,SDK请看EDP-SDK,工具请看EDP调试工具,工具使用可参考博客OneNET云平台-EDP协议数据传输。

本文简单讲解使用EDP协议的关键,对于EDP使用大概步骤为:连接平台-->连接设备-->发送心跳保持设备在线-->上报数据流到设备-->平台下发命令到设备-->设备处理命令并执行对应操作。本文用socket的方式连接、上发、接收平台来讲解EDP的应用,贴出关键代码,代码除socket部分,连接设备、上报数据、发送心跳以及命令下发处理有些是参考OneNET工程师——张继瑞的代码修改的,代码可能存在bug,请读者自行辨别,仅作为参考。本文不讲解数据转发,对EPD协议的数据转发有兴趣的读者请自行研究。

如果你是首次使用OneNET,不知道如何创建产品和设备等,可参考我的另外一篇博客OneNET MQTT的简单使用,前面有讲解,也可以直接到OneNET平台开发文档查看资料,都非常详细。

一、socket函数

1、创建socket

/**************************************************************
函数名称 : socket_create
函数功能 : socket创建
输入参数 : 无
返回值      : socket_id
备注       : 无
**************************************************************/
int socket_create(void)
{int socket_id = -1;unsigned char domain = AF_INET;unsigned char type = SOCK_STREAM;unsigned char protocol = IPPROTO_IP;struct timeval send_timeout = {0};socket_id = socket(domain, type, protocol);if(socket_id < 0){SOC_COMMON_LOG("socket create failed!!!, socket_id:%d", socket_id);return socket_id;}else{SOC_COMMON_LOG("socket create success!!!, socket_id:%d", socket_id);send_timeout.tv_sec = 120;send_timeout.tv_usec = 0;lwip_setsockopt(socket_id, SOL_SOCKET, SO_SNDTIMEO, &send_timeout, sizeof(send_timeout));return socket_id;}
}

2、socket 连接远程服务器

/**************************************************************
函数名称 : socket_connect_service
函数功能 : socket 连接远程服务器
输入参数 : socket_id:创建socket时返回的idremote_addr:远程服务器地址remote_port:端口
返回值      : CONNECT_OK:连接成功,CONNECT_ERROR:连接失败
备注       : 无
**************************************************************/
socket_connect_t socket_connect_service(int socket_id, char *remote_addr, unsigned int remote_port)
{socket_connect_t connect_result = CONNECT_ERROR;struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = lwip_htons(remote_port);addr.sin_addr.s_addr = inet_addr(remote_addr);if(0 == connect(socket_id, (struct sockaddr *)&addr, sizeof(addr))){  SOC_COMMON_LOG("socket connect success!!!");connect_result = CONNECT_OK;}else{SOC_COMMON_LOG("socket connect failed!!!");connect_result = CONNECT_ERROR;}return connect_result;
}

3、socket发送数据

/**************************************************************
函数名称 : socket_send
函数功能 : socket 发送数据
输入参数 : socket_id:创建socket时返回的iddata_buf:数据包data_len:数据包大小
返回值      : 发送成功返回数据包大小
备注       : 无
**************************************************************/
int socket_send(int socket_id, char *data_buf, int data_len)
{int send_rec  = 0;send_rec = send(socket_id, data_buf, data_len, 0);return send_rec;
}

4、socket接收数据

/**************************************************************
函数名称 : socket_receive
函数功能 : socket 接收服务器下发的数据
输入参数 : socket_id:创建socket时返回的iddata_buf:存储接收到的数据区data_len:最大接收大小
返回值      : 成功时返回大于0
备注       : 无
**************************************************************/
int socket_receive(int socket_id, char *data_buf, int data_len)
{int recv_result = 0;recv_result = recv(socket_id, data_buf, data_len, MSG_DONTWAIT);return recv_result;
}

5、关闭socket连接

/**************************************************************
函数名称 : socket_close
函数功能 : 关闭socket
输入参数 : socket_id:创建socket时返回的id
返回值      : CLOSE_OK:关闭成功,CLOSE_ERROR:关闭失败
备注       : 无
**************************************************************/
socket_close_t socket_close(int socket_id)
{socket_close_t close_result = CLOSE_ERROR;if(0 == close(socket_id)){SOC_COMMON_LOG("socket close success!!!");close_result = CLOSE_OK;}else{SOC_COMMON_LOG("socket close failed!!!");close_result = CLOSE_ERROR;}return close_result;
}
typedef enum
{CONNECT_OK = 0,CONNECT_ERROR = 1
}socket_connect_t;typedef enum
{   CLOSE_OK = 0,CLOSE_ERROR = 1
}socket_close_t;

二、EDP协议讲解及应用

1、连接请求 

(1)连接OneNET平台,EDP协议对应的服务器地址为:"183.230.40.39",端口为876。

char *g_edp_ip_addr = "183.230.40.39";
int g_edp_ip_port = 876;

使用socket连接:

/* socket id */
int g_onenet_socket_id = -1;/**************************************************************
函数名称 : onenet_edp_service_connect
函数功能 : edp 服务器连接
输入参数 : ip_addr:ip地址,ip_port:端口
返回值      : 0:连接成功,1:连接失败
备注       : 无
**************************************************************/
unsigned char onenet_edp_service_connect(char *ip_addr, unsigned int ip_port)
{g_onenet_socket_id = socket_create();if(g_onenet_socket_id < 0){ONENET_EDP_LOG("oconnect_onenet_service failed, g_onenet_socket_id < 0");return 1;}if(CONNECT_ERROR == socket_connect_service(g_onenet_socket_id, ip_addr, ip_port)){ONENET_EDP_LOG("connect_onenet_service failed, connect error");return 1;}else{ONENET_EDP_LOG("connect_onenet_service success");return 0;}}

socket连接服务器:

onenet_edp_service_connect(g_edp_ip_addr, g_edp_ip_port);

(2)连接设备,连接设备的方式有两种:

代码:

char *g_edp_device_id = "504890772";  /* 设备id */
char *g_edp_api_key = "cWPICK6PDU6cOHP=T0SqMcXWRc4=";/*api key*/
char *g_device_auth_info = "edp20181122";    /* 设备鉴权信息 */
char *g_edp_prd_id = "190254";           /* 产品id *//**************************************************************
函数名称 : onenet_edp_device_link
函数功能 : edp 设备连接
输入参数 : id:设备/产品id,auth_key:apikey
返回值      : 0;成功,1:失败
备注       : 无
**************************************************************/
unsigned char onenet_edp_device_link(const char* id, const char* auth_key)
{EDP_PACKET_STRUCTURE edpPacket = {NULL, 0, 0, 0};             //协议包unsigned char time_out = 200;ONENET_EDP_LOG("id: %s, api_key: %s\r\n", id, auth_key);#if 1if(EDP_PacketConnect1(id, auth_key, 256, &edpPacket) == 0)  //根据devid 和 apikey封装协议包
#elseif(EDP_PacketConnect2(id, auth_key, 256, &edpPacket) == 0)   //根据产品id 和 鉴权信息封装协议包
#endif{socket_send(g_onenet_socket_id, edpPacket._data, edpPacket._len);//上传平台vTaskDelay(1);EDP_DeleteBuffer(&edpPacket);                               //删包return 0;}else{ONENET_EDP_LOGW("EDP_PacketConnect failed, onenet_edp_device_link failed\r\n");return 1;}}

连接设备:

onenet_edp_device_link(g_edp_device_id, g_edp_api_key);

连接设备成功之后,可以在页面看到设备在线状态:

2、心跳保持

EDP连接默认超时时间为4分钟。设备登录后,在超时期内无数据传输时,需要定期向平台发送PING_REQ消息以保持连接,在这我使用FreeRTOS的软件定时每隔3min向平台发送一次心跳。

发送心跳代码:

/* 任务句柄 */
TimerHandle_t g_onenet_edp_send_heart_sw_timer_handle = NULL;/**************************************************************
函数名称 : onenet_edp_send_heart
函数功能 : 发送心跳
输入参数 : 无
返回值      : 无
备注  : EDP连接默认超时时间为4分钟。设备登录后,在超时期内无数据传输时,需要定期向平台发送PING_REQ消息以保持连接
**************************************************************/
void onenet_edp_send_heart(void)
{EDP_PACKET_STRUCTURE edpPacket = {NULL, 0, 0, 0}; //协议包EDP_PacketPing(&edpPacket);socket_send(g_onenet_socket_id, edpPacket._data, edpPacket._len);//向平台上传心跳请求ONENET_EDP_LOG("onenet_edp_send_heart");EDP_DeleteBuffer(&edpPacket); //删包
}/**************************************************************
函数名称 : onenet_edp_send_heart_sw_timer_callback
函数功能 : 用FreeRTOS软件定时器定时发送心跳
输入参数 : xTimer:软件定时器任务句柄
返回值     : 无
备注  :无
**************************************************************/
void onenet_edp_send_heart_sw_timer_callback(TimerHandle_t xTimer)
{onenet_edp_send_heart();//发送心跳
}/**************************************************************
函数名称 : onenet_edp_send_heart_sw_timer_task_init
函数功能 : 创建发送心跳软件定时器任务
输入参数 : 无
返回值     : 无
备注    : 无
**************************************************************/
void onenet_edp_send_heart_sw_timer_task_init(void)
{g_onenet_edp_send_heart_sw_timer_handle = xTimerCreate("onenet_edp_send_heart_sw_timer_task",1800 * COAP_MAX_TRANSMIT_WAIT / portTICK_PERIOD_MS,        /* 180s(3 min)定时,软件定时器误差大 */pdTRUE,NULL,onenet_edp_send_heart_sw_timer_callback);
}

在连接上设备之后,就开启软件定时器:

if(0 == onenet_edp_device_link(g_edp_device_id, g_edp_api_key))
{xTimerStart(g_onenet_edp_send_heart_sw_timer_handle, 0);/* 连接设备成功,开始发心跳 */
}

3、数据上发到平台

在这里,作为测试,我使用FreeRTOS的软件定时器,定时向平台上传数据流。

上传数据流代码:

/---------------------------------------------------------------------------------------/
typedef enum
{TYPE_BOOL = 0,TYPE_CHAR,TYPE_UCHAR,TYPE_SHORT,TYPE_USHORT,TYPE_INT,TYPE_UINT,TYPE_LONG,TYPE_ULONG,TYPE_FLOAT,TYPE_DOUBLE,TYPE_GPS,TYPE_STRING,
} DATA_TYPE;typedef struct
{char *name;void *dataPoint;DATA_TYPE dataType;bool flag;} DATA_STREAM;typedef enum
{FORMAT_TYPE1 = 1,FORMAT_TYPE2,FORMAT_TYPE3,FORMAT_TYPE4,FORMAT_TYPE5} FORMAT_TYPE;/---------------------------------------------------------------------------------------//* 任务句柄 */
TimerHandle_t g_onenet_edp_send_data_sw_timer_handle = NULL;//数据流
float g_temperature = 23.5;
DATA_STREAM data_stream[] = {{"temperature", &g_temperature, TYPE_FLOAT, 1},};
unsigned char data_stream_cnt = sizeof(data_stream) / sizeof(data_stream[0]);/* 数据流个数 *//**************************************************************
函数名称 : oennet_edp_send_data
函数功能 : 上传数据到平台设备
输入参数 : type:发送数据的格式devid:设备IDapikey:设备apikeystreamArray:数据流streamArrayNum:数据流个数
返回值      : 无
备注       : 无
**************************************************************/
void oennet_edp_send_data(FORMAT_TYPE type, char *devid, char *apikey, DATA_STREAM *streamArray, unsigned short streamArrayCnt)
{EDP_PACKET_STRUCTURE edpPacket = {NULL, 0, 0, 0};                                         //协议包short body_len = 0;ONENET_EDP_LOG("oennet_edp_send_data, type:%d\r\n", type);if(type != kTypeBin)                                                                       //二进制文件吧全部工作做好,不需要执行这些{body_len = DSTREAM_GetDataStream_Body_Measure(type, streamArray, streamArrayCnt, 0); //获取当前需要发送的数据流的总长度if(body_len > 0){if(EDP_PacketSaveData(devid, body_len, NULL, (SaveDataType)type, &edpPacket) == 0)  //封包{body_len = DSTREAM_GetDataStream_Body(type, streamArray, streamArrayCnt, edpPacket._data, edpPacket._size, edpPacket._len);if(body_len > 0){edpPacket._len += body_len;ONENET_EDP_LOG("Send %d Bytes\r\n", edpPacket._len);socket_send(g_onenet_socket_id, edpPacket._data, edpPacket._len);}else{ONENET_EDP_LOGW("DSTREAM_GetDataStream_Body Failed\r\n");}EDP_DeleteBuffer(&edpPacket);    //删包}else{ONENET_EDP_LOG("EDP_NewBuffer Failed\r\n");}}   }}/**************************************************************
函数名称 : onenet_edp_send_data_sw_timer_callback
函数功能 : 用FreeRTOS软件定时器定时上发数据的回掉函数
输入参数 : xTimer:软件定时器任务句柄
返回值      : 无
备注       :
**************************************************************/
void onenet_edp_send_data_sw_timer_callback(TimerHandle_t xTimer)
{oennet_edp_send_data(FORMAT_TYPE3, g_edp_device_id, g_edp_api_key, data_stream, data_stream_cnt);//上传数据到平台
}/**************************************************************
函数名称 : onenet_edp_send_data_sw_timer_task_init
函数功能 : 创建软件定时器任务
输入参数 : 无
返回值      : 无
备注       : 无
**************************************************************/
void onenet_edp_send_data_sw_timer_task_init(void)
{g_onenet_edp_send_data_sw_timer_handle = xTimerCreate("onenet_edp_send_data_sw_timer_task",200 * COAP_MAX_TRANSMIT_WAIT / portTICK_PERIOD_MS,       /* 20s定时,软件定时器误差大 */pdTRUE,NULL,onenet_edp_send_data_sw_timer_callback);
}

打开上传数据流软件定时器开始定时上传数据流:

xTimerStart(g_onenet_edp_send_data_sw_timer_handle, 0);

如果不想上传数据流,则关闭软件定时器:

xTimerStop(g_onenet_edp_send_data_sw_timer_handle, 0);

上传成功后,可在设备查看到对应的数据:

 

4、接收平台下发命令

对应EPD协议,下发命令应该最多的便是在开关值了,对于开关命令,为了区分不同开关,OneNET使用命令构体+命令值的方式来区分,格式为:命令结构+冒号+命令值。

下面我用一个开关来控制LED为例讲解,当点击ON按钮时,下发命令LED:1,当点击OFF按钮时,下发命令LED:0。在接收到开关值之后,将开关值上传到平台。

(1)创建应用

在应用在我们创建一个开关按钮,并与设备和数据流关联

在EDP命令内容,根据命令格式命令结构+冒号+命令值,填写为LED:{V},其中{V}为开关值,LED为命令结构体。

命令下发及其处理代码:

/* led状态 */
int g_led_status = 0;
DATA_STREAM led_status_data_stream[] = {{"LED_STATUS", &g_led_status, TYPE_INT, 1},};
unsigned char led_status_data_stream_cnt = sizeof(led_status_data_stream) / sizeof(led_status_data_stream[0]);/**************************************************************
函数名称 : onenet_edp_recv_cmd_pro
函数功能 : edp命令下发处理
输入参数 : cmd:命令值
返回值      : 无
备注       :对于开关命令,为了区分,onenet采用命令结构体+命令值的方式,格式为:命令结构+冒号+命令值,如:LED:1
**************************************************************/
void onenet_edp_recv_cmd_pro(unsigned char *cmd)
{EDP_PACKET_STRUCTURE edpPacket = {NULL, 0, 0, 0};//协议包signed char *cmdid_devid = NULL;unsigned short cmdid_len = 0;signed char *req = NULL;unsigned int req_len = 0;switch(EDP_UnPacketRecv(cmd)){case CONNRESP:{switch(EDP_UnPacketConnectRsp(cmd)){case 0:ONENET_EDP_LOG("Tips:    连接成功\r\n");break;case 1:ONENET_EDP_LOG("WARN: 连接失败:协议错误\r\n");break;case 2:ONENET_EDP_LOG("WARN: 连接失败:设备ID鉴权失败\r\n");break;case 3:ONENET_EDP_LOG("WARN: 连接失败:服务器失败\r\n");break;case 4:ONENET_EDP_LOG("WARN:    连接失败:用户ID鉴权失败\r\n");break;case 5:ONENET_EDP_LOG("WARN: 连接失败:未授权\r\n");break;case 6:ONENET_EDP_LOG("WARN:  连接失败:授权码无效\r\n");break;case 7:ONENET_EDP_LOG("WARN:    连接失败:激活码未分配\r\n");break;case 8:ONENET_EDP_LOG("WARN:   连接失败:该设备已被激活\r\n");break;case 9:ONENET_EDP_LOG("WARN:  连接失败:重复发送连接请求包\r\n");break;default:ONENET_EDP_LOG("ERR:    连接失败:未知错误\r\n");break;}break;}case DISCONNECT:{ONENET_EDP_LOG("WARN:   连接断开,准备重连。错误码:%d\r\n", cmd[2]);break;}case PINGRESP:{ONENET_EDP_LOG("Tips:  HeartBeat OK\r\n");break;}case PUSHDATA:   //解pushdata包{if(EDP_UnPacketPushData(cmd, &cmdid_devid, &req, &req_len) == 0){ONENET_EDP_LOG("src_devid: %s, req: %s, req_len: %d\r\n", cmdid_devid, req, req_len);//执行命令回调------------------------------------------------------------edp_free_buffer(cmdid_devid);    //释放内存edp_free_buffer(req);}break;}case CMDREQ: //解命令包{if(EDP_UnPacketCmd(cmd, &cmdid_devid, &cmdid_len, &req, &req_len) == 0){//命令回复组包------------------------------------------------------------EDP_PacketCmdResp(cmdid_devid, cmdid_len, req, req_len, &edpPacket);ONENET_EDP_LOG("cmdid: %s, req: %s, req_len: %d\r\n", cmdid_devid, req, req_len);//执行命令回调------------------------------------------------------------if(strcmp("LED:1", req) == 0){g_led_status = 1;}else if(strcmp("LED:0", req) == 0){g_led_status = 0;}//上传LED状态数据到平台oennet_edp_send_data(FORMAT_TYPE3, g_edp_device_id, g_edp_api_key, led_status_data_stream, led_status_data_stream_cnt);edp_free_buffer(cmdid_devid);       //释放内存edp_free_buffer(req);//回复命令---------------------------------------------------------------socket_send(g_onenet_socket_id, edpPacket._data, edpPacket._len);//上传平台EDP_DeleteBuffer(&edpPacket);                                //删包}break;}    case SAVEACK:{if(cmd[3] == MSG_ID_HIGH && cmd[4] == MSG_ID_LOW){ONENET_EDP_LOG("Tips:  Send %s\r\n", cmd[5] ? "Err" : "Ok");}else{ONENET_EDP_LOG("Tips:  Message ID Err\r\n");}break;}default:break;}}/* 最大接收onenet下发命令大小 */
#define ONENET_EDP_RECV_MAX_SIZE    256/**************************************************************
函数名称 : onenet_edp_send_data_sw_timer_task_init
函数功能 : 接收onenet下发命令任务函数
输入参数 : pvParameter:任务入口参数
返回值      : 无
备注       : 无
**************************************************************/
void onenet_edp_receive_cmd_task(void *pvParameter)
{unsigned char data_ptr[ONENET_EDP_RECV_MAX_SIZE];memset(data_ptr, 0, sizeof(data_ptr));while(1){if(socket_receive(g_onenet_socket_id, data_ptr, ONENET_EDP_RECV_MAX_SIZE) > 0)  //使用MSG_DONTWAIT会比较稳定{onenet_edp_recv_cmd_pro(data_ptr);    //集中处理} vTaskDelay(1);  //挂起任务10ms}}/**************************************************************
函数名称 : onenet_edp_receive_cmd_task_init
函数功能 : 创建接收onenet下发命令任务
输入参数 : 无
返回值      : 无
备注       : 无
**************************************************************/
void onenet_edp_receive_cmd_task_init(void)
{if(g_onenet_edp_recv_cmd_task_handle == NULL) {xTaskCreate(onenet_edp_receive_cmd_task,"onenet_edp_receive_cmd_task",1024 * 4 / sizeof(portSTACK_TYPE),(void*)1,TASK_PRIORITY_NORMAL,&g_onenet_edp_recv_cmd_task_handle);ONENET_EDP_LOG("onenet_edp_receive_cmd_task");}}

当在应用点击ON/OFF按钮时,命令开始下发,通过串口打印抓取到的下发命令信息如下:

cmdid: 53fb996e-1d76-54e3-afe5-ae77079692a9, req: LED:1, req_len: 5
cmdid: 07ba5b64-a672-58ec-9bd7-9d326c38936c, req: LED:0, req_len: 5

得到命令,执行相应的操作,将开关值上传到平台:

if(strcmp("LED:1", req) == 0)
{g_led_status = 1;
}
else if(strcmp("LED:0", req) == 0)
{g_led_status = 0;
}
//上传LED状态数据到平台
oennet_edp_send_data(FORMAT_TYPE3, g_edp_device_id, g_edp_api_key, led_status_data_stream, led_status_data_stream_cnt);

上传成功,可在设备查看到对应的数据流:

三、贴出EDP协议代码

以下代码作者是OneNET工程师——张继瑞,本人只是根据自己的使用的平台修改了内存申请和释放函数。

1、edpkit.c

#include "FreeRTOS.h"
#include "string.h"
#include "edpkit.h"#if 0
void* edp_alloc_buffer(int buffer_size)
{return pvPortCalloc(1, buffer_size);
}void edp_free_buffer(void* buffer)
{if (buffer) {vPortFree(buffer);buffer = NULL;}
}
#endif
//==========================================================
//  函数名称:    EDP_NewBuffer
//
//  函数功能:    申请内存
//
//  入口参数:    edpPacket:包结构体
//              size:大小
//
//  返回参数:    无
//
//  说明:      1.可使用动态分配来分配内存
//              2.可使用局部或全局数组来指定内存
//==========================================================
void EDP_NewBuffer(EDP_PACKET_STRUCTURE *edpPacket, uint32_t size)
{uint32_t i = 0;if(edpPacket->_data == NULL){edpPacket->_memFlag = MEM_FLAG_ALLOC;edpPacket->_data = (char *)edp_alloc_buffer(size);if(edpPacket->_data != NULL){edpPacket->_len = 0;edpPacket->_size = size;for(; i < edpPacket->_size; i++)edpPacket->_data[i] = 0;}}else{edpPacket->_memFlag = MEM_FLAG_STATIC;for(; i < edpPacket->_size; i++)edpPacket->_data[i] = 0;edpPacket->_len = 0;if(edpPacket->_size < size)edpPacket->_data = NULL;}}//==========================================================
//  函数名称:    EDP_DeleteBuffer
//
//  函数功能:    释放数据内存
//
//  入口参数:    edpPacket:包结构体
//
//  返回参数:    无
//
//  说明:      当使用的局部或全局数组时不释放内存
//==========================================================
void EDP_DeleteBuffer(EDP_PACKET_STRUCTURE *edpPacket)
{if(edpPacket->_memFlag == MEM_FLAG_ALLOC)edp_free_buffer(edpPacket->_data);edpPacket->_data = NULL;edpPacket->_len = 0;edpPacket->_size = 0;edpPacket->_memFlag = MEM_FLAG_NULL;}//==========================================================
//  函数名称:    EDP_UnPacketRecv
//
//  函数功能:    EDP数据接收类型判断
//
//  入口参数:    dataPtr:接收的数据指针
//
//  返回参数:    0-成功        其他-失败原因
//
//  说明:
//==========================================================
uint8_t EDP_UnPacketRecv(uint8_t *dataPtr){return dataPtr[0];}//==========================================================
//  函数名称:    EDP_PacketConnect1
//
//  函数功能:    登录方式1组包
//
//  入口参数:    devid:设备ID
//              apikey:APIKEY
//              cTime:连接保持时间
//              edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
bool EDP_PacketConnect1(const int8_t *devid, const int8_t *apikey, uint16_t cTime, EDP_PACKET_STRUCTURE *edpPacket)
{uint8_t devid_len = strlen(devid);uint8_t apikey_len = strlen(apikey);//分配内存---------------------------------------------------------------------EDP_NewBuffer(edpPacket, 56);if(edpPacket->_data == NULL)return 1;//Byte0:连接类型--------------------------------------------------------------edpPacket->_data[0] = CONNREQ;edpPacket->_len++;//Byte1:剩余消息长度----------------------------------------------------------edpPacket->_data[1] = 13 + devid_len + apikey_len;edpPacket->_len++;//Byte2~3:协议名长度----------------------------------------------------------edpPacket->_data[2] = 0;edpPacket->_data[3] = 3;edpPacket->_len += 2;//Byte4~6:协议名--------------------------------------------------------------strncat((char *)edpPacket->_data + 4, "EDP", 3);edpPacket->_len += 3;//Byte7:协议版本--------------------------------------------------------------edpPacket->_data[7] = 1;edpPacket->_len++;//Byte8:连接标志--------------------------------------------------------------edpPacket->_data[8] = 0x40;edpPacket->_len++;//Byte9~10:连接保持时间-------------------------------------------------------edpPacket->_data[9] = MOSQ_MSB(cTime);edpPacket->_data[10] = MOSQ_LSB(cTime);edpPacket->_len += 2;//Byte11~12:DEVID长度---------------------------------------------------------edpPacket->_data[11] = MOSQ_MSB(devid_len);edpPacket->_data[12] = MOSQ_LSB(devid_len);edpPacket->_len += 2;//Byte13~13+devid_len:DEVID---------------------------------------------------strncat((char *)edpPacket->_data + 13, devid, devid_len);edpPacket->_len += devid_len;//Byte13+devid_len~13+devid_len+2:APIKEY长度----------------------------------edpPacket->_data[13 + devid_len] = MOSQ_MSB(apikey_len);edpPacket->_data[14 + devid_len] = MOSQ_LSB(apikey_len);edpPacket->_len += 2;//Byte15+devid_len~15+devid_len+apikey_len:APIKEY-----------------------------strncat((char *)edpPacket->_data + 15 + devid_len, apikey, apikey_len);edpPacket->_len += apikey_len;return 0;}//==========================================================
//  函数名称:    EDP_PacketConnect2
//
//  函数功能:    登录方式2组包
//
//  入口参数:    devid:设备ID
//              auth_key:鉴权信息
//              cTime:连接保持时间
//              edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
bool EDP_PacketConnect2(const int8_t *proid, const int8_t *auth_key, uint16_t cTime, EDP_PACKET_STRUCTURE *edpPacket)
{uint8_t proid_len = strlen(proid);uint8_t authkey_len = strlen(auth_key);//分配内存---------------------------------------------------------------------EDP_NewBuffer(edpPacket, 56);if(edpPacket->_data == NULL)return 1;//Byte0:连接类型--------------------------------------------------------------edpPacket->_data[0] = CONNREQ;edpPacket->_len++;//Byte1:剩余消息长度----------------------------------------------------------edpPacket->_data[1] = 15 + proid_len + authkey_len;edpPacket->_len++;//Byte2~3:协议名长度----------------------------------------------------------edpPacket->_data[2] = 0;edpPacket->_data[3] = 3;edpPacket->_len += 2;//Byte4~6:协议名--------------------------------------------------------------strncat((char *)edpPacket->_data + 4, "EDP", 3);edpPacket->_len += 3;//Byte7:协议版本--------------------------------------------------------------edpPacket->_data[7] = 1;edpPacket->_len++;//Byte8:连接标志--------------------------------------------------------------edpPacket->_data[8] = 0xC0;edpPacket->_len++;//Byte9~10:连接保持时间-------------------------------------------------------edpPacket->_data[9] = MOSQ_MSB(cTime);edpPacket->_data[10] = MOSQ_LSB(cTime);edpPacket->_len += 2;//Byte11~12:DEVID长度---------------------------------------------------------edpPacket->_data[11] = 0;edpPacket->_data[12] = 0;edpPacket->_len += 2;//Byte13~14:PROID长度---------------------------------------------------------edpPacket->_data[13] = MOSQ_MSB(proid_len);edpPacket->_data[14] = MOSQ_LSB(proid_len);edpPacket->_len += 2;//Byte15~15+proid_len:RPOID---------------------------------------------------strncat((char *)edpPacket->_data + 15, proid, proid_len);edpPacket->_len += proid_len;//Byte15+devid_len~15+proid_len+1:APIKEY长度----------------------------------edpPacket->_data[15 + proid_len] = MOSQ_MSB(authkey_len);edpPacket->_data[16 + proid_len] = MOSQ_LSB(authkey_len);edpPacket->_len += 2;//Byte17+proid_len~17+proid_len+apikey_len:APIKEY-----------------------------strncat((char *)edpPacket->_data + 17 + proid_len, auth_key, authkey_len);edpPacket->_len += authkey_len;return 0;}//==========================================================
//  函数名称:    EDP_UnPacketConnectRsp
//
//  函数功能:    连接回复解包
//
//  入口参数:    rev_data:接收到的数据
//
//  返回参数:    登录结果
//
//  说明:
//==========================================================
uint8_t EDP_UnPacketConnectRsp(uint8_t *rev_data)
{//0        连接成功//1     验证失败:协议错误//2     验证失败:设备ID鉴权失败//3     验证失败:服务器失败//4        验证失败:用户ID鉴权失败//5     验证失败:未授权//6      验证失败:授权码无效//7        验证失败:激活码未分配//8       验证失败:该设备已被激活//9      验证失败:重复发送连接请求包return rev_data[3];}int32_t WriteRemainlen(uint8_t *buf, uint32_t len_val, uint16_t write_pos){int32_t remaining_count = 0;uint8_t byte = 0;do{byte = len_val % 128;len_val = len_val >> 7;/* If there are more digits to encode, set the top bit of this digit */if (len_val > 0){byte = byte | 0x80;}buf[write_pos++] = byte;remaining_count++;} while(len_val > 0 && remaining_count < 5);return --write_pos;
}int32_t ReadRemainlen(int8_t *buf, uint32_t *len_val, uint16_t read_pos)
{uint32_t multiplier = 1;uint32_t len_len = 0;uint8_t onebyte = 0;*len_val = 0;do{onebyte = buf[read_pos++];*len_val += (onebyte & 0x7f) * multiplier;multiplier <<= 7;len_len++;if (len_len > 4){return -1;/*len of len more than 4;*/}} while((onebyte & 0x80) != 0);return read_pos;
}//==========================================================
//  函数名称:    EDP_PacketSaveJson
//
//  函数功能:    封装协议头
//
//  入口参数:    devid:设备ID(可为空)
//              send_buf:json缓存buf
//              send_len:json总长
//              type_bin_head:bin文件的消息头
//              type:类型
//              edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:      当不为Type2的时候,type_bin_head可为NULL
//==========================================================
uint8_t EDP_PacketSaveData(const int8_t *devid, int16_t send_len, int8_t *type_bin_head, SaveDataType type, EDP_PACKET_STRUCTURE *edpPacket){int16_t remain_len = 0;uint8_t devid_len = 0;if(devid != NULL)devid_len = strlen(devid);if(type == 2 && type_bin_head == NULL)return 1;if(type == 2)EDP_NewBuffer(edpPacket, strlen(type_bin_head));elseEDP_NewBuffer(edpPacket, send_len + 24);if(edpPacket->_data == NULL)return 2;//Byte0:消息类型--------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = SAVEDATA;if(devid){if(type == 2)remain_len = 12 + strlen(type_bin_head) + send_len;elseremain_len = 8 + send_len + devid_len;//剩余消息长度-------------------------------------------------------------edpPacket->_len += WriteRemainlen(edpPacket->_data, remain_len, edpPacket->_len);//标志--bit7:1-有devid,0-无devid     bit6:1-有消息编号,0-无消息编号----edpPacket->_data[edpPacket->_len++] = 0xC0;//DEVID长度---------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = 0;edpPacket->_data[edpPacket->_len++] = devid_len;//DEVID------------------------------------------------------------------strncat((char *)edpPacket->_data + edpPacket->_len, devid, devid_len);edpPacket->_len += devid_len;//消息编号----------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = MSG_ID_HIGH;edpPacket->_data[edpPacket->_len++] = MSG_ID_LOW;}else{if(type == 2)remain_len = 10 + strlen(type_bin_head) + send_len;elseremain_len = 6 + send_len;//剩余消息长度------------------------------------------------------------edpPacket->_len += WriteRemainlen(edpPacket->_data, remain_len, edpPacket->_len);//标志--bit7:1-有devid,0-无devid      bit6:1-有消息编号,0-无消息编号----edpPacket->_data[edpPacket->_len++] = 0x40;//消息编号----------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = MSG_ID_HIGH;edpPacket->_data[edpPacket->_len++] = MSG_ID_LOW;}edpPacket->_data[edpPacket->_len++] = type;if(type == 2){unsigned char type_bin_head_len = strlen(type_bin_head);unsigned char i = 0;//消息头长度---------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = MOSQ_MSB(type_bin_head_len);edpPacket->_data[edpPacket->_len++] = MOSQ_LSB(type_bin_head_len);//消息头-------------------------------------------------------------------for(; i < type_bin_head_len; i++)edpPacket->_data[edpPacket->_len++] = type_bin_head[i];//图片长度-----------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = (unsigned char)(send_len >> 24);edpPacket->_data[edpPacket->_len++] = (unsigned char)(send_len >> 16);edpPacket->_data[edpPacket->_len++] = (unsigned char)(send_len >> 8);edpPacket->_data[edpPacket->_len++] = (unsigned char)send_len;}else{//json长度-----------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = MOSQ_MSB(send_len);edpPacket->_data[edpPacket->_len++] = MOSQ_LSB(send_len);}return 0;}//==========================================================
//  函数名称:    EDP_PacketPushData
//
//  函数功能:    PushData功能组包
//
//  入口参数:    devid:设备ID
//              msg:推送数据
//              msg_len:推送的数据长度
//              edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
uint8_t EDP_PacketPushData(const int8_t *devid, const int8_t *msg, uint32_t msg_len, EDP_PACKET_STRUCTURE *edpPacket)
{uint32_t remain_len = 2 + strlen(devid) + msg_len;uint8_t devid_len = strlen(devid);uint16_t i = 0;uint16_t size = 5 + strlen(devid) + msg_len;if(devid == NULL || msg == NULL || msg_len == 0)return 1;EDP_NewBuffer(edpPacket, size);if(edpPacket->_data == NULL)return 2;//Byte0:pushdata类型-----------------------------------------------------------edpPacket->_data[edpPacket->_len++] = PUSHDATA;//剩余长度----------------------------------------------------------------------edpPacket->_len += WriteRemainlen(edpPacket->_data, remain_len, edpPacket->_len);//DEVID长度---------------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = MOSQ_MSB(devid_len);edpPacket->_data[edpPacket->_len++] = MOSQ_LSB(devid_len);//写入DEVID---------------------------------------------------------------------for(; i < devid_len; i++)edpPacket->_data[edpPacket->_len++] = devid[i];//写入数据----------------------------------------------------------------------for(i = 0; i < msg_len; i++)edpPacket->_data[edpPacket->_len++] = msg[i];return 0;}//==========================================================
//  函数名称:    EDP_UnPacketPushData
//
//  函数功能:    PushData功能解包
//
//  入口参数:    rev_data:收到的数据
//              src_devid:源devid缓存
//              req:命令缓存
//              req_len:命令长度
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
uint8_t EDP_UnPacketPushData(uint8_t *rev_data, int8_t **src_devid, int8_t **req, uint32_t *req_len)
{int32_t read_pos = 0;uint32_t remain_len = 0;uint16_t devid_len = 0;//Byte0:PushData消息------------------------------------------------------------if(rev_data[read_pos++] != PUSHDATA)return 1;//读取剩余长度--------------------------------------------------------------------read_pos = ReadRemainlen((char *)rev_data, &remain_len, read_pos);if(read_pos == -1)return 2;//读取源devid长度-----------------------------------------------------------------devid_len = (uint16_t)rev_data[read_pos] << 8 | rev_data[read_pos + 1];read_pos += 2;//分配内存------------------------------------------------------------------------*src_devid = (char *)edp_alloc_buffer(devid_len + 1);if(*src_devid == NULL)return 3;//读取源devid---------------------------------------------------------------------memset(*src_devid, 0, devid_len + 1);strncpy(*src_devid, (const char *)rev_data + read_pos, devid_len);read_pos += devid_len;remain_len -= 2 + devid_len;//分配内存------------------------------------------------------------------------*req = (char *)edp_alloc_buffer(remain_len + 1);if(*req == NULL){edp_free_buffer(*src_devid);return 4;}//读取命令------------------------------------------------------------------------memset(*req, 0, remain_len + 1);strncpy(*req, (const char *)rev_data + read_pos, remain_len);read_pos += remain_len;*req_len = remain_len;return 0;}//==========================================================
//  函数名称:    EDP_UnPacketCmd
//
//  函数功能:    下发命令解包
//
//  入口参数:    rev_data:收到的数据
//              cmdid:cmdid
//              cmdid_len:cmdid长度
//              req:命令
//              req_len:命令长度
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
uint8_t EDP_UnPacketCmd(uint8_t *rev_data, int8_t **cmdid, uint16_t *cmdid_len, int8_t **req, uint32_t *req_len)
{uint32_t remain_len = 0;int32_t read_pos = 0;//Byte0:PushData消息------------------------------------------------------------if(rev_data[read_pos++] != CMDREQ)return 1;//读取剩余长度--------------------------------------------------------------------read_pos = ReadRemainlen((char *)rev_data, &remain_len, read_pos);if(read_pos == -1)return 2;//读取cmdid长度-------------------------------------------------------------------*cmdid_len = (uint16_t)rev_data[read_pos] << 8 | rev_data[read_pos + 1];read_pos += 2;//分配内存------------------------------------------------------------------------*cmdid = (char *)edp_alloc_buffer(*cmdid_len + 1);if(*cmdid == NULL)return 3;//读取cmdid-----------------------------------------------------------------------memset(*cmdid, 0, *cmdid_len + 1);strncpy(*cmdid, (const char *)rev_data + read_pos, *cmdid_len);read_pos += *cmdid_len;//读取req长度---------------------------------------------------------------------*req_len = (uint32_t)rev_data[read_pos] << 24 | (uint32_t)rev_data[read_pos + 1] << 16| (uint32_t)rev_data[read_pos + 2] << 8 | (uint32_t)rev_data[read_pos + 3];read_pos += 4;//分配内存------------------------------------------------------------------------*req = (char *)edp_alloc_buffer(*req_len + 1);if(*req == NULL){edp_free_buffer(*cmdid);return 4;}//读取req-------------------------------------------------------------------------memset(*req, 0, *req_len + 1);strncpy(*req, (const char *)rev_data + read_pos, *req_len);read_pos += *req_len;return 0;}//==========================================================
//  函数名称:    EDP_PacketCmdResp
//
//  函数功能:    命令回复组包
//
//  入口参数:    cmdid:命令的cmdid(随命令下发)
//              cmdid_len:cmdid长度
//              req:命令
//              req_len:命令长度
//              edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
bool EDP_PacketCmdResp(const int8_t *cmdid, uint16_t cmdid_len, const int8_t *resp, uint32_t resp_len, EDP_PACKET_STRUCTURE *edpPacket)
{uint32_t remain_len = cmdid_len + resp_len + (resp_len ? 6 : 2);EDP_NewBuffer(edpPacket, remain_len + 5);if(edpPacket->_data == NULL)return 1;//Byte0:CMDRESP消息------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = CMDRESP;//写入剩余长度------------------------------------------------------------------edpPacket->_len += WriteRemainlen(edpPacket->_data, remain_len, edpPacket->_len);//写入cmdid长度------------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = cmdid_len >> 8;edpPacket->_data[edpPacket->_len++] = cmdid_len & 0x00FF;//写入cmdid----------------------------------------------------------------------strncpy((char *)edpPacket->_data + edpPacket->_len, cmdid, cmdid_len);edpPacket->_len += cmdid_len;if(resp_len){//写入req长度-----------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = (unsigned char)(resp_len >> 24);edpPacket->_data[edpPacket->_len++] = (unsigned char)(resp_len >> 16);edpPacket->_data[edpPacket->_len++] = (unsigned char)(resp_len >> 8);edpPacket->_data[edpPacket->_len++] = (unsigned char)(resp_len & 0x00FF);//写入req---------------------------------------------------------------------strncpy((char *)edpPacket->_data + edpPacket->_len, resp, resp_len);edpPacket->_len += resp_len;}return 0;}//==========================================================
//  函数名称:    EDP_PacketPing
//
//  函数功能:    心跳请求组包
//
//  入口参数:    edpPacket:包指针
//
//  返回参数:    0-成功        1-失败
//
//  说明:
//==========================================================
bool EDP_PacketPing(EDP_PACKET_STRUCTURE *edpPacket)
{EDP_NewBuffer(edpPacket, 2);if(edpPacket->_data == NULL)return 1;//Byte0:PINGREQ消息------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = PINGREQ;//Byte1:0----------------------------------------------------------------------edpPacket->_data[edpPacket->_len++] = 0;return 0;}

2、edpkit.h

#ifndef _EDPKIT_H_
#define _EDPKIT_H_#include "system.h"#define edp_alloc_buffer(buffer_size) pvPortCalloc(1, buffer_size);
#define edp_free_buffer(buffer)\
{\if (buffer) {\vPortFree(buffer);\buffer = NULL;\}\
}\//=============================配置==============================
#define MOSQ_MSB(A)         (uint8_t)((A & 0xFF00) >> 8)
#define MOSQ_LSB(A)         (uint8_t)(A & 0x00FF)/*--------------------------------消息编号--------------------------------*/
#define MSG_ID_HIGH         0x55
#define MSG_ID_LOW          0xAA/*--------------------------------消息类型--------------------------------*/
/* 连接请求 */
#define CONNREQ             0x10
/* 连接响应 */
#define CONNRESP            0x20
/* 连接关闭 */
#define DISCONNECT          0x40
/* 转发(透传)数据 */
#define PUSHDATA            0x30
/* 存储(转发)数据 */
#define SAVEDATA            0x80
/* 存储确认 */
#define SAVEACK             0x90
/* 命令请求 */
#define CMDREQ              0xA0
/* 命令响应 */
#define CMDRESP             0xB0
/* 心跳请求 */
#define PINGREQ             0xC0
/* 心跳响应 */
#define PINGRESP            0xD0
/* 加密请求 */
#define ENCRYPTREQ          0xE0
/* 加密响应 */
#define ENCRYPTRESP         0xF0#ifndef NULL
#define NULL (void*)0
#endif/*--------------------------------SAVEDATA消息支持的格式类型--------------------------------*/
typedef enum
{kTypeFullJson = 0x01,kTypeBin = 0x02,kTypeSimpleJsonWithoutTime = 0x03,kTypeSimpleJsonWithTime = 0x04,kTypeString = 0x05} SaveDataType;/*--------------------------------内存分配方案标志--------------------------------*/
#define MEM_FLAG_NULL       0
#define MEM_FLAG_ALLOC      1
#define MEM_FLAG_STATIC     2typedef struct Buffer
{uint8_t    *_data;     //协议数据uint32_t  _len;       //写入的数据长度uint32_t   _size;      //缓存总大小uint8_t  _memFlag;   //内存使用的方案:0-未分配  1-使用的动态分配       2-使用的固定内存} EDP_PACKET_STRUCTURE;/*--------------------------------删包--------------------------------*/
void EDP_DeleteBuffer(EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------解包--------------------------------*/
uint8_t EDP_UnPacketRecv(uint8_t *dataPtr);/*--------------------------------登录方式1组包--------------------------------*/
bool EDP_PacketConnect1(const int8_t *devid, const int8_t *apikey, uint16_t cTime, EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------登录方式2组包--------------------------------*/
bool EDP_PacketConnect2(const int8_t *proid, const int8_t *auth_key, uint16_t cTime, EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------连接回复解包--------------------------------*/
uint8_t EDP_UnPacketConnectRsp(uint8_t *rev_data);/*--------------------------------数据点上传组包--------------------------------*/
uint8_t EDP_PacketSaveData(const int8_t *devid, int16_t send_len, int8_t *type_bin_head, SaveDataType type, EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------PushData组包--------------------------------*/
uint8_t EDP_PacketPushData(const int8_t *devid, const int8_t *msg, uint32_t msg_len, EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------PushData解包--------------------------------*/
uint8_t EDP_UnPacketPushData(uint8_t *rev_data, int8_t **src_devid, int8_t **req, uint32_t *req_len);/*--------------------------------命令下发解包--------------------------------*/
uint8_t EDP_UnPacketCmd(uint8_t *rev_data, int8_t **cmdid, uint16_t *cmdid_len, int8_t **req, uint32_t *req_len);/*--------------------------------命令回复组包--------------------------------*/
bool EDP_PacketCmdResp(const int8_t *cmdid, uint16_t cmdid_len, const int8_t *resp, uint32_t resp_len, EDP_PACKET_STRUCTURE *edpPacket);/*--------------------------------心跳请求组包--------------------------------*/
bool EDP_PacketPing(EDP_PACKET_STRUCTURE *edpPacket);#endif

3、data_stream.c

/*************************************************************************************************************************************************************************************** 文件名:     dStream.c** 作者:      张继瑞**   日期:      2017-09-11**    版本:      V1.1**  说明:      cJson格式数据流通用封装**    修改记录:    V1.1:修复当数据流flag全为0时封装错误的bug。************************************************************************************************************************************************************************************
**///C库
#include "string.h"
#include "stdio.h"
//协议封装文件
#include "data_stream.h"//==========================================================
//  函数名称:    DSTREAM_toString
//
//  函数功能:    将数值转为字符串
//
//  入口参数:    StreamArray:数据流
//              buf:转换后的缓存
//              pos:数据流中的哪个数据
//              bufLen:缓存长度
//
//  返回参数:    无
//
//  说明:
//==========================================================
void DSTREAM_toString(DATA_STREAM *streamArray, char *buf, unsigned short pos, unsigned short bufLen)
{memset(buf, 0, bufLen);switch((unsigned char)streamArray[pos].dataType){case TYPE_BOOL:snprintf(buf, bufLen, "%d", *(bool *)streamArray[pos].dataPoint);break;case TYPE_CHAR:snprintf(buf, bufLen, "%d", *(signed char *)streamArray[pos].dataPoint);break;case TYPE_UCHAR:snprintf(buf, bufLen, "%d", *(unsigned char *)streamArray[pos].dataPoint);break;case TYPE_SHORT:snprintf(buf, bufLen, "%d", *(signed short *)streamArray[pos].dataPoint);break;case TYPE_USHORT:snprintf(buf, bufLen, "%d", *(unsigned short *)streamArray[pos].dataPoint);break;case TYPE_INT:snprintf(buf, bufLen, "%d", *(signed int *)streamArray[pos].dataPoint);break;case TYPE_UINT:snprintf(buf, bufLen, "%d", *(unsigned int *)streamArray[pos].dataPoint);break;case TYPE_LONG:snprintf(buf, bufLen, "%ld", *(signed long *)streamArray[pos].dataPoint);break;case TYPE_ULONG:snprintf(buf, bufLen, "%ld", *(unsigned long *)streamArray[pos].dataPoint);break;case TYPE_FLOAT:snprintf(buf, bufLen, "%f", *(float *)streamArray[pos].dataPoint);break;case TYPE_DOUBLE:snprintf(buf, bufLen, "%f", *(double *)streamArray[pos].dataPoint);break;case TYPE_GPS:snprintf(buf, bufLen, "{\"lon\":%s,\"lat\":%s}", (char *)streamArray[pos].dataPoint, (char *)(streamArray[pos].dataPoint) + 16);break;case TYPE_STRING:snprintf(buf, bufLen, "\"%s\"", (char *)streamArray[pos].dataPoint);break;}}//==========================================================
//  函数名称:     DSTREAM_GetDataStream_Body
//
//  函数功能:    获取数据流格式消息体
//
//  入口参数:    type:格式类型
//              streamArray:数据流结构
//              streamArrayCnt:数据流个数
//              buffer:缓存
//              maxLen:最大缓存长度
//              offset:偏移
//
//  返回参数:    Body的长度,0-失败
//
//  说明:
//==========================================================
short DSTREAM_GetDataStream_Body(unsigned char type, DATA_STREAM *streamArray, unsigned short streamArrayCnt, unsigned char *buffer, short maxLen, short offset)
{short count = 0, numBytes = 0;                               //count-循环计数。numBytes-记录数据装载长度char stream_buf[96];char data_buf[48];short cBytes = 0;unsigned char *dataPtr = buffer + offset;for(; count < streamArrayCnt; count++){if(streamArray[count].flag)break;}if(count == streamArrayCnt)return -1;count = 0;maxLen -= 1;                                              //预留结束符位置switch(type){case FORMAT_TYPE1:if(numBytes + 16 < maxLen){memcpy(dataPtr, "{\"datastreams\":[", 16);numBytes += 16;}elsereturn 0;for(; count < streamArrayCnt; count++){if(streamArray[count].flag)                     //如果使能发送标志位{DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "{\"id\":\"%s\",\"datapoints\":[{\"value\":%s}]},", streamArray[count].name, data_buf);cBytes = strlen(stream_buf);if(cBytes >= maxLen - numBytes){//UsartPrintf(USART_DEBUG, "dStream_Get_dFormatBody Load Failed %d\r\n", numBytes);return 0;}memcpy(dataPtr + numBytes, stream_buf, cBytes);numBytes += cBytes;if(numBytes > maxLen)                        //内存长度判断return 0;}}dataPtr[numBytes] = '\0';                         //将最后的','替换为结束符if(numBytes + 1 <= maxLen){memcpy(dataPtr + numBytes - 1, "]}", 2);numBytes++;}elsereturn 0;break;case FORMAT_TYPE3:if(numBytes + 1 < maxLen){memcpy(dataPtr, "{", 1);numBytes++;}elsereturn 0;for(; count < streamArrayCnt; count++){if(streamArray[count].flag)                       //如果使能发送标志位{DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "\"%s\":%s,", streamArray[count].name, data_buf);cBytes = strlen(stream_buf);if(cBytes >= maxLen - numBytes){//UsartPrintf(USART_DEBUG, "dStream_Get_dFormatBody Load Failed %d\r\n", numBytes);return 0;}memcpy(dataPtr + numBytes, stream_buf, cBytes);numBytes += cBytes;if(numBytes > maxLen)                        //内存长度判断return 0;}}dataPtr[numBytes] = '\0';                         //将最后的','替换为结束符memcpy(dataPtr + numBytes - 1, "}", 1);break;case FORMAT_TYPE4:if(numBytes + 1 < maxLen){memcpy(dataPtr, "{", 1);numBytes++;}elsereturn 0;for(; count < streamArrayCnt; count++){if(streamArray[count].flag)                       //如果使能发送标志位{DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "\"%s\":{\"2016-08-10T12:31:17\":%s},", streamArray[count].name, data_buf);cBytes = strlen(stream_buf);if(cBytes >= maxLen - numBytes){//UsartPrintf(USART_DEBUG, "dStream_Get_dFormatBody Load Failed %d\r\n", numBytes);return 0;}memcpy(dataPtr + numBytes, stream_buf, cBytes);numBytes += cBytes;if(numBytes > maxLen)                        //内存长度判断return 0;}}dataPtr[numBytes] = '\0';                         //将最后的','替换为结束符memcpy(dataPtr + numBytes - 1, "}", 1);break;case FORMAT_TYPE5:if(numBytes + 2 < maxLen){memcpy(dataPtr, ",;", 2);numBytes += 2;}elsereturn 0;for(; count < streamArrayCnt; count++){if(streamArray[count].flag && streamArray[count].dataType != TYPE_GPS)   //如果使能发送标志位 格式5不支持GPS{DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "%s,%s;", streamArray[count].name, data_buf);cBytes = strlen(stream_buf);if(cBytes >= maxLen - numBytes - 2){//UsartPrintf(USART_DEBUG, "dStream_Get_dFormatBody Load Failed %d\r\n", numBytes);return 0;}memcpy(dataPtr + numBytes, stream_buf, cBytes);numBytes += cBytes;if(numBytes > maxLen)                        //内存长度判断return 0;}}break;default:break;}//UsartPrintf(USART_DEBUG, "Body Len: %d\r\n", numBytes);return numBytes;}//==========================================================
//  函数名称:     DSTREAM_GetDataStream_Body_Measure
//
//  函数功能:    测量当前使能的数据流长度
//
//  入口参数:    type:格式类型
//              streamArray:数据流结构
//              streamArrayCnt:数据流个数
//              flag:1-测量全部数据流长度 0-测量当前需要发送的数据流长度
//
//  返回参数:    Body的长度
//
//  说明:
//==========================================================
short DSTREAM_GetDataStream_Body_Measure(unsigned char type, DATA_STREAM *streamArray, unsigned short streamArrayCnt, bool flag)
{short count = 0, numBytes = 0;                       //count-循环计数。numBytes-记录数据装载长度char stream_buf[96];char data_buf[48];for(; count < streamArrayCnt; count++){if(streamArray[count].flag)break;}if(count == streamArrayCnt)return -1;count = 0;switch(type){case FORMAT_TYPE1:numBytes += 16;for(; count < streamArrayCnt; count++){if(streamArray[count].flag || flag){DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "{\"id\":\"%s\",\"datapoints\":[{\"value\":%s}]},", streamArray[count].name, data_buf);numBytes += strlen(stream_buf);}}numBytes += 1;break;case FORMAT_TYPE3:numBytes++;for(; count < streamArrayCnt; count++){if(streamArray[count].flag || flag){DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "\"%s\":%s,", streamArray[count].name, data_buf);numBytes += strlen(stream_buf);}}break;case FORMAT_TYPE4:numBytes++;for(; count < streamArrayCnt; count++){if(streamArray[count].flag || flag){DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "\"%s\":{\"2016-08-10T12:31:17\":%s},", streamArray[count].name, data_buf);numBytes += strlen(stream_buf);}}break;case FORMAT_TYPE5:numBytes += 2;for(; count < streamArrayCnt; count++){if(streamArray[count].flag || flag){DSTREAM_toString(streamArray, data_buf, count, sizeof(data_buf));snprintf(stream_buf, sizeof(stream_buf), "%s,%s;", streamArray[count].name, data_buf);numBytes += strlen(stream_buf);}}break;default:break;}return numBytes;}

4、data_stream.h


#ifndef __DATA_STREAM_H__
#define __DATA_STREAM_H__#include "system.h"typedef enum
{TYPE_BOOL = 0,TYPE_CHAR,TYPE_UCHAR,TYPE_SHORT,TYPE_USHORT,TYPE_INT,TYPE_UINT,TYPE_LONG,TYPE_ULONG,TYPE_FLOAT,TYPE_DOUBLE,TYPE_GPS,TYPE_STRING,
} DATA_TYPE;typedef struct
{char *name;void *dataPoint;DATA_TYPE dataType;bool flag;} DATA_STREAM;typedef enum
{FORMAT_TYPE1 = 1,FORMAT_TYPE2,FORMAT_TYPE3,FORMAT_TYPE4,FORMAT_TYPE5} FORMAT_TYPE;short DSTREAM_GetDataStream_Body(unsigned char type, DATA_STREAM *streamArray, unsigned short streamArrayCnt, unsigned char *buffer, short maxLen, short offset);
short DSTREAM_GetDataStream_Body_Measure(unsigned char type, DATA_STREAM *streamArray, unsigned short streamArrayCnt, bool flag);#endif

总结

更多关于EDP协议的使用可以看OneNET平台的社区帖子或开发文档。本文是直接在无线通讯模块上使用的是socket接口完成的,也就是把无线通讯模块当做一个MCU来使用,如果你只有无线通讯模块,而没有这个模块的SDK代码,只是有一些AT命令来控制这个模块的通信,例如ESP8266模块,GSM模块等等,本文也适用,只需要将socket部分的连接、发送、接收等函数处理修改为自己的代码即可。

本文还有很多不足之处,读者若有自己的看法和建议,评论留言。

OneNET EDP协议讲解与应用相关推荐

  1. STM32F407-OV7670(无FIFO)-ONENET-实现摄像头画面上传到onenet(EDP协议)

    EDP协议 EDP协议文档说明:https://leoeinstein.lanzous.com/ifX1Ckfkaaf 服务器登录 登录流程: (1)客户端发送连接请求(CONN_REQ) (2)服务 ...

  2. WIZnet W5500系列培训活动之“MQTT协议讲解和实践(接入OneNET)”

     万物联网的时代已经到来,物联网也由当初的概念开始进一步落实.物联网通信协议当中发展最迅速.应用最广泛的就是MQTT,它是轻量级基于代理的发布/订阅的消息传输协议,并且可以通过很少的代码和带宽与远程设 ...

  3. OneNET云平台-EDP协议数据传输

    OneNet真是中移动的良心之作,对比阿里云和庆科云,OneNet不但免费而且功能也足够嵌入式应用,对学生党而言真是大大的福利,感谢中移动!!!. 一.云端创建设备与应用 (1)创建产品:进入开发者中 ...

  4. 北斗通讯协议4.0 java_北斗4.0协议讲解.doc

    北斗4.0协议讲解 北斗用户机用户接口协议 (4.0版本外用) 接口数据传输约定 串口非同步传送,参数定义如下: 传输速率:19200bit/s(默认),可根据用户机具体情况设置其它速率: 1 bit ...

  5. Camera DVP协议讲解

    Camera DVP协议讲解 该文章写于2016年,一直未发表.近期工作中又涉及到了Camera相关的内容,重新温习了下相关知识.决定把这篇文章发表出来,大家共同学习.   DVP(Digital V ...

  6. DP/eDP协议学习--协议简介

    最近一段时间由于项目接触到该协议,该协议不像HDMI,USB资料那么多,虽然应用还是很广泛的,但是生态不是很好.自己看了一段时间的协议,想着记录下来大家一起讨论学习. 1综述 eDP(Embedded ...

  7. 蓝牙DID协议讲解 Bluetooth Device ID

    零. 概述 主要介绍下蓝牙协议栈(bluetooth stack)DID(Device ID)协议讲解 btsnoop以及流程在资料中的......\STM32_UBUNTU_BLUETOOTH\2- ...

  8. C语言实现MQTT协议(一)协议讲解

    MQTT介绍 MQTT是一个客户端服务端架构的发布/订阅模式的消息传输协议.它的设计思想是轻巧.开放.简单.规范,易于实现.这些特点使得它对很多场景来说都是很好的选择,特别是对于受限的环境如机器与机器 ...

  9. DeviceNet现场总线协议讲解

    DeviceNet现场总线协议讲解 2008-2-28 10:27:00 来源:作者: 网友评论 0条 点击查看 <script src="http://www.ca800.com/a ...

  10. BT.656协议讲解与解码

    BT.656支持不同位数和分辨率的视频,本文以标准分辨率为720*576i 8bit BT.656(4:2:2)YCbCr SDTV 数字视频信号格式讲解协议和解码方法:采集图像的时候使用隔行扫描,每 ...

最新文章

  1. usaco Picture(离散化求线段周长)
  2. log4j打印mybatis执行的sql
  3. 小强学渲染之OpenGL渲染管线详析
  4. MyEclipse 15 集成SVN
  5. History操作历史记录
  6. SQL Server 创建表
  7. Spring实战——无需一行xml配置实现自动化注入
  8. HTML 标签学习总结第一天
  9. 使用 lanmps 环境套件安装设置新站点 案例
  10. 用UltraEdit软件替换回车换行的窍门
  11. 五款最好的免费同步软件
  12. dart语言和PHP,如何以Dart语言完全转储/打印变量到控制台?
  13. 记录Android Studio KeyMap 导入的问题
  14. atomic 原子操作
  15. zabbix企业应用之自动语音报警平台
  16. (SEO优化)现身说法教你如何优化百度的收录,权重,关键词排名 SEO优化(一)
  17. mysql字符集与校对规则设置_MySQL 字符集与校对规则
  18. tableview的详解
  19. 无法安装X64 在计算机找到X32,怎么看电脑适合装32位还是64位
  20. 如何看计算机接口类型,怎么看自己电脑cpu的接口类型

热门文章

  1. 碎碎念情境记忆法——最适合程序员的背单词方法
  2. Feescale K60开发笔记3: Tftpd32的使用
  3. HTML标签关系——双标签和单标签,标签的嵌套与并列
  4. python符号或非并列,Python运算符
  5. 如何建设网站才有利于网站优化
  6. MapReduce 内部实现机制,你真的懂吗?
  7. DotaMax网站”获取“自己与职业选手(知名玩家)对战记录
  8. 基于pyod中机器学习与神经网络方法的异常值识别方法合集(含2022年全国服务外包大赛实例)
  9. WIN7+LR11+IE8无法打开的问题解决方法
  10. 电脑连接android手机测试,关于如何将手机画面投屏到PC的测试(Android)