LiteOS云端对接教程09-LiteOS基于LWM2M对接华为OC平台实战
1. LiteOS OC lwm2m 抽象组件
概述
为了适应各种各样的使用lwm2m接入华为OC的模式,特采用该层次接口,对上提供应用所需的接口,对下允许接入方式的灵活适配。
oc_lwm2m_agent是处理使用lwm2m协议对接华为OC的流程抽象层,允许使用流程进行对接,也允许使用NB芯片内置的流程进行对接。对于应用程序开发者而言,无需关注对接流程的实现细节,仅仅需要调用该模块提供的api即可。
OC lwm2m AL的api接口声明在<oc_lwm2m_al.h>
中,使用相关的接口需要包含该头文件。
配置并连接
对接服务器的所有信息保存在结构体oc_config_param_t
中,其定义在oc_lwm2m_al.h
中,如下:
typedef struct { en_oc_boot_strap_mode_t boot_mode; ///< bootmode,if boot client_initialize, then the bs must be set oc_server_t boot_server; ///< which will be used by the bootstrap, if not, set NULL here oc_server_t app_server; ///< if factory or smart boot, must be set here fn_oc_lwm2m_msg_deal rcv_func; ///< receive function caller here void *usr_data; ///< used for the user }oc_config_param_t;
其中boot_mode
是对接模式,对应华为平台的三种模式:
typedef enum { en_oc_boot_strap_mode_factory = 0, en_oc_boot_strap_mode_client_initialize, en_oc_boot_strap_mode_sequence, } en_oc_boot_strap_mode_t;
app_server参数是服务器信息,定义如下:
typedef struct { char *ep_id; ///< endpoint identifier, which could be recognized by the server char *address; ///< server address,maybe domain name char *port; ///< server port char *psk_id; ///< server encode by psk, if not set NULL here char *psk; int psk_len; } oc_server_t;
参数说明如下:
ep_id:设备标识符
address:服务器地址
port:服务器端口
psk_id:DTLS使用,不使用的话设置为NULL
rcv_func是回调函数的函数指针,当设备接收到lwm2m消息后回调:
typedef int (*fn_oc_lwm2m_msg_deal)(void *usr_data, en_oc_lwm2m_msg_t type, void *msg, int len);
在配置结构体完成之后,调用配置函数进行配置并连接,API如下:
/** * @brief the application use this function to configure the lwm2m agent * @param[in] param, refer to oc_config_param_t * @return the context, while NULL means failed */ void* oc_lwm2m_config(oc_config_param_t *param);
函数参数很清楚,将存放对接信息的结构体指针传入即可,其中handle是oc lwm2m handle指针,后续使用。
数据上报
连接成功之后,因为平台部署了编解码插件,直接向华为云平台上报二进制数据即可,oc_lwm2m提供的API如下:
/** * @brief the application use this function to send the message to the cdp * @param[in] hanlde, returned by the config * @param[in] buf the message to send * @param[in] len the message length * @param[in] timeout block time * * @return 0 success while <0 failed */ int oc_lwm2m_report(void *context, char *buf, int len, int timeout);
命令接收
当OC平台发布该主题数据时,oc_lwm2m组件会拉起接收回调函数将数据保存,进而用户解析接收到的数据即可。
oc_lwm2m组件自动初始化
在SDK目录中的IoT_LINK_1.0.0\iot_link\link_main.c
中可以看到自动初始化函数:
2. 配置准备
Makefile配置
因为本次实验用到的组件较多:
AT框架
ESP8266设备驱动
串口驱动框架
SAL组件
lwm2m组件
oc_lwm2m组件
这些实验代码全部编译下来,有350KB,而小熊派开发板所使用的主控芯片STM32L431RCT6的 Flash 仅有256KB,会导致编译器无法链接出可执行文件,所以要在makefile中修改优化选项,修改为-Os
参数,即最大限度的优化代码尺寸,并去掉-g
参数,即代码只能下载运行,无法调试,如图:
ESP8266设备配置
在工程目录中的OS_CONFIG/iot_link_config.h
文件中,配置ESP8266设备的波特率和设备名称:
WIFI对接信息配置
SDK:C:\Users\Administrator\.icode\sdk\IoT_LINK_1.0.0
(其中Administrator是实验电脑的用户名)。
在SDK目录中的iot_link\network\tcpip\esp8266_socket\esp8266_socket_imp.c
文件中,配置连接信息:
之后修改同路径下的esp8266_socket_imp.mk
文件,如图,将 TOP_DIR 改为 SDK_DIR :
3. 上云实验
编写实验文件
在 Demo 文件夹下创建cloud_test_demo
文件夹,在其中创建oc_lwm2m_demo.c
文件。
编写以下代码:
#include <osal.h> #include <oc_lwm2m_al.h> #include <link_endian.h> #include <string.h> #define cn_endpoint_id "867725038317248" #define cn_app_server "49.4.85.232" #define cn_app_port "5683" #define cn_app_light 0 #define cn_app_ledcmd 1 #pragma pack(1) typedef struct { int8_t msgid; int16_t intensity; }app_light_intensity_t; typedef struct { int8_t msgid; char led[3]; }app_led_cmd_t; #pragma pack() #define cn_app_rcv_buf_len 128 static int8_t s_rcv_buffer[cn_app_rcv_buf_len]; static int s_rcv_datalen; static osal_semp_t s_rcv_sync; static void *s_lwm2m_handle = NULL; static int app_msg_deal(void *usr_data,en_oc_lwm2m_msg_t type, void *msg, int len) { int ret = -1; if(len <= cn_app_rcv_buf_len) { memcpy(s_rcv_buffer,msg,len); s_rcv_datalen = len; osal_semp_post(s_rcv_sync); ret = 0; } return ret; } static int app_cmd_task_entry() { int ret = -1; app_led_cmd_t *led_cmd; int8_t msgid; while(1) { if(osal_semp_pend(s_rcv_sync,cn_osal_timeout_forever)) { msgid = s_rcv_buffer[0]; switch (msgid) { case cn_app_ledcmd: led_cmd = (app_led_cmd_t *)s_rcv_buffer; printf("LEDCMD:msgid:%d msg:%s \n\r",led_cmd->msgid,led_cmd->led); if (led_cmd->led[0] == 'o' && led_cmd->led[1] == 'n') { printf("--------------- LED ON! --------------------\r\n"); } else if (led_cmd->led[0] == 'o' && led_cmd->led[1] == 'f' && led_cmd->led[2] == 'f') { printf("--------------- LED OFF! --------------------\r\n"); } else { } break; default: break; } } } return ret; } static int app_report_task_entry() { int ret = 0; int lux = 0; oc_config_param_t oc_param; app_light_intensity_t light; memset(&oc_param,0,sizeof(oc_param)); oc_param.app_server.address = cn_app_server; oc_param.app_server.port = cn_app_port; oc_param.app_server.ep_id = cn_endpoint_id; oc_param.boot_mode = en_oc_boot_strap_mode_factory; oc_param.rcv_func = app_msg_deal; s_lwm2m_handle = oc_lwm2m_config(&oc_param); if(NULL != s_lwm2m_handle) { while(1) { lux++; lux= lux%10000; light.msgid = cn_app_light; light.intensity = htons(lux); oc_lwm2m_report(s_lwm2m_handle,(char *)&light,sizeof(light),1000); osal_task_sleep(2*1000); } } return ret; } int standard_app_demo_main() { osal_semp_create(&s_rcv_sync,1,0); osal_task_create("app_report",app_report_task_entry,NULL,0x1000,NULL,2); osal_task_create("app_command",app_cmd_task_entry,NULL,0x1000,NULL,3); return 0; }
添加路径
在user_demo.mk中添加如下:
#example for oc_lwm2m_demo ifeq ($(CONFIG_USER_DEMO), "oc_lwm2m_demo") user_demo_src = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/cloud_test_demo/oc_lwm2m_demo.c} endif
添加位置如下:
配置.sdkconfig
上报数据实验结果
编译,下载,在云端的实验现象如下:
命令下发实验结果
在云端下发“on”命令:
在串口助手中可以看到:
下发“off”命令:
在串口助手中可以看到:
- 点赞
- 收藏
- 关注作者
评论(0)