Add octet and character string buffer codecs to used with fixed size buffers that are not declared as BACNET_OCTET_STRING or BACNET_CHARACTER_STRING. (#1237)

This commit is contained in:
Steve Karg
2026-02-19 13:52:23 -06:00
committed by GitHub
parent 44b230a068
commit 2874dcea5e
4 changed files with 1261 additions and 58 deletions
+605 -30
View File
@@ -1394,6 +1394,31 @@ int encode_context_null(uint8_t *apdu, uint8_t tag_number)
return encode_tag(apdu, tag_number, true, 0);
}
/**
* @brief Encode the NULL value as application encoded
* From clause 20.2.2 Encoding of a Null Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
*
* @return returns the number of apdu bytes consumed,
* or 0 if apdu_size is too small to fit the data
*/
int bacnet_null_application_encode(uint8_t *apdu, uint32_t apdu_size)
{
int apdu_len = 0; /* total length of the apdu, return value */
apdu_len = encode_application_null(NULL);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = encode_application_null(apdu);
}
return apdu_len;
}
/**
* @brief Decode the NULL value when application encoded
* From clause 20.2.2 Encoding of a Null Value
@@ -2224,6 +2249,283 @@ int encode_application_object_id(
return apdu_len;
}
/**
* @brief Encode the BACnet Octet String value as application tagged
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
* @param apdu - buffer to hold the bytes
* @param buffer - the octet string to be encoded
* @param buffer_size - the size of the octet string to be encoded
* @return returns the number of apdu bytes encoded
*/
int encode_application_octet_string_buffer(
uint8_t *apdu, const uint8_t *buffer, size_t buffer_size)
{
int apdu_len = 0, len = 0, i = 0;
len = encode_tag(
apdu, BACNET_APPLICATION_TAG_OCTET_STRING, false, buffer_size);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (i = 0; i < buffer_size; i++) {
if (apdu && buffer) {
apdu[i] = buffer[i];
}
}
apdu_len += buffer_size;
return apdu_len;
}
/**
* @brief Encode the BACnet Octet String Value as context tagged
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes, or NULL for length
* @param tag_number - context tag number to be encoded
* @param buffer - the octet string to be encoded
* @param buffer_size - the size of the octet string to be encoded
* @return returns the number of apdu bytes encoded
*/
int encode_context_octet_string_buffer(
uint8_t *apdu,
uint8_t tag_number,
const uint8_t *buffer,
size_t buffer_size)
{
int apdu_len = 0, len = 0, i = 0;
len = encode_tag(apdu, tag_number, true, buffer_size);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (i = 0; i < buffer_size; i++) {
if (apdu && buffer) {
apdu[i] = buffer[i];
}
}
apdu_len += buffer_size;
return apdu_len;
}
/**
* @brief Encode an application tagged BACnet Octet String Value
* From clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
* @param value - value to encode
*
* @return returns the number of apdu bytes encoded
* or 0 if apdu_size is too small to fit the data
*/
int bacnet_octet_string_buffer_application_encode(
uint8_t *apdu,
uint32_t apdu_size,
const uint8_t *buffer,
size_t buffer_size)
{
int apdu_len = 0; /* total length of the apdu, return value */
apdu_len =
encode_application_octet_string_buffer(NULL, buffer, buffer_size);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len =
encode_application_octet_string_buffer(apdu, buffer, buffer_size);
}
return apdu_len;
}
/**
* @brief Encode an context tagged BACnet Octet String Value
* From clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
* @param tag_number - context tag number to be encoded
* @param buffer - the octet string to be encoded
* @param buffer_size - the size of the octet string to be encoded
*
* @return returns the number of apdu bytes encoded
* or 0 if apdu_size is too small to fit the data
*/
int bacnet_octet_string_buffer_context_encode(
uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
const uint8_t *buffer,
size_t buffer_size)
{
int apdu_len = 0; /* total length of the apdu, return value */
apdu_len = encode_context_octet_string_buffer(
NULL, tag_number, buffer, buffer_size);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = encode_context_octet_string_buffer(
apdu, tag_number, buffer, buffer_size);
}
return apdu_len;
}
/**
* @brief Decode the BACnet Octet String Value
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes
* @param apdu_size - number of bytes in the buffer to decode
* @param len_value - number of bytes in the octet string value encoding,
* may be zero
* @param buffer - the buffer where the decoded value is stored,
* or NULL for length only.
* @param buffer_size - number of bytes in the buffer where the
* decoded value is stored
*
* @return number of bytes in the octet string value encoding (0..N)
* or BACNET_STATUS_ERROR if malformed
*/
int bacnet_octet_string_buffer_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint32_t len_value,
uint8_t *buffer,
size_t buffer_size)
{
size_t i;
size_t copy_len;
if (len_value > apdu_size) {
/* malformed */
return BACNET_STATUS_ERROR;
}
if (apdu && buffer && buffer_size > 0) {
/* copy only the available octets, up to the buffer size */
copy_len = (len_value < buffer_size) ? (size_t)len_value : buffer_size;
for (i = 0; i < copy_len; i++) {
buffer[i] = apdu[i];
}
/* pad any remaining buffer space with zeros */
for (i = copy_len; i < buffer_size; i++) {
buffer[i] = 0;
}
}
return (int)len_value;
}
/**
* @brief Decodes from bytes into a BACnet Octet String application encoding
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param buffer - the buffer where the decoded value is stored,
* or NULL for length only.
* @param buffer_size - number of bytes in the buffer where the
* decoded value is stored
*
* @return number of bytes decoded, zero if tag mismatch,
* or #BACNET_STATUS_ERROR (-1) if malformed
*/
int bacnet_octet_string_buffer_application_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t *buffer,
size_t buffer_size)
{
int apdu_len = BACNET_STATUS_ERROR;
int len = 0;
BACNET_TAG tag = { 0 };
if (apdu_size == 0) {
return 0;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if (len > 0) {
if (tag.application &&
(tag.number == BACNET_APPLICATION_TAG_OCTET_STRING)) {
apdu_len = len;
len = bacnet_octet_string_buffer_decode(
&apdu[len], apdu_size - apdu_len, tag.len_value_type, buffer,
buffer_size);
if (len >= 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = 0;
}
}
return apdu_len;
}
/**
* @brief Decodes from bytes into a BACnet Octet String application encoding
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes
* @param apdu_size - number of bytes in the buffer to decode
* @param tag_value - context tag number expected
* @param buffer - the buffer where the decoded value is stored,
* or NULL for length only.
* @param buffer_size - number of bytes in the buffer where the
* decoded value is stored
*
* @return number of bytes decoded, or zero if tag mismatch, or
* #BACNET_STATUS_ERROR (-1) if malformed
*/
int bacnet_octet_string_buffer_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_value,
uint8_t *buffer,
size_t buffer_size)
{
int apdu_len = BACNET_STATUS_ERROR;
int len = 0;
BACNET_TAG tag = { 0 };
if (apdu_size == 0) {
return 0;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if (len > 0) {
if (tag.context && (tag.number == tag_value)) {
apdu_len = len;
len = bacnet_octet_string_buffer_decode(
&apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type,
buffer, buffer_size);
if (len >= 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = 0;
}
}
return apdu_len;
}
#if BACNET_USE_OCTETSTRING
/**
* @brief Encode the BACnet Octet String value
@@ -2282,36 +2584,6 @@ int encode_application_octet_string(
return len;
}
/**
* @brief Encode the BACnet Octet String value as application tagged
* from clause 20.2.8 Encoding of an Octet String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
* @param apdu - buffer to hold the bytes
* @param buffer - the octet string to be encoded
* @param buffer_size - the size of the octet string to be encoded
* @return returns the number of apdu bytes encoded
*/
int encode_application_octet_string_buffer(
uint8_t *apdu, const uint8_t *buffer, size_t buffer_size)
{
int apdu_len = 0, len = 0, i = 0;
len = encode_tag(
apdu, BACNET_APPLICATION_TAG_OCTET_STRING, false, buffer_size);
apdu_len += len;
if (apdu) {
apdu += len;
}
for (i = 0; i < buffer_size; i++) {
if (apdu && buffer) {
apdu[i] = buffer[i];
}
}
apdu_len += buffer_size;
return apdu_len;
}
/**
* @brief Encode the BACnet Octet String Value as context tagged
* from clause 20.2.8 Encoding of an Octet String Value
@@ -2881,6 +3153,309 @@ int decode_context_character_string(
return len;
}
/**
* @brief Encode the BACnet Character String Value
* from 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes
* @param value - the BACnetCharacterString buffer value to be encoded
*
* @return returns the number of apdu bytes consumed, or 0 if too large
*/
uint32_t encode_bacnet_character_string_buffer(
uint8_t *apdu, const BACNET_CHARACTER_STRING_BUFFER *value)
{
uint32_t apdu_len = 1 /*encoding */;
uint32_t i;
if (!value || !value->buffer) {
return 0;
}
if (value->buffer_length > value->buffer_size) {
return 0;
}
if (apdu) {
apdu[0] = value->encoding;
for (i = 0; i < value->buffer_length; i++) {
apdu[1 + i] = value->buffer[i];
}
}
apdu_len += value->buffer_length;
return apdu_len;
}
/**
* @brief Encode the BACnet Character String Value as context tagged
* from 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes, or NULL for length
* @param tag_number - context tag number to encode
* @param char_string - the BACnet Character String to be encoded
*
* @return returns the number of apdu bytes consumed
*/
int encode_context_character_string_buffer(
uint8_t *apdu,
uint8_t tag_number,
const BACNET_CHARACTER_STRING_BUFFER *char_string)
{
int apdu_len = 0;
int len = 0;
uint32_t tag_len;
tag_len = encode_bacnet_character_string_buffer(NULL, char_string);
if (tag_len == 0) {
/* malformed, cannot be zero */
return 0;
}
len = encode_tag(apdu, tag_number, true, tag_len);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_bacnet_character_string_buffer(apdu, char_string);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode the BACnet Character String Value as application tagged
* from 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes, or NULL for length
* @param char_string - the BACnet Character String to be encoded
*
* @return returns the number of apdu bytes consumed
*/
int encode_application_character_string_buffer(
uint8_t *apdu, const BACNET_CHARACTER_STRING_BUFFER *char_string)
{
int apdu_len = 0;
int len = 0;
uint32_t tag_len;
tag_len = encode_bacnet_character_string_buffer(NULL, char_string);
len = encode_tag(
apdu, BACNET_APPLICATION_TAG_CHARACTER_STRING, false, tag_len);
apdu_len += len;
if (apdu) {
apdu += len;
}
len = encode_bacnet_character_string_buffer(apdu, char_string);
apdu_len += len;
return apdu_len;
}
/**
* @brief Encode the BACnet Character String Value as application tagged
* from 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
* @param value - the BACnet Character String to be encoded
*
* @return returns the number of apdu bytes encoded
* or 0 if apdu_size is too small to fit the data
*/
int bacnet_character_string_buffer_application_encode(
uint8_t *apdu,
uint32_t apdu_size,
const BACNET_CHARACTER_STRING_BUFFER *value)
{
int apdu_len = 0; /* total length of the apdu, return value */
apdu_len = encode_application_character_string_buffer(NULL, value);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len = encode_application_character_string_buffer(apdu, value);
}
return apdu_len;
}
/**
* @brief Encode the BACnet Character String Value as context tagged
* from 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the data to be encoded, or NULL for length
* @param apdu_size - number of bytes in the buffer
* @param tag_number - context tag number to be encoded
* @param value - the BACnet Character String to be encoded
*
* @return returns the number of apdu bytes encoded
* or 0 if apdu_size is too small to fit the data
*/
int bacnet_character_string_buffer_context_encode(
uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
const BACNET_CHARACTER_STRING_BUFFER *value)
{
int apdu_len = 0; /* total length of the apdu, return value */
apdu_len = encode_context_character_string_buffer(NULL, tag_number, value);
if (apdu_len > apdu_size) {
apdu_len = 0;
} else {
apdu_len =
encode_context_character_string_buffer(apdu, tag_number, value);
}
return apdu_len;
}
/**
* @brief Decodes from bytes into a BACnet Character String value
* from clause 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes
* @param apdu_size - number of bytes in the buffer to decode
* @param len_value - number of bytes in the unsigned value encoding
* @param value - the BACnetCharacterString buffer value to be encoded
*
* @return number of bytes decoded, or zero if malformed or APDU overflow.
* String size overflow is detectable by the caller by comparing the
* buffer size to the buffer length in the value.
*/
int bacnet_character_string_buffer_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint32_t len_value,
BACNET_CHARACTER_STRING_BUFFER *value)
{
const char *string_value = NULL;
uint32_t string_length = 0;
int len = 0, i = 0;
uint8_t encoding = 0;
if ((len_value > apdu_size) || (len_value == 0)) {
/* malformed */
return 0;
}
encoding = apdu[0];
if (len_value > 1) {
string_length = len_value - 1;
}
if (value) {
value->encoding = encoding;
value->buffer_length = string_length;
if (value->buffer) {
string_value = (const char *)&apdu[1];
for (i = 0; i < value->buffer_size; i++) {
if (i < string_length) {
value->buffer[i] = string_value[i];
} else {
/* pad buffer */
value->buffer[i] = 0;
}
}
}
}
len = (int)len_value;
return len;
}
/**
* @brief Decodes from bytes into a BACnet Character String value
* from clause 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer of data to be decoded
* @param apdu_size - number of bytes in the buffer
* @param value - the BACnetCharacterString buffer value to be decoded
*
* @return number of bytes decoded, zero if tag mismatch,
* or #BACNET_STATUS_ERROR (-1) if malformed
*/
int bacnet_character_string_buffer_application_decode(
const uint8_t *apdu,
uint32_t apdu_size,
BACNET_CHARACTER_STRING_BUFFER *value)
{
int apdu_len = BACNET_STATUS_ERROR;
int len = 0;
BACNET_TAG tag = { 0 };
if (apdu_size == 0) {
return 0;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if (len > 0) {
if (tag.application &&
(tag.number == BACNET_APPLICATION_TAG_CHARACTER_STRING)) {
apdu_len = len;
len = bacnet_character_string_buffer_decode(
&apdu[len], apdu_size - apdu_len, tag.len_value_type, value);
if (len > 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = 0;
}
}
return apdu_len;
}
/**
* @brief Decodes from bytes into a BACnet Character String value
* from clause 20.2.9 Encoding of a Character String Value
* and 20.2.1 General Rules for Encoding BACnet Tags
*
* @param apdu - buffer to hold the bytes
* @param apdu_size - number of bytes in the buffer to decode
* @param tag_value - context tag number expected
* @param value - the BACnetCharacterString buffer value to be decoded
*
* @return number of bytes decoded, or zero if tag mismatch, or
* #BACNET_STATUS_ERROR (-1) if malformed
*/
int bacnet_character_string_buffer_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_value,
BACNET_CHARACTER_STRING_BUFFER *value)
{
int apdu_len = BACNET_STATUS_ERROR;
int len = 0;
BACNET_TAG tag = { 0 };
if (apdu_size == 0) {
return 0;
}
len = bacnet_tag_decode(apdu, apdu_size, &tag);
if (len > 0) {
if (tag.context && (tag.number == tag_value)) {
apdu_len = len;
len = bacnet_character_string_buffer_decode(
&apdu[apdu_len], apdu_size - apdu_len, tag.len_value_type,
value);
if (len > 0) {
apdu_len += len;
} else {
apdu_len = BACNET_STATUS_ERROR;
}
} else {
apdu_len = 0;
}
}
return apdu_len;
}
/**
* @brief Decodes from bytes into a BACnet Unsigned value
* from clause 20.2.4 Encoding of an Unsigned Integer Value
+98 -3
View File
@@ -86,6 +86,19 @@ typedef struct BACnetTag {
uint32_t len_value_type;
} BACNET_TAG;
typedef struct BACnetCharacterStringBuffer {
uint8_t encoding;
char *buffer;
size_t buffer_size;
uint32_t buffer_length;
} BACNET_CHARACTER_STRING_BUFFER;
typedef struct BACnetOctetStringBuffer {
uint8_t *buffer;
size_t buffer_size;
uint32_t buffer_length;
} BACNET_OCTET_STRING_BUFFER;
/* max size of a BACnet tag */
#define BACNET_TAG_SIZE 7
@@ -183,6 +196,8 @@ int encode_application_null(uint8_t *apdu);
BACNET_STACK_EXPORT
int encode_context_null(uint8_t *apdu, uint8_t tag_number);
BACNET_STACK_EXPORT
int bacnet_null_application_encode(uint8_t *apdu, uint32_t apdu_size);
BACNET_STACK_EXPORT
int bacnet_null_application_decode(const uint8_t *apdu, uint32_t apdu_size);
BACNET_STACK_EXPORT
int bacnet_null_context_decode(
@@ -384,15 +399,55 @@ bool bacnet_object_id_same(
BACNET_OBJECT_TYPE object_type2,
uint32_t instance2);
BACNET_STACK_EXPORT
int encode_application_octet_string_buffer(
uint8_t *apdu, const uint8_t *buffer, size_t buffer_size);
BACNET_STACK_EXPORT
int encode_context_octet_string_buffer(
uint8_t *apdu,
uint8_t tag_number,
const uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int bacnet_octet_string_buffer_application_encode(
uint8_t *apdu,
uint32_t apdu_size,
const uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int bacnet_octet_string_buffer_context_encode(
uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
const uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int bacnet_octet_string_buffer_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint32_t len_value,
uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int bacnet_octet_string_buffer_application_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int bacnet_octet_string_buffer_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_value,
uint8_t *buffer,
size_t buffer_size);
BACNET_STACK_EXPORT
int encode_octet_string(uint8_t *apdu, const BACNET_OCTET_STRING *octet_string);
BACNET_STACK_EXPORT
int encode_application_octet_string(
uint8_t *apdu, const BACNET_OCTET_STRING *octet_string);
BACNET_STACK_EXPORT
int encode_application_octet_string_buffer(
uint8_t *apdu, const uint8_t *buffer, size_t buffer_size);
BACNET_STACK_EXPORT
int encode_context_octet_string(
uint8_t *apdu, uint8_t tag_number, const BACNET_OCTET_STRING *octet_string);
BACNET_STACK_EXPORT
@@ -431,6 +486,46 @@ uint32_t encode_bacnet_character_string_safe(
const char *pString,
uint32_t length);
BACNET_STACK_EXPORT
uint32_t encode_bacnet_character_string_buffer(
uint8_t *apdu, const BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int encode_context_character_string_buffer(
uint8_t *apdu,
uint8_t tag_number,
const BACNET_CHARACTER_STRING_BUFFER *char_string);
BACNET_STACK_EXPORT
int encode_application_character_string_buffer(
uint8_t *apdu, const BACNET_CHARACTER_STRING_BUFFER *char_string);
BACNET_STACK_EXPORT
int bacnet_character_string_buffer_application_encode(
uint8_t *apdu,
uint32_t apdu_size,
const BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int bacnet_character_string_buffer_context_encode(
uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_number,
const BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int bacnet_character_string_buffer_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint32_t len_value,
BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int bacnet_character_string_buffer_application_decode(
const uint8_t *apdu,
uint32_t apdu_size,
BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int bacnet_character_string_buffer_context_decode(
const uint8_t *apdu,
uint32_t apdu_size,
uint8_t tag_value,
BACNET_CHARACTER_STRING_BUFFER *value);
BACNET_STACK_EXPORT
int encode_bacnet_character_string(
uint8_t *apdu, const BACNET_CHARACTER_STRING *char_string);
BACNET_STACK_EXPORT