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
8888extern void vOtaNotActiveHook ( void );
8989extern void vOtaActiveHook ( void );
@@ -190,6 +190,8 @@ char globalJobId[ MAX_JOB_ID_LENGTH ] = { 0 };
190190 */
191191static 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 );
264266STATIC 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
498572STATIC 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" ) );
0 commit comments