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
7676extern void vOtaNotActiveHook ( void );
7777extern void vOtaActiveHook ( void );
@@ -178,6 +178,8 @@ char globalJobId[ MAX_JOB_ID_LENGTH ] = { 0 };
178178 */
179179static 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 );
252254STATIC 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
486560STATIC 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" ) );
0 commit comments