LWM2M---Wakaama源码对接华为云平台

文章目录


前言

华为云注册设备,然后通过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;
}

三、网络报文分析

在仓库中有完整的网络数据包交互,可以查看分析

四、结果

注意:上面列出的代码片段不是完善的,需要去仓库中看完善的代码。如有问题,可评论区沟通交流。

相关推荐
佳心饼干-2 小时前
单片机-静动态数码管实验
单片机·嵌入式硬件
小禾苗_5 小时前
51单片机——按键实验
单片机·嵌入式硬件·51单片机
浅陌pa6 小时前
I2C(一):存储器模式:stm32作为主机对AT24C02写读数据
c语言·stm32·单片机·嵌入式硬件
半个番茄7 小时前
STM32 和 ESP32
stm32·单片机·嵌入式硬件
code .8 小时前
STM32G431收发CAN
单片机·嵌入式硬件·can·canfd·stm32g4
无情大菜刀10 小时前
EPS32基础篇开发
单片机·嵌入式硬件
亿道电子Emdoor16 小时前
【ARM】MDK-快捷键添加及修改
arm开发·stm32·单片机
heater40419 小时前
【STM32】stm32启动流程
stm32·单片机·嵌入式硬件
honey ball21 小时前
滤波器的主要参数
人工智能·单片机·嵌入式硬件·学习
浅陌pa21 小时前
RTC:实时时钟
c语言·stm32·单片机·嵌入式硬件