in device_firmware/libraries/freertos_plus/aws/ota/src/aws_iot_ota_agent.c [1536:1797]
static void prvOTAUpdateTask( void * pvUnused )
{
DEFINE_OTA_METHOD_NAME( "prvOTAUpdateTask" );
EventBits_t uxBits;
OTA_FileContext_t * C = NULL;
OTA_Err_t xErr;
OTA_PubMsg_t * pxMsgMetaData;
uint32_t ulNumOfBlocksToReceive = otaconfigMAX_NUM_BLOCKS_REQUEST;
( void ) pvUnused;
/* Subscribe to the OTA job notification topic. */
if( prvSubscribeToJobNotificationTopics() == ( bool_t ) pdTRUE )
{
xOTA_Agent.xOTA_EventFlags = xEventGroupCreate();
if( xOTA_Agent.xOTA_EventFlags != NULL )
{
/* Check if the firmware image is in self test mode. If so, enable the self test timer. */
( void ) OTA_CheckForSelfTest();
/*Save the self-test mode in a flag. This flag is cleared when self-test is successful.*/
xInSelfTest = prvInSelftest();
/* Send a request to the job service for the latest available job. */
( void ) OTA_CheckForUpdate();
/* Put the OTA agent in the ready state. */
xOTA_Agent.eState = eOTA_AgentState_Ready;
for( ; ; )
{
uxBits = xEventGroupWaitBits(
xOTA_Agent.xOTA_EventFlags, /* The event group being tested. */
OTA_EVT_MASK_ALL_EVENTS, /* The bits within the event group to wait for. */
pdTRUE, /* Bits should be cleared before returning. */
pdFALSE, /* Any bit set will do. */
( TickType_t ) ~( 0U ) ); /* Wait forever. */
/* Check for the shutdown event. */
if( ( ( uint32_t ) uxBits & OTA_EVT_MASK_SHUTDOWN ) != 0U )
{
OTA_LOG_L1( "[%s] Received shutdown event.\r\n", OTA_METHOD_NAME );
break; /* Break, so we stop all OTA processing. */
}
/* Check for a user initiated abort. */
if( ( ( ( uint32_t ) uxBits & OTA_EVT_MASK_USER_ABORT ) != 0U ) && ( C != NULL ) )
{
OTA_LOG_L1( "[%s] Received user abort event.\r\n", OTA_METHOD_NAME );
( void ) prvSetImageStateWithReason( eOTA_ImageState_Aborted, kOTA_Err_UserAbort );
( void ) prvOTA_Close( C ); /* Ignore false result since we're setting the pointer to null on the next line. */
C = NULL;
}
/* On OTA request timer timeout, publish the stream request if we have context. */
if( ( ( uxBits & OTA_EVT_MASK_REQ_TIMEOUT ) != 0U ) && ( C != NULL ) )
{
if( C->ulBlocksRemaining > 0U )
{
ulNumOfBlocksToReceive = otaconfigMAX_NUM_BLOCKS_REQUEST;
xErr = prvPublishGetStreamMessage( C );
if( xErr != kOTA_Err_None )
{ /* Abort the current OTA. */
( void ) prvSetImageStateWithReason( eOTA_ImageState_Aborted, xErr );
( void ) prvOTA_Close( C ); /* Ignore false result since we're setting the pointer to null on the next line. */
C = NULL;
}
}
else
{
/* If there are no blocks remaining, this may have been in flight when the
* last block was received. Just ignore it since it will be cleaned up by
* the agent as required. */
}
}
/* Check if a MQTT message is ready for us to process. */
if( ( uxBits & OTA_EVT_MASK_MSG_READY ) != 0U )
{
if( ( xOTA_Agent.eState == eOTA_AgentState_Ready ) || ( xOTA_Agent.eState == eOTA_AgentState_Active ) )
{
while( xQueueReceive( xOTA_Agent.xOTA_MsgQ, &pxMsgMetaData, 0 ) != pdFALSE )
{
/* Check for OTA update job messages. */
if( ( pxMsgMetaData->eMsgType == eOTA_PubMsgType_Job ) && ( xOTA_Agent.eState == eOTA_AgentState_Ready ) )
{
if( C != NULL )
{
( void ) prvOTA_Close( C ); /* Abort the existing OTA and ignore impossible false result by design. */
}
C = prvProcessOTAJobMsg( ( const char * ) pxMsgMetaData->pxPubData.vData, /*lint !e9079 pointer to void is OK to cast to the real type. */
pxMsgMetaData->pxPubData.ulDataLength );
/* A null context here could either mean we didn't receive a valid job or it could
* signify that we're in the self test phase (where the OTA file transfer is already
* completed and we've reset the device and are now running the new firmware). We
* will check the state to determine which case we're in. */
if( C == NULL )
{
/* If the OTA job is in the self_test state, alert the application layer. */
if( OTA_GetImageState() == eOTA_ImageState_Testing )
{
/* Check the platform's OTA update image state. It should also be in self test. */
if( OTA_CheckForSelfTest() == pdTRUE )
{
xOTA_Agent.xPALCallbacks.xCompleteCallback( eOTA_JobEvent_StartTest );
}
else
{
/* The job is in self test but the platform image state is not so it could be
* an attack on the platform image state. Reject the update (this should also
* cause the image to be erased), aborting the job and reset the device. */
OTA_LOG_L1( "[%s] Job in self test but platform state is not!\r\n", OTA_METHOD_NAME );
( void ) prvSetImageStateWithReason( eOTA_ImageState_Rejected, kOTA_Err_ImageStateMismatch );
( void ) prvResetDevice(); /* Ignore return code since there's nothing we can do if we can't force reset. */
}
}
else
{
/* If the job context returned NULL and the image state is not in the self_test state,
* then an error occurred parsing the OTA job message. Abort the OTA job with a parse error.
*
* If there is a valid job id, then a job status update will be sent.
*/
( void ) prvSetImageStateWithReason( eOTA_ImageState_Aborted, kOTA_Err_JobParserError );
}
}
else
{
xOTA_Agent.eState = eOTA_AgentState_Active;
}
}
/* It's not a job message, maybe it's a data stream message... */
else if( pxMsgMetaData->eMsgType == eOTA_PubMsgType_Stream )
{
/* Ingest data blocks if the platform is not in self-test. */
if( ( C != NULL ) && ( xInSelfTest == false ) )
{
OTA_Err_t xCloseResult;
IngestResult_t xResult = prvIngestDataBlock( C,
( const char * ) pxMsgMetaData->pxPubData.vData, /*lint !e9079 pointer to void is OK to cast to the real type. */
pxMsgMetaData->pxPubData.ulDataLength,
&xCloseResult );
if( xResult < eIngest_Result_Accepted_Continue )
{
/* Negative result codes mean we should stop the OTA process
* because we are either done or in an unrecoverable error state.
* We don't want to hang on to the resources. */
if( xResult == eIngest_Result_FileComplete )
{
/* File receive is complete and authenticated. Update the job status with the self_test ready identifier. */
prvUpdateJobStatus( C, eJobStatus_InProgress, ( int32_t ) eJobReason_SigCheckPassed, ( int32_t ) NULL );
}
else
{
OTA_LOG_L1( "[%s] Aborting due to IngestResult_t error %d\r\n", OTA_METHOD_NAME, ( int32_t ) xResult );
/* Call the platform specific code to reject the image. */
xErr = xOTA_Agent.xPALCallbacks.xSetPlatformImageState( xOTA_Agent.ulServerFileID, eOTA_ImageState_Rejected );
if( xErr != kOTA_Err_None )
{
OTA_LOG_L2( "[%s] Error trying to set platform image state (0x%08x)\r\n", OTA_METHOD_NAME, ( int32_t ) xErr );
}
else
{
/* Nothing special to do on success. */
}
prvUpdateJobStatus( C, eJobStatus_FailedWithVal, ( int32_t ) xCloseResult, ( int32_t ) xResult );
}
/* Release all remaining resources of the OTA file. */
( void ) prvOTA_Close( C ); /* Ignore false result since we're setting the pointer to null on the next line. */
C = NULL;
/* Let main application know of our result. */
xOTA_Agent.xPALCallbacks.xCompleteCallback( ( xResult == eIngest_Result_FileComplete ) ? eOTA_JobEvent_Activate : eOTA_JobEvent_Fail );
/* Free any remaining string memory holding the job name since this job is done. */
if( xOTA_Agent.pcOTA_Singleton_ActiveJobName != NULL )
{
vPortFree( xOTA_Agent.pcOTA_Singleton_ActiveJobName );
xOTA_Agent.pcOTA_Singleton_ActiveJobName = NULL;
}
}
else
{
if( xResult == eIngest_Result_Accepted_Continue )
{
/* We're actively receiving a file so update the job status as needed. */
/* First reset the momentum counter since we received a good block. */
C->ulRequestMomentum = 0;
prvUpdateJobStatus( C, eJobStatus_InProgress, ( int32_t ) eJobReason_Receiving, ( int32_t ) NULL );
/* Check if we have received expected number of blocks for the current request. */
if( ulNumOfBlocksToReceive > 1 )
{
ulNumOfBlocksToReceive--;
}
else
{
/* Received number of data blocks requested so restart the request timer.*/
prvStartRequestTimer( C );
/* Send the event to request next set of data blocks.*/
if( xOTA_Agent.xOTA_EventFlags != NULL )
{
( void ) xEventGroupSetBits( xOTA_Agent.xOTA_EventFlags, OTA_EVT_MASK_REQ_TIMEOUT );
}
}
}
}
}
}
else
{
/* Ignore unknown message types. */
OTA_LOG_L2( "[%s] Ignoring unknown message type %d.\r\n", OTA_METHOD_NAME, xMsgMetaData.lMsgType );
}
if( pxMsgMetaData->pxPubData.vData != NULL )
{
xOTA_Agent.xStatistics.ulOTA_PacketsProcessed++;
/* Free the MQTT buffer since we're done with it (even if we ignored the message). */
prvOTAPubMessageFree( pxMsgMetaData );
}
else
{
/* Safety ignore messages not associated with an MQTT buffer. */
}
}
}
}
if( C == NULL )
{ /* Any event that releases the context structure tells us we're not active anymore. */
xOTA_Agent.eState = eOTA_AgentState_Ready;
}
}
/* If we're here, we're shutting down the OTA agent. Free up all resources and quit. */
prvAgentShutdownCleanup();
vEventGroupDelete( xOTA_Agent.xOTA_EventFlags );
}
}
/* Clear the entire agent context. This includes the OTA agent state. */
memset( &xOTA_Agent, 0, sizeof( xOTA_Agent ) );
/* Reset the image and agent states. Possibly redundant but safer.
* Finally, self destruct. */
xOTA_Agent.eImageState = eOTA_ImageState_Unknown;
xOTA_Agent.eState = eOTA_AgentState_NotReady;
vTaskDelete( NULL );
}