Feature/writepropertymultiple error handler (#289)
* Added extended BACnet Error PDU handling for WPM * Added BACnetObjectPropertyReference to bacapp module. * Added unit testing for BACnetObjectPropertyReference Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+17
-1
@@ -99,6 +99,21 @@ static void MyErrorHandler(BACNET_ADDRESS *src,
|
||||
/* Error_Detected = true; */
|
||||
}
|
||||
|
||||
/* complex error reply function */
|
||||
static void MyPrivateTransferErrorHandler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t service_choice,
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len)
|
||||
{
|
||||
(void)src;
|
||||
(void)invoke_id;
|
||||
(void)service_choice;
|
||||
(void)service_request;
|
||||
(void)service_len;
|
||||
}
|
||||
|
||||
static void MyAbortHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id, uint8_t abort_reason, bool server)
|
||||
{
|
||||
@@ -148,7 +163,8 @@ static void Init_Service_Handlers(void)
|
||||
|
||||
/* handle any errors coming back */
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_PRIVATE_TRANSFER, MyErrorHandler);
|
||||
apdu_set_complex_error_handler(SERVICE_CONFIRMED_PRIVATE_TRANSFER,
|
||||
MyPrivateTransferErrorHandler);
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,6 @@ static void Init_Service_Handlers(void)
|
||||
|
||||
/* handle any errors coming back */
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_PRIVATE_TRANSFER, MyErrorHandler);
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
+21
-7
@@ -70,18 +70,30 @@ static bool Error_Detected = false;
|
||||
/* Used for verbose */
|
||||
static bool Verbose = false;
|
||||
|
||||
static void MyErrorHandler(BACNET_ADDRESS *src,
|
||||
static void MyWritePropertyMultipleErrorHandler(
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code)
|
||||
uint8_t service_choice,
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_WRITE_PROPERTY_DATA wp_data = { 0 };
|
||||
|
||||
(void)service_choice;
|
||||
if (address_match(&Target_Address, src) &&
|
||||
(invoke_id == Request_Invoke_ID)) {
|
||||
len = wpm_error_ack_decode_apdu(service_request, service_len, &wp_data);
|
||||
if (len > 0) {
|
||||
printf("BACnet Error: %s: %s\n",
|
||||
bactext_error_class_name((int)error_class),
|
||||
bactext_error_code_name((int)error_code));
|
||||
bactext_error_class_name((int)wp_data.error_class),
|
||||
bactext_error_code_name((int)wp_data.error_code));
|
||||
printf("BACnet Error: %s %u: %s\n",
|
||||
bactext_object_type_name((int)wp_data.object_type),
|
||||
(unsigned)wp_data.object_instance,
|
||||
bactext_property_name((int)wp_data.object_property));
|
||||
}
|
||||
Error_Detected = true;
|
||||
/* FIXME: WPM error has extra data for first failed write. */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +121,7 @@ static void MyRejectHandler(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void MyWritePropertyMultipleSimpleAckHandler(
|
||||
BACNET_ADDRESS *src, uint8_t invoke_id)
|
||||
{
|
||||
@@ -136,7 +149,8 @@ static void Init_Service_Handlers(void)
|
||||
apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE,
|
||||
MyWritePropertyMultipleSimpleAckHandler);
|
||||
/* handle any errors coming back */
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
|
||||
apdu_set_complex_error_handler(SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE,
|
||||
MyWritePropertyMultipleErrorHandler);
|
||||
apdu_set_abort_handler(MyAbortHandler);
|
||||
apdu_set_reject_handler(MyRejectHandler);
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ int bacapp_encode_application_data(
|
||||
apdu, &value->type.Lighting_Command);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_HOST_N_PORT:
|
||||
/* BACnetHostNPort */
|
||||
apdu_len = host_n_port_encode(apdu,
|
||||
&value->type.Host_Address);
|
||||
break;
|
||||
@@ -166,6 +167,16 @@ int bacapp_encode_application_data(
|
||||
apdu_len = bacapp_encode_device_obj_property_ref(
|
||||
apdu, &value->type.Device_Object_Property_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE:
|
||||
/* BACnetDeviceObjectReference */
|
||||
apdu_len = bacapp_encode_device_obj_ref(
|
||||
apdu, &value->type.Device_Object_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE:
|
||||
/* BACnetObjectPropertyReference */
|
||||
apdu_len = bacapp_encode_obj_property_ref(
|
||||
apdu, &value->type.Object_Property_Reference);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
@@ -289,6 +300,17 @@ int bacapp_decode_data(uint8_t *apdu,
|
||||
len = bacapp_decode_device_obj_property_ref(
|
||||
apdu, &value->type.Device_Object_Property_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE:
|
||||
/* BACnetDeviceObjectReference */
|
||||
len = bacapp_decode_device_obj_ref(
|
||||
apdu, &value->type.Device_Object_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE:
|
||||
/* BACnetObjectPropertyReference */
|
||||
len = bacapp_decode_obj_property_ref(
|
||||
apdu, len_value_type,
|
||||
&value->type.Object_Property_Reference);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
@@ -589,6 +611,18 @@ int bacapp_encode_context_data_value(uint8_t *apdu,
|
||||
apdu, context_tag_number,
|
||||
&value->type.Device_Object_Property_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE:
|
||||
/* BACnetDeviceObjectReference */
|
||||
apdu_len = bacapp_encode_context_device_obj_ref(
|
||||
apdu, context_tag_number,
|
||||
&value->type.Device_Object_Reference);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE:
|
||||
/* BACnetObjectPropertyReference */
|
||||
apdu_len = bacapp_encode_context_obj_property_ref(
|
||||
apdu, context_tag_number,
|
||||
&value->type.Object_Property_Reference);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -84,6 +84,10 @@ typedef struct BACnet_Application_Data_Value {
|
||||
BACNET_HOST_N_PORT Host_Address;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE
|
||||
Device_Object_Property_Reference;
|
||||
BACNET_DEVICE_OBJECT_REFERENCE
|
||||
Device_Object_Reference;
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE
|
||||
Object_Property_Reference;
|
||||
#endif
|
||||
} type;
|
||||
/* simple linked list if needed */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2008 John Minack
|
||||
Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@@ -400,3 +401,216 @@ int bacapp_decode_context_device_obj_ref(
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Encode a BACnetObjectPropertyReference
|
||||
*
|
||||
* BACnetObjectPropertyReference ::= SEQUENCE {
|
||||
* object-identifier [0] BACnetObjectIdentifier,
|
||||
* property-identifier [1] BACnetPropertyIdentifier,
|
||||
* property-array-index [2] Unsigned OPTIONAL
|
||||
* -- used only with array datatype
|
||||
* -- if omitted with an array the entire array is referenced
|
||||
* }
|
||||
*
|
||||
* @param apdu - the APDU buffer, or NULL for length
|
||||
* @param reference - BACnetObjectPropertyReference
|
||||
* @return length of the APDU buffer
|
||||
*/
|
||||
int bacapp_encode_obj_property_ref(uint8_t *apdu,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE *reference)
|
||||
{
|
||||
int len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
int apdu_len = 0;
|
||||
|
||||
if (!reference) {
|
||||
return 0;
|
||||
}
|
||||
if (reference->object_identifier.type == OBJECT_NONE) {
|
||||
return 0;
|
||||
}
|
||||
if (apdu) {
|
||||
apdu_offset = apdu;
|
||||
}
|
||||
len = encode_context_object_id(apdu_offset, 0,
|
||||
reference->object_identifier.type,
|
||||
reference->object_identifier.instance);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_context_enumerated(
|
||||
apdu_offset, 1, reference->property_identifier);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
if (reference->property_array_index != BACNET_ARRAY_ALL) {
|
||||
len = encode_context_unsigned(
|
||||
apdu_offset, 2, reference->property_array_index);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode the BACnetObjectPropertyReference as Context Tagged
|
||||
* @param apdu - the APDU buffer
|
||||
* @param tag_number - context tag number to be encoded
|
||||
* @param reference - BACnetObjectPropertyReference to encode
|
||||
* @return length of the APDU buffer
|
||||
*/
|
||||
int bacapp_encode_context_obj_property_ref(uint8_t *apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE *reference)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
|
||||
if (reference && (reference->object_identifier.type == OBJECT_NONE)) {
|
||||
return 0;
|
||||
}
|
||||
if (apdu) {
|
||||
apdu_offset = apdu;
|
||||
}
|
||||
len = encode_opening_tag(apdu_offset, tag_number);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = bacapp_encode_obj_property_ref(apdu_offset, reference);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_closing_tag(apdu_offset, tag_number);
|
||||
apdu_len += len;
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode a BACnetObjectPropertyReference
|
||||
*
|
||||
* BACnetObjectPropertyReference ::= SEQUENCE {
|
||||
* object-identifier [0] BACnetObjectIdentifier,
|
||||
* property-identifier [1] BACnetPropertyIdentifier,
|
||||
* property-array-index [2] Unsigned OPTIONAL
|
||||
* -- used only with array datatype
|
||||
* -- if omitted with an array the entire array is referenced
|
||||
* }
|
||||
*
|
||||
* @param apdu - the APDU buffer
|
||||
* @param apdu_len_max - the APDU buffer length
|
||||
* @param reference - BACnetObjectPropertyReference to decode into
|
||||
* @return length of the APDU buffer decoded, or 0 if failed to decode
|
||||
*/
|
||||
int bacapp_decode_obj_property_ref(uint8_t *apdu,
|
||||
uint16_t apdu_len_max,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE *reference)
|
||||
{
|
||||
int apdu_len = 0;
|
||||
int len = 0;
|
||||
BACNET_OBJECT_ID object_identifier;
|
||||
BACNET_PROPERTY_ID property_identifier;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value;
|
||||
|
||||
if (apdu && (apdu_len_max > 0)) {
|
||||
/* object-identifier [0] BACnetObjectIdentifier */
|
||||
len = bacnet_object_id_context_decode(&apdu[apdu_len],
|
||||
apdu_len_max - apdu_len, 0, &object_identifier.type,
|
||||
&object_identifier.instance);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
/* property-identifier [1] BACnetPropertyIdentifier */
|
||||
len = bacnet_enumerated_context_decode(
|
||||
&apdu[apdu_len], apdu_len_max - apdu_len, 1, &property_identifier);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if (reference) {
|
||||
reference->object_identifier.type = object_identifier.type;
|
||||
reference->object_identifier.instance = object_identifier.instance;
|
||||
reference->property_identifier = property_identifier;
|
||||
reference->property_array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
/* property-array-index [2] Unsigned OPTIONAL */
|
||||
if (apdu_len_max > apdu_len) {
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 2)) {
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_len_max - apdu_len, 2,
|
||||
&unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (unsigned_value > UINT32_MAX) {
|
||||
return 0;
|
||||
}
|
||||
if (reference) {
|
||||
reference->property_array_index = unsigned_value;
|
||||
}
|
||||
} else if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the context object property reference. Check for
|
||||
* an opening tag and a closing tag as well.
|
||||
*
|
||||
* @param apdu Pointer to the buffer containing the data to decode.
|
||||
* @param apdu_len_max - the APDU buffer length
|
||||
* @param tag_number Tag number
|
||||
* @param value Pointer to the context device object reference,
|
||||
* that shall be decoded.
|
||||
*
|
||||
* @return Bytes decoded or BACNET_STATUS_ERROR on failure.
|
||||
*/
|
||||
int bacapp_decode_context_obj_property_ref(
|
||||
uint8_t * apdu,
|
||||
uint16_t apdu_len_max,
|
||||
uint8_t tag_number,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE * value)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
|
||||
if (apdu_len_max == 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
|
||||
apdu_len++;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
len = bacapp_decode_obj_property_ref(&apdu[apdu_len],
|
||||
apdu_len_max - apdu_len, value);
|
||||
if (len == 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
} else {
|
||||
apdu_len += len;
|
||||
}
|
||||
if ((apdu_len_max - apdu_len) == 0) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (decode_is_closing_tag_number(&apdu[apdu_len], tag_number)) {
|
||||
apdu_len++;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2008 John Minack
|
||||
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@@ -49,7 +50,22 @@ typedef struct BACnetDeviceObjectReference {
|
||||
BACNET_OBJECT_ID objectIdentifier;
|
||||
} BACNET_DEVICE_OBJECT_REFERENCE;
|
||||
|
||||
|
||||
/**
|
||||
* BACnetObjectPropertyReference ::= SEQUENCE {
|
||||
* object-identifier [0] BACnetObjectIdentifier,
|
||||
* property-identifier [1] BACnetPropertyIdentifier,
|
||||
* property-array-index [2] Unsigned OPTIONAL
|
||||
* -- used only with array datatype
|
||||
* -- if omitted with an array the entire array is referenced
|
||||
* }
|
||||
*/
|
||||
typedef struct BACnet_Object_Property_Reference {
|
||||
/* note: use type = OBJECT_NONE for unused reference */
|
||||
BACNET_OBJECT_ID object_identifier;
|
||||
BACNET_PROPERTY_ID property_identifier;
|
||||
/* optional array index - use BACNET_ARRAY_ALL when not used */
|
||||
BACNET_ARRAY_INDEX property_array_index;
|
||||
} BACNET_OBJECT_PROPERTY_REFERENCE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -77,7 +93,6 @@ extern "C" {
|
||||
uint8_t tag_number,
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE * value);
|
||||
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bacapp_encode_device_obj_ref(
|
||||
uint8_t * apdu,
|
||||
@@ -100,6 +115,30 @@ extern "C" {
|
||||
uint8_t tag_number,
|
||||
BACNET_DEVICE_OBJECT_REFERENCE * value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bacapp_encode_obj_property_ref(
|
||||
uint8_t * apdu,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE * value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bacapp_encode_context_obj_property_ref(
|
||||
uint8_t * apdu,
|
||||
uint8_t tag_number,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE * value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bacapp_decode_obj_property_ref(
|
||||
uint8_t * apdu,
|
||||
uint16_t apdu_len_max,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE * value);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int bacapp_decode_context_obj_property_ref(
|
||||
uint8_t * apdu,
|
||||
uint16_t apdu_len_max,
|
||||
uint8_t tag_number,
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE * value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
+37
-11
@@ -1417,17 +1417,21 @@ typedef enum {
|
||||
PDU_TYPE_ABORT = 0x70
|
||||
} BACNET_PDU_TYPE;
|
||||
|
||||
typedef enum {
|
||||
/* BACnetConfirmedServiceChoice ::= ENUMERATED */
|
||||
typedef enum BACnet_Confirmed_Service_Choice {
|
||||
/* Alarm and Event Services */
|
||||
SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM = 0,
|
||||
SERVICE_CONFIRMED_AUDIT_NOTIFICATION = 32,
|
||||
SERVICE_CONFIRMED_COV_NOTIFICATION = 1,
|
||||
SERVICE_CONFIRMED_COV_NOTIFICATION_MULTIPLE = 31,
|
||||
SERVICE_CONFIRMED_EVENT_NOTIFICATION = 2,
|
||||
SERVICE_CONFIRMED_GET_ALARM_SUMMARY = 3,
|
||||
SERVICE_CONFIRMED_GET_ENROLLMENT_SUMMARY = 4,
|
||||
SERVICE_CONFIRMED_GET_EVENT_INFORMATION = 29,
|
||||
SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION = 27,
|
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV = 5,
|
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY = 28,
|
||||
SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION = 27,
|
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY_MULTIPLE = 30,
|
||||
/* File Access Services */
|
||||
SERVICE_CONFIRMED_ATOMIC_READ_FILE = 6,
|
||||
SERVICE_CONFIRMED_ATOMIC_WRITE_FILE = 7,
|
||||
@@ -1442,6 +1446,7 @@ typedef enum {
|
||||
SERVICE_CONFIRMED_READ_RANGE = 26,
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY = 15,
|
||||
SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE = 16,
|
||||
SERVICE_CONFIRMED_AUDIT_LOG_QUERY = 33,
|
||||
/* Remote Device Management Services */
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL = 17,
|
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER = 18,
|
||||
@@ -1455,14 +1460,21 @@ typedef enum {
|
||||
SERVICE_CONFIRMED_AUTHENTICATE = 24,
|
||||
SERVICE_CONFIRMED_REQUEST_KEY = 25,
|
||||
/* Services added after 1995 */
|
||||
/* readRange (26) see Object Access Services */
|
||||
/* lifeSafetyOperation (27) see Alarm and Event Services */
|
||||
/* subscribeCOVProperty (28) see Alarm and Event Services */
|
||||
/* getEventInformation (29) see Alarm and Event Services */
|
||||
/* readRange [26] see Object Access Services */
|
||||
/* lifeSafetyOperation [27] see Alarm and Event Services */
|
||||
/* subscribeCOVProperty [28] see Alarm and Event Services */
|
||||
/* getEventInformation [29] see Alarm and Event Services */
|
||||
/* Services added after 2012 */
|
||||
/* subscribe-cov-property-multiple [30] see Alarm and Event Services */
|
||||
/* confirmed-cov-notification-multiple [31] see Alarm and Event Services */
|
||||
/* Services added after 2016 */
|
||||
/* confirmed-audit-notification [32] see Alarm and Event Services */
|
||||
/* audit-log-query [33] see Object Access Services */
|
||||
MAX_BACNET_CONFIRMED_SERVICE = 30
|
||||
} BACNET_CONFIRMED_SERVICE;
|
||||
|
||||
typedef enum {
|
||||
/* BACnetUnconfirmedServiceChoice ::= ENUMERATED */
|
||||
typedef enum BACnet_Unconfirmed_Service_Choice {
|
||||
SERVICE_UNCONFIRMED_I_AM = 0,
|
||||
SERVICE_UNCONFIRMED_I_HAVE = 1,
|
||||
SERVICE_UNCONFIRMED_COV_NOTIFICATION = 2,
|
||||
@@ -1475,16 +1487,21 @@ typedef enum {
|
||||
SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION = 9,
|
||||
/* addendum 2010-aa */
|
||||
SERVICE_UNCONFIRMED_WRITE_GROUP = 10,
|
||||
/* addendum 2012-aq */
|
||||
SERVICE_UNCONFIRMED_COV_NOTIFICATION_MULTIPLE = 11,
|
||||
/* addendum 2016-bz */
|
||||
SERVICE_UNCONFIRMED_WHO_AM_I = 13,
|
||||
SERVICE_UNCONFIRMED_YOU_ARE = 14,
|
||||
/* Other services to be added as they are defined. */
|
||||
/* All choice values in this production are reserved */
|
||||
/* for definition by ASHRAE. */
|
||||
/* Proprietary extensions are made by using the */
|
||||
/* UnconfirmedPrivateTransfer service. See Clause 23. */
|
||||
MAX_BACNET_UNCONFIRMED_SERVICE = 11
|
||||
MAX_BACNET_UNCONFIRMED_SERVICE = 15
|
||||
} BACNET_UNCONFIRMED_SERVICE;
|
||||
|
||||
/* Bit String Enumerations */
|
||||
typedef enum {
|
||||
/* BACnetServicesSupported ::= BIT STRING */
|
||||
typedef enum BACnet_Services_Supported {
|
||||
/* Alarm and Event Services */
|
||||
SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM = 0,
|
||||
SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION = 1,
|
||||
@@ -1494,7 +1511,10 @@ typedef enum {
|
||||
SERVICE_SUPPORTED_GET_EVENT_INFORMATION = 39,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV = 5,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY = 38,
|
||||
SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY_MULTIPLE = 41,
|
||||
SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION = 37,
|
||||
SERVICE_SUPPORTED_CONFIRMED_AUDIT_NOTIFICATION = 44,
|
||||
SERVICE_SUPPORTED_AUDIT_LOG_QUERY = 45,
|
||||
/* File Access Services */
|
||||
SERVICE_SUPPORTED_ATOMIC_READ_FILE = 6,
|
||||
SERVICE_SUPPORTED_ATOMIC_WRITE_FILE = 7,
|
||||
@@ -1515,6 +1535,8 @@ typedef enum {
|
||||
SERVICE_SUPPORTED_PRIVATE_TRANSFER = 18,
|
||||
SERVICE_SUPPORTED_TEXT_MESSAGE = 19,
|
||||
SERVICE_SUPPORTED_REINITIALIZE_DEVICE = 20,
|
||||
SERVICE_SUPPORTED_WHO_AM_I = 47,
|
||||
SERVICE_SUPPORTED_YOU_ARE = 48,
|
||||
/* Virtual Terminal Services */
|
||||
SERVICE_SUPPORTED_VT_OPEN = 21,
|
||||
SERVICE_SUPPORTED_VT_CLOSE = 22,
|
||||
@@ -1524,17 +1546,21 @@ typedef enum {
|
||||
SERVICE_SUPPORTED_REQUEST_KEY = 25,
|
||||
SERVICE_SUPPORTED_I_AM = 26,
|
||||
SERVICE_SUPPORTED_I_HAVE = 27,
|
||||
/* Unconfirmed Services */
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION = 28,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION_MULTIPLE = 43,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_EVENT_NOTIFICATION = 29,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_PRIVATE_TRANSFER = 30,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_TEXT_MESSAGE = 31,
|
||||
SERVICE_SUPPORTED_TIME_SYNCHRONIZATION = 32,
|
||||
SERVICE_SUPPORTED_UTC_TIME_SYNCHRONIZATION = 36,
|
||||
SERVICE_SUPPORTED_WHO_HAS = 33,
|
||||
SERVICE_SUPPORTED_WHO_IS = 34
|
||||
SERVICE_SUPPORTED_WHO_IS = 34,
|
||||
SERVICE_SUPPORTED_UNCONFIRMED_AUDIT_NOTIFICATION = 46,
|
||||
/* Other services to be added as they are defined. */
|
||||
/* All values in this production are reserved */
|
||||
/* for definition by ASHRAE. */
|
||||
BACNET_SERVICES_SUPPORTED_MAX = 47
|
||||
} BACNET_SERVICES_SUPPORTED;
|
||||
|
||||
/* Bit String Enumerations */
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacenum.h"
|
||||
#include "bacnet/bacerror.h"
|
||||
#include "bacnet/dcc.h"
|
||||
#include "bacnet/iam.h"
|
||||
/* basic objects, services, TSM */
|
||||
@@ -302,7 +303,36 @@ void apdu_set_confirmed_ack_handler(
|
||||
}
|
||||
}
|
||||
|
||||
static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
static union {
|
||||
error_function error;
|
||||
complex_error_function complex;
|
||||
} Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
|
||||
/**
|
||||
* @brief Determine if the service uses Complex Error function
|
||||
* @param service_choice Service, see SERVICE_CONFIRMED_X enumeration.
|
||||
* @return true if the service uses a Complex Error function
|
||||
*/
|
||||
bool apdu_complex_error(BACNET_CONFIRMED_SERVICE service_choice)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
switch (service_choice) {
|
||||
case SERVICE_CONFIRMED_SUBSCRIBE_COV_PROPERTY_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_ADD_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_REMOVE_LIST_ELEMENT:
|
||||
case SERVICE_CONFIRMED_CREATE_OBJECT:
|
||||
case SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE:
|
||||
case SERVICE_CONFIRMED_PRIVATE_TRANSFER:
|
||||
case SERVICE_CONFIRMED_VT_CLOSE:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a error handler function for the given confirmed service.
|
||||
@@ -312,10 +342,28 @@ static error_function Error_Function[MAX_BACNET_CONFIRMED_SERVICE];
|
||||
* handling.
|
||||
*/
|
||||
void apdu_set_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice, error_function pFunction)
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction)
|
||||
{
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
|
||||
Error_Function[service_choice] = pFunction;
|
||||
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
|
||||
(!apdu_complex_error(service_choice))) {
|
||||
Error_Function[service_choice].error = pFunction;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set a complex error handler function for the given confirmed service.
|
||||
*
|
||||
* @param service_choice Service, see SERVICE_CONFIRMED_X enumeration.
|
||||
* @param pFunction Pointer to the function, being in charge of the error
|
||||
* handling.
|
||||
*/
|
||||
void apdu_set_complex_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
complex_error_function pFunction)
|
||||
{
|
||||
if (apdu_complex_error(service_choice)) {
|
||||
Error_Function[service_choice].complex = pFunction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -499,8 +547,6 @@ void apdu_handler(BACNET_ADDRESS *src,
|
||||
uint8_t *service_request = NULL;
|
||||
uint16_t service_request_len = 0;
|
||||
int len = 0; /* counts where we are in PDU */
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value = 0;
|
||||
uint32_t error_code = 0;
|
||||
uint32_t error_class = 0;
|
||||
uint8_t reason = 0;
|
||||
@@ -648,65 +694,19 @@ void apdu_handler(BACNET_ADDRESS *src,
|
||||
if (apdu_len >= 3) {
|
||||
invoke_id = apdu[1];
|
||||
service_choice = apdu[2];
|
||||
len = 3;
|
||||
|
||||
/* FIXME: Currently special case for C_P_T but there are
|
||||
others which may need consideration such as
|
||||
ChangeList-Error, CreateObject-Error,
|
||||
WritePropertyMultiple-Error and VTClose_Error but they
|
||||
may be left as is for now until support for these
|
||||
services is added */
|
||||
|
||||
if (service_choice ==
|
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER) { /* skip over
|
||||
opening tag 0
|
||||
*/
|
||||
if (decode_is_opening_tag_number(&apdu[len], 0)) {
|
||||
len++; /* a tag number of 0 is not extended so only
|
||||
one octet */
|
||||
if (apdu_complex_error(service_choice)) {
|
||||
if (Error_Function[service_choice].complex) {
|
||||
Error_Function[service_choice].complex(src,
|
||||
invoke_id, service_choice,
|
||||
&apdu[3], apdu_len - 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (len < apdu_len) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
|
||||
if (len < apdu_len) {
|
||||
/* FIXME: we could validate that the tag is
|
||||
* enumerated... */
|
||||
len += decode_enumerated(
|
||||
&apdu[len], len_value, &error_class);
|
||||
|
||||
if (len < apdu_len) {
|
||||
len += decode_tag_number_and_value(
|
||||
&apdu[len], &tag_number, &len_value);
|
||||
|
||||
if (len < apdu_len) {
|
||||
/* FIXME: we could validate that the tag is
|
||||
* enumerated... */
|
||||
len += decode_enumerated(
|
||||
&apdu[len], len_value, &error_code);
|
||||
|
||||
if (service_choice ==
|
||||
SERVICE_CONFIRMED_PRIVATE_TRANSFER) {
|
||||
if (len < apdu_len) {
|
||||
/* skip over closing tag 0 */
|
||||
if (decode_is_closing_tag_number(
|
||||
&apdu[len], 0)) {
|
||||
len++; /* a tag number of 0 is
|
||||
not extended so only
|
||||
one octet */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
|
||||
if (Error_Function[service_choice]) {
|
||||
Error_Function[service_choice](src, invoke_id,
|
||||
} else if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
|
||||
len = bacerror_decode_error_class_and_code(&apdu[3],
|
||||
apdu_len - 3, &error_class, &error_code);
|
||||
if ((len != 0) &&
|
||||
(Error_Function[service_choice].error)) {
|
||||
Error_Function[service_choice].error(src,
|
||||
invoke_id,
|
||||
(BACNET_ERROR_CLASS)error_class,
|
||||
(BACNET_ERROR_CODE)error_code);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,15 @@ extern "C" {
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code);
|
||||
|
||||
/* complex error reply function */
|
||||
typedef void (
|
||||
*complex_error_function) (
|
||||
BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t service_choice,
|
||||
uint8_t * service_request,
|
||||
uint16_t service_len);
|
||||
|
||||
/* generic abort reply function */
|
||||
typedef void (
|
||||
*abort_function) (
|
||||
@@ -150,12 +159,20 @@ extern "C" {
|
||||
size_t * index,
|
||||
bool * bIsConfirmed);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool apdu_complex_error(
|
||||
BACNET_CONFIRMED_SERVICE service_choice);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void apdu_set_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
error_function pFunction);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void apdu_set_complex_error_handler(
|
||||
BACNET_CONFIRMED_SERVICE service_choice,
|
||||
complex_error_function pFunction);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void apdu_set_abort_handler(
|
||||
abort_function pFunction);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "bacnet/bacenum.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacdef.h"
|
||||
#include "bacnet/bacerror.h"
|
||||
#include "bacnet/wp.h"
|
||||
#include "bacnet/wpm.h"
|
||||
|
||||
@@ -435,3 +436,138 @@ int wpm_error_ack_encode_apdu(
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Decoding for WritePropertyMultiple Error
|
||||
* @ingroup DSWPM
|
||||
* WritePropertyMultiple-Error ::= SEQUENCE {
|
||||
* error-type [0] Error,
|
||||
* first-failed-write-attempt [1] BACnetObjectPropertyReference
|
||||
* }
|
||||
*
|
||||
* @param apdu [in] The contents of the APDU buffer.
|
||||
* @param apdu_size [in] The size of the APDU buffer.
|
||||
* @param wp_data [out] The BACNET_WRITE_PROPERTY_DATA structure
|
||||
* which will contain the response values or error.
|
||||
*
|
||||
* @return Count of decoded bytes.
|
||||
*/
|
||||
int wpm_error_ack_decode_apdu(
|
||||
uint8_t *apdu, uint16_t apdu_size, BACNET_WRITE_PROPERTY_DATA *wp_data)
|
||||
{
|
||||
int len = 0, apdu_len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
BACNET_ERROR_CLASS error_class = ERROR_CLASS_SERVICES;
|
||||
BACNET_ERROR_CODE error_code = ERROR_CODE_SUCCESS;
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE value;
|
||||
|
||||
if (apdu) {
|
||||
apdu_offset = apdu;
|
||||
}
|
||||
if (wp_data) {
|
||||
wp_data->error_class = ERROR_CLASS_SERVICES;
|
||||
wp_data->error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
/* Context tag 0 - Error */
|
||||
if (apdu_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (decode_is_opening_tag_number(apdu_offset, 0)) {
|
||||
len = 1;
|
||||
apdu_len -= len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
if (apdu_size > len) {
|
||||
apdu_size -= len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
len = bacerror_decode_error_class_and_code(apdu_offset, apdu_size,
|
||||
&error_class, &error_code);
|
||||
if (len > 0) {
|
||||
if (wp_data) {
|
||||
wp_data->error_class = error_class;
|
||||
wp_data->error_code = error_code;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
if (apdu_size > len) {
|
||||
apdu_size -= len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if (apdu_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (decode_is_closing_tag_number(apdu_offset, 0)) {
|
||||
len = 1;
|
||||
apdu_len -= len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
if (apdu_size > len) {
|
||||
apdu_size -= len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
/* Context tag 1 - BACnetObjectPropertyReference */
|
||||
if (apdu_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (decode_is_opening_tag_number(apdu_offset, 1)) {
|
||||
len = 1;
|
||||
apdu_len -= len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
if (apdu_size > len) {
|
||||
apdu_size -= len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
len = bacapp_decode_obj_property_ref(apdu_offset, apdu_size, &value);
|
||||
if (len > 0) {
|
||||
if (wp_data) {
|
||||
wp_data->object_instance = value.object_identifier.instance;
|
||||
wp_data->object_type = value.object_identifier.type;
|
||||
wp_data->object_property = value.property_identifier;
|
||||
wp_data->array_index = value.property_array_index;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
if (apdu_size > len) {
|
||||
apdu_size -= len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if (apdu_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (decode_is_closing_tag_number(apdu_offset, 1)) {
|
||||
len = 1;
|
||||
apdu_len += len;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,11 @@ extern "C" {
|
||||
uint8_t invoke_id,
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
int wpm_error_ack_decode_apdu(
|
||||
uint8_t *apdu,
|
||||
uint16_t apdu_size,
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -114,6 +114,54 @@ static void testDevIdRef(void)
|
||||
zassert_equal(
|
||||
inData.deviceIdentifier.type, outData.deviceIdentifier.type, NULL);
|
||||
}
|
||||
|
||||
static void testObjPropRef(void)
|
||||
{
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE inData;
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE outData;
|
||||
uint8_t apdu[MAX_APDU];
|
||||
uint8_t tag_number = 1;
|
||||
int inLen;
|
||||
int outLen;
|
||||
|
||||
inData.object_identifier.instance = 12345;
|
||||
inData.object_identifier.type = OBJECT_ANALOG_VALUE;
|
||||
inData.property_identifier = PROP_PRESENT_VALUE;
|
||||
inData.property_array_index = BACNET_ARRAY_ALL;
|
||||
inLen = bacapp_encode_obj_property_ref(apdu, &inData);
|
||||
outLen = bacapp_decode_obj_property_ref(apdu, inLen, &outData);
|
||||
zassert_equal(outLen, inLen, NULL);
|
||||
zassert_equal(
|
||||
inData.object_identifier.type,
|
||||
outData.object_identifier.type, NULL);
|
||||
zassert_equal(
|
||||
inData.object_identifier.instance,
|
||||
outData.object_identifier.instance, NULL);
|
||||
zassert_equal(
|
||||
inData.property_identifier,
|
||||
outData.property_identifier, NULL);
|
||||
zassert_equal(
|
||||
inData.property_array_index,
|
||||
outData.property_array_index, NULL);
|
||||
/* context */
|
||||
inLen = bacapp_encode_context_obj_property_ref(apdu, tag_number, &inData);
|
||||
outLen = bacapp_decode_context_obj_property_ref(apdu, inLen, tag_number,
|
||||
&outData);
|
||||
zassert_equal(outLen, inLen, NULL);
|
||||
zassert_equal(
|
||||
inData.object_identifier.type,
|
||||
outData.object_identifier.type, NULL);
|
||||
zassert_equal(
|
||||
inData.object_identifier.instance,
|
||||
outData.object_identifier.instance, NULL);
|
||||
zassert_equal(
|
||||
inData.property_identifier,
|
||||
outData.property_identifier, NULL);
|
||||
zassert_equal(
|
||||
inData.property_array_index,
|
||||
outData.property_array_index, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -123,7 +171,8 @@ void test_main(void)
|
||||
{
|
||||
ztest_test_suite(bacdevobjpropref_tests,
|
||||
ztest_unit_test(testDevIdPropRef),
|
||||
ztest_unit_test(testDevIdRef)
|
||||
ztest_unit_test(testDevIdRef),
|
||||
ztest_unit_test(testObjPropRef)
|
||||
);
|
||||
|
||||
ztest_run_test_suite(bacdevobjpropref_tests);
|
||||
|
||||
@@ -36,6 +36,7 @@ add_executable(${PROJECT_NAME}
|
||||
# Support files and stubs (pathname alphabetical)
|
||||
${SRC_DIR}/bacnet/bacaddr.c
|
||||
${SRC_DIR}/bacnet/bacdcode.c
|
||||
${SRC_DIR}/bacnet/bacerror.c
|
||||
${SRC_DIR}/bacnet/bacint.c
|
||||
${SRC_DIR}/bacnet/bacreal.c
|
||||
${SRC_DIR}/bacnet/bacstr.c
|
||||
|
||||
Reference in New Issue
Block a user