source/include/jobs.h (188 lines of code) (raw):

/* * AWS IoT Jobs v2.0.0 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * SPDX-License-Identifier: MIT * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /** * @file jobs.h * @brief Client library APIs for the AWS IoT Jobs service. * * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-api.html#jobs-mqtt-api */ #ifndef JOBS_H_ #define JOBS_H_ #include <stdbool.h> #include <stddef.h> #include <stdint.h> /* *INDENT-OFF* */ #ifdef __cplusplus extern "C" { #endif /* *INDENT-ON* */ /** * @ingroup jobs_constants * @brief Size of Topic Buffer */ #define TOPIC_BUFFER_SIZE 256U /** * @ingroup jobs_constants * @brief Size of Jobs Start Next Message Buffer */ #define START_JOB_MSG_LENGTH 147U /** * @ingroup jobs_constants * @brief Size of Jobs Update Message Buffer */ #define UPDATE_JOB_MSG_LENGTH 48U /** * @ingroup jobs_constants * @brief Maximum length of a thing name for the AWS IoT Jobs Service. */ #define JOBS_THINGNAME_MAX_LENGTH 128U /* per AWS IoT API Reference */ /** * @ingroup jobs_constants * @brief Maximum length of a job ID for the AWS IoT Jobs Service. */ #define JOBS_JOBID_MAX_LENGTH 64U /* per AWS IoT API Reference */ #ifndef THINGNAME_MAX_LENGTH /** * @brief User defined maximum length of a thing name for the application. * * <br><b>Default value</b>: @ref JOBS_THINGNAME_MAX_LENGTH "JOBS_THINGNAME_MAX_LENGTH" */ #define THINGNAME_MAX_LENGTH JOBS_THINGNAME_MAX_LENGTH #endif #ifndef JOBID_MAX_LENGTH /** * @brief User defined maximum length of a job ID for the application. * * <br><b>Default value</b>: @ref JOBS_JOBID_MAX_LENGTH "JOBS_JOBID_MAX_LENGTH" */ #define JOBID_MAX_LENGTH JOBS_JOBID_MAX_LENGTH #endif #if ( THINGNAME_MAX_LENGTH > JOBS_THINGNAME_MAX_LENGTH ) #error "The value of THINGNAME_MAX_LENGTH exceeds the AWS IoT Jobs Service limit." #endif #if ( JOBID_MAX_LENGTH > JOBS_JOBID_MAX_LENGTH ) #error "The value of JOBID_MAX_LENGTH exceeds the AWS IoT Jobs Service limit." #endif /** * @cond DOXYGEN_IGNORE * Doxygen should ignore these macros as they are private. */ #define JOBS_API_PREFIX "$aws/things/" #define JOBS_API_PREFIX_LENGTH ( sizeof( JOBS_API_PREFIX ) - 1U ) #define JOBS_API_BRIDGE "/jobs/" #define JOBS_API_BRIDGE_LENGTH ( sizeof( JOBS_API_BRIDGE ) - 1U ) #define JOBS_API_SUCCESS "/accepted" #define JOBS_API_SUCCESS_LENGTH ( sizeof( JOBS_API_SUCCESS ) - 1U ) #define JOBS_API_FAILURE "/rejected" #define JOBS_API_FAILURE_LENGTH ( sizeof( JOBS_API_FAILURE ) - 1U ) #define JOBS_API_JOBSCHANGED "notify" #define JOBS_API_JOBSCHANGED_LENGTH ( sizeof( JOBS_API_JOBSCHANGED ) - 1U ) #define JOBS_API_NEXTJOBCHANGED "notify-next" #define JOBS_API_NEXTJOBCHANGED_LENGTH ( sizeof( JOBS_API_NEXTJOBCHANGED ) - 1U ) #define JOBS_API_GETPENDING "get" #define JOBS_API_GETPENDING_LENGTH ( sizeof( JOBS_API_GETPENDING ) - 1U ) #define JOBS_API_STARTNEXT "start-next" #define JOBS_API_STARTNEXT_LENGTH ( sizeof( JOBS_API_STARTNEXT ) - 1U ) #define JOBS_API_DESCRIBE "get" #define JOBS_API_DESCRIBE_LENGTH ( sizeof( JOBS_API_DESCRIBE ) - 1U ) #define JOBS_API_UPDATE "update" #define JOBS_API_UPDATE_LENGTH ( sizeof( JOBS_API_UPDATE ) - 1U ) #define JOBS_API_JOBID_NEXT "$next" #define JOBS_API_JOBID_NEXT_LENGTH ( sizeof( JOBS_API_JOBID_NEXT ) - 1U ) #define JOBS_API_JOBID_NULL "" #define JOBS_API_LEVEL_SEPARATOR "/" #define JOBS_API_CLIENTTOKEN "{\"clientToken\":\"" #define JOBS_API_CLIENTTOKEN_LENGTH ( sizeof( JOBS_API_CLIENTTOKEN ) - 1U ) #define JOBS_API_STATUS "{\"status\":\"" #define JOBS_API_STATUS_LENGTH ( sizeof( JOBS_API_STATUS ) - 1U ) #define JOBS_API_EXPECTED_VERSION "\",\"expectedVersion\":\"" #define JOBS_API_EXPECTED_VERSION_LENGTH ( sizeof( JOBS_API_EXPECTED_VERSION ) - 1U ) #define JOBS_API_STATUS_DETAILS "\",\"statusDetails\":" #define JOBS_API_STATUS_DETAILS_LENGTH ( sizeof( JOBS_API_STATUS_DETAILS ) - 1U ) #define JOBS_API_COMMON_LENGTH( thingNameLength ) \ ( JOBS_API_PREFIX_LENGTH + ( thingNameLength ) + JOBS_API_BRIDGE_LENGTH ) /** @endcond */ /** * @cond DOXYGEN_IGNORE * Doxygen should ignore this macro as it is private. */ /* AWS IoT Jobs API topics. */ #define JOBS_TOPIC_COMMON( thingName, jobId, jobsApi ) \ ( JOBS_API_PREFIX \ thingName \ JOBS_API_BRIDGE \ jobId \ jobsApi ) /** @endcond */ /** * @ingroup jobs_constants * @brief Topic string for subscribing to the NextJobExecutionChanged API. * * This macro should be used when the thing name is known at the compile time. * If the thing name is not known at compile time, the #Jobs_GetTopic API * should be used instead. * * @param thingName The thing name as registered with AWS IoT Core. */ #define JOBS_API_SUBSCRIBE_NEXTJOBCHANGED( thingName ) \ JOBS_TOPIC_COMMON( thingName, JOBS_API_JOBID_NULL, JOBS_API_NEXTJOBCHANGED ) /** * @ingroup jobs_constants * @brief Topic string for subscribing to the JobExecutionsChanged API. * * This macro should be used when the thing name is known at the compile time. * If the thing name is not known at compile time, the #Jobs_GetTopic API * should be used instead. * * @param thingName The thing name as registered with AWS IoT Core. */ #define JOBS_API_SUBSCRIBE_JOBSCHANGED( thingName ) \ JOBS_TOPIC_COMMON( thingName, JOBS_API_JOBID_NULL, JOBS_API_JOBSCHANGED ) /** * @ingroup jobs_constants * @brief Topic string for publishing to the StartNextPendingJobExecution API. * * This macro should be used when the thing name is known at the compile time. * If the thing name is not known at compile time, the #Jobs_StartNext API * should be used instead. * * @param thingName The thing name as registered with AWS IoT Core. */ #define JOBS_API_PUBLISH_STARTNEXT( thingName ) \ JOBS_TOPIC_COMMON( thingName, JOBS_API_JOBID_NULL, JOBS_API_STARTNEXT ) /** * @ingroup jobs_constants * @brief Topic string for publishing to the GetPendingJobExecutions API. * * This macro should be used when the thing name is known at the compile time. * If the thing name is not known at compile time, the #Jobs_GetPending API * should be used instead. * * @param thingName The thing name as registered with AWS IoT Core. */ #define JOBS_API_PUBLISH_GETPENDING( thingName ) \ JOBS_TOPIC_COMMON( thingName, JOBS_API_JOBID_NULL, JOBS_API_GETPENDING ) /** * @ingroup jobs_constants * @brief Topic string for querying the next pending job from the * DescribeJobExecution API. * * This macro should be used when the thing name and jobID are known at the * compile time. If next pending job is being queried, use $next as job ID. * If the thing name or job ID are not known at compile time, the #Jobs_Describe API * should be used instead. * * @param thingName The thing name as registered with AWS IoT Core. */ #define JOBS_API_PUBLISH_DESCRIBENEXTJOB( thingName ) \ JOBS_TOPIC_COMMON( thingName, JOBS_API_JOBID_NEXT JOBS_API_LEVEL_SEPARATOR, JOBS_API_DESCRIBE ) /** * @ingroup jobs_constants * @brief The size needed to hold the longest topic for a given thing name length. * @note This includes space for a terminating NUL character. */ #define JOBS_API_MAX_LENGTH( thingNameLength ) \ ( JOBS_API_COMMON_LENGTH( thingNameLength ) + \ JOBID_MAX_LENGTH + sizeof( '/' ) + JOBS_API_UPDATE_LENGTH + \ JOBS_API_SUCCESS_LENGTH + 1U ) /** * @ingroup jobs_enum_types * @brief Return codes from jobs functions. */ typedef enum { JobsError = 0, JobsSuccess, /**< @brief The buffer was properly written or a match was found. */ JobsNoMatch, /**< @brief The buffer does not contain a jobs topic. */ JobsBadParameter, /**< @brief A function parameter was NULL or has an illegal value. */ JobsBufferTooSmall /**< @brief The buffer write was truncated. */ } JobsStatus_t; /** * @brief Status codes for jobs */ typedef enum { Queued, InProgress, Failed, Succeeded, Rejected } JobCurrentStatus_t; /** * @brief Status codes for job update status */ typedef enum { JobUpdateStatus_Accepted, JobUpdateStatus_Rejected } JobUpdateStatus_t; /** * @ingroup jobs_enum_types * @brief Topic values for subscription requests. * * @note The enum values for valid topics must be contiguous, * starting with 0. The last valid topic must be followed * by JobsMaxTopic. This arrangement is necessary since the * enum values are used as indexes to arrays of topic strings * and lengths. * * @note The ordering is important, providing a means * to divide topics into those that use a job ID * and those that do not. * * @note These constraints are enforced by a unit test. */ typedef enum { JobsInvalidTopic = -1, JobsJobsChanged, JobsNextJobChanged, JobsGetPendingSuccess, JobsGetPendingFailed, JobsStartNextSuccess, JobsStartNextFailed, /* Topics below use a job ID. */ JobsDescribeSuccess, JobsDescribeFailed, JobsUpdateSuccess, JobsUpdateFailed, JobsMaxTopic } JobsTopic_t; /** * @ingroup jobs_struct_types * @brief Structure for Jobs_UpdateMsg request parameters. * * @note For optional fields setting a pointer to NULL or * the length to 0U will disable this field from being used. * * * @note Optional fields include: * * expectedVersion * * expectedVersionLength * * statusDetails * * statusDetailsLength * * @note The status details must be a JSON formatted key-value * pair. */ typedef struct { JobCurrentStatus_t status; /**< Status to update the job to. */ const char * expectedVersion; /**< Expected version, optional. */ size_t expectedVersionLength; /**< Expected version length, optional. */ const char * statusDetails; /**< JSON key-value pair, optional. */ size_t statusDetailsLength; /**< JSON key-value pair length, optional. */ } JobsUpdateRequest_t; /*-----------------------------------------------------------*/ /** * @brief Populate a topic string for a subscription request. * * @param[in] buffer The buffer to contain the topic string. * @param[in] length The size of the buffer. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[in] api The desired Jobs API, e.g., JobsNextJobChanged. * @param[out] outLength The length of the topic string written to the buffer. * * @return #JobsSuccess if the topic was written to the buffer; * #JobsBadParameter if invalid parameters are passed; * #JobsBufferTooSmall if the buffer cannot hold the full topic string. * * When all parameters are valid, the topic string is written to * the buffer up to one less than the buffer size. The topic is * ended with a NUL character. * * @note The thingName parameter does not need a NUL terminator. * * @note The AWS IoT Jobs service does not require clients to subscribe * to the "/accepted" and "/rejected" response topics for the APIs that * accept requests on PUBLISH topics. The Jobs service will send responses * to requests from clients irrespective of whether they have subscribed to * response topics or not. For more information, refer to the AWS docs here: * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-mqtt-api.html * * <b>Example</b> * @code{c} * * // The following example shows usage of the Jobs_GetTopic API to * // generate topic string for the NextJobExecutionChanged API * // of AWS IoT Jobs service. * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * // This example allocates a buffer of maximum length for a Jobs topic * // possible for the thing name using the JOBS_API_MAX_LENGTH macro. * char topicBuffer[ JOBS_API_MAX_LENGTH( THING_NAME_LENGTH ) ] = { 0 }; * uint16_t topicLength = 0U; * JobsStatus_t status = JobsSuccess; * status = Jobs_GetTopic( topicBuffer, * sizeof( topicBuffer ), * THING_NAME, * THING_NAME_LENGTH, * &( topicLength ) ); * * if( status == JobsSuccess ) * { * // The topic string of length, topicLength, has been * // generated in the buffer, topicBuffer, for the NextJobExecutionChanged API. * // Subscribe to this topic using an MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_gettopic] */ JobsStatus_t Jobs_GetTopic( char * buffer, size_t length, const char * thingName, uint16_t thingNameLength, JobsTopic_t api, size_t * outLength ); /* @[declare_jobs_gettopic] */ /** * @brief Output a topic value if a Jobs API topic string is present. * Optionally, output a pointer to a jobID within the topic and its * length. * * @param[in] topic The topic string to check. * @param[in] length The length of the topic string. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[out] outApi The jobs topic API value if present, e.g., JobsUpdateSuccess. * @param[out] outJobId The beginning of the jobID in the topic string. * @param[out] outJobIdLength The length of the jobID in the topic string. * * @return #JobsSuccess if a matching topic was found; * #JobsNoMatch if a matching topic was NOT found * (parameter outApi gets JobsInvalidTopic ); * #JobsBadParameter if invalid parameters are passed. * * @note The topic and thingName parameters do not need a NUL terminator. * * @note Not all Jobs APIs have jobIDs within the topic string. * NULL and 0 are output when no jobID is present. * The parameters jobId and jobIdLength may be NULL. * * <b>Example</b> * @code{c} * * // The following example shows how to use the Jobs_MatchTopic API to * // check if an incoming MQTT publish message is from the AWS IoT Jobs * // service. * * // Assuming that these variables contain incoming topic data received * // from the MQTT client used. * char * pIncomingTopic; * size_t topicLength; * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * // The Jobs_MatchTopic API will check that the incoming message topic contains * // this thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * JobsTopic_t api; * char * pJobId = NULL; * uint16_t jobIdLength; * JobsStatus_t status = JobsSuccess; * * status = Jobs_MatchTopic( pIncomingTopic, * topicLength, * THING_NAME, * THING_NAME_LENGTH, * &api, * &pJobId, * &jobIdLength ); * * if( status == JobsSuccess ) * { * // The Jobs_MatchTopic API has determined that the incoming topic is from * // AWS IoT Jobs service for the expected thing name. * // If the topic contains a jobID, then the pJobId and jobIdLength parameters * // populated by the API. * * if( api == JobsJobsChanged ) * { // Message from JobExecutionsChanged API. * } * * else if( api == JobsNextJobChanged ) * { // Message from NextJobExecutionChanged API. * } * * else if( api == JobsGetPendingSuccess ) * { // Received accepted response for request to GetPendingJobExecutions API. * } * * else if( api == JobsGetPendingFailed ) * { // Received rejected response for request to GetPendingJobExecutions API. * } * * else if( api == JobsStartNextSuccess ) * { // Received accepted response for request to StartNextPendingJobExecution API. * } * * else if( api == JobsStartNextFailed ) * { // Received rejected response for request to StartNextPendingJobExecution API. * } * * else if( api == JobsDescribeSuccess ) * { // Received accepted response for request to DescribeJobExecution API. * } * * else if( api == JobsDescribeFailed ) * { // Received rejected response for request to DescribeJobExecution API. * } * * else if( api == JobsUpdateSuccess ) * { // Received accepted response for request to UpdateJobExecution API. * } * * else if( api == JobsUpdateFailed ) * { // Received rejected response for request to UpdateJobExecution API. * } * else * { * // Unexpected response. * } * } * @endcode */ /* @[declare_jobs_matchtopic] */ JobsStatus_t Jobs_MatchTopic( char * topic, size_t length, const char * thingName, uint16_t thingNameLength, JobsTopic_t * outApi, char ** outJobId, uint16_t * outJobIdLength ); /* @[declare_jobs_matchtopic] */ /** * @brief Populate a topic string for a GetPendingJobExecutions request. * * @param[in] buffer The buffer to contain the topic string. * @param[in] length The size of the buffer. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[out] outLength The length of the topic string written to the buffer. * * @return #JobsSuccess if the topic was written to the buffer; * #JobsBadParameter if invalid parameters are passed; * #JobsBufferTooSmall if the buffer cannot hold the full topic string. * * When all parameters are valid, the topic string is written to * the buffer up to one less than the buffer size. The topic is * ended with a NUL character. * * @note The thingName parameter does not need a NUL terminator. * * @note The AWS IoT Jobs service does not require clients to subscribe * to the "/accepted" and "/rejected" response topics of the * GetPendingJobExecutions API. * The Jobs service will send responses to requests published to the API * from clients irrespective of whether they have subscribed to response topics * or not. For more information, refer to the AWS docs here: * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-mqtt-api.html * * <b>Example</b> * @code{c} * * // The following example shows usage of the Jobs_GetPending API to * // generate topic string for the GetPendingJobExecutions API * // of the AWS IoT Jobs service. * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * // This example allocates a buffer of maximum length for a Jobs topic * // possible for the thing name using the JOBS_API_MAX_LENGTH macro. * char topicBuffer[ JOBS_API_MAX_LENGTH( THING_NAME_LENGTH ) ] = { 0 }; * uint16_t topicLength = 0U; * JobsStatus_t status = JobsSuccess; * status = Jobs_GetPending( topicBuffer, * sizeof( topicBuffer ), * THING_NAME, * THING_NAME_LENGTH, * &( topicLength ) ); * * if( status == JobsSuccess ) * { * // The topic string of length, topicLength, has been * // generated in the buffer, topicBuffer, for the GetPendingJobExecutions API. * // Publish to this topic using an MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_getpending] */ JobsStatus_t Jobs_GetPending( char * buffer, size_t length, const char * thingName, uint16_t thingNameLength, size_t * outLength ); /* @[declare_jobs_getpending] */ /** * @brief Populate a topic string for a StartNextPendingJobExecution request. * * @param[in] buffer The buffer to contain the topic string. * @param[in] length The size of the buffer. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[out] outLength The length of the topic string written to the buffer. * * @return #JobsSuccess if the topic was written to the buffer; * #JobsBadParameter if invalid parameters are passed; * #JobsBufferTooSmall if the buffer cannot hold the full topic string. * * When all parameters are valid, the topic string is written to * the buffer up to one less than the buffer size. The topic is * ended with a NUL character. * * @note The thingName parameter does not need a NUL terminator. * * @note The AWS IoT Jobs service does not require clients to subscribe * to the "/accepted" and "/rejected" response topics of the * StartNextPendingJobExecution API. * The Jobs service will send responses to requests published to the API * from clients irrespective of whether they have subscribed to response topics * or not. For more information, refer to the AWS docs here: * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-mqtt-api.html * * <b>Example</b> * @code{c} * * // The following example shows usage of the Jobs_StartNext API to * // generate topic string for the StartNextPendingJobExecution API * // of the AWS IoT Jobs service. * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * // This example allocates a buffer of maximum length for a Jobs topic * // possible for the thing name using the JOBS_API_MAX_LENGTH macro. * char topicBuffer[ JOBS_API_MAX_LENGTH( THING_NAME_LENGTH ) ] = { 0 }; * uint16_t topicLength = 0U; * JobsStatus_t status = JobsSuccess; * status = Jobs_StartNext( topicBuffer, * sizeof( topicBuffer ), * THING_NAME, * THING_NAME_LENGTH, * &( topicLength ) ); * * if( status == JobsSuccess ) * { * // The topic string of length, topicLength, has been generated in * // the buffer, topicBuffer, for the StartNextPendingJobExecution API. * // Publish to this topic using an MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_startnext] */ JobsStatus_t Jobs_StartNext( char * buffer, size_t length, const char * thingName, uint16_t thingNameLength, size_t * outLength ); /* @[declare_jobs_startnext] */ /** * @brief Populate a message string for a StartNextPendingJobExecution request. * * @param clientToken The device's token * @param clientTokenLength The expected length of the clientToken * @param buffer The buffer to be written to * @param bufferSize The size of the buffer * * @return 0 if write to buffer fails * @return The message length if the write is successful * * <b>Example</b> * @code{c} * * * // The Following Example shows usage of the Jobs_StartNextMsg API * // to generate a message string for a StartNextPendingJobExecution request. * * const char clientToken[] = "test"; * size_t clientTokenLength = ( sizeof( clientToken ) - 1U ); * char messageBuffer[ START_JOB_MSG_LENGTH ] = {0}; * size_t messageLength = 0U; * * messageLength = Jobs_StartNextMsg( clientToken, * clientTokenLength, * messageBuffer, * START_JOB_MSG_LENGTH ); * * if ( messageLength > 0 ) * { * // The message string of the clientToken has been generated in * // the buffer, messageBuffer, for the StartNextPendingJobExecution request * // Publish to the topic string generated by Jobs_StartNext() using an * // MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_startnextmsg] */ size_t Jobs_StartNextMsg( const char * clientToken, size_t clientTokenLength, char * buffer, size_t bufferSize ); /* @[declare_jobs_startnextmsg] */ /** * @brief Populate a topic string for a DescribeJobExecution request. * * @param[in] buffer The buffer to contain the topic string. * @param[in] length The size of the buffer. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[out] jobId The ID of the job to describe. * @param[out] jobIdLength The length of the job ID. * @param[out] outLength The length of the topic string written to the buffer. * * @return #JobsSuccess if the topic was written to the buffer; * #JobsBadParameter if invalid parameters are passed; * #JobsBufferTooSmall if the buffer cannot hold the full topic string. * * When all parameters are valid, the topic string is written to * the buffer up to one less than the buffer size. The topic is * ended with a NUL character. * * @note A jobId consisting of the string, "$next", is supported to generate * a topic string to request the next pending job. * * @note The thingName and jobId parameters do not need a NUL terminator. * * @note The AWS IoT Jobs service does not require clients to subscribe * to the "/accepted" and "/rejected" response topics of the * DescribeJobExecution API. * The Jobs service will send responses to requests published to the API * from clients irrespective of whether they have subscribed to response topics * or not. For more information, refer to the AWS docs here: * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-mqtt-api.html * * <b>Example</b> * @code{c} * * // The following example shows usage of the Jobs_Describe API to * // generate topic string for the DescribeJobExecution API * // of the AWS IoT Jobs service. * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * // The job ID is required to send a status update for a job to the AWS IoT * // Jobs service. * #define JOB_ID "My_Job" * #define JOB_ID_LENGTH ( sizeof( JOB_ID ) - 1U ) * * // This example allocates a buffer of maximum length for a Jobs topic * // possible for the thing name using the JOBS_API_MAX_LENGTH macro. * char topicBuffer[ JOBS_API_MAX_LENGTH( THING_NAME_LENGTH ) ] = { 0 }; * uint16_t topicLength = 0U; * JobsStatus_t status = JobsSuccess; * status = Jobs_Describe( topicBuffer, * sizeof( topicBuffer ), * THING_NAME, * THING_NAME_LENGTH, * JOB_ID, * JOB_ID_LENGTH, * &( topicLength ) ); * * if( status == JobsSuccess ) * { * // The topic string of length, topicLength, has been generated in * // the buffer, topicBuffer, for the DescribeJobExecution API. * // Publish to this topic using an MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_describe] */ JobsStatus_t Jobs_Describe( char * buffer, size_t length, const char * thingName, uint16_t thingNameLength, const char * jobId, uint16_t jobIdLength, size_t * outLength ); /* @[declare_jobs_describe] */ /** * @brief Populate a topic string for an UpdateJobExecution request. * * @param[in] buffer The buffer to contain the topic string. * @param[in] length The size of the buffer. * @param[in] thingName The device's thingName as registered with AWS IoT. * @param[in] thingNameLength The length of the thingName. * @param[out] jobId The ID of the job to describe. * @param[out] jobIdLength The length of the job ID. * @param[out] outLength The length of the topic string written to the buffer. * * @return #JobsSuccess if the topic was written to the buffer; * #JobsBadParameter if invalid parameters are passed; * #JobsBufferTooSmall if the buffer cannot hold the full topic string. * * When all parameters are valid, the topic string is written to * the buffer up to one less than the buffer size. The topic is * ended with a NUL character. * * @note The thingName and jobId parameters do not need a NUL terminator. * * @note The AWS IoT Jobs service does not require clients to subscribe * to the "/accepted" and "/rejected" response topics of the * UpdateJobExecution API. * The Jobs service will send responses to requests published to the API * from clients irrespective of whether they have subscribed to response topics * or not. For more information, refer to the AWS docs here: * https://docs.aws.amazon.com/iot/latest/developerguide/jobs-mqtt-api.html * * <b>Example</b> * @code{c} * * // The following example shows usage of the Jobs_Update API to * // generate topic string for the UpdateJobExecution API * // of the AWS IoT Jobs service. * * // Every device should have a unique thing name registered with AWS IoT Core. * // This example uses a dummy serial number for the thing name. * #define THING_NAME "11223445566" * #define THING_NAME_LENGTH ( sizeof( THING_NAME ) - 1U ) * * // The job ID is required to send a status update for a job to the AWS IoT * // Jobs service. * #define JOB_ID "My_Job" * #define JOB_ID_LENGTH ( sizeof( JOB_ID ) - 1U ) * * // This example allocates a buffer of maximum length for a Jobs topic * // possible for the thing name using the JOBS_API_MAX_LENGTH macro. * char topicBuffer[ JOBS_API_MAX_LENGTH( THING_NAME_LENGTH ) ] = { 0 }; * uint16_t topicLength = 0U; * JobsStatus_t status = JobsSuccess; * status = Jobs_Update( topicBuffer, * sizeof( topicBuffer ), * THING_NAME, * THING_NAME_LENGTH, * JOB_ID, * JOB_ID_LENGTH, * &( topicLength ) ); * * if( status == JobsSuccess ) * { * // The topic string of length, topicLength, has been * // generated in the buffer, topicBuffer, for the UpdateJobExecution API. * // Publish to this topic using an MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_update] */ JobsStatus_t Jobs_Update( char * buffer, size_t length, const char * thingName, uint16_t thingNameLength, const char * jobId, uint16_t jobIdLength, size_t * outLength ); /* @[declare_jobs_update] */ /** * @brief Populate a message string for an UpdateJobExecution request. * * @param request A jobs update request structure. * @param buffer The buffer to be written to. * @param bufferSize the size of the buffer. * * @return 0 if write to buffer fails. * @return messageLength if the write is successful. * * <b>Example</b> * @code{c} * * // The Following Example shows usage of the Jobs_UpdateMsg API to * // generate a message string for the UpdateJobExecution API * // of the AWS IoT Jobs Service. * * const char expectedVersion[] = "2"; * const char statusDetails[] = "{\"key\":\"value\"}"; * char messageBuffer[ UPDATE_JOB_MSG_LENGTH ] = {0}; * size_t messageLength = 0U; * * JobsUpdateRequest_t request; * request.status = Succeeded; * request.expectedVersion = expectedVersion; * request.expectedVersionLength = ( sizeof( expectedVersion ) - 1U ); * request.statusDetails = statusDetails; * request.statusDetailsLength = ( sizeof( statusDetails ) - 1U ); * * messageLength = Jobs_UpdateMsg( request * messageBuffer, * UPDATE_JOB_MSG_LENGTH ); * * if (messageLength > 0 ) * { * // The message string of length, messageLength, has been * // generated in the buffer, messageBuffer, for the UpdateJobExecution API * // Publish this message to the topic generated by Jobs_Update using an * // MQTT client of your choice. * } * @endcode */ /* @[declare_jobs_updatemsg] */ size_t Jobs_UpdateMsg( JobsUpdateRequest_t request, char * buffer, size_t bufferSize ); /* @[declare_jobs_updatemsg] */ /** * @brief Retrieves the job ID from a given message (if applicable) * * @param message [In] A JSON formatted message * @param messageLength [In] The length of the message * @param jobId [Out] The job ID * @return size_t The job ID length * * <b>Example</b> * @code{c} * * // The following example shows the usage of the Jobs_GetJobId API to * // extract the jobId and its length from a message, if present. * * const char * message; // A JSON formatted message from the IoT core * size_t messageLength; // Length of the JSON formatted message * const char * jobId; // variable to hold jobId * size_t jobIdLength = 0U; // Holds length of the jobId * * jobIdLength = Jobs_GetJobId( message, * messageLength, * &jobId); * * if ( jobIdLength > 0 ) * { * // Job ID was successfully extracted from the message * // Store the Job ID so that it can be used as needed by other functions. * // For example, as an input to Jobs_Update. * } * @endcode */ /* @[declare_jobs_getjobid] */ size_t Jobs_GetJobId( const char * message, size_t messageLength, const char ** jobId ); /* @[declare_jobs_getjobid] */ /** * @brief Retrieves the job document from a given message (if applicable) * * @param message [In] A JSON formatted message which * @param messageLength [In] The length of the message * @param jobDoc [Out] The job document * @return size_t The length of the job document * * <b>Example</b> * @code{c} * * // The following example shows the usage of the Jobs_GetJobId API to * // extract the jobId and its length from a message, if present. * * const char * message; // A JSON formatted message from the IoT core * size_t messageLength; // Length of the JSON formatted message * const char * jobDoc; // variable to hold the job doc * size_t jobDocLength = 0U; // Holds length of the job doc * * jobDocLength = Jobs_GetJobDocument( message, * messageLength, * &jobDoc); * * if ( jobDocLength > 0 ) * { * // JobDoc was successfully extracted from the message. * // Pass JobDoc as input to otaParser_parseJobDocFile to * // extract the fields from the job document and store them * // in a AfrOtaJobDocumentFields_t stuct. * } * @endcode */ /* @[declare_jobs_getjobdocument] */ size_t Jobs_GetJobDocument( const char * message, size_t messageLength, const char ** jobDoc ); /* @[declare_jobs_getjobdocument] */ /** * @brief Checks if a message comes from the start-next/accepted reserved topic * * @param topic The topic to check against * @param topicLength The expected topic length * @param thingName The device's thingName as registered with AWS IoT. * @param thingNameLength The length of the thingName. * @return true If the topic is the start-next/accepted topic * @return false If the topic is not the start-next/accepted topic * */ /* @[declare_jobs_isstartnextaccepted] */ bool Jobs_IsStartNextAccepted( const char * topic, const size_t topicLength, const char * thingName, const size_t thingNameLength ); /* @[declare_jobs_isstartnextaccepted] */ /** * @brief Checks if a message comes from the update/accepted reserved topic * * @param topic The topic to check against * @param topicLength The expected topic length * @param jobId Corresponding Job ID which the update was accepted for * @param jobIdLength The Job ID length * @param thingName The device's thingName as registered with AWS IoT. * @param thingNameLength The length of the thingName. * @param expectedStatus The job update status reported by AWS IoT Jobs * @return true If the topic is the update/\<expectedStatus\> topic * @return false If the topic is not the update/\<expectedStatus\> topic */ /* @[declare_jobs_isjobupdatestatus] */ bool Jobs_IsJobUpdateStatus( const char * topic, const size_t topicLength, const char * jobId, const size_t jobIdLength, const char * thingName, const size_t thingNameLength, JobUpdateStatus_t expectedStatus ); /* @[declare_jobs_isjobupdatestatus] */ /* *INDENT-OFF* */ #ifdef __cplusplus } #endif /* *INDENT-ON* */ #endif /* ifndef JOBS_H_ */