Skip to content

Commit f7e612e

Browse files
chuyue-luo-armurutva
authored andcommitted
applications: Check if new firmware version higher than previous version
The OTA orchestrator now checks if the updated firmware version is higher than the previous firmware version. Signed-off-by: Chuyue Luo <[email protected]>
1 parent a79b36f commit f7e612e

File tree

2 files changed

+155
-20
lines changed

2 files changed

+155
-20
lines changed

applications/helpers/ota_orchestrator/src/ota_orchestrator.c

Lines changed: 153 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
#define NUM_OF_BLOCKS_REQUESTED 1U
8484
#define START_JOB_MSG_LENGTH 147U
8585
#define MAX_JOB_ID_LENGTH 64U
86-
#define UPDATE_JOB_MSG_LENGTH 48U
86+
#define UPDATE_JOB_MSG_LENGTH 128U
8787

8888
extern void vOtaNotActiveHook( void );
8989
extern void vOtaActiveHook( void );
@@ -190,6 +190,8 @@ char globalJobId[ MAX_JOB_ID_LENGTH ] = { 0 };
190190
*/
191191
static AfrOtaJobDocumentFields_t jobFields = { 0 };
192192

193+
static AfrOtaJobDocumentStatusDetails_t jobStatusDetails = { 0 };
194+
193195
/**
194196
* @brief Structure used to hold data from a job document.
195197
*/
@@ -264,9 +266,16 @@ STATIC bool closeFile( void );
264266
STATIC bool activateImage( void );
265267

266268
/**
267-
* @brief Send a message to notify that the firmware image was accepted.
269+
* @brief Send a message to the cloud to update the statusDetails field of the
270+
* job.
268271
*/
269-
STATIC bool sendSuccessMessage( void );
272+
STATIC void sendStatusDetailsMessage( void );
273+
274+
/**
275+
* @brief Send a message to notify the cloud of the job's final status (i.e.
276+
* accepted or failed).
277+
*/
278+
STATIC void sendFinalJobStatusMessage( JobCurrentStatus_t status );
270279

271280
/**
272281
* @brief Print the OTA job document metadata.
@@ -461,7 +470,7 @@ STATIC bool activateImage( void )
461470
return otaPal_ActivateNewImage( &jobFields );
462471
}
463472

464-
STATIC bool sendSuccessMessage( void )
473+
STATIC void sendStatusDetailsMessage( void )
465474
{
466475
char topicBuffer[ TOPIC_BUFFER_SIZE + 1 ] = { 0 };
467476
size_t topicBufferLength = 0U;
@@ -479,20 +488,85 @@ STATIC bool sendSuccessMessage( void )
479488
( uint16_t ) app_strnlen( globalJobId, 1000U ),
480489
&topicBufferLength );
481490

491+
/*
492+
* Convert the current app firmware version to a string and send it to the
493+
* the cloud
494+
*/
495+
496+
/*
497+
* Calling snprintf() with NULL and 0 as first two parameters gives the
498+
* required length of the destination string.
499+
*/
500+
int updatedByBufferLength = snprintf( NULL,
501+
0,
502+
"%u",
503+
appFirmwareVersion.u.x.build );
504+
505+
char updatedByBuffer[ updatedByBufferLength + 1 ];
506+
507+
( void ) snprintf( updatedByBuffer,
508+
updatedByBufferLength + 1,
509+
"%u",
510+
appFirmwareVersion.u.x.build );
511+
482512
/*
483513
* AWS IoT Jobs library:
484514
* Creating the message which contains the status of OTA job.
485515
* It will be published on the topic created in the previous step.
486516
*/
487-
size_t messageBufferLength = Jobs_UpdateMsg( Succeeded,
517+
size_t messageBufferLength = Jobs_UpdateMsg( InProgress,
488518
"2",
489519
1U,
520+
updatedByBuffer,
521+
updatedByBufferLength,
522+
messageBuffer,
523+
UPDATE_JOB_MSG_LENGTH );
524+
525+
prvMQTTPublish( topicBuffer,
526+
topicBufferLength,
527+
messageBuffer,
528+
messageBufferLength,
529+
0 );
530+
}
531+
532+
STATIC void sendFinalJobStatusMessage( JobCurrentStatus_t status )
533+
{
534+
char topicBuffer[ TOPIC_BUFFER_SIZE + 1 ] = { 0 };
535+
size_t topicBufferLength = 0U;
536+
char messageBuffer[ UPDATE_JOB_MSG_LENGTH ] = { 0 };
537+
538+
/*
539+
* AWS IoT Jobs library:
540+
* Creating the MQTT topic to update the status of OTA job.
541+
*/
542+
Jobs_Update( topicBuffer,
543+
TOPIC_BUFFER_SIZE,
544+
OTA_THING_NAME,
545+
( uint16_t ) app_strnlen( OTA_THING_NAME, 1000U ),
546+
globalJobId,
547+
( uint16_t ) app_strnlen( globalJobId, 1000U ),
548+
&topicBufferLength );
549+
550+
/*
551+
* AWS IoT Jobs library:
552+
* Creating the message which contains the status of OTA job.
553+
* It will be published on the topic created in the previous step.
554+
*/
555+
size_t messageBufferLength = Jobs_UpdateMsg( status,
556+
"3",
557+
1U,
558+
jobStatusDetails.updatedBy,
559+
jobStatusDetails.updatedByLen,
490560
messageBuffer,
491561
UPDATE_JOB_MSG_LENGTH );
492562

493563
prvMQTTPublish( topicBuffer, topicBufferLength, messageBuffer, messageBufferLength, 0 );
494-
LogInfo( ( "OTA update completed successfully.\n" ) );
495564
globalJobId[ 0 ] = 0U;
565+
566+
if( status == Succeeded )
567+
{
568+
LogInfo( ( "OTA update completed successfully.\n" ) );
569+
}
496570
}
497571

