5.Agent Tiny
概述
Agent Tiny是部署在具备广域网能力、对功耗/存储/计算资源有苛刻限制的终端设备上的轻量级互联互通中间件,开发者只需调用几个简单的API接口,便可实现设备快速接入到华为IoT云平台(OceanConnect)以及数据上报和命令接收等功能。
以彩灯应用举例,Agent Tiny工作原理如下:
开发指导
使用场景
开发者只需实现平台抽象层接口,即可对接OceanConncet平台。
功能
Agent Tiny互联互通中间件为用户提供以下几类接口:
接口分类 | 接口名 | 描述 |
---|---|---|
Agent Tiny依赖接口 | atiny_cmd_ioctl | Agent Tiny申明和调用,开发者实现。该接口是LwM2M标准对象向设备下发命令的统一入口,比如读写设备数据,下发复位,升级命令等。为了避免死锁,该接口中禁止调用Agent Tiny对外接口 |
atiny_event_notify | Agent Tiny申明和调用,开发者实现,Agent Tiny把注册过程的关键状态,以及运行过程的关键事件通知用户,便于用户根据自身的应用场景灵活地做可靠性处理。此外,为了避免死锁,该接口中禁止调用Agent Tiny对外接口 | |
Agent Tiny对外接口 | atiny_init | Agent Tiny的初始化接口,由Agent Tiny实现,开发者调用 |
atiny_bind | Agent Tiny的主函数体,由Agent Tiny实现,开发者调用,调用成功后,不会返回。该接口是Agent Tiny主循环体,实现了LwM2M协议处理,注册状态机,重传队列,订阅上报 | |
atiny_deinit | Agent Tiny的去初始化接口,由Agent Tiny实现,开发者调用,该接口为阻塞式接口,调用该接口时,会直到agent tiny主任务退出,资源释放完毕,该接口才会退出 | |
atiny_data_report | Agent Tiny数据上报接口,由agent Tiny实现,开发者调用,用户APP数据使用该接口上报,该接口为阻塞接口,不允许在中断中使用 |
开发流程
Agent Tiny典型场景的开发流程:
根据Agent Tiny提供的头文件说明,实现atiny_cmd_ioctl接口。该接口有三个参数,参数cmd为命令类型,参数arg的内存空间由Agent Tiny分配,其内容填充视cmd而异,如读数据相关命令,由device侧填充,Agent Tiny使用,如写数据命令,则由agent Tiny填充,device侧使用。参数len指arg所指向的内存空间长度,device侧填充或读取时,务必防止溢出。
根据Agent Tiny提供的头文件说明,实现atiny_event_notify接口。该接口有三个参数,参数stat为事件类型,参数arg是 Agent Tiny根据事件类型,传递给device侧的具体的事件信息,len为arg长度,device侧使用时务分防止溢出。
调用atiny_init初始化Agent Tiny,获取对应的Agent Tiny句柄,开发者应处理该接口返回值,返回错误时,句柄无效。
创建一个新任务,栈大小建议不小于4K,调用atiny_bind,启动Agent Tiny。atiny_bind调用成功后不再返回,atiny_bind内部实现了Agent Tiny的主体任务。
如需要停止Agent Tiny,调用atiny_deinit,该接口等待Agent Tiny退出且释放资源后返回。
atiny_data_report可以在开发者业务的任何一个任务中调用。
互斥锁错误码
Agent Tiny对外接口和依赖接口,可能存在的错误,统一用以下错误码。
序号 | 定义 | 实际数值 | 描述 | 参考解决方案 |
---|---|---|---|---|
1 | ATINY_OK | 0 | 正常返回码 | |
2 | ATINY_ARG_INVALID | -1 | 非法参数 | 确保入参合法 |
3 | ATINY_BUF_OVERFLOW | -2 | 缓冲区溢出 | 确保缓冲区充足 |
4 | ATINY_MSG_CONGEST | -3 | 消息拥塞 | 暂缓数据上报 |
5 | ATINY_MALLOC_FAILED | -4 | 内存申请失败 | 检查内存是否有泄漏 |
6 | ATINY_RESOURCE_NOT_FOUND | -5 | 数据上报类型非法 | 检查数据类型是否正确 |
7 | ATINY_RESOURCE_NOT_ENOUGH | -6 | 系统资源不足 | 检查系统资源,比如信号量,套接字个数等,是否配置过少,或是否有泄漏 |
8 | ATINY_CLIENT_UNREGISTERED | -7 | AgentTiny注册失败 | 检查psk,服务器信息等是否正确 |
9 | ATINY_SOCKET_CREATE_FAILED | -8 | 网络套接字创建失败 | 检查网络配置和参数是否正确 |
平台差异性
无。
注意事项
atiny_cmd_ioctl和atiny_event_notify禁止调用atiny_deinit,atiny_data_report,atiny_init,atiny_bind四个Agent Tiny对外接口,否则可能产生死锁,或其他异常。
调用atiny_deinit之前务必确认已调用atiny_bin,否则atiny_deinit将一直阻塞,调用完atiny_deinit后,对应的Agent Tiny句柄将失效,禁止再使用。
承载atiny_bind的任务栈大小建议不小于4K,任务优先级视系统情况而定,太低可能会导致接收丢包,发送延迟等现象。
编程实例
实例描述
本实例实现如下流程:
实现atiny_cmd_ioctl和atiny_event_notify。
创建数据上报任务。
调用atiny_init初始化AgentTiny。
调用atiny_bind启动AgentTiny。
编程示例
前提条件:
在工程配置中,WITH_DTLS编译选项打开。
代码实现如下:
#define MAX_PSK_LEN 16
#define DEFAULT_SERVER_IPV4 "139.159.209.89"
#define DEFAULT_SERVER_PORT "5684"
#define LWM2M_LIFE_TIME 50000
char * g_endpoint_name_s = "11110001";
unsigned char g_psk_value[MAX_PSK_LEN] = {0xef,0xe8,0x18,0x45,0xa3,0x53,0xc1,0x3c,0x0c,0x89,0x92,0xb3,0x1d,0x6b,0x6a,0x33};
UINT32 TskHandle;
static void* g_phandle = NULL;
static atiny_device_info_t g_device_info;
static atiny_param_t g_atiny_params;
int atiny_cmd_ioctl(atiny_cmd_e cmd, char* arg, int len)
{
int result = ATINY_OK;
switch(cmd)
{
case ATINY_DO_DEV_REBOOT:
result = atiny_do_dev_reboot();
break;
case ATINY_GET_MIN_VOLTAGE:
result = atiny_get_min_voltage((int*)arg);
break;
default:
result = ATINY_RESOURCE_NOT_FOUND;
break;
}
return result;
}
void atiny_event_notify(atiny_event_e stat, char* arg, int len)
{
(void)atiny_printf("notify:stat:%d\r\n", stat);
}
void ack_callback(atiny_report_type_e type, int cookie, data_send_status_e status)
{
printf("ack type:%d cookie:%d status:%d\n", type,cookie, status);
}
void app_data_report(void)
{
uint8_t buf[5] = {0,1,6,5,9};
data_report_t report_data;
int cnt = 0;
report_data.buf = buf;
report_data.callback = ack_callback;
report_data.cookie = 0;
report_data.len = sizeof(buf);
report_data.type = APP_DATA;
while(1)
{
report_data.cookie = cnt;
cnt++;
(void)atiny_data_report(g_phandle, &report_data);
(void)LOS_TaskDelay(2000);
}
}
UINT32 creat_report_task()
{
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 1;
task_init_param.pcName = "app_data_report";
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)app_data_report;
task_init_param.uwStackSize = 0x1000;
uwRet = LOS_TaskCreate(&TskHandle, &task_init_param);
if(LOS_OK != uwRet)
{
return uwRet;
}
return uwRet;
}
void agent_tiny_entry(void)
{
UINT32 uwRet = LOS_OK;
atiny_param_t* atiny_params;
atiny_security_param_t *security_param = NULL;
atiny_device_info_t *device_info = &g_device_info;
device_info->endpoint_name = g_endpoint_name_s;
device_info->manufacturer = "test";
atiny_params = &g_atiny_params;
atiny_params->server_params.binding = "UQ";
atiny_params->server_params.life_time = LWM2M_LIFE_TIME;
atiny_params->server_params.storing_cnt = 0;
security_param = &(atiny_params->security_params[0]);
security_param->is_bootstrap = FALSE;
security_param->server_ip = DEFAULT_SERVER_IPV4;
security_param->server_port = DEFAULT_SERVER_PORT;
security_param->psk_Id = g_endpoint_name_s;
security_param->psk = (char*)g_psk_value;
security_param->psk_len = sizeof(g_psk_value);
if(ATINY_OK != atiny_init(atiny_params, &g_phandle))
{
return;
}
uwRet = creat_report_task();
if(LOS_OK != uwRet)
{
return;
}
(void)atiny_bind(device_info, g_phandle);
}
结果验证
- 登录OceanConncet测试平台:
https://139.159.209.89:8843/index.html#/device
请在OceanConnect平台上提前注册账号。
选择查看“设备”。
点击第一个设备,查看其设备标识码为11110001,说明设备已经注册。