同步操作将从 SpunkyWX/netbox 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
当前国内互联网的发展迅猛,物联网云、边缘计算等技术也从概念技术逐步变为可靠的工程应用技术,加之国民对智能化生活的强烈需求,市场上涌现出许多的物联网设备需求,如智能售货柜、智能洗车机、智能储物箱等等。然而这些物联网设备与具体应用有关,不同的个体应用案例,对物联网设备的功能要求差异也较大。同时为了满足市场的商机,要求物联网设备能够快速开发出来,并且稳定可靠。因此为了避免重复开发打造一款通用的物联网平台非常必要。
物联网系统平台包含多个终端设备、后台服务器和人机设备(如手机、平板等),因此打造一套通用的物联网系统平台需要首先确定整个物联网系统的拓扑架构。
物联网终端设备硬件框图如下:
实现功能说明:
使用的RTT软件包说明:
设备使用RT-Thrad 4.0.X作为操作系统,采用RTT官方的目录结构和框架:
使用RT-Thread系统,其软件框架就已经基本构架完成,采用compention方式进行自动初始化相关例程。这里我以智能存储柜应用为例子。
智能储存柜应用对终端设备的主要需求如下:
智能存储柜应用设备使用了多个RTT软件包,这里不再详细叙述每个软件包的使用方法,请自行看代码和软件包的说明即可。以下详细阐述下应用业务层面的逻辑框架。应用层代码全部放置于/application文件夹中,其主要的实现文件就3个:mqtt-device.c,mqtt-ota.c,dev_modbus_rtu.c。
static int ali_mqtt_init(void)
{
rt_thread_t tid;
/* 建立mqtt.main线程 */
tid = rt_thread_create("mqtt.main", mqtt_thread_main_thread, RT_NULL, 6 * 1024, RT_THREAD_PRIORITY_MAX / 2, 10);
if (tid != RT_NULL)
rt_thread_startup(tid);
/* 建立mqtt.chk线程 */
tid = rt_thread_create("mqtt.chk", mqtt_connect_check_thread, RT_NULL, 512, RT_THREAD_PRIORITY_MAX / 2 + 1, 10);
if (tid != RT_NULL)
rt_thread_startup(tid);
return 0;
}
INIT_APP_EXPORT(ali_mqtt_init);
1.负责与阿里物联网服务器的通讯建立
if (topic_buff != RT_NULL)
{
rt_free(topic_buff);
topic_buff = RT_NULL;
}
/* mqtt_check_load_topic()函数是应用需要订阅和发布的主题全部组合起来,存储于topic_buff缓冲区 */
topic_buff = mqtt_check_load_topic();
if (topic_buff == RT_NULL)
{
LOG_D("Load MQTT Topic failed!");
return;
}
while (is_mqtt_exit == 0)
{
iotx_http_region_types_t region = IOTX_HTTP_REGION_SHANGHAI;
IOT_Ioctl(IOTX_IOCTL_SET_REGION, (void *)®ion);
/* Initialize MQTT parameter */
iotx_mqtt_param_t mqtt_params;
rt_memset(&mqtt_params, 0x0, sizeof(mqtt_params));
mqtt_params.customize_info = MQTT_MAN_INFO_STRING;
/* timeout of request. uint: ms */
mqtt_params.request_timeout_ms = MQTT_REQUEST_TIMEOUT;
/* internal of keepalive checking: 60s~300s */
mqtt_params.keepalive_interval_ms = MQTT_KEEPALIVE_INTERNAL * 1000;
/* default is 0 */
mqtt_params.clean_session = 0;
/* MQTT read/write buffer size */
mqtt_params.read_buf_size = MQTT_MSGLEN;
mqtt_params.write_buf_size = MQTT_MSGLEN;
/* configure handle of event */
mqtt_params.handle_event.h_fp = ali_mqtt_event_handle;
mqtt_params.handle_event.pcontext = RT_NULL;
/* construct a MQTT device with specify parameter */
mqtt_client_hd = IOT_MQTT_Construct(&mqtt_params);
if (RT_NULL == mqtt_client_hd)
{
LOG_D("construct MQTT failed!");
rt_thread_mdelay(rt_tick_from_millisecond(RT_TICK_PER_SECOND));
continue;
}
/* 实现消息的订阅 */
for (int i = 0; i < (sizeof(mqtt_sub_item) / sizeof(mqtt_subscribe_item)); i++)
{
if (mqtt_sub_item[i].topic_handle_func == RT_NULL)
continue;
if (IOT_MQTT_Subscribe(mqtt_client_hd, &topic_buff[i * 128], mqtt_sub_item[i].qos, mqtt_sub_item[i].topic_handle_func, mqtt_sub_item[i].pcontext) < 0)
{
LOG_D("IOT_MQTT_Subscribe() failed, topic = %s", &topic_buff[i * 128]);
goto __do_main_release;
}
}
2.负责执行周期性任务
IOT_MQTT_Yield(mqtt_client_hd, 200);
is_mqtt_disconnect = 0;
/* 每次连接成功后发送一次设备标签信息 */
mqtt_devtag_task();
/* 只要通讯不出错就一直循环下去 */
while (is_mqtt_exit == 0)
{
/* handle the MQTT packet received from TCP or SSL connection */
IOT_MQTT_Yield(mqtt_client_hd, 200);
/* 每10s执行一次周期任务,执行消息的订阅和发布操作 */
if ((mqtt_period_cnt % 50) == 0)
mqtt_period_task();
/* OTA周期执行,检查平台是否下发固件更新指令 */
extern rt_err_t mqtt_ota(void *mqtt_ota_hd);
mqtt_ota(mqtt_client_hd);
mqtt_period_cnt++;
}
IOT_MQTT_Yield(mqtt_client_hd, 200);
is_mqtt_disconnect = 1;
/* OTA模块释放 */
extern void mqtt_ota_deinit(void);
mqtt_ota_deinit();
mqtt_period_task() 函数是周期检查订阅的消息的来到,并发送消息队列给modbus线程执行相应动作;
mqtt_ota() 函数是周期检查平台下发的固件升级消息,并执行相应的固件下载存储工作;
modbus的实现使用libmodbus软件包,其初始化非常简单:
modbus_t *ctx;
ctx = modbus_new_rtu(MODBUS_SERIAL_DEV, MODBUS_SERIAL_BANDRATE, 'N', 8, 1);
RT_ASSERT(ctx != RT_NULL);
/* 初始化RS485方向控制引脚 */
#ifdef BSP_USING_SUB_CTRL
rt_pin_mode(BSP_RS485_DIR_PIN, PIN_MODE_OUTPUT);
modbus_rtu_set_serial_mode(ctx, BSP_RS485_DIR_PIN);
modbus_rtu_set_rts(ctx, BSP_RS485_DIR_PIN, MODBUS_RTU_RTS_UP);
#endif
/* 初始化先设置为广播地址, 从机地址最大不能超过247 */
modbus_set_slave(ctx, 0);
/* 打开串口操作,包括波特率设置和串口初始化等 */
modbus_connect(ctx);
/* 初始化设置超时时间为1s */
modbus_set_response_timeout(ctx, 1, 0);
#ifdef DEV_MODBUS_DEBUG
modbus_set_debug(ctx, RT_TRUE);
#else
modbus_set_debug(ctx, RT_FALSE);
#endif
modbus是国际标准协议,采用一主多从的架构。平台设备硬件是主节点,所有的事件均由主节点发起,采取一问一答的方式进行通讯。因此modbus线程首先是接收到mqtt.main线程发送的消息队列信号,才开始执行相应的动作:
err = rt_mq_recv(msg_queue, msg_buff, THE_MAX_QUEUE_MSG_SIZE, THE_QUEUE_TIMEOUT);
if (err == RT_EOK)
{
/* 指令消息格式:id=123;door_idx=1,2,3,4,5,6,....,MAXDOOR */
char *str_id, *str_cmd, *str_val;
/* 任何消息都应该带有id=XXX,解析id */
str_id = rt_strstr(msg_buff, "=");
if (str_id == RT_NULL)
continue;
str_val = rt_strstr(msg_buff, ";");
if (str_val == RT_NULL)
continue;
str_id = str_id + 1;
*str_val = '\0';
if (str_id == str_val)
continue;
/* 解析具体命令 */
str_cmd = str_val + 1;
str_val = rt_strstr(str_cmd, "=");
if (str_val)
{
extern void mqtt_service_reply_pub(const char *topic_idx, const char *id, const char *code, const char *data);
*str_val = '\0'; str_val++;
if (!rt_strcasecmp(str_cmd, DOOR_CTRL_CMD))
{
rt_uint8_t door_idx, last_door_idx = 0;
/* 1个字节代表1个门,首先全部初始化为不控制开门:THE_DOOR_CTRL_CLOSE */
rt_memset(door_coil_buff, THE_DOOR_CTRL_CLOSE, device_chn_num * device_num);
/* 1个字节代表1个门,首先全部初始化为不控制开门:THE_DOOR_IS_CLOSE */
rt_memset(door_status_buff, THE_DOOR_IS_CLOSE, device_chn_num * device_num);
/* 解析消息数据 */
while (1)
{
str_cmd = rt_strstr(str_val, ",");
if (str_cmd)
{
*str_cmd = '\0';
door_idx = atoi(str_val);
if ((door_idx > 0) && (door_idx > last_door_idx) && (door_idx <= (device_chn_num * device_num)))
door_coil_buff[door_idx - 1] = THE_DOOR_CTRL_OPEN;
else
LOG_D("door control message have some error to igiore.");
str_val = str_cmd + 1;
last_door_idx = door_idx;
}
else
{
door_idx = atoi(str_val);
if ((door_idx > 0) && (door_idx > last_door_idx) && (door_idx <= (device_chn_num * device_num)))
door_coil_buff[door_idx - 1] = THE_DOOR_CTRL_OPEN;
else
LOG_D("door control message have some error to igiore.");
break;
}
}
/* 消息解析完毕进行数据发送 */
for (int i = 0; i < device_num; i++)
{
/* 设置从机地址,从机地址从1开始 */
modbus_set_slave(ctx, i + 1);
uint32_t timeout_cnt = 0;
for (int j = 0; j < device_chn_num; j++)
{
if (door_coil_buff[i * device_chn_num + j])
timeout_cnt++;
}
if (timeout_cnt)
/* 设置超时时间,按照1个门1s超时时间计算 */
modbus_set_response_timeout(ctx, timeout_cnt, 0);
else
/* 当前设备没有需要打开的门,直接跳过 */
continue;
/* 通过MODBUS发送数据,等待回应 */
if (modbus_write_bits(ctx, 0, device_chn_num, &door_coil_buff[i * device_chn_num]) > 0)
{
LOG_D("modbus device[%d] write success.", i + 1);
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
}
else
{
LOG_D("modbus device[%d] write failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
}
}
/* 等待分板执行 */
rt_thread_mdelay(RT_TICK_PER_SECOND);
rt_memset(door_fail_buff, 0, device_num * device_chn_num);
/* 读取门状态值,查看是否打开成功 */
for (int i = 0; i < device_num; i++)
{
/* 设置从机地址,从机地址从1开始 */
modbus_set_slave(ctx, i + 1);
/* 设置单个设备的超时时间: 1s */
modbus_set_response_timeout(ctx, 1, 0);
/* 通过MODBUS发送数据,等待回应 */
if (modbus_read_input_bits(ctx, 0, device_chn_num, &door_status_buff[i * device_chn_num]) > 0)
{
LOG_D("modbus device[%d] read success.", i + 1);
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
for (int j = 0; j < device_chn_num; j++)
{
if ((door_coil_buff[i * device_chn_num + j] == THE_DOOR_IS_OPEN) && (door_coil_buff[i * device_chn_num + j] != door_status_buff[i * device_chn_num + j]))
{
LOG_D("door[%d] open failed.", (i * device_chn_num) + j + 1);
door_fail_buff[i * device_chn_num + j] = 1;
}
}
}
else
{
LOG_D("modbus device[%d] read failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
for (int j = 0; j < device_chn_num; j++)
{
if ((door_coil_buff[i * device_chn_num + j] == THE_DOOR_IS_OPEN) && (door_coil_buff[i * device_chn_num + j] != door_status_buff[i * device_chn_num + j]))
door_fail_buff[i * device_chn_num + j] = 1;
}
}
}
/* 构造门打开失败的topic_data */
char topic_data[256];
rt_memset(topic_data, 0, sizeof(topic_data));
int err_cnt = 0;
int pos = 0;
pos += rt_snprintf(&topic_data[pos], sizeof(topic_data) - pos - 1, "%s", "\"open_fail\":\"");
for (int i = 0; (i < (device_num * device_chn_num)) && (pos < sizeof(topic_data)); i++)
{
if (door_fail_buff[i])
{
pos += rt_snprintf(&topic_data[pos], sizeof(topic_data) - pos - 1, "%d,", i + 1);
err_cnt++;
}
}
if (err_cnt > 0)
{
topic_data[rt_strlen(topic_data) - 1] = '\"';
topic_data[rt_strlen(topic_data)] = '\0';
mqtt_service_reply_pub(ALI_SERVICE_DOOR_CTRL_REPLY_PUB, str_id, ALI_CODE_DOOR_CTRL_FAIL, topic_data);
}
else
mqtt_service_reply_pub(ALI_SERVICE_DOOR_CTRL_REPLY_PUB, str_id, ALI_CODE_OK, RT_NULL);
}
/* 指令消息格式:id=123;ctrl_cmd=xxx;ctrl_para=xxx */
else if (!rt_strstr(str_cmd, DEV_CTRL_CMD) && !rt_strstr(str_cmd, DEV_CTRL_PARA))
{
str_cmd = str_val + 1;
str_val = rt_strstr(str_cmd, ";");
if (str_val == RT_NULL)
continue;
str_val = '\0';
if (!rt_strcasecmp(str_cmd, DEV_CTRL_CMD_OPENTIME))
{
str_cmd = str_val + 1;
str_val = rt_strstr(str_cmd, "=");
if (str_val == RT_NULL)
continue;
str_cmd = str_val + 1;
rt_uint16_t open_time = atoi(str_cmd);
LOG_I("set door max open time: %dsec", open_time);
rt_bool_t is_set_ok = RT_TRUE;
/* 设置单个设备超时时间: 1s */
modbus_set_response_timeout(ctx, 1, 0);
for (int i = 0; i < device_num; i++)
{
/* 设置从机地址,从机地址从1开始 */
modbus_set_slave(ctx, i + 1);
/* 写最大开门报警时间参数 */
if (modbus_write_registers(ctx, MODBUS_MAX_OPEN_TIME_ADDR, MODBUS_MAX_OPEN_TIME_NUM, &open_time) > 0)
{
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
}
else
{
LOG_D("modbus device[%d] door max open time write failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
is_set_ok = RT_FALSE;
}
}
if (is_set_ok == RT_TRUE)
mqtt_service_reply_pub(ALI_SERVICE_DEVICE_CTRL_REPLY_PUB, str_id, ALI_CODE_OK, RT_NULL);
else
mqtt_service_reply_pub(ALI_SERVICE_DEVICE_CTRL_REPLY_PUB, str_id, ALI_CODE_DEVICE_CTRL_ERROR, RT_NULL);
}
else if (!rt_strcasecmp(str_cmd, DEV_CTRL_CMD_POWERTIME))
{
str_cmd = str_val + 1;
str_val = rt_strstr(str_cmd, "=");
if (str_val == RT_NULL)
continue;
str_cmd = str_val + 1;
rt_uint16_t power_time = atoi(str_cmd);
LOG_I("set door max power time: %dsec", power_time);
rt_bool_t is_set_ok = RT_TRUE;
/* 设置单个设备超时时间: 1s */
modbus_set_response_timeout(ctx, 1, 0);
for (int i = 0; i < device_num; i++)
{
/* 设置从机地址,从机地址从1开始 */
modbus_set_slave(ctx, i + 1);
/* 写最大开门报警时间参数 */
if (modbus_write_registers(ctx, MODBUS_MAX_POWER_TIME_ADDR, MODBUS_MAX_POWER_TIME_NUM, &power_time) > 0)
{
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
}
else
{
LOG_D("modbus device[%d] door max power time write failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
is_set_ok = RT_FALSE;
}
}
if (is_set_ok == RT_TRUE)
mqtt_service_reply_pub(ALI_SERVICE_DEVICE_CTRL_REPLY_PUB, str_id, ALI_CODE_OK, RT_NULL);
else
mqtt_service_reply_pub(ALI_SERVICE_DEVICE_CTRL_REPLY_PUB, str_id, ALI_CODE_DEVICE_CTRL_ERROR, RT_NULL);
}
else
{
mqtt_service_reply_pub(ALI_SERVICE_DEVICE_CTRL_REPLY_PUB, str_id, ALI_CODE_DEVICE_CTRL_ERROR, RT_NULL);
}
}
}
}
消息队列传递的信息包括各种控制命令及相关参数,为了满足不同的平台要求,并且这些内容必须是可变长度且方便协议的增减。权衡利弊因此采用ASCII方式,接收到一帧消息队列信号,首先进行命令和参数解析,然后再执行相应动作。
消息队列的接收超时作为modbus的周期检查:
else if (err == -RT_ETIMEOUT) /* 超时代表定时扫描时间到 */
{
/* 设置单个设备超时时间: 1s */
modbus_set_response_timeout(ctx, 1, 0);
for (int i = 0; i < device_num; i++)
{
/* 设置从机地址,从机地址从1开始 */
modbus_set_slave(ctx, i + 1);
/* 读门状态 */
if (modbus_read_input_bits(ctx, 0, device_chn_num, &door_status_buff[i * device_chn_num]) > 0)
{
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
}
else
{
LOG_D("modbus device[%d] door status read failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
}
/* 读报警状态 */
if (modbus_read_registers(ctx, MODBUS_REGS_ADDR, MODBUS_ALARM_NUMS, &door_alarm_buff[i * MODBUS_ALARM_NUMS]) > 0)
{
THE_DEVICE_COMM_CLEAN(dev_error_buff[i]);
}
else
{
LOG_D("modbus device[%d] door alarm read failed.", i + 1);
THE_DEVICE_COMM_ERROR(dev_error_buff[i]);
}
}
}
通过阿里物联网平台可以下载固件,固件下载的状态信息通过MQTT通道,而固件数据的下载使用HTTPS/HTTPS通道。因此如果采用TLS方式,在OTA执行后将增加一倍的内存使用量。
由于使用了FAL组件,将设备板上所有存储区器划分为几个区域:
/* ===================== Flash device Configuration ========================= */
extern const struct fal_flash_dev stm32f4_onchip_flash;
extern struct fal_flash_dev nor_flash0;
/* flash device table */
#define FAL_FLASH_DEV_TABLE \
{ \
&stm32f4_onchip_flash, \
&nor_flash0, \
}
/* ====================== Partition Configuration ========================== */
#ifdef FAL_PART_HAS_TABLE_CFG
/* partition table */
#define FAL_PART_TABLE \
{ \
{FAL_PART_MAGIC_WROD, "app", "onchip_flash", 0, 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "dl-area", FAL_USING_NOR_FLASH_DEV_NAME, 0, 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "df-area", FAL_USING_NOR_FLASH_DEV_NAME, 1024 * 1024, 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "kv-area", FAL_USING_NOR_FLASH_DEV_NAME, (1024 + 1024) * 1024, 1024 * 1024, 0}, \
{FAL_PART_MAGIC_WROD, "elmfs", FAL_USING_NOR_FLASH_DEV_NAME, (1024 + 1024 + 1024) * 1024, 13 * 1024 * 1024, 0}, \
}
#endif /* FAL_PART_HAS_TABLE_CFG */
存储设备有两个:STM32内部FLASH和W25Q128,其中:
app区域:STM32内部FLASH;
dl-area区域:固件存储区;
df-area区域:出厂固件存储区;
kv-area区域:参数存储区;
elmfs区域:文件系统区;
通过阿里物联网平台下载的代码首先存入dl-area中,然后通过bootloader程序对固件进行判断和搬运;
OTA部分的实现相对比较简单,阿里物联网SDK例程已经给出实例,在mqtt.main线程中周期性调用mqtt_ota()即可:
rt_err_t mqtt_ota(void *mqtt_ota_hd)
{
rt_err_t result = RT_ERROR;
if (mqtt_ota_init(mqtt_ota_hd) != RT_EOK)
goto __mqtt_ota_exit;
if (IOT_OTA_IsFetching(ota_hd))
{
char fm_ver[MQTT_OTA_VERSION_MAXLEN], md5sum[33];
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_VERSION, fm_ver, MQTT_OTA_VERSION_MAXLEN);
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_MD5SUM, md5sum, 33);
if (!rt_strcasecmp(firmware_verison, fm_ver))
{
IOT_OTA_ReportVersion(ota_hd, fm_ver);
result = RT_EOK;
goto __mqtt_ota_exit;
}
const struct fal_partition *dl_partition;
dl_partition = fal_partition_find(MQTT_OTA_DOWNLOAD_PARTITION_NAME);
if (dl_partition == RT_NULL)
{
LOG_I("can not find %s partition", MQTT_OTA_DOWNLOAD_PARTITION_NAME);
goto __mqtt_ota_exit;
}
if (fal_partition_erase_all(dl_partition) < 0)
{
LOG_I("can not erase %s partition", dl_partition->name);
goto __mqtt_ota_exit;
}
mqtt_stop_period_timer();
int fetch_len;
rt_uint32_t last_percent = 0, percent = 0;
rt_uint32_t size_of_download = 0, size_of_file;
rt_uint32_t content_pos = 0, content_write_sz;
rt_uint32_t update_grade = 0;;
/* 循环条件:未下载完成or设备在线 */
while (!IOT_OTA_IsFetchFinish(ota_hd))
{
fetch_len = IOT_OTA_FetchYield(ota_hd, ota_recv_buff, MQTT_OTA_RECV_BUFF_LEN, 1);
if (fetch_len > 0)
{
content_write_sz = fal_partition_write(dl_partition, content_pos, (uint8_t *)ota_recv_buff, fetch_len);
if (content_write_sz != fetch_len)
{
LOG_I("Write OTA data to file failed");
IOT_OTA_ReportProgress(ota_hd, IOT_OTAP_BURN_FAILED, RT_NULL);
mqtt_ota_deinit();
mqtt_start_period_timer();
goto __mqtt_ota_exit;
}
else
{
content_pos = content_pos + fetch_len;
LOG_I("receive %d bytes, total recieve: %d bytes", content_pos, size_of_file);
}
}
else
{
LOG_I("ota fetch failed.");
IOT_OTA_ReportProgress(ota_hd, IOT_OTAP_FETCH_FAILED, NULL);
if (fetch_len < 0)
{
mqtt_ota_deinit();
mqtt_start_period_timer();
goto __mqtt_ota_exit;
}
}
/* get OTA information */
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_FETCHED_SIZE, &size_of_download, 4);
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_FILE_SIZE, &size_of_file, 4);
last_percent = percent;
percent = (size_of_download * 100) / size_of_file;
if (percent - last_percent > 0)
{
/* 每下载400K上报一次进度 */
update_grade = (update_grade + 1) % (((MQTT_OTA_RECV_BUFF_LEN - 1) / 1024) * 50);
if (update_grade == 0)
IOT_OTA_ReportProgress(ota_hd, (IOT_OTA_Progress_t)percent, RT_NULL);
}
IOT_MQTT_Yield(mqtt_ota_hd, 100);
}
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_MD5SUM, md5sum, 33);
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_VERSION, fm_ver, MQTT_OTA_VERSION_MAXLEN);
uint32_t firmware_valid;
IOT_OTA_Ioctl(ota_hd, IOT_OTAG_CHECK_FIRMWARE, &firmware_valid, 4);
if ((firmware_valid) && (size_of_download == size_of_file) && (size_of_file > 0))
{
LOG_D("The firmware is valid! Download firmware successfully.");
LOG_D("OTA FW version: %s", fm_ver);
LOG_D("OTA FW MD5 Sum: %s", md5sum);
ef_set_env_blob(MQTT_OTA_FIRMWARE_VERSION, fm_ver, rt_strlen(fm_ver));
IOT_OTA_ReportVersion(ota_hd, fm_ver);
result = RT_EOK;
}
mqtt_ota_deinit();
mqtt_start_period_timer();
}
__mqtt_ota_exit:
return result;
}
本次使用的软件包比较多,分类如下:
MQTT和OTA使用的软件包:
ali-iotkit: RTT官方移植的阿里物联网SDK,使用的最新的V3.0.2版本;
cJSON:用于解析MQTT的JSON消息包;
mbedtls:用于MQTT和OTA通讯的TLS加密;
at_device:GPRS模块AT命令包;
子模块通讯使用的软件包:
libmodbus:modbus软件包,可以实现主从节点的modbus协议;
SignalLed:用于通讯LED的闪烁控制;
存储使用的软件包:
FAL:用于存储区域划分;
EasyFlash:用于KV参数的存储,可以实现平衡擦除和断电备份,同时也可以实现二进制存储,使用非常方便;
调试使用的软件包:
adbd:主要用于shell调试和文件的传输;
ota_downloader:ota _downloader包含HTTP和ymodem协议的软件包,这里我们只用于测试和生产下线使用;
nettutils:网络工具包,用于网络相关测试使用;
https://gitee.com/spunky_973/netbox
维护人: 王希
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。