From 3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Thu, 23 Aug 2018 17:08:59 +0200 Subject: o Initial import. --- .../components/iot/coap/coap_message.c | 804 +++++++++++++++++++++ 1 file changed, 804 insertions(+) create mode 100644 thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c') diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c new file mode 100644 index 0000000..db0f7bf --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/coap/coap_message.c @@ -0,0 +1,804 @@ +/** + * Copyright (c) 2014 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include + +#include "nordic_common.h" +#include "coap_message.h" +#include "coap_api.h" +#include "iot_common.h" +#include "sdk_config.h" +#include "app_util.h" + +#define COAP_PAYLOAD_MARKER_SIZE 1 + +/**@brief Verify that there is a index available for a new option. */ +#define OPTION_INDEX_AVAIL_CHECK(COUNT) \ + if ((COUNT) >= COAP_MAX_NUMBER_OF_OPTIONS) \ + { \ + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); \ + } + +#if (COAP_DISABLE_API_PARAM_CHECK == 0) + +/**@brief Verify NULL parameters are not passed to API by application. */ +#define NULL_PARAM_CHECK(PARAM) \ + if ((PARAM) == NULL) \ + { \ + return (NRF_ERROR_NULL | IOT_COAP_ERR_BASE); \ + } +#else + +#define NULL_PARAM_CHECK(PARAM) +#define OPTION_INDEX_AVAIL_CHECK(COUNT) + +#endif // COAP_DISABLE_API_PARAM_CHECK + +uint32_t coap_message_create(coap_message_t * p_message, coap_message_conf_t * p_init_config) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_init_config); + + // Setting default value for version. + p_message->header.version = COAP_VERSION; + + // Copy values from the init config. + p_message->header.type = p_init_config->type; + p_message->header.token_len = p_init_config->token_len; + p_message->header.code = p_init_config->code; + p_message->header.id = p_init_config->id; + p_message->response_callback = p_init_config->response_callback; + p_message->p_arg = NULL; + + if (p_init_config->port.port_number == 0) + { + return (NRF_ERROR_INVALID_PARAM | IOT_COAP_ERR_BASE); + } + memcpy(&p_message->port, &p_init_config->port, sizeof(coap_port_t)); + + memcpy(p_message->token, p_init_config->token, sizeof(p_init_config->token)); + return NRF_SUCCESS; +} + +/**@brief Decode CoAP option + * + * @param[in] p_raw_option Pointer to the memory buffer where the raw option is located. + * @param[inout] p_message Pointer to the current message. Used to retrieve information about + * where current option delta and the size of free memory to add the + * values of the option. Used as a container where to put + * the parsed option. + * @param[out] byte_count Number of bytes parsed. Used to indicate where the next option + * might be located (if any left) in the raw message buffer. + * + * @retval NRF_SUCCESS If the option parsing went successful. + * @retval NRF_ERROR_DATA_SIZE If there is no more space left in the free memory to add the + * option value to the p_message. + */ +static uint32_t decode_option(const uint8_t * p_raw_option, coap_message_t * p_message, uint16_t * byte_count) +{ + uint16_t byte_index = 0; + uint8_t option_num = p_message->options_count; + + // Calculate the option number. + uint16_t option_delta = (p_raw_option[byte_index] & 0xF0) >> 4; + // Calculate the option length. + uint16_t option_length = (p_raw_option[byte_index] & 0x0F); + byte_index++; + + uint16_t acc_option_delta = p_message->options_delta; + + if (option_delta == 13) + { + // read one additional byte to get the extended delta. + acc_option_delta += 13 + p_raw_option[byte_index++]; + + } + else if (option_delta == 14) + { + // read one additional byte to get the extended delta. + acc_option_delta += 269; + acc_option_delta += (p_raw_option[byte_index++] << 8); + acc_option_delta += (p_raw_option[byte_index++]); + } + else + { + acc_option_delta += option_delta; + } + + // Set the accumlated delta as the option number. + p_message->options[option_num].number = acc_option_delta; + + if (option_length == 13) + { + option_length = 13 + p_raw_option[byte_index++]; + } + else if (option_length == 14) + { + option_length = 269; + option_length += (p_raw_option[byte_index++] << 8); + option_length += p_raw_option[byte_index++]; + } + + // Set the option length including extended bytes. + p_message->options[option_num].length = option_length; + + // Point p_data to the memory where to find the option value. + p_message->options[option_num].p_data = (uint8_t *)&p_raw_option[byte_index]; + + // Update the delta counter with latest option number. + p_message->options_delta = p_message->options[option_num].number; + + byte_index += p_message->options[option_num].length; + *byte_count = byte_index; + + return NRF_SUCCESS; +} + + +/**@brief Encode CoAP option delta and length bytes. + * + * @param[inout] encoded_value Value to encode. In return the value after encoding. + * @param[out] encoded_value_ext The value of the encoded extended bytes. + * + * @return The size of the extended byte field. + */ +static inline uint8_t encode_extended_bytes(uint16_t * value, + uint16_t * value_ext) +{ + uint16_t raw_value = *value; + + uint8_t ext_size = 0; + + if (raw_value >= 269) + { + *value = 14; + *value_ext = raw_value - 269; + ext_size = 2; + } + else if (raw_value >= 13) + { + *value = 13; + *value_ext = raw_value - 13; + ext_size = 1; + } + else + { + *value = raw_value; + *value_ext = 0; + } + + return ext_size; +} + + +static uint32_t encode_option(uint8_t * p_buffer, coap_option_t * p_option, uint16_t * byte_count) +{ + uint16_t delta_ext = 0; + uint16_t delta = p_option->number; + + uint8_t delta_ext_size = encode_extended_bytes(&delta, + &delta_ext); + + uint16_t length = p_option->length; + uint16_t length_ext = 0; + + uint8_t length_ext_size = encode_extended_bytes(&length, + &length_ext); + + if (p_buffer == NULL) + { + uint16_t header_size = 1; + *byte_count = header_size + delta_ext_size + length_ext_size + p_option->length; + return NRF_SUCCESS; + } + + uint16_t byte_index = 0; + + // Add the option header. + p_buffer[byte_index++] = ((delta & 0x0F) << 4) | (length & 0x0F); + + // Add option delta extended bytes to the buffer. + if (delta_ext_size == 1) + { + // Add first byte of delta_ext to the option header. + p_buffer[byte_index++] = (uint8_t)delta_ext; + } + else if (delta_ext_size == 2) + { + // uint16 in Network Byte Order. + p_buffer[byte_index++] = (uint8_t)((delta_ext & 0xFF00) >> 8); + p_buffer[byte_index++] = (uint8_t)((delta_ext & 0x00FF)); + } + + if (length_ext_size == 1) + { + // Add first byte of length_ext to the option header. + p_buffer[byte_index++] = (uint8_t)length_ext; + } + else if (length_ext_size == 2) + { + // uint16 in Network Byte Order. + p_buffer[byte_index++] = (uint8_t)((length_ext & 0xFF00) >> 8); + p_buffer[byte_index++] = (uint8_t)((length_ext & 0x00FF)); + } + + memcpy(&p_buffer[byte_index], p_option->p_data, p_option->length); + *byte_count = byte_index + p_option->length; + + return NRF_SUCCESS; +} + +uint32_t coap_message_decode(coap_message_t * p_message, + const uint8_t * p_raw_message, + uint16_t message_len) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_raw_message); + + // Check that the raw message contains the mandatory header. + if (message_len < 4) + { + return (NRF_ERROR_INVALID_LENGTH | IOT_COAP_ERR_BASE); + } + + // Parse the content of the raw message buffer. + uint16_t byte_index = 0; + + // Parse the 4 byte CoAP header. + p_message->header.version = (p_raw_message[byte_index] >> 6); + p_message->header.type = (coap_msg_type_t)((p_raw_message[byte_index] >> 4) & 0x03); + p_message->header.token_len = (p_raw_message[byte_index] & 0x0F); + byte_index++; + + p_message->header.code = (coap_msg_code_t)p_raw_message[byte_index]; + byte_index++; + + p_message->header.id = p_raw_message[byte_index++] << 8; + p_message->header.id += p_raw_message[byte_index++]; + + // Parse the token, if any. + for (uint8_t index = 0; (byte_index < message_len) && (index < p_message->header.token_len); index++) + { + p_message->token[index] = p_raw_message[byte_index++]; + } + + p_message->options_count = 0; + p_message->options_delta = 0; + + // Parse the options if any. + while ((byte_index < message_len) && (p_raw_message[byte_index] != COAP_PAYLOAD_MARKER)) + { + + uint32_t err_code; + uint16_t byte_count = 0; + + err_code = decode_option(&p_raw_message[byte_index], p_message, &byte_count); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + p_message->options_count += 1; + + byte_index += byte_count; + } + + // If there any more bytes to parse this would be the payload. + if (byte_index < message_len) + { + // Verify that we have a payload marker. + if (p_raw_message[byte_index] == COAP_PAYLOAD_MARKER) + { + byte_index++; + } + else + { + return COAP_MESSAGE_INVALID_CONTENT; + } + + p_message->payload_len = message_len - byte_index; + p_message->p_payload = (uint8_t *)&p_raw_message[byte_index]; + } + + return NRF_SUCCESS; +} + + +uint32_t coap_message_encode(coap_message_t * p_message, + uint8_t * p_buffer, + uint16_t * p_length) +{ + NULL_PARAM_CHECK(p_length); + NULL_PARAM_CHECK(p_message); + + // calculated size + uint16_t total_packet_size = 4; + + if (p_message->payload_len > 0) + { + total_packet_size += p_message->payload_len; + total_packet_size += COAP_PAYLOAD_MARKER_SIZE; + } + + if (p_message->header.token_len > 8) + { + return (NRF_ERROR_INVALID_DATA | IOT_COAP_ERR_BASE); + } + total_packet_size += p_message->header.token_len; + total_packet_size += p_message->options_len; + + // If this was a length check, return after setting the length in the output parameter. + if (*p_length == 0) + { + *p_length = total_packet_size; + return NRF_SUCCESS; + } + + // Check that the buffer provided is sufficient. + if (*p_length < total_packet_size) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + if (((p_message->payload_len > 0 && p_message->p_payload == NULL)) || + (p_buffer == NULL)) + { + return COAP_MESSAGE_ERROR_NULL; + } + + // Start filling the bytes. + uint16_t byte_index = 0; + + // TODO: Verify the values of the header fields. + // if (version > 1) + // if (p_message->type > COAP_TYPE_RST) + // if (p_message->token_len > 8) + + + p_buffer[byte_index] = (((p_message->header.version & 0x3) << 6) | ((p_message->header.type & 0x3) << 4)) | (p_message->header.token_len & 0x0F); + byte_index++; + + p_buffer[byte_index] = p_message->header.code; + byte_index++; + + p_buffer[byte_index++] = (p_message->header.id & 0xFF00) >> 8; + p_buffer[byte_index++] = (p_message->header.id & 0x00FF); + + memcpy(&p_buffer[byte_index], p_message->token, p_message->header.token_len); + byte_index += p_message->header.token_len; + + //memcpy(&p_buffer[byte_index], &p_message->p_data[0], p_message->options_len); + for (uint8_t i = 0; i < p_message->options_count; i++) + { + uint32_t err_code; + + uint16_t byte_count = 0; + err_code = encode_option(&p_buffer[byte_index], &p_message->options[i], &byte_count); + if (err_code == NRF_SUCCESS) + { + byte_index += byte_count; + } + else + { + // Throw an error. + } + } + + if (p_message->payload_len > 0 && p_message->p_payload != NULL) + { + p_buffer[byte_index++] = 0xFF; + memcpy(&p_buffer[byte_index], p_message->p_payload, p_message->payload_len); + } + + *p_length = total_packet_size; + + return NRF_SUCCESS; +} + +uint32_t coap_message_opt_empty_add(coap_message_t * p_message, uint16_t option_num) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + uint16_t encoded_len = 0; + uint8_t current_option_index = p_message->options_count; + + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + + return err_code; +} + +uint32_t coap_message_opt_uint_add(coap_message_t * p_message, + uint16_t option_num, + uint32_t data) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + uint16_t encoded_len = p_message->data_len - p_message->options_offset; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + // If the value of the option is 0, do not encode the 0, as this can be omitted. (RFC7252 3.2) + if (data == 0) + { + encoded_len = 0; + } + else + { + err_code = coap_opt_uint_encode(p_next_option_data, &encoded_len, data); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + } + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size. + uint16_t option_byte_count = 0; + + // Do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + + // Increase the pointer offset for the next option data in the scratch buffer. + p_message->options_offset += encoded_len; + + return err_code; +} + +uint32_t coap_message_opt_str_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + uint32_t err_code; + + uint16_t encoded_len = length; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + + err_code = coap_opt_string_encode(p_next_option_data, &encoded_len, p_data, length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + p_message->options_offset += encoded_len; + + return err_code; + +} + +uint32_t coap_message_opt_opaque_add(coap_message_t * p_message, uint16_t option_num, uint8_t * p_data, uint16_t length) +{ + OPTION_INDEX_AVAIL_CHECK(p_message->options_count); + + // Check if it is possible to add a new option of this length. + if ((p_message->data_len - p_message->options_offset) < length) + { + return (NRF_ERROR_DATA_SIZE | IOT_COAP_ERR_BASE); + } + + uint32_t err_code = NRF_SUCCESS; + + uint16_t encoded_len = length; + uint8_t current_option_index = p_message->options_count; + uint8_t * p_next_option_data = &p_message->p_data[p_message->options_offset]; + + + memcpy(p_next_option_data, p_data, encoded_len); + + p_message->options[current_option_index].p_data = p_next_option_data; + p_message->options[current_option_index].number = option_num - p_message->options_delta; + p_message->options[current_option_index].length = encoded_len; + + // Set accumulated option delta for next option. + p_message->options_delta = option_num; + + // Calculate option size + uint16_t option_byte_count = 0; + + // do a length check to encode_option to get the header length. + err_code = encode_option(NULL, &p_message->options[current_option_index], &option_byte_count); + + // Accumulate expected size of all options with headers. + p_message->options_len += option_byte_count; + + p_message->options_count += 1; + p_message->options_offset += encoded_len; + + return err_code; +} + +uint32_t coap_message_payload_set(coap_message_t * p_message, + void * p_payload, + uint16_t payload_len) +{ + // Check that there is available memory in the p_message->p_data scratch buffer. + if (payload_len > (COAP_MESSAGE_DATA_MAX_SIZE - p_message->options_offset)) + { + return (NRF_ERROR_NO_MEM | IOT_COAP_ERR_BASE); + } + + p_message->p_payload = &p_message->p_data[p_message->options_offset]; + p_message->payload_len = payload_len; + memcpy(p_message->p_payload, p_payload, payload_len); + + return NRF_SUCCESS; +} + + +uint32_t coap_message_remote_addr_set(coap_message_t * p_message, coap_remote_t * p_address) +{ + memcpy(&p_message->remote, p_address, sizeof(coap_remote_t)); + return NRF_SUCCESS; +} + +uint32_t coap_message_opt_index_get(uint8_t * p_index, coap_message_t * p_message, uint16_t option) +{ + NULL_PARAM_CHECK(p_index); + NULL_PARAM_CHECK(p_message); + + uint8_t index; + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == option) + { + *p_index = index; + return NRF_SUCCESS; + } + } + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +uint32_t coap_message_opt_present(coap_message_t * p_message, uint16_t option) +{ + NULL_PARAM_CHECK(p_message); + + uint8_t index; + for (index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == option) + { + return NRF_SUCCESS; + } + } + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); +} + +static uint32_t bit_to_content_format(coap_content_type_t * p_ct, uint32_t bit) +{ + switch (bit) + { + case COAP_CT_MASK_PLAIN_TEXT: + *p_ct = COAP_CT_PLAIN_TEXT; + break; + + case COAP_CT_MASK_APP_LINK_FORMAT: + *p_ct = COAP_CT_APP_LINK_FORMAT; + break; + + case COAP_CT_MASK_APP_XML: + *p_ct = COAP_CT_APP_XML; + break; + + case COAP_CT_MASK_APP_OCTET_STREAM: + *p_ct = COAP_CT_APP_OCTET_STREAM; + break; + + case COAP_CT_MASK_APP_EXI: + *p_ct = COAP_CT_APP_EXI; + break; + + case COAP_CT_MASK_APP_JSON: + *p_ct = COAP_CT_APP_JSON; + break; + + default: + return (NRF_ERROR_NOT_FOUND | IOT_COAP_ERR_BASE); + } + return NRF_SUCCESS; +} + +static uint32_t content_format_to_bit(coap_content_type_t ct) +{ + uint32_t mask = 0; + switch (ct) + { + case COAP_CT_PLAIN_TEXT: + mask = COAP_CT_MASK_PLAIN_TEXT; + break; + + case COAP_CT_APP_LINK_FORMAT: + mask = COAP_CT_MASK_APP_LINK_FORMAT; + break; + + case COAP_CT_APP_XML: + mask = COAP_CT_MASK_APP_XML; + break; + + case COAP_CT_APP_OCTET_STREAM: + mask = COAP_CT_MASK_APP_OCTET_STREAM; + break; + + case COAP_CT_APP_EXI: + mask = COAP_CT_MASK_APP_EXI; + break; + + case COAP_CT_APP_JSON: + mask = COAP_CT_MASK_APP_JSON; + break; + + default: + break; + } + + return mask; +} + +uint32_t coap_message_ct_mask_get(coap_message_t * p_message, uint32_t * p_mask) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_mask); + + (*p_mask) = 0; + + for (uint8_t index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_CONTENT_FORMAT) + { + uint32_t value; + uint32_t err_code = coap_opt_uint_decode(&value, + p_message->options[index].length, + p_message->options[index].p_data); + if (err_code == NRF_SUCCESS) + { + coap_content_type_t ct = (coap_content_type_t)value; + *p_mask |= content_format_to_bit(ct); + } + else + { + return err_code; + } + } + } + return NRF_SUCCESS; +} + +uint32_t coap_message_accept_mask_get(coap_message_t * p_message, uint32_t * p_mask) +{ + NULL_PARAM_CHECK(p_message); + NULL_PARAM_CHECK(p_mask); + + (*p_mask) = 0; + + for (uint8_t index = 0; index < p_message->options_count; index++) + { + if (p_message->options[index].number == COAP_OPT_ACCEPT) + { + uint32_t value; + uint32_t err_code = coap_opt_uint_decode(&value, + p_message->options[index].length, + p_message->options[index].p_data); + if (err_code == NRF_SUCCESS) + { + coap_content_type_t ct = (coap_content_type_t)value; + (*p_mask) |= content_format_to_bit(ct); + } + else + { + return err_code; + } + } + } + + return NRF_SUCCESS; +} + +uint32_t coap_message_ct_match_select(coap_content_type_t * p_ct, coap_message_t * p_message, coap_resource_t * p_resource) +{ + // Check ACCEPT options + uint32_t accept_mask = 0; + (void)coap_message_accept_mask_get(p_message, &accept_mask); + + if (accept_mask == 0) + { + // Default to plain text if option not set. + accept_mask = COAP_CT_MASK_PLAIN_TEXT; + } + + // Select the first common content-type between the resource and the CoAP client. + uint32_t common_ct = p_resource->ct_support_mask & accept_mask; + uint32_t bit_index; + for (bit_index = 0; bit_index < 32; bit_index++) + { + if (((common_ct >> bit_index) & 0x1 ) == 1) + { + break; + } + } + + uint32_t err_code = bit_to_content_format(p_ct, 1 << bit_index); + + return err_code; +} -- cgit v1.2.3