diff --git a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/include/aws_iot_ota_agent.h b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/include/aws_iot_ota_agent.h index b929a8b029..69040c1ac2 100755 --- a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/include/aws_iot_ota_agent.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/include/aws_iot_ota_agent.h @@ -162,7 +162,8 @@ typedef enum eOTA_JobParseErr_ZeroFileSize, /* Job document specified a zero sized file. This is not allowed. */ eOTA_JobParseErr_NonConformingJobDoc, /* The job document failed to fulfill the model requirements. */ eOTA_JobParseErr_BadModelInitParams, /* There was an invalid initialization parameter used in the document model. */ - eOTA_JobParseErr_NoContextAvailable /* There wasn't an OTA context available. */ + eOTA_JobParseErr_NoContextAvailable, /* There wasn't an OTA context available. */ + eOTA_JobParseErr_NoActiveJobs, /* No active jobs are available in the service. */ } OTA_JobParseErr_t; diff --git a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent.c b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent.c index 2d63d128ac..29a79c3293 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent.c @@ -259,6 +259,7 @@ static OTA_Err_t prvCloseFileHandler( OTA_EventData_t * pxEventData ); static OTA_Err_t prvUserAbortHandler( OTA_EventData_t * pxEventData ); static OTA_Err_t prvSuspendHandler( OTA_EventData_t * pxEventData ); static OTA_Err_t prvResumeHandler( OTA_EventData_t * pxEventData ); +static OTA_Err_t prvJobNotificationHandler( OTA_EventData_t * pxEventData ); /* OTA default callback initializer. */ @@ -287,6 +288,7 @@ static OTA_AgentContext_t xOTA_Agent = .ulServerFileID = 0, .pcOTA_Singleton_ActiveJobName = NULL, .pcClientTokenFromJob = NULL, + .ulTimestampFromJob = 0, .pvSelfTestTimer = NULL, .xRequestTimer = NULL, .xOTA_EventQueue = NULL, @@ -301,24 +303,25 @@ static OTA_AgentContext_t xOTA_Agent = static OTAStateTableEntry_t OTATransitionTable[] = { /*STATE , EVENT , ACTION , NEXT STATE */ - { eOTA_AgentState_Ready, eOTA_AgentEvent_Start, prvStartHandler, eOTA_AgentState_RequestingJob }, - { eOTA_AgentState_RequestingJob, eOTA_AgentEvent_RequestJobDocument, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_RequestingJob, eOTA_AgentEvent_RequestTimer, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_WaitingForJob, eOTA_AgentEvent_ReceivedJobDocument, prvProcessJobHandler, eOTA_AgentState_CreatingFile }, - { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_StartSelfTest, prvInSelfTestHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_CreateFile, prvInitFileHandler, eOTA_AgentState_RequestingFileBlock }, - { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_RequestTimer, prvInitFileHandler, eOTA_AgentState_RequestingFileBlock }, - { eOTA_AgentState_RequestingFileBlock, eOTA_AgentEvent_RequestFileBlock, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, - { eOTA_AgentState_RequestingFileBlock, eOTA_AgentEvent_RequestTimer, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, - { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_ReceivedFileBlock, prvProcessDataHandler, eOTA_AgentState_WaitingForFileBlock }, - { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestTimer, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, - { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestFileBlock, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, - { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestJobDocument, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_CloseFile, prvCloseFileHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_Suspended, eOTA_AgentEvent_Resume, prvResumeHandler, eOTA_AgentState_RequestingJob }, - { eOTA_AgentState_All, eOTA_AgentEvent_Suspend, prvSuspendHandler, eOTA_AgentState_Suspended }, - { eOTA_AgentState_All, eOTA_AgentEvent_UserAbort, prvUserAbortHandler, eOTA_AgentState_WaitingForJob }, - { eOTA_AgentState_All, eOTA_AgentEvent_Shutdown, prvShutdownHandler, eOTA_AgentState_ShuttingDown }, + { eOTA_AgentState_Ready, eOTA_AgentEvent_Start, prvStartHandler, eOTA_AgentState_RequestingJob }, + { eOTA_AgentState_RequestingJob, eOTA_AgentEvent_RequestJobDocument, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_RequestingJob, eOTA_AgentEvent_RequestTimer, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_WaitingForJob, eOTA_AgentEvent_ReceivedJobDocument, prvProcessJobHandler, eOTA_AgentState_CreatingFile }, + { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_StartSelfTest, prvInSelfTestHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_CreateFile, prvInitFileHandler, eOTA_AgentState_RequestingFileBlock }, + { eOTA_AgentState_CreatingFile, eOTA_AgentEvent_RequestTimer, prvInitFileHandler, eOTA_AgentState_RequestingFileBlock }, + { eOTA_AgentState_RequestingFileBlock, eOTA_AgentEvent_RequestFileBlock, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, + { eOTA_AgentState_RequestingFileBlock, eOTA_AgentEvent_RequestTimer, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_ReceivedFileBlock, prvProcessDataHandler, eOTA_AgentState_WaitingForFileBlock }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestTimer, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestFileBlock, prvRequestDataHandler, eOTA_AgentState_WaitingForFileBlock }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_RequestJobDocument, prvRequestJobHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_ReceivedJobDocument, prvJobNotificationHandler, eOTA_AgentState_RequestingJob }, + { eOTA_AgentState_WaitingForFileBlock, eOTA_AgentEvent_CloseFile, prvCloseFileHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_Suspended, eOTA_AgentEvent_Resume, prvResumeHandler, eOTA_AgentState_RequestingJob }, + { eOTA_AgentState_All, eOTA_AgentEvent_Suspend, prvSuspendHandler, eOTA_AgentState_Suspended }, + { eOTA_AgentState_All, eOTA_AgentEvent_UserAbort, prvUserAbortHandler, eOTA_AgentState_WaitingForJob }, + { eOTA_AgentState_All, eOTA_AgentEvent_Shutdown, prvShutdownHandler, eOTA_AgentState_ShuttingDown }, }; static const char * pcOTA_AgentState_Strings[ eOTA_AgentState_All ] = @@ -688,7 +691,7 @@ static OTA_JobParseErr_t prvDefaultCustomJobCallback( const char * pcJSON, * custom OTA job. No applciation callback for handling custom job document is registered so just * return error code for non conforming job document from this default handler. */ - OTA_LOG_L1( "[%s] Received Custom Job inside OTA Agent which is not supported.\r\n", OTA_METHOD_NAME ); + OTA_LOG_L2( "[%s] Received Custom Job inside OTA Agent which is not supported.\r\n", OTA_METHOD_NAME ); return eOTA_JobParseErr_NonConformingJobDoc; } @@ -948,29 +951,44 @@ static OTA_Err_t prvProcessJobHandler( OTA_EventData_t * pxEventData ) } else { - /* Init data interface routines */ - xReturn = prvSetDataInterface( &xOTA_DataInterface, xOTA_Agent.pxOTA_Files[ xOTA_Agent.ulFileIndex ].pucProtocols ); - - if( xReturn == kOTA_Err_None ) + /* + * If the platform is not in the self_test state, initiate file download. + */ + if( prvInSelftest() == false ) { - OTA_LOG_L1( "[%s] Setting OTA data inerface.\r\n", OTA_METHOD_NAME ); + /* Init data interface routines */ + xReturn = prvSetDataInterface( &xOTA_DataInterface, xOTA_Agent.pxOTA_Files[ xOTA_Agent.ulFileIndex ].pucProtocols ); - /* Received a valid context so send event to request file blocks. */ - xEventMsg.xEventId = eOTA_AgentEvent_CreateFile; - - /*Send the event to OTA Agent task. */ - if( !OTA_SignalEvent( &xEventMsg ) ) + if( xReturn == kOTA_Err_None ) { - xReturn = kOTA_Err_EventQueueSendFailed; + OTA_LOG_L1( "[%s] Setting OTA data inerface.\r\n", OTA_METHOD_NAME ); + + /* Received a valid context so send event to request file blocks. */ + xEventMsg.xEventId = eOTA_AgentEvent_CreateFile; + + /*Send the event to OTA Agent task. */ + if( !OTA_SignalEvent( &xEventMsg ) ) + { + xReturn = kOTA_Err_EventQueueSendFailed; + } + } + else + { + /* + * Failed to set the data interface so abort the OTA.If there is a valid job id, + * then a job status update will be sent. + */ + ( void ) prvSetImageStateWithReason( eOTA_ImageState_Aborted, xReturn ); } } else { /* - * Failed to set the data interface so abort the OTA.If there is a valid job id, - * then a job status update will be sent. + * Received a job that is not in self-test but platform is, so reboot the device to allow + * roll back to previous image. */ - ( void ) prvSetImageStateWithReason( eOTA_ImageState_Aborted, xReturn ); + OTA_LOG_L1( "[%s] Platform is in self-test but job is not, rebooting ! \r\n", OTA_METHOD_NAME ); + ( void ) xOTA_Agent.xPALCallbacks.xResetDevice( xOTA_Agent.ulServerFileID ); } } @@ -1286,6 +1304,34 @@ static OTA_Err_t prvResumeHandler( OTA_EventData_t * pxEventData ) return OTA_SignalEvent( &xEventMsg ) ? kOTA_Err_None : kOTA_Err_EventQueueSendFailed; } +static OTA_Err_t prvJobNotificationHandler( OTA_EventData_t * pxEventData ) +{ + ( void ) pxEventData; + OTA_Err_t xErr = kOTA_Err_Uninitialized; + OTA_EventMsg_t xEventMsg = { 0 }; + + /* We receieved job notification so stop the data request timer. */ + prvStopRequestTimer(); + + /* Abort the current job. */ + ( void ) xOTA_Agent.xPALCallbacks.xSetPlatformImageState( xOTA_Agent.ulServerFileID, eOTA_ImageState_Aborted ); + ( void ) prvOTA_Close( &xOTA_Agent.pxOTA_Files[ xOTA_Agent.ulFileIndex ] ); + + /* Free the active job name as its no longer required. */ + if( xOTA_Agent.pcOTA_Singleton_ActiveJobName != NULL ) + { + vPortFree( xOTA_Agent.pcOTA_Singleton_ActiveJobName ); + xOTA_Agent.pcOTA_Singleton_ActiveJobName = NULL; + } + + /* + * Send signal to request next OTA job document from service. + */ + xEventMsg.xEventId = eOTA_AgentEvent_RequestJobDocument; + + return OTA_SignalEvent( &xEventMsg ) ? kOTA_Err_None : kOTA_Err_EventQueueSendFailed; +} + /* * This is a private function only meant to be called by the OTA agent after the * currently running image that is in the self test phase rejects the update. @@ -1426,7 +1472,13 @@ static bool prvOTA_Close( OTA_FileContext_t * const C ) bool bResult = false; - OTA_LOG_L1( "[%s] Context->0x%p\r\n", OTA_METHOD_NAME, C ); + OTA_LOG_L2( "[%s] Context->0x%p\r\n", OTA_METHOD_NAME, C ); + + /* Cleanup related to selected protocol. */ + if( xOTA_DataInterface.prvCleanup != NULL ) + { + ( void ) xOTA_DataInterface.prvCleanup( &xOTA_Agent ); + } if( C != NULL ) { @@ -2000,6 +2052,7 @@ static OTA_FileContext_t * prvParseJobDoc( const char * pcJSON, static const JSON_DocParam_t xOTA_JobDocModelParamStructure[ OTA_NUM_JOB_PARAMS ] = { { OTA_JSON_CLIENT_TOKEN_KEY, OTA_JOB_PARAM_OPTIONAL, { ( uint32_t ) &xOTA_Agent.pcClientTokenFromJob }, eModelParamType_StringInDoc, JSMN_STRING }, /*lint !e9078 !e923 Get address of token as value. */ + { OTA_JSON_TIMESTAMP_KEY, OTA_JOB_PARAM_OPTIONAL, { ( uint32_t ) &xOTA_Agent.ulTimestampFromJob }, eModelParamType_UInt32, JSMN_PRIMITIVE }, { OTA_JSON_EXECUTION_KEY, OTA_JOB_PARAM_REQUIRED, { OTA_DONT_STORE_PARAM }, eModelParamType_Object, JSMN_OBJECT }, { OTA_JSON_JOB_ID_KEY, OTA_JOB_PARAM_REQUIRED, { offsetof( OTA_FileContext_t, pucJobName ) }, eModelParamType_StringCopy, JSMN_STRING }, { OTA_JSON_STATUS_DETAILS_KEY, OTA_JOB_PARAM_OPTIONAL, { OTA_DONT_STORE_PARAM }, eModelParamType_Object, JSMN_OBJECT }, @@ -2055,8 +2108,18 @@ static OTA_FileContext_t * prvParseJobDoc( const char * pcJSON, /* C->pucJobName is guaranteed to be zero terminated. */ if( strcmp( ( char * ) xOTA_Agent.pcOTA_Singleton_ActiveJobName, ( char * ) C->pucJobName ) != 0 ) { - OTA_LOG_L1( "[%s] Busy with existing job. Ignoring.\r\n", OTA_METHOD_NAME ); - eErr = eOTA_JobParseErr_BusyWithExistingJob; + OTA_LOG_L1( "[%s] New job document received,aborting current job.\r\n", OTA_METHOD_NAME ); + + /* Abort the current job. */ + ( void ) xOTA_Agent.xPALCallbacks.xSetPlatformImageState( xOTA_Agent.ulServerFileID, eOTA_ImageState_Aborted ); + ( void ) prvOTA_Close( &xOTA_Agent.pxOTA_Files[ xOTA_Agent.ulFileIndex ] ); + + /* Set new active job name. */ + vPortFree( xOTA_Agent.pcOTA_Singleton_ActiveJobName ); + xOTA_Agent.pcOTA_Singleton_ActiveJobName = C->pucJobName; + C->pucJobName = NULL; + + eErr = eOTA_JobParseErr_None; } else { /* The same job is being reported so update the url. */ @@ -2189,6 +2252,21 @@ static OTA_FileContext_t * prvParseJobDoc( const char * pcJSON, eErr = eOTA_JobParseErr_NonConformingJobDoc; } } + else + { + /*Check if we received a timestamp and client token but no job ID.*/ + if( ( xOTA_Agent.pcClientTokenFromJob != NULL ) && ( xOTA_Agent.ulTimestampFromJob != 0 ) && ( C->pucJobName == NULL ) ) + { + /* Received job docuement with no execution so no active job is available.*/ + OTA_LOG_L1( "[%s] No active jobs available in the service for execution.\r\n", OTA_METHOD_NAME ); + eErr = eOTA_JobParseErr_NoActiveJobs; + } + else + { + /* Job is malformed - return an error */ + eErr = eOTA_JobParseErr_NonConformingJobDoc; + } + } } configASSERT( eErr != eOTA_JobParseErr_Unknown ); diff --git a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent_internal.h b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent_internal.h index 6c03fb41fb..02b9a61cd3 100755 --- a/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent_internal.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-IoT-Libraries-LTS-Beta1/c_sdk/aws/ota/src/aws_iot_ota_agent_internal.h @@ -205,10 +205,11 @@ enum * size, attributes, etc. The following value specifies the number of parameters * that are included in the job document model although some may be optional. */ -#define OTA_NUM_JOB_PARAMS ( 19 ) /* Number of parameters in the job document. */ +#define OTA_NUM_JOB_PARAMS ( 20 ) /* Number of parameters in the job document. */ /* Keys in OTA job doc . */ #define OTA_JSON_CLIENT_TOKEN_KEY "clientToken" +#define OTA_JSON_TIMESTAMP_KEY "timestamp" #define OTA_JSON_EXECUTION_KEY "execution" #define OTA_JSON_JOB_ID_KEY "jobId" #define OTA_JSON_STATUS_DETAILS_KEY "statusDetails" @@ -245,10 +246,11 @@ typedef struct ota_agent_context uint8_t pcThingName[ otaconfigMAX_THINGNAME_LEN + 1U ]; /* Thing name + zero terminator. */ void * pvConnectionContext; /* Connection context for control and data plane. */ OTA_FileContext_t pxOTA_Files[ OTA_MAX_FILES ]; /* Static array of OTA file structures. */ - uint32_t ulFileIndex; /* Static array of OTA file structures. */ + uint32_t ulFileIndex; /* Index of current file in the array. */ uint32_t ulServerFileID; /* Variable to store current file ID passed down */ uint8_t * pcOTA_Singleton_ActiveJobName; /* The currently active job name. We only allow one at a time. */ uint8_t * pcClientTokenFromJob; /* The clientToken field from the latest update job. */ + uint32_t ulTimestampFromJob; /* Timestamp received from the latest job document. */ TimerHandle_t pvSelfTestTimer; /* The self-test response expected timer. */ TimerHandle_t xRequestTimer; /* The request timer associated with this OTA context. */ QueueHandle_t xOTA_EventQueue; /* Event queue for communicating with the OTA Agent task. */