

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 将 OTA 代理集成到应用程序中
<a name="integrate-ota-agent"></a>

 over-the-air(OTA) 代理旨在简化为产品添加 OTA 更新功能而必须编写的代码量。集成负担主要包括 OTA 代理的初始化，以及创建自定义回调函数以响应 OTA 代理完成事件消息。在操作系统初始化期间，MQTT、HTTP（如果文件下载使用 HTTP）和平台特定实现 (PAL) 接口将传递给 OTA 代理。也可以初始化缓冲区并将其传递给 OTA 代理。

**注意**  
尽管将 OTA 更新功能集成到应用程序中非常简单，但 OTA 更新系统需要了解的不仅仅是设备代码集成。[要熟悉如何使用 AWS IoT 内容、凭证、代码签名证书、配置设备和 OTA 更新任务来配置 AWS 账户，请参阅 FreeRTOS 先决条件。](https://docs.aws.amazon.com/freertos/latest/userguide/freertos-prereqs.html)

## 连接管理
<a name="ota-agent-http-mqtt"></a>

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

## 简单的 OTA 演示
<a name="simple-demo-agent"></a>

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

OTA 演示还通过监控断开回调连接并重新建立连接来演示 MQTT 连接管理。当断开连接时，此演示会先暂停 OTA 代理操作，然后尝试重新建立 MQTT 连接。MQTT 重新连接尝试会延迟一段时间，该时间以指数方式增加到最大值，并且还会增加抖动。如果重新建立连接，OTA 代理将继续运行。

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

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

```
static BaseType_t prvRunOTADemo( void )
{
    /* Status indicating a successful demo or not. */
    BaseType_t xStatus = pdFAIL;

    /* OTA library return status. */
    OtaErr_t xOtaError = OtaErrUninitialized;

    /* OTA event message used for sending event to OTA Agent.*/
    OtaEventMsg_t xEventMsg = { 0 };

    /* OTA interface context required for library interface functions.*/
    OtaInterfaces_t xOtaInterfaces;

    /* OTA library packet statistics per job.*/
    OtaAgentStatistics_t xOtaStatistics = { 0 };

    /* OTA Agent state returned from calling OTA_GetState.*/
    OtaState_t xOtaState = OtaAgentStateStopped;

    /* Set OTA Library interfaces.*/
    prvSetOtaInterfaces( &xOtaInterfaces );

    /*************************** Init OTA Library. ***************************/

    if( ( xOtaError = OTA_Init( &xOtaBuffer,
                                &xOtaInterfaces,
                                ( const uint8_t * ) ( democonfigCLIENT_IDENTIFIER ),
                                prvOtaAppCallback ) ) != OtaErrNone )
    {
        LogError( ( "Failed to initialize OTA Agent, exiting = %u.",
                    xOtaError ) );
    }
    else
    {
        xStatus = pdPASS;
    }

    /************************ Create OTA Agent Task. ************************/

    if( xStatus == pdPASS )
    {
        xStatus = xTaskCreate( prvOTAAgentTask,
                               "OTA Agent Task",
                               otaexampleAGENT_TASK_STACK_SIZE,
                               NULL,
                               otaexampleAGENT_TASK_PRIORITY,
                               NULL );

        if( xStatus != pdPASS )
        {
            LogError( ( "Failed to create OTA agent task:" ) );
        }
    }

    /****************************** Start OTA ******************************/

    if( xStatus == pdPASS )
    {
        /* Send start event to OTA Agent.*/
        xEventMsg.eventId = OtaAgentEventStart;
        OTA_SignalEvent( &xEventMsg );
    }

    /******************** Loop and display OTA statistics ********************/

    if( xStatus == pdPASS )
    {
        while( ( xOtaState = OTA_GetState() ) != OtaAgentStateStopped )
        {
            /* Get OTA statistics for currently executing job. */
            if( xOtaState != OtaAgentStateSuspended )
            {
                OTA_GetStatistics( &xOtaStatistics );

                LogInfo( ( " Received: %u   Queued: %u   Processed: %u   Dropped: %u",
                           xOtaStatistics.otaPacketsReceived,
                           xOtaStatistics.otaPacketsQueued,
                           xOtaStatistics.otaPacketsProcessed,
                           xOtaStatistics.otaPacketsDropped ) );
            }

            vTaskDelay( pdMS_TO_TICKS( otaexampleEXAMPLE_TASK_DELAY_MS ) );
        }
    }

    return xStatus;
}
```

以下是该演示应用程序的主要流程：
+ 创建 MQTT 代理上下文。
+ 连接到您的 AWS IoT 终端节点。
+ 初始化 OTA 代理。
+ 循环执行 OTA 更新作业并每一秒输出一次统计数据。
+ 如果 MQTT 断开连接，则暂停 OTA 代理操作。
+ 尝试使用指数延迟和抖动再次连接。
+ 如果已重新连接，则恢复 OTA 代理操作。
+ 如果代理停止，则延迟一秒钟，然后尝试重新连接。

## 对 OTA 代理事件使用应用程序回调
<a name="application-callback-ota"></a>

前面的示例使用 `prvOtaAppCallback` 作为 OTA 代理事件的回调处理程序。（请参阅 `OTA_Init` API 调用的第四个参数）。如果要实现对完成事件的自定义处理，则必须在 OTA 演示/应用程序中更改默认处理。在 OTA 过程中，OTA 代理可将以下事件枚举中的任意一个发送给回调处理程序。如何以及何时处理这些事件由应用程序开发人员决定。

```
/**
 * @ingroup ota_enum_types
 * @brief OTA Job callback events.
 *
 * After an OTA update image is received and authenticated, the agent calls the user
 * callback (set with the @ref OTA_Init API) with the value OtaJobEventActivate 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 OtaJobEventStartTest, 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 OtaJobEventFail instead to allow the user to log the failure and take
 * any action deemed appropriate by the user code.
 *
 * See the OtaImageState_t type for more information.
 */
typedef enum OtaJobEvent
{
    OtaJobEventActivate = 0,       /*!< @brief OTA receive is authenticated and ready to activate. */
    OtaJobEventFail = 1,           /*!< @brief OTA receive failed. Unable to use this update. */
    OtaJobEventStartTest = 2,      /*!< @brief OTA job is now in self test, perform user tests. */
    OtaJobEventProcessed = 3,      /*!< @brief OTA event queued by OTA_SignalEvent is processed. */
    OtaJobEventSelfTestFailed = 4, /*!< @brief OTA self-test failed for current job. */
    OtaJobEventParseCustomJob = 5, /*!< @brief OTA event for parsing custom job document. */
    OtaJobEventReceivedJob = 6,    /*!< @brief OTA event when a new valid AFT-OTA job is received. */
    OtaJobEventUpdateComplete = 7, /*!< @brief OTA event when the update is completed. */
    OtaLastJobEvent = OtaJobEventStartTest
} OtaJobEvent_t;
```

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

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

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

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

**`OtaJobEventProcessed`**  
已处理 `OTA_SignalEvent` 排队的 OTA 事件，因此可以执行清理操作，例如释放 OTA 缓冲区。

**`OtaJobEventSelfTestFailed`**  
当前作业的 OTA 自检失败。此事件的默认处理方式是关闭并重新启动 OTA 代理，以便设备回滚到之前的映像。

**`OtaJobEventUpdateComplete`**  
OTA 任务更新完成的通知事件。