将 OTA 代理集成到应用程序中 - FreeRTOS
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

将 OTA 代理集成到应用程序中

无线 (OTA) 代理旨在简化为将 OTA 更新功能添加到产品中所必须编写的代码。集成负担主要包括 OTA 代理的初始化,以及创建自定义回调函数以响应 OTA 完成事件消息(后者为可选操作)。

注意

尽管将 OTA 更新功能集成到应用程序中非常简单,但 OTA 更新系统需要了解的不仅仅是设备代码集成。要熟悉如何配置 AWS 账户的 AWS IoT 事物、凭证、代码签名证书、预配置设备和 OTA 更新作业,请参阅 FreeRTOS 先决条件

连接管理

OTA 代理使用 MQTT 协议完成所有涉及 AWS IoT 服务的控制通信操作,但它并不管理 MQTT 连接。要确保 OTA 代理不会干扰应用程序的连接管理策略,必须由主用户应用程序处理 MQTT 连接(包括断开连接和任何重新连接功能)。可以通过 MQTT 或 HTTP 协议下载该文件。可以在创建 OTA 作业时选择协议。如果选择 MQTT,则 OTA 代理将使用相同的连接来控制操作和下载文件。如果选择 HTTP,则 OTA 代理将处理 HTTP 连接。

使用 MQTT 的简单 OTA 演示

下面是一个简单的 OTA 演示节选,说明了代理如何连接到 MQTT 代理并初始化 OTA 代理。在该示例中,我们对演示进行配置,使用默认的 OTA 完成回调,并每隔一秒打印输出某些统计数据。为简洁起见,我们省略了演示的某些细节。

有关使用 AWS IoT MQTT 代理的工作示例,请参阅 demos/ota 目录中的 OTA 演示代码。

由于 OTA 代理是它自己的任务,该示例中刻意的一秒延迟只会影响本应用程序。对代理的性能不会有任何影响。

void vRunOTAUpdateDemo( const IotNetworkInterface_t * pNetworkInterface, void * pNetworkCredentialInfo ) { IotMqttConnectInfo_t xConnectInfo = IOT_MQTT_CONNECT_INFO_INITIALIZER; OTA_State_t eState; OTA_ConnectionContext_t xOTAConnectionCtx = { 0 }; configPRINTF( ( "OTA demo version %u.%u.%u\r\n", xAppFirmwareVersion.u.x.ucMajor, xAppFirmwareVersion.u.x.ucMinor, xAppFirmwareVersion.u.x.usBuild ) ); configPRINTF( ( "Creating MQTT Client...\r\n" ) ); /* Create the MQTT Client. */ for( ; ; ) { xNetworkConnected = prxCreateNetworkConnection(); if( xNetworkConnected ) { configPRINTF( ( "Connecting to broker...\r\n" ) ); memset( &xConnectInfo, 0, sizeof( xConnectInfo ) ); if( xConnection.ulNetworkType == AWSIOT_NETWORK_TYPE_BLE ) { xConnectInfo.awsIotMqttMode = false; xConnectInfo.keepAliveSeconds = 0; } else { xConnectInfo.awsIotMqttMode = true; xConnectInfo.keepAliveSeconds = otaDemoKEEPALIVE_SECONDS; } xConnectInfo.cleanSession = true; xConnectInfo.clientIdentifierLength = ( uint16_t ) strlen( clientcredentialIOT_THING_NAME ); xConnectInfo.pClientIdentifier = clientcredentialIOT_THING_NAME; /* Connect to the broker. */ if( IotMqtt_Connect( &( xConnection.xNetworkInfo ), &xConnectInfo, otaDemoCONN_TIMEOUT_MS, &( xConnection.xMqttConnection ) ) == IOT_MQTT_SUCCESS ) { configPRINTF( ( "Connected to broker.\r\n" ) ); xOTAConnectionCtx.pvControlClient = xConnection.xMqttConnection; xOTAConnectionCtx.pxNetworkInterface = ( void * ) pNetworkInterface; xOTAConnectionCtx.pvNetworkCredentials = pNetworkCredentialInfo; OTA_AgentInit( ( void * ) ( &xOTAConnectionCtx ), ( const uint8_t * ) ( clientcredentialIOT_THING_NAME ), App_OTACompleteCallback, ( TickType_t ) ~0 ); while( ( eState = OTA_GetAgentState() ) != eOTA_AgentState_Stopped ) { /* Wait forever for OTA traffic but allow other tasks to run and output statistics only once per second. */ vTaskDelay( myappONE_SECOND_DELAY_IN_TICKS ); configPRINTF( ( "State: %s Received: %u Queued: %u Processed: %u Dropped: %u\r\n", pcStateStr[ eState ], OTA_GetPacketsReceived(), OTA_GetPacketsQueued(), OTA_GetPacketsProcessed(), OTA_GetPacketsDropped() ) ); } IotMqtt_Disconnect( xConnection.xMqttConnection, false ); } else { configPRINTF( ( "ERROR: MQTT_AGENT_Connect() Failed.\r\n" ) ); } vMqttDemoDeleteNetworkConnection( &xConnection ); /* After failure to connect or a disconnect, wait an arbitrary one second before retry. */ vTaskDelay( myappONE_SECOND_DELAY_IN_TICKS ); } else { configPRINTF( ( "Failed to create MQTT client.\r\n" ) ); } } }

