Skip to content

Commit ac2b4f6

Browse files
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 40dc58e commit ac2b4f6

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
@@ -71,7 +71,7 @@
7171
#define NUM_OF_BLOCKS_REQUESTED 1U
7272
#define START_JOB_MSG_LENGTH 147U
7373
#define MAX_JOB_ID_LENGTH 64U
74-
#define UPDATE_JOB_MSG_LENGTH 48U
74+
#define UPDATE_JOB_MSG_LENGTH 128U
7575

7676
extern void vOtaNotActiveHook( void );
7777
extern void vOtaActiveHook( void );
@@ -178,6 +178,8 @@ char globalJobId[ MAX_JOB_ID_LENGTH ] = { 0 };
178178
*/
179179
static AfrOtaJobDocumentFields_t jobFields = { 0 };
180180

181+
static AfrOtaJobDocumentStatusDetails_t jobStatusDetails = { 0 };
182+
181183
/**
182184
* @brief Structure used to hold data from a job document.
183185
*/
@@ -252,9 +254,16 @@ STATIC bool closeFile( void );
252254
STATIC bool activateImage( void );
253255

254256
/**
255-
* @brief Send a message to notify that the firmware image was accepted.
257+
* @brief Send a message to the cloud to update the statusDetails field of the
258+
* job.
256259
*/
257-
STATIC bool sendSuccessMessage( void );
260+
STATIC void sendStatusDetailsMessage( void );
261+
262+
/**
263+
* @brief Send a message to notify the cloud of the job's final status (i.e.
264+
* accepted or failed).
265+
*/
266+
STATIC void sendFinalJobStatusMessage( JobCurrentStatus_t status );
258267

259268
/**
260269
* @brief Print the OTA job document metadata.
@@ -449,7 +458,7 @@ STATIC bool activateImage( void )
449458
return otaPal_ActivateNewImage( &jobFields );
450459
}
451460

452-
STATIC bool sendSuccessMessage( void )
461+
STATIC void sendStatusDetailsMessage( void )
453462
{
454463
char topicBuffer[ TOPIC_BUFFER_SIZE + 1 ] = { 0 };
455464
size_t topicBufferLength = 0U;
@@ -467,20 +476,85 @@ STATIC bool sendSuccessMessage( void )
467476
( uint16_t ) app_strnlen( globalJobId, 1000U ),
468477
&topicBufferLength );
469478

479+
/*
480+
* Convert the current app firmware version to a string and send it to the
481+
* the cloud
482+
*/
483+
484+
/*
485+
* Calling snprintf() with NULL and 0 as first two parameters gives the
486+
* required length of the destination string.
487+
*/
488+
int updatedByBufferLength = snprintf( NULL,
489+
0,
490+
"%u",
491+
appFirmwareVersion.u.x.build );
492+
493+
char updatedByBuffer[ updatedByBufferLength + 1 ];
494+
495+
( void ) snprintf( updatedByBuffer,
496+
updatedByBufferLength + 1,
497+
"%u",
498+
appFirmwareVersion.u.x.build );
499+
470500
/*
471501
* AWS IoT Jobs library:
472502
* Creating the message which contains the status of OTA job.
473503
* It will be published on the topic created in the previous step.
474504
*/
475-
size_t messageBufferLength = Jobs_UpdateMsg( Succeeded,
505+
size_t messageBufferLength = Jobs_UpdateMsg( InProgress,
476506
"2",
477507
1U,
508+
updatedByBuffer,
509+
updatedByBufferLength,
510+
messageBuffer,
511+
UPDATE_JOB_MSG_LENGTH );
512+
513+
prvMQTTPublish( topicBuffer,
514+
topicBufferLength,
515+
messageBuffer,
516+
messageBufferLength,
517+
0 );
518+
}
519+
520+
STATIC void sendFinalJobStatusMessage( JobCurrentStatus_t status )
521+
{
522+
char topicBuffer[ TOPIC_BUFFER_SIZE + 1 ] = { 0 };
523+
size_t topicBufferLength = 0U;
524+
char messageBuffer[ UPDATE_JOB_MSG_LENGTH ] = { 0 };
525+
526+
/*
527+
* AWS IoT Jobs library:
528+
* Creating the MQTT topic to update the status of OTA job.
529+
*/
530+
Jobs_Update( topicBuffer,
531+
TOPIC_BUFFER_SIZE,
532+
OTA_THING_NAME,
533+
( uint16_t ) app_strnlen( OTA_THING_NAME, 1000U ),
534+
globalJobId,
535+
( uint16_t ) app_strnlen( globalJobId, 1000U ),
536+
&topicBufferLength );
537+
538+
/*
539+
* AWS IoT Jobs library:
540+
* Creating the message which contains the status of OTA job.
541+
* It will be published on the topic created in the previous step.
542+
*/
543+
size_t messageBufferLength = Jobs_UpdateMsg( status,
544+
"3",
545+
1U,
546+
jobStatusDetails.updatedBy,
547+
jobStatusDetails.updatedByLen,
478548
messageBuffer,
479549
UPDATE_JOB_MSG_LENGTH );
480550

481551
prvMQTTPublish( topicBuffer, topicBufferLength, messageBuffer, messageBufferLength, 0 );
482-
LogInfo( ( "OTA update completed successfully.\n" ) );
483552
globalJobId[ 0 ] = 0U;
553+
554+
if( status == Succeeded )
555+
{
556+
LogInfo( ( "OTA update completed successfully.\n" ) );
557+
}
484558
}
485559

