文章目录
前言
华为云注册设备,然后通过lwm2m协议对接华为云平台,硬件选型rk3588或者任务支持linux系统的设备。
一、整体思路
1.华为云创建设备
(1)定义产品
(2)创建物模型,创建数据模型
(3)创建插件
设备上传的格式就说0012345678,一共5个字节,00是地址域,后面4个字节是你的数据,二进制码流的形式。
(4)保存部署
(5)创建个虚拟设备测试(这个自己操作一下就行)
2.LWM2M2源码拉取
(1)需要配置一个高版本的cmake
(2)gcc编译器版本要高,那种7.5.0的版本编译会报错
(3)拉去代码编译
c
# 拉去代码
git clone https://gitee.com/benxiongben/wakaama.git
cd wakaama
mkdir build
cd build
cmake ..
make -j
二、修改源代码
1.修改lwm2mclient.c文件
这边只列出跟原来不同的代码段,减轻修改压力
c
#define OBJ_COUNT 3
//封装了一个主动上报的函数接口,通过调用观察者列表来完成这个操作
static void send_client_data(lwm2m_context_t *contextP)
{
lwm2m_observed_t * targetP;
for (targetP = contextP->observedList ; targetP != NULL ; targetP = targetP->next)
{
lwm2m_watcher_t * watcherP;
uint8_t * buffer = NULL;
size_t length = 0;
lwm2m_data_t * dataP = NULL;
lwm2m_data_type_t dataType = LWM2M_TYPE_UNDEFINED;
int size = 0;
coap_packet_t message[1];
time_t interval;
// TODO: handle resource instances
LOG_URI(&(targetP->uri));
if (LWM2M_URI_IS_SET_RESOURCE(&targetP->uri))
{
lwm2m_data_t *valueP;
if (COAP_205_CONTENT != object_readData(contextP, &targetP->uri, &size, &dataP)) continue;
}
for (watcherP = targetP->watcherList ; watcherP != NULL ; watcherP = watcherP->next)
{
if (watcherP->active == true)
{
int res;
res = lwm2m_data_serialize(&targetP->uri, size, dataP, &(watcherP->format), &buffer);
length = res;
coap_init_message(message, COAP_TYPE_NON, COAP_205_CONTENT, 0);
coap_set_header_content_type(message, watcherP->format);
coap_set_payload(message, buffer, length);
watcherP->lastMid = contextP->nextMID++;
message->mid = watcherP->lastMid;
coap_set_header_token(message, watcherP->token, watcherP->tokenLen);
coap_set_header_observe(message, watcherP->counter++);
(void)message_send(contextP, message, watcherP->server->sessionH);
}
}
if (dataP != NULL) lwm2m_data_free(size, dataP);
if (buffer != NULL) lwm2m_free(buffer);
}
}
//接收服务端发来的数据包,其实根本上就是修改了原来的一部分代码
static void recvggmsg(client_data_t data,lwm2m_context_t *lwm2mH,fd_set readfds)
{
uint8_t buffer[MAX_PACKET_SIZE];
ssize_t numBytes=0;
if (FD_ISSET(data.sock, &readfds))
{
struct sockaddr_storage addr;
socklen_t addrLen;
addrLen = sizeof(addr);
/*
* We retrieve the data received
*/
numBytes = recvfrom(data.sock, buffer, MAX_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrLen);
if (0 < numBytes)
{
in_port_t port;
char s[100];
connection_t * connP;
if (AF_INET == addr.ss_family)
{
struct sockaddr_in *saddr = (struct sockaddr_in *)&addr;
inet_ntop(saddr->sin_family, &saddr->sin_addr, s, INET6_ADDRSTRLEN);
port = saddr->sin_port;
}
fprintf(stderr, "%zd bytes received from [%s]:%hu\r\n", numBytes, s, ntohs(port));
connP = connection_find(data.connList, &addr, addrLen);
if (connP != NULL)
{
lwm2m_handle_packet(lwm2mH, buffer, (size_t)numBytes, connP);
}
else
{
fprintf(stderr, "received bytes ignored!\r\n");
}
}
}
}
//这部分代码
int main()
{
client_data_t data;
int result;
lwm2m_context_t *lwm2mH = NULL;
/* 绑定登录信息 */
const char *localPort = "6677";
const char *server = "119.3.250.80";
const char *serverPort = LWM2M_STANDARD_PORT_STR;
char *name = "xxxxxxxxxx"; // 华为云上面的设备标识码
int lifetime = 300; // 保活时间,这个很重要,过了这个时间,就需要重新登录才能发送信息
char *pskId = NULL;
uint16_t pskLen = -1;
char *pskBuffer = NULL;
/* 创建socket */
memset(&data, 0, sizeof(client_data_t));
data.addressFamily = AF_INET;
data.sock = create_socket(localPort, data.addressFamily);
/* 获取对象 */
char serverUri[100];
int serverId = 123;
sprintf(serverUri, "coap://%s:%s", server, serverPort);
objArray[0] = get_security_object(serverId, serverUri, pskId, pskBuffer, pskLen, false);
data.securityObjP = objArray[0];
objArray[1] = get_server_object(serverId, "U", lifetime, false);
objArray[2] = get_object_device();
/* 协议栈初始化及配置 */
lwm2mH = lwm2m_init(&data);
lwm2m_configure(lwm2mH, name, NULL, NULL, OBJ_COUNT, objArray);
add_object(lwm2mH); // 添加自己的对象
fd_set readfds;
struct timeval tv;
time_t timeout;
while (1)
{
tv.tv_sec = 5;
tv.tv_usec = 0;
timeout = 60;
FD_ZERO(&readfds);
FD_SET(data.sock, &readfds);
lwm2m_step(lwm2mH, &timeout);
printf("tv_sec %ld lwm2mH->state %d \n", lwm2m_gettime(), lwm2mH->state);
// 阻塞5s获取服务器发送的数据
result = select(FD_SETSIZE, &readfds, NULL, NULL, &tv);
if (result)
{
recvggmsg(data, lwm2mH, readfds);
}
// 发送数据
if (lwm2mH->state == STATE_READY)
{
send_client_data(lwm2mH);
}
}
lwm2m_close(lwm2mH);
close(data.sock);
connection_free(data.connList);
clean_security_object(objArray[0]);
lwm2m_free(objArray[0]);
clean_server_object(objArray[1]);
lwm2m_free(objArray[1]);
free_object_device(objArray[2]);
return 0;
}
2.修改object_test.c文件
c
static uint8_t prv_read(lwm2m_context_t *contextP,
uint16_t instanceId,
int * numDataP,
lwm2m_data_t ** dataArrayP,
lwm2m_object_t * objectP)
{
prv_instance_t * targetP;
static char rom =0x01;
int i;
printf("-------- test prv_read instanceId %d\n",instanceId);
/* unused parameter */
(void)contextP;
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP) return COAP_404_NOT_FOUND;
if (*numDataP == 0)
{
*dataArrayP = lwm2m_data_new(3);
if (*dataArrayP == NULL) return COAP_500_INTERNAL_SERVER_ERROR;
*numDataP = 3;
(*dataArrayP)[0].id = 0;
(*dataArrayP)[1].id = 3;
(*dataArrayP)[2].id = 5;
}
uint8_t test[5]={0x00,0x12,0x34,0x56,0x78};
for (i = 0 ; i < *numDataP ; i++)
{
if ((*dataArrayP)[i].type == LWM2M_TYPE_MULTIPLE_RESOURCE)
{
return COAP_404_NOT_FOUND;
}
switch ((*dataArrayP)[i].id)
{
case 0:
test[4] = rom++;
printf("--------test[4] %02x\n",test[4]);
lwm2m_data_encode_opaque(test,5, *dataArrayP + i);
break;
case 2:
return COAP_405_METHOD_NOT_ALLOWED;
case 3:
lwm2m_data_encode_float(targetP->dec, *dataArrayP + i);
break;
case 5:
lwm2m_data_encode_string(targetP->str, *dataArrayP + i);
break;
default:
return COAP_404_NOT_FOUND;
}
}
return COAP_205_CONTENT;
}
static uint8_t prv_write(lwm2m_context_t *contextP,
uint16_t instanceId,
int numData,
lwm2m_data_t *dataArray,
lwm2m_object_t *objectP,
lwm2m_write_type_t writeType)
{
prv_instance_t *targetP;
int i;
char *tmp;
printf("\n-----------------------prv_write--------------------------\n");
printf("instanceId %d writeType %d numData %d\n", instanceId, writeType, numData);
targetP = (prv_instance_t *)lwm2m_list_find(objectP->instanceList, instanceId);
if (NULL == targetP)
return COAP_404_NOT_FOUND;
if (writeType == LWM2M_WRITE_REPLACE_INSTANCE)
{
uint8_t result = prv_delete(contextP, instanceId, objectP);
if (result == COAP_202_DELETED)
{
result = prv_create(contextP, instanceId, numData, dataArray, objectP);
if (result == COAP_201_CREATED)
{
result = COAP_204_CHANGED;
}
}
return result;
}
for (i = 0; i < numData; i++)
{
/* No multiple instance resources */
if (dataArray[i].type == LWM2M_TYPE_MULTIPLE_RESOURCE)
return COAP_404_NOT_FOUND;
switch (dataArray[i].id)
{
case 0:
{
int64_t value;
if (1 != lwm2m_data_decode_int(dataArray + i, &value))
{
return COAP_400_BAD_REQUEST;
}
printf("recv value %d \n", value);
}
break;
case 1:
{
int64_t value;
if (1 != lwm2m_data_decode_int(dataArray + i, &value) || value < 0 || value > 0xFF)
{
return COAP_400_BAD_REQUEST;
}
targetP->test = (uint8_t)value;
}
break;
case 2:
return COAP_405_METHOD_NOT_ALLOWED;
case 3:
if (1 != lwm2m_data_decode_float(dataArray + i, &(targetP->dec)))
{
return COAP_400_BAD_REQUEST;
}
break;
case 5:
if (dataArray[i].type == LWM2M_TYPE_STRING || dataArray[i].type == LWM2M_TYPE_OPAQUE)
{
tmp = targetP->str;
targetP->str = lwm2m_malloc(dataArray[i].value.asBuffer.length + 1);
strncpy(targetP->str, (char *)dataArray[i].value.asBuffer.buffer, dataArray[i].value.asBuffer.length);
lwm2m_free(tmp);
break;
}
else
{
return COAP_400_BAD_REQUEST;
}
default:
return COAP_404_NOT_FOUND;
}
}
printf("-----------------------------------------------------\n");
return COAP_204_CHANGED;
}
三、网络报文分析
在仓库中有完整的网络数据包交互,可以查看分析
四、结果
注意:上面列出的代码片段不是完善的,需要去仓库中看完善的代码。如有问题,可评论区沟通交流。