

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 將 OTA 代理程式整合到您的應用程式
<a name="integrate-ota-agent"></a>

無線 (OTA) 代理程式旨在簡化為了將 OTA 更新功能新增到您的產品，所需要撰寫的程式碼數量。整合負擔主要包含初始化 OTA 代理程式，以及建立自訂回呼函數以回應 OTA 代理程式事件訊息。在初始化作業系統期間，MQTT、HTTP （如果 HTTP 用於檔案下載） 和平台特定實作 (PAL) 界面會傳遞給 OTA 代理程式。緩衝區也可以初始化並傳遞給 OTA 代理程式。

**注意**  
雖然將 OTA 更新功能整合到您的應用程式相對簡單，但 OTA 更新系統需要您對裝置程式碼整合之外的知識有更進一步的了解。若要熟悉如何使用物件、登入資料、程式碼簽署憑證、佈建裝置和 OTA 更新任務來設定 AWS 您的帳戶 AWS IoT ，請參閱 [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 代理程式可在主要應用程式的作用中處理期間，於背景接收更新。交付這些事件的目的是讓應用程式決定是否可立即採取動作，或是是否應進行延遲，直到完成某些其他應用程式限定處理為止。這個防止您的裝置在作用中處理期間因韌體更新後重設而發生未預期的插斷 (例如真空)。以下是回撥處理常式會接收到的任務事件：

**`OtaJobEventActivate `**  
當回呼處理常式收到此事件時，您可以立即重設裝置，或排程呼叫以稍後重設裝置。這可讓您延期裝置重設及自我測試階段 (若需要的話)。

**`OtaJobEventFail`**  
當回呼處理常式收到此事件時，更新已失敗。在這種情況下，您無須採取任何行動。您可能會希望輸出日誌訊息或執行某些應用程式限定操作。

**`OtaJobEventStartTest`**  
自我測試階段旨在允許新更新的韌體先執行和測試本身，再判斷其是否正常運作，並將自己遞交為最新的永久應用程式映像。接收到新的更新並完成驗證，且重設裝置後，OTA 代理程式會在準備好進行測試時傳送 `OtaJobEventStartTest` 事件給回撥函數。開發人員可以新增必要測試，以判斷裝置韌體在更新之後是否正常運作。當裝置韌體已由自我測試視為可靠時，程式碼必須透過呼叫 `OTA_SetImageState( OtaImageStateAccepted )` 函數來將韌體遞交為新的永久映像。

**`OtaJobEventProcessed`**  
`OTA_SignalEvent` 系統會處理 佇列的 OTA 事件，因此可以完成清除操作，例如釋放 OTA 緩衝區。

**`OtaJobEventSelfTestFailed`**  
目前任務的 OTA 自我測試失敗。此事件的預設處理方式是關閉 OTA 代理程式並重新啟動它，讓裝置回復到上一個映像。

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