以下是该演示应用程序的主要流程:

  • 创建 MQTT 代理上下文。

  • 连接到 AWS IoT 终端节点。

  • 初始化 OTA 代理。

  • 循环执行 OTA 更新作业并每秒钟输出一次统计数据。

  • 如果代理停止,请等待一秒后尝试重新连接。

使用自定义回调处理 OTA 完成事件

以上示例使用了内置的回调处理程序来处理 OTA 完成事件,方法是将 OTA_AgentInit API 的第三个参数指定为 NULL。如果要对完成事件实施自定义处理,则必须将回调处理程序的函数地址传递到 OTA_AgentInit API。在 OTA 过程中,代理可将以下事件枚举中的任意一个发送给回调处理程序。如何以及何时处理这些事件由应用程序开发人员决定。

/** * @brief OTA Job callback events. * * After an OTA update image is received and authenticated, the Agent calls the user * callback (set with the OTA_AgentInit API) with the value eOTA_JobEvent_Activate to * signal that the device must be rebooted to activate the new image. When the device * boots, if the OTA job status is in self test mode, the Agent calls the user callback * with the value eOTA_JobEvent_StartTest, signaling that any additional self tests * should be performed. * * If the OTA receive fails for any reason, the Agent calls the user callback with * the value eOTA_JobEvent_Fail instead to allow the user to log the failure and take * any action deemed appropriate by the user code. * */ typedef enum { eOTA_JobEvent_Activate, /*! OTA receive is authenticated and ready to activate. */ eOTA_JobEvent_Fail, /*! OTA receive failed. Unable to use this update. */ eOTA_JobEvent_StartTest /*! OTA job is now in self test, perform user tests. */ } OTA_JobEvent_t;

OTA 代理可以在主应用程序的活动处理期间,在后台接收更新。交付这些事件的目的在于,允许应用程序决定是立即采取行动,还是应当推迟行动,直到其他某些特定于应用程序的处理过程完成。这可以防止设备在活动处理期间(例如,执行 vacuum 操作时),由于固件更新后的重置而导致意外中断。以下是回调处理程序接收的作业事件:

eOTA_JobEvent_Activate event

如果回调处理程序收到此事件,则可以立即重置设备,或安排调用以稍后重置设备。您可以通过此方法来推迟设备重置和自检阶段(如有必要)。

eOTA_JobEvent_Fail event

如果回调处理程序收到此事件,则更新失败。在这种情况下不需要执行任何操作。您可能希望输出日志消息或执行某些特定于应用程序的操作。

eOTA_JobEvent_StartTest event

自检阶段旨在允许最近更新的固件执行并测试自身,然后再确定该固件可以正常使用,并提交为最新的永久应用程序映像。当收到已经过身份验证的新的更新,且设备已重置时,OTA 代理会将 eOTA_JobEvent_StartTest 事件发送给已准备好进行测试的回调函数。开发人员可以添加任何必需的测试,以确定设备固件在更新后是否能正常工作。如果通过自检认为设备固件是可靠的,则代码必须调用 OTA_SetImageState( eOTA_ImageState_Accepted ) 函数,将该固件提交为新的永久映像。

如果设备没有特殊的硬件或机制需要进行测试,则可以使用默认的回调处理程序。一旦收到 eOTA_JobEvent_Activate 事件,默认处理程序将立即重置设备。