Sync OTA from latest AFR 202007 release (#137)

This commit is contained in:
Tiangang Song
2020-07-10 16:06:40 -07:00
committed by GitHub
parent 47ced49201
commit 9db0f87358
3 changed files with 120 additions and 39 deletions

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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. */