486560
STATIC void printJobParams( const char * jobId,
@@ -709,31 +783,83 @@ STATIC OtaPalJobDocProcessingResult_t receivedJobDocumentHandler( OtaJobEventDat
709783
{
710784
bool handled = jobDocumentParser( ( char * ) jobDoc->jobData, jobDoc->jobDataLength, &jobFields );
711785

712-
if( otaPal_GetPlatformImageState( &jobFields ) == OtaPalImageStatePendingCommit )
713-
{
714-
( void ) sendSuccessMessage();
715-
716-
otaAgentShutdown();
717-
}
786+
populateJobStatusDetailsFields( ( char * ) jobDoc->jobData, jobDoc->jobDataLength, &jobStatusDetails );
718787

719788
if( handled )
720789
{
721790
printJobParams( globalJobId, jobFields );
722791

723-
initMqttDownloader( &jobFields );
792+
/*In pending commit state, the device is in self test mode */
793+
if( otaPal_GetPlatformImageState( &jobFields ) == OtaPalImageStatePendingCommit )
794+
{
795+
/*
796+
* Convert the updatedBy string to an integer so the updatedBy
797+
* version can be compared to the update firmware version.
798+
*/
799+
char updatedByBuffer[ jobStatusDetails.updatedByLen ];
800+
char * endPtr;
801+
802+
/*
803+
* updatedBy string is not null terminated so copy it to a
804+
* temporary string and null terminate.
805+
*/
806+
( void ) memcpy( updatedByBuffer,
807+
jobStatusDetails.updatedBy,
808+
jobStatusDetails.updatedByLen );
809+
810+
updatedByBuffer[ jobStatusDetails.updatedByLen ] = '\0';
811+
812+
uint16_t updatedByVer = ( uint16_t ) strtoul( updatedByBuffer,
813+
&endPtr,
814+
10 );
815+
816+
if( updatedByVer < appFirmwareVersion.u.x.build )
817+
{
818+
LogInfo( ( "New image has a higher version number than the current image: "
819+
"New image version=%u"
820+
", Previous image version=%u",
821+
appFirmwareVersion.u.x.build,
822+
updatedByVer ) );
823+
824+
otaPal_SetPlatformImageState( &jobFields, OtaImageStateAccepted );
825+
( void ) sendFinalJobStatusMessage( Succeeded );
724826

725-
/* AWS IoT core returns the signature in a PEM format. We need to
726-
* convert it to DER format for image signature verification. */
827+
xResult = OtaPalNewImageBooted;
828+
}
829+
else
830+
{
831+
LogInfo( ( "Application version of the new image is not higher than the current image: "
832+
"New images are expected to have a higher version number." ) );
727833

728-
handled = convertSignatureToDER( OtaImageSignatureDecoded, sizeof( OtaImageSignatureDecoded ), &jobFields );
834+
otaPal_SetPlatformImageState( &jobFields, OtaImageStateRejected );
729835

730-
if( handled )
731-
{
732-
xResult = otaPal_CreateFileForRx( &jobFields );
836+
/*
837+
* Mark the job as FAILED (AWS Job Service will not allow
838+
* the job to be set to REJECTED if the job has been
839+
* started already).
840+
*/
841+
( void ) sendFinalJobStatusMessage( Failed );
842+
843+
xResult = OtaPalNewImageBootFailed;
844+
}
733845
}
734846
else
735847
{
736-
LogError( ( "Failed to decode the image signature to DER format." ) );
848+
initMqttDownloader( &jobFields );
849+
850+
/* AWS IoT core returns the signature in a PEM format. We need to
851+
* convert it to DER format for image signature verification. */
852+
853+
handled = convertSignatureToDER( OtaImageSignatureDecoded, sizeof( OtaImageSignatureDecoded ), &jobFields );
854+
855+
if( handled )
856+
{
857+
xResult = otaPal_CreateFileForRx( &jobFields );
858+
}
859+
else
860+
{
861+
LogError( ( "Failed to decode the image signature to DER format." ) );
862+
}
737863
}
738864
}
739865
}
@@ -908,6 +1034,11 @@ STATIC void processOTAEvents()
9081034
vOtaActiveHook();
9091035
break;
9101036

1037+
case OtaPalNewImageBooted:
1038+
LogInfo( ( "New firmware image booted.\n" ) );
1039+
vOtaNotActiveHook();
1040+
break;
1041+
9111042
case OtaPalJobDocFileCreateFailed:
9121043
case OtaPalNewImageBootFailed:
9131044
case OtaPalJobDocProcessingStateInvalid:
@@ -1004,6 +1135,8 @@ STATIC void processOTAEvents()
10041135
case OtaAgentEventActivateImage:
10051136
LogInfo( ( "Attempting to activate image.\n" ) );
10061137

1138+
sendStatusDetailsMessage();
1139+
10071140
if( activateImage() == true )
10081141
{
10091142
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)