498572
STATIC void printJobParams( const char * jobId,
@@ -721,31 +795,83 @@ STATIC OtaPalJobDocProcessingResult_t receivedJobDocumentHandler( OtaJobEventDat
721795
{
722796
bool handled = jobDocumentParser( ( char * ) jobDoc->jobData, jobDoc->jobDataLength, &jobFields );
723797

724-
if( otaPal_GetPlatformImageState( &jobFields ) == OtaPalImageStatePendingCommit )
725-
{
726-
( void ) sendSuccessMessage();
727-
728-
otaAgentShutdown();
729-
}
798+
populateJobStatusDetailsFields( ( char * ) jobDoc->jobData, jobDoc->jobDataLength, &jobStatusDetails );
730799

731800
if( handled )
732801
{
733802
printJobParams( globalJobId, jobFields );
734803

735-
initMqttDownloader( &jobFields );
804+
/*In pending commit state, the device is in self test mode */
805+
if( otaPal_GetPlatformImageState( &jobFields ) == OtaPalImageStatePendingCommit )
806+
{
807+
/*
808+
* Convert the updatedBy string to an integer so the updatedBy
809+
* version can be compared to the update firmware version.
810+
*/
811+
char updatedByBuffer[ jobStatusDetails.updatedByLen ];
812+
char * endPtr;
813+
814+
/*
815+
* updatedBy string is not null terminated so copy it to a
816+
* temporary string and null terminate.
817+
*/
818+
( void ) memcpy( updatedByBuffer,
819+
jobStatusDetails.updatedBy,
820+
jobStatusDetails.updatedByLen );
821+
822+
updatedByBuffer[ jobStatusDetails.updatedByLen ] = '\0';
823+
824+
uint16_t updatedByVer = ( uint16_t ) strtoul( updatedByBuffer,
825+
&endPtr,
826+
10 );
827+
828+
if( updatedByVer < appFirmwareVersion.u.x.build )
829+
{
830+
LogInfo( ( "New image has a higher version number than the current image: "
831+
"New image version=%u"
832+
", Previous image version=%u",
833+
appFirmwareVersion.u.x.build,
834+
updatedByVer ) );
835+
836+
otaPal_SetPlatformImageState( &jobFields, OtaImageStateAccepted );
837+
( void ) sendFinalJobStatusMessage( Succeeded );
736838

737-
/* AWS IoT core returns the signature in a PEM format. We need to
738-
* convert it to DER format for image signature verification. */
839+
xResult = OtaPalNewImageBooted;
840+
}
841+
else
842+
{
843+
LogInfo( ( "Application version of the new image is not higher than the current image: "
844+
"New images are expected to have a higher version number." ) );
739845

740-
handled = convertSignatureToDER( OtaImageSignatureDecoded, sizeof( OtaImageSignatureDecoded ), &jobFields );
846+
otaPal_SetPlatformImageState( &jobFields, OtaImageStateRejected );
741847

742-
if( handled )
743-
{
744-
xResult = otaPal_CreateFileForRx( &jobFields );
848+
/*
849+
* Mark the job as FAILED (AWS Job Service will not allow
850+
* the job to be set to REJECTED if the job has been
851+
* started already).
852+
*/
853+
( void ) sendFinalJobStatusMessage( Failed );
854+
855+
xResult = OtaPalNewImageBootFailed;
856+
}
745857
}
746858
else
747859
{
748-
LogError( ( "Failed to decode the image signature to DER format." ) );
860+
initMqttDownloader( &jobFields );
861+
862+
/* AWS IoT core returns the signature in a PEM format. We need to
863+
* convert it to DER format for image signature verification. */
864+
865+
handled = convertSignatureToDER( OtaImageSignatureDecoded, sizeof( OtaImageSignatureDecoded ), &jobFields );
866+
867+
if( handled )
868+
{
869+
xResult = otaPal_CreateFileForRx( &jobFields );
870+
}
871+
else
872+
{
873+
LogError( ( "Failed to decode the image signature to DER format." ) );
874+
}
749875
}
750876
}
751877
}
@@ -920,6 +1046,11 @@ STATIC void processOTAEvents()
9201046
vOtaActiveHook();
9211047
break;
9221048

1049+
case OtaPalNewImageBooted:
1050+
LogInfo( ( "New firmware image booted.\n" ) );
1051+
vOtaNotActiveHook();
1052+
break;
1053+
9231054
case OtaPalJobDocFileCreateFailed:
9241055
case OtaPalNewImageBootFailed:
9251056
case OtaPalJobDocProcessingStateInvalid:
@@ -1016,6 +1147,8 @@ STATIC void processOTAEvents()
10161147
case OtaAgentEventActivateImage:
10171148
LogInfo( ( "Attempting to activate image.\n" ) );
10181149

1150+
sendStatusDetailsMessage();
1151+
10191152
if( activateImage() == true )
10201153
{
10211154
LogInfo( ( "Activated image.\n" ) );
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Modular OTA improvements: Print job metadata and check if new firmware version
2+
higher than previous version

0 commit comments

Comments
 (0)