diff --git a/bacnet-stack/bacdcode.c b/bacnet-stack/bacdcode.c index 23257a26..c4857414 100644 --- a/bacnet-stack/bacdcode.c +++ b/bacnet-stack/bacdcode.c @@ -544,6 +544,30 @@ bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number) return (closing_tag && (my_tag_number == tag_number)); } +static uint8_t byte_reverse_bits(uint8_t in_byte) +{ + uint8_t out_byte = 0; + + if (in_byte & BIT0) + out_byte |= BIT7; + if (in_byte & BIT1) + out_byte |= BIT6; + if (in_byte & BIT2) + out_byte |= BIT5; + if (in_byte & BIT3) + out_byte |= BIT4; + if (in_byte & BIT4) + out_byte |= BIT3; + if (in_byte & BIT5) + out_byte |= BIT2; + if (in_byte & BIT6) + out_byte |= BIT1; + if (in_byte & BIT7) + out_byte |= BIT0; + + return out_byte; +} + // from clause 20.2.10 Encoding of a Bit String Value // returns the number of apdu bytes consumed int decode_bitstring(uint8_t * apdu, uint32_t len_value, @@ -565,7 +589,7 @@ int decode_bitstring(uint8_t * apdu, uint32_t len_value, len = 1; for (i = 0; i < bytes_used; i++) { - bit_string->value[i] = apdu[len++]; + bit_string->value[i] = byte_reverse_bits(apdu[len++]); } unused_bits = apdu[0] & 0x07; bit_string->bits_used = bytes_used * 8; @@ -615,7 +639,7 @@ int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING *bit_string) apdu[len++] = 8 - remaining_used_bits; for (i = 0; i < used_bytes; i++) { - apdu[len++] = bit_string->value[i]; + apdu[len++] = byte_reverse_bits(bit_string->value[i]); } } diff --git a/bacnet-stack/bacdcode.h b/bacnet-stack/bacdcode.h index 8c0ff926..cea84a1c 100644 --- a/bacnet-stack/bacdcode.h +++ b/bacnet-stack/bacdcode.h @@ -38,6 +38,14 @@ #include #include +// bit strings +#define MAX_BITSTRING_BYTES 15 +typedef struct BACnet_Bit_String +{ + uint8_t bits_used; + uint8_t value[MAX_BITSTRING_BYTES]; +} BACNET_BIT_STRING; + // from clause 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed int encode_tag(uint8_t * apdu, uint8_t tag_number, bool context_specific, @@ -58,6 +66,18 @@ bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number); // returns true if the tag is context specific and matches bool decode_is_context_tag(uint8_t * apdu, uint8_t tag_number); +// from clause 20.2.10 Encoding of a Bit String Value +void bitstring_init(BACNET_BIT_STRING *bit_string); +void bitstring_set_bit(BACNET_BIT_STRING *bit_string, uint8_t bit, bool value); +bool bitstring_bit(BACNET_BIT_STRING *bit_string, uint8_t bit); +uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string); +// returns the number of apdu bytes consumed +int decode_bitstring(uint8_t * apdu, uint32_t len_value, + BACNET_BIT_STRING *bit_string); +// returns the number of apdu bytes consumed +int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING *bit_string); +int encode_tagged_bitstring(uint8_t * apdu, BACNET_BIT_STRING *bit_string); + // from clause 20.2.6 Encoding of a Real Number Value // and 20.2.1 General Rules for Encoding BACnet Tags // returns the number of apdu bytes consumed diff --git a/bacnet-stack/bacenum.h b/bacnet-stack/bacenum.h index fe94fb99..999b9755 100644 --- a/bacnet-stack/bacenum.h +++ b/bacnet-stack/bacenum.h @@ -555,7 +555,7 @@ typedef enum OBJECT_COMMAND = 7, OBJECT_DEVICE = 8, OBJECT_EVENT_ENROLLMENT = 9, - OBJECT_FILE_O = 10, + OBJECT_FILE_ = 10, OBJECT_GROUP = 11, OBJECT_LOOP = 12, OBJECT_MULTI_STATE_INPUT = 13, @@ -703,6 +703,61 @@ typedef enum { MAX_BACNET_UNCONFIRMED_SERVICE = 10 } BACNET_UNCONFIRMED_SERVICE; +// Bit String Enumerations +typedef enum +{ + // Alarm and Event Services + SERVICE_SUPPORTED_ACKNOWLEDGE_ALARM = 0, + SERVICE_SUPPORTED_CONFIRMED_COV_NOTIFICATION = 1, + SERVICE_SUPPORTED_CONFIRMED_EVENT_NOTIFICATION = 2, + SERVICE_SUPPORTED_GET_ALARM_SUMMARY = 3, + SERVICE_SUPPORTED_GET_ENROLLMENT_SUMMARY = 4, + SERVICE_SUPPORTED_GET_EVENT_INFORMATION = 39, + SERVICE_SUPPORTED_SUBSCRIBE_COV = 5, + SERVICE_SUPPORTED_SUBSCRIBE_COV_PROPERTY = 38, + SERVICE_SUPPORTED_LIFE_SAFETY_OPERATION = 37, + // File Access Services + SERVICE_SUPPORTED_ATOMIC_READ_FILE = 6, + SERVICE_SUPPORTED_ATOMIC_WRITE_FILE = 7, + // Object Access Services + SERVICE_SUPPORTED_ADD_LIST_ELEMENT = 8, + SERVICE_SUPPORTED_REMOVE_LIST_ELEMENT = 9, + SERVICE_SUPPORTED_CREATE_OBJECT = 10, + SERVICE_SUPPORTED_DELETE_OBJECT = 11, + SERVICE_SUPPORTED_READ_PROPERTY = 12, + SERVICE_SUPPORTED_READ_PROPERTY_CONDITIONAL = 13, + SERVICE_SUPPORTED_READ_PROPERTY_MULTIPLE = 14, + SERVICE_SUPPORTED_READ_RANGE = 35, + SERVICE_SUPPORTED_WRITE_PROPERTY = 15, + SERVICE_SUPPORTED_WRITE_PROPERTY_MULTIPLE = 16, + // Remote Device Management Services + SERVICE_SUPPORTED_DEVICE_COMMUNICATION_CONTROL = 17, + SERVICE_SUPPORTED_PRIVATE_TRANSFER = 18, + SERVICE_SUPPORTED_TEXT_MESSAGE = 19, + SERVICE_SUPPORTED_REINITIALIZE_DEVICE = 20, + // Virtual Terminal Services + SERVICE_SUPPORTED_VT_OPEN = 21, + SERVICE_SUPPORTED_VT_CLOSE = 22, + SERVICE_SUPPORTED_VT_DATA = 23, + // Security Services + SERVICE_SUPPORTED_AUTHENTICATE = 24, + SERVICE_SUPPORTED_REQUEST_KEY = 25, + SERVICE_SUPPORTED_I_AM = 26, + SERVICE_SUPPORTED_I_HAVE = 27, + SERVICE_SUPPORTED_UNCONFIRMED_COV_NOTIFICATION = 28, + 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, + // Other services to be added as they are defined. + // All values in this production are reserved + // for definition by ASHRAE. + MAX_BACNET_SERVICES_SUPPORTED = 40 +} BACNET_SERVICES_SUPPORTED; + typedef enum { ACKNOWLEDGMENT_FILTER_ALL = 0, ACKNOWLEDGMENT_FILTER_ACKED = 1, diff --git a/bacnet-stack/device.c b/bacnet-stack/device.c index 8e503f78..be91998c 100644 --- a/bacnet-stack/device.c +++ b/bacnet-stack/device.c @@ -188,9 +188,6 @@ BACNET_SEGMENTATION Device_Segmentation_Supported(void) return SEGMENTATION_NONE; } -//FIXME: This need some bit string encodings... -//Protocol_Services_Supported -//Protocol_Object_Types_Supported //FIXME: Probably return one at a time, or be supported by // an object module, or encode the APDU here. //Object_List @@ -233,7 +230,8 @@ int Device_Encode_Property_APDU( int32_t array_index) { int apdu_len = 0; // return value - + BACNET_BIT_STRING bit_string; + switch (property) { case PROP_OBJECT_IDENTIFIER: @@ -292,30 +290,26 @@ int Device_Encode_Property_APDU( case PROP_PROTOCOL_VERSION: apdu_len = encode_tagged_unsigned(&apdu[0], Device_Protocol_Version()); break; - // BACnet Legacy Support - necessary? - //case PROP_PROTOCOL_CONFORMANCE_CLASS: - // apdu_len = encode_tagged_unsigned(&apdu[0], 1); - // break; + // BACnet Legacy Support + case PROP_PROTOCOL_CONFORMANCE_CLASS: + apdu_len = encode_tagged_unsigned(&apdu[0], 1); + break; case PROP_PROTOCOL_SERVICES_SUPPORTED: - // FIXME: needs an encoding function for bitstring - apdu[0] = 0x85; /* what is following? (this is a bitstring) */ - apdu[1] = 0x06; /* length extension to 6 bytes */ - apdu[2] = 0x05; /* 5 unused bits in the final byte */ - apdu[3] = 0x00; /* none of the first 8 bits are set */ - apdu[4] = 0x09; /* bits 3,0 are set */ - apdu[5] = 0x00; /* none of the 3rd set of bits are set */ - apdu[6] = 0x20; /* bit 5 is set */ - apdu[7] = 0x20; /* bit 5 is set */ - apdu_len = 8; /* bytes in this apdu */ + bitstring_init(&bit_string); + // when APDU does automatic reject when service is NULL, then add this + //for (i = 0; i < MAX_BACNET_SERVICES_SUPPORTED; i++) + //{ + // bitstring_set_bit(&bit_string, i, apdu_service_supported(i)); + //} + bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_WHO_IS, true); + bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_I_AM, true); + bitstring_set_bit(&bit_string, SERVICE_SUPPORTED_READ_PROPERTY, true); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); break; case PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED: - // FIXME: needs an encoding function for bitstring - apdu[0] = 0x84; /* what is following? (this is a bitstring) */ - apdu[1] = 0x06; /* 6 unused bits in the final byte */ - apdu[2] = 0xFF; /* All of the first 8 bits are set */ - apdu[3] = 0xFF; /* All of the second 8 bits are set */ - apdu[4] = 0xC0; /* All of the valid bits are set */ - apdu_len = 5; /* bytes in this apdu */ + bitstring_init(&bit_string); + bitstring_set_bit(&bit_string, OBJECT_DEVICE, true); + apdu_len = encode_tagged_bitstring(&apdu[0], &bit_string); break; case PROP_OBJECT_LIST: // FIXME: hook into real object list, not just device