概述
前言
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时返回的id
remote_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时返回的id
data_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时返回的id
data_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: %srn", id, auth_key);
#if 1
if(EDP_PacketConnect1(id, auth_key, 256, &edpPacket) == 0) //根据devid 和 apikey封装协议包
#else
if(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 failedrn");
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:设备ID
apikey:设备apikey
streamArray:数据流
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:%drn", 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 Bytesrn", edpPacket._len);
socket_send(g_onenet_socket_id, edpPacket._data, edpPacket._len);
}
else
{
ONENET_EDP_LOGW("DSTREAM_GetDataStream_Body Failedrn");
}
EDP_DeleteBuffer(&edpPacket); //删包
}
else
{
ONENET_EDP_LOG("EDP_NewBuffer Failedrn");
}
}
}
}
/**************************************************************
函数名称 : 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: 连接成功rn");break;
case 1:ONENET_EDP_LOG("WARN: 连接失败:协议错误rn");break;
case 2:ONENET_EDP_LOG("WARN: 连接失败:设备ID鉴权失败rn");break;
case 3:ONENET_EDP_LOG("WARN: 连接失败:服务器失败rn");break;
case 4:ONENET_EDP_LOG("WARN: 连接失败:用户ID鉴权失败rn");break;
case 5:ONENET_EDP_LOG("WARN: 连接失败:未授权rn");break;
case 6:ONENET_EDP_LOG("WARN: 连接失败:授权码无效rn");break;
case 7:ONENET_EDP_LOG("WARN: 连接失败:激活码未分配rn");break;
case 8:ONENET_EDP_LOG("WARN: 连接失败:该设备已被激活rn");break;
case 9:ONENET_EDP_LOG("WARN: 连接失败:重复发送连接请求包rn");break;
default:ONENET_EDP_LOG("ERR: 连接失败:未知错误rn");break;
}
break;
}
case DISCONNECT:
{
ONENET_EDP_LOG("WARN: 连接断开,准备重连。错误码:%drn", cmd[2]);
break;
}
case PINGRESP:
{
ONENET_EDP_LOG("Tips: HeartBeat OKrn");
break;
}
case PUSHDATA: //解pushdata包
{
if(EDP_UnPacketPushData(cmd, &cmdid_devid, &req, &req_len) == 0)
{
ONENET_EDP_LOG("src_devid: %s, req: %s, req_len: %drn", 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: %drn", 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 %srn", cmd[5] ? "Err" : "Ok");
}
else
{
ONENET_EDP_LOG("Tips: Message ID Errrn");
}
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));
else
EDP_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;
else
remain_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;
else
remain_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 2
typedef 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;
}
else
return 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 %drn", numBytes);
return 0;
}
memcpy(dataPtr + numBytes, stream_buf, cBytes);
numBytes += cBytes;
if(numBytes > maxLen) //内存长度判断
return 0;
}
}
dataPtr[numBytes] = '