/** * @file * @brief BACnet error encode and decode helper functions * @author Steve Karg * @date 2005 * @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ #include /* BACnet Stack defines - first */ #include "bacnet/bacdef.h" /* BACnet Stack API */ #include "bacnet/bacdcode.h" #include "bacnet/bacerror.h" /** @file bacerror.c Encode/Decode BACnet Errors */ /** * @brief Encodes BACnet Error class and code values into a PDU * From clause 21. FORMAL DESCRIPTION OF APPLICATION PROTOCOL DATA UNITS * * Error ::= SEQUENCE { * -- NOTE: The valid combinations of error-class and error-code * -- are defined in Clause 18. * error-class ENUMERATED, * error-code ENUMERATED * } * * @param apdu - buffer for the data to be encoded, or NULL for length * @param invoke_id - invokeID to be encoded * @param service - BACnet service to be encoded * @param error_class - #BACNET_ERROR_CLASS value to be encoded * @param error_code - #BACNET_ERROR_CODE value to be encoded * @return number of bytes encoded */ int bacerror_encode_apdu( uint8_t *apdu, uint8_t invoke_id, BACNET_CONFIRMED_SERVICE service, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code) { /* length of the specific element of the PDU */ int len = 0; /* total length of the apdu, return value */ int apdu_len = 0; if (apdu) { apdu[0] = PDU_TYPE_ERROR; apdu[1] = invoke_id; apdu[2] = service; } len = 3; apdu_len = len; if (apdu) { apdu += len; } /* service parameters */ len = encode_application_enumerated(apdu, error_class); apdu_len += len; if (apdu) { apdu += len; } len = encode_application_enumerated(apdu, error_code); apdu_len += len; return apdu_len; } #if !BACNET_SVC_SERVER /** * @brief Decodes from bytes a BACnet Error service APDU * From clause 21. FORMAL DESCRIPTION OF APPLICATION PROTOCOL DATA UNITS * * Error ::= SEQUENCE { * -- NOTE: The valid combinations of error-class and error-code * -- are defined in Clause 18. * error-class ENUMERATED, * error-code ENUMERATED * } * * @param apdu - buffer of data to be decoded * @param apdu_size - number of bytes in the buffer * @param error_class - decoded #BACNET_ERROR_CLASS value * @param error_code - decoded #BACNET_ERROR_CODE value * * @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed */ int bacerror_decode_error_class_and_code( const uint8_t *apdu, unsigned apdu_size, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { int apdu_len = 0; int tag_len = 0; uint32_t decoded_value = 0; if (apdu) { /* error class */ tag_len = bacnet_enumerated_application_decode( &apdu[apdu_len], apdu_size - apdu_len, &decoded_value); if (tag_len <= 0) { return BACNET_STATUS_ERROR; } if (error_class) { *error_class = (BACNET_ERROR_CLASS)decoded_value; } apdu_len += tag_len; /* error code */ tag_len = bacnet_enumerated_application_decode( &apdu[apdu_len], apdu_size - apdu_len, &decoded_value); if (tag_len <= 0) { return BACNET_STATUS_ERROR; } if (error_code) { *error_code = (BACNET_ERROR_CODE)decoded_value; } apdu_len += tag_len; } return apdu_len; } /** * @brief Decodes from bytes a BACnet Error service * @param apdu - buffer of data to be decoded * @param apdu_size - number of bytes in the buffer * @param invoke_id - decoded invokeID * @param service - decoded BACnet service * @param error_class - decoded #BACNET_ERROR_CLASS value * @param error_code - decoded #BACNET_ERROR_CODE value * * @return number of bytes decoded, or #BACNET_STATUS_ERROR (-1) if malformed */ int bacerror_decode_service_request( const uint8_t *apdu, unsigned apdu_size, uint8_t *invoke_id, BACNET_CONFIRMED_SERVICE *service, BACNET_ERROR_CLASS *error_class, BACNET_ERROR_CODE *error_code) { int apdu_len = BACNET_STATUS_ERROR; int len = 0; if (apdu && (apdu_size > 2)) { if (invoke_id) { *invoke_id = apdu[0]; } if (service) { *service = (BACNET_CONFIRMED_SERVICE)apdu[1]; } len = 2; apdu_len = len; /* decode the application class and code */ len = bacerror_decode_error_class_and_code( &apdu[apdu_len], apdu_size - apdu_len, error_class, error_code); if (len > 0) { apdu_len += len; } else { apdu_len = BACNET_STATUS_ERROR; } } return apdu_len; } #endif