From ce18b3a55d95535747e4119774047ac5333c2753 Mon Sep 17 00:00:00 2001 From: skarg Date: Thu, 9 Feb 2006 17:28:03 +0000 Subject: [PATCH] Added BACnet application encoding and decoding for bit strings. Added BACnet text for month_name, week_of_month, day_of_week, event_state, binary_present_value, reliability, device_status, and segmentation. Added BACnet application handling for printing the property value to a stream. --- bacnet-stack/bacapp.c | 225 ++++++++++++++++++++++++++++++----------- bacnet-stack/bacapp.h | 8 +- bacnet-stack/bactext.c | 157 +++++++++++++++++++++++++++- bacnet-stack/bactext.h | 14 ++- 4 files changed, 338 insertions(+), 66 deletions(-) diff --git a/bacnet-stack/bacapp.c b/bacnet-stack/bacapp.c index 87ce99f4..3b5b9b4b 100644 --- a/bacnet-stack/bacapp.c +++ b/bacnet-stack/bacapp.c @@ -36,10 +36,12 @@ #include #include #include +#include #include "bacenum.h" #include "bacdcode.h" #include "bacdef.h" #include "bacapp.h" +#include "bactext.h" int bacapp_encode_application_data( uint8_t *apdu, @@ -68,14 +70,18 @@ int bacapp_encode_application_data( apdu_len += encode_tagged_double(&apdu[apdu_len], value->type.Double); #endif - else if (value->tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) - apdu_len += encode_tagged_character_string( - &apdu[apdu_len], - &value->type.Character_String); else if (value->tag == BACNET_APPLICATION_TAG_OCTET_STRING) apdu_len += encode_tagged_octet_string( &apdu[apdu_len], &value->type.Octet_String); + else if (value->tag == BACNET_APPLICATION_TAG_CHARACTER_STRING) + apdu_len += encode_tagged_character_string( + &apdu[apdu_len], + &value->type.Character_String); + else if (value->tag == BACNET_APPLICATION_TAG_BIT_STRING) + apdu_len += encode_tagged_bitstring( + &apdu[apdu_len], + &value->type.Bit_String); else if (value->tag == BACNET_APPLICATION_TAG_ENUMERATED) apdu_len += encode_tagged_enumerated(&apdu[apdu_len], value->type.Enumerated); @@ -122,65 +128,45 @@ int bacapp_decode_application_data( if (tag_len) { len += tag_len; + value->tag = tag_number; if (tag_number == BACNET_APPLICATION_TAG_NULL) { - value->tag = tag_number; + /* nothing else to do */ } else if (tag_number == BACNET_APPLICATION_TAG_BOOLEAN) - { - value->tag = tag_number; value->type.Boolean = decode_boolean(len_value_type); - } else if (tag_number == BACNET_APPLICATION_TAG_UNSIGNED_INT) - { - value->tag = tag_number; len += decode_unsigned(&apdu[len], len_value_type, &value->type.Unsigned_Int); - } else if (tag_number == BACNET_APPLICATION_TAG_SIGNED_INT) - { - value->tag = tag_number; len += decode_signed(&apdu[len], len_value_type, &value->type.Signed_Int); - } else if (tag_number == BACNET_APPLICATION_TAG_REAL) - { - value->tag = tag_number; len += decode_real(&apdu[len],&(value->type.Real)); - } #if 0 else if (tag_number == BACNET_APPLICATION_TAG_DOUBLE) - { - value->tag = tag_number; len += decode_double(&apdu[len],&(value->type.Double)); - } #endif - else if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) - { - value->tag = tag_number; - len += decode_character_string(&apdu[len], - len_value_type, - &value->type.Character_String); - } else if (tag_number == BACNET_APPLICATION_TAG_OCTET_STRING) - { - value->tag = tag_number; len += decode_octet_string(&apdu[len], len_value_type, &value->type.Octet_String); - } + else if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING) + len += decode_character_string(&apdu[len], + len_value_type, + &value->type.Character_String); + else if (tag_number == BACNET_APPLICATION_TAG_BIT_STRING) + len += decode_bitstring(&apdu[len], + len_value_type, + &value->type.Bit_String); else if (tag_number == BACNET_APPLICATION_TAG_ENUMERATED) - { - value->tag = tag_number; len += decode_enumerated(&apdu[len], len_value_type, &value->type.Enumerated); - } else if (tag_number == BACNET_APPLICATION_TAG_DATE) { - value->tag = tag_number; len += decode_date(&apdu[len], &year, &month, &day, &wday); value->type.Date.year = year; value->type.Date.month = month; @@ -189,7 +175,6 @@ int bacapp_decode_application_data( } else if (tag_number == BACNET_APPLICATION_TAG_TIME) { - value->tag = tag_number; len += decode_bacnet_time(&apdu[len], &hour, &min, &sec, &hundredths); value->type.Time.hour = hour; value->type.Time.min = min; @@ -198,9 +183,8 @@ int bacapp_decode_application_data( } else if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) { - value->tag = tag_number; len += decode_object_id(&apdu[len], - &object_type, + &object_type, &instance); value->type.Object_Id.type = object_type; value->type.Object_Id.instance = instance; @@ -258,23 +242,24 @@ bool bacapp_copy( dest_value->type.Object_Id.type = src_value->type.Object_Id.type; dest_value->type.Object_Id.instance = src_value->type.Object_Id.instance; break; - case BACNET_APPLICATION_TAG_CHARACTER_STRING: - characterstring_copy( - &dest_value->type.Character_String, - &src_value->type.Character_String); - break; case BACNET_APPLICATION_TAG_OCTET_STRING: octetstring_copy( &dest_value->type.Octet_String, &src_value->type.Octet_String); break; + case BACNET_APPLICATION_TAG_CHARACTER_STRING: + characterstring_copy( + &dest_value->type.Character_String, + &src_value->type.Character_String); + break; + case BACNET_APPLICATION_TAG_BIT_STRING: default: status = false; break; } } - - return status; + + return status; } /* generic - can be used by other unit tests */ bool bacapp_compare( @@ -344,27 +329,147 @@ bool bacapp_compare( status = false; break; case BACNET_APPLICATION_TAG_CHARACTER_STRING: + status = !characterstring_same( + &value->type.Character_String, + &test_value->type.Character_String); + break; + case BACNET_APPLICATION_TAG_BIT_STRING: + default: + status = false; + break; + } + } + return status; +} + +bool bacapp_print_value( + FILE *stream, + BACNET_APPLICATION_DATA_VALUE *value, + BACNET_PROPERTY_ID property) +{ + bool status = true; /*return value*/ + size_t len = 0, i = 0; + char *char_str; + uint8_t *octet_str; + + if (value) + { + switch (value->tag) + { + case BACNET_APPLICATION_TAG_NULL: + fprintf(stream,"Null"); + break; + case BACNET_APPLICATION_TAG_BOOLEAN: + fprintf(stream,"%s",value->type.Boolean?"TRUE":"FALSE"); + break; + case BACNET_APPLICATION_TAG_UNSIGNED_INT: + fprintf(stream,"%u",value->type.Unsigned_Int); + break; + case BACNET_APPLICATION_TAG_SIGNED_INT: + fprintf(stream,"%d",value->type.Signed_Int); + break; + case BACNET_APPLICATION_TAG_REAL: + fprintf(stream,"%f",(double)value->type.Real); + break; + case BACNET_APPLICATION_TAG_DOUBLE: + fprintf(stream,"%f",value->type.Double); + break; + case BACNET_APPLICATION_TAG_ENUMERATED: + switch (property) { - size_t length, test_length, i; - char *str,*test_str; - length = characterstring_length(&value->type.Character_String); - str = characterstring_value(&value->type.Character_String); - test_length = characterstring_length(&test_value->type.Character_String); - test_str = characterstring_value(&test_value->type.Character_String); - if (length != test_length) - status = false; - for (i = 0; i < test_length; i++) - { - if (str[i] != test_str[i]) - status = false; - } + case PROP_OBJECT_TYPE: + fprintf(stream,"%s", + bactext_object_type_name(value->type.Enumerated)); + break; + case PROP_EVENT_STATE: + fprintf(stream,"%s", + bactext_event_state_name(value->type.Enumerated)); + break; + case PROP_UNITS: + fprintf(stream,"%s", + bactext_engineering_unit_name(value->type.Enumerated)); + break; + case PROP_PRESENT_VALUE: + fprintf(stream,"%s", + bactext_binary_present_value_name(value->type.Enumerated)); + break; + case PROP_RELIABILITY: + fprintf(stream,"%s", + bactext_reliability_name(value->type.Enumerated)); + break; + case PROP_SYSTEM_STATUS: + fprintf(stream,"%s", + bactext_device_status_name(value->type.Enumerated)); + break; + case PROP_SEGMENTATION_SUPPORTED: + fprintf(stream,"%s", + bactext_segmentation_name(value->type.Enumerated)); + break; + default: + fprintf(stream,"%u",value->type.Enumerated); + break; } break; + case BACNET_APPLICATION_TAG_DATE: + fprintf(stream,"%s, %s %u, %u", + bactext_day_of_week_name(value->type.Date.wday), + bactext_month_name(value->type.Date.month), + (unsigned)value->type.Date.day, + (unsigned)value->type.Date.year); + break; + case BACNET_APPLICATION_TAG_TIME: + fprintf(stream,"%02u:%02u:%02u.%03u", + (unsigned)value->type.Time.hour, + (unsigned)value->type.Time.min, + (unsigned)value->type.Time.sec, + (unsigned)value->type.Time.hundredths); + break; + case BACNET_APPLICATION_TAG_OBJECT_ID: + fprintf(stream,"%s %u", + bactext_object_type_name(value->type.Object_Id.type), + value->type.Object_Id.instance); + break; + case BACNET_APPLICATION_TAG_OCTET_STRING: + len = octetstring_length(&value->type.Octet_String); + octet_str = octetstring_value(&value->type.Octet_String); + for (i = 0; i < len; i++) + { + fprintf(stream,"%02X",*octet_str); + octet_str++; + } + break; + case BACNET_APPLICATION_TAG_CHARACTER_STRING: + len = characterstring_length(&value->type.Character_String); + char_str = characterstring_value(&value->type.Character_String); + fprintf(stream,"\""); + for (i = 0; i < len; i++) + { + if (isprint(*char_str)) + fprintf(stream,"%c",*char_str); + else + fprintf(stream,".",*char_str); + char_str++; + } + fprintf(stream,"\""); + break; + case BACNET_APPLICATION_TAG_BIT_STRING: + len = bitstring_bits_used(&value->type.Bit_String); + fprintf(stream,"{"); + for (i = 0; i < len; i++) + { + fprintf(stream,"%s", + bitstring_bit(&value->type.Bit_String,i)?"true":"false"); + if (i < len-1) + fprintf(stream,","); + } + fprintf(stream,"}"); + break; default: status = false; break; } } + return status; } @@ -578,7 +683,7 @@ void testBACnetApplicationData(Test * pTest) ct_test(pTest,status == true); ct_test(pTest,value.type.Signed_Int == -32768); ct_test(pTest,testBACnetApplicationDataValue(&value)); - + status = bacapp_parse_application_data( BACNET_APPLICATION_TAG_REAL, "0.0", @@ -609,7 +714,7 @@ void testBACnetApplicationData(Test * pTest) &value); ct_test(pTest,status == true); ct_test(pTest,testBACnetApplicationDataValue(&value)); - + status = bacapp_parse_application_data( BACNET_APPLICATION_TAG_ENUMERATED, "0", @@ -631,7 +736,7 @@ void testBACnetApplicationData(Test * pTest) ct_test(pTest,status == true); ct_test(pTest,value.type.Enumerated == 0xFFFFFFFF); ct_test(pTest,testBACnetApplicationDataValue(&value)); - + status = bacapp_parse_application_data( BACNET_APPLICATION_TAG_DATE, "5/5/22:1", diff --git a/bacnet-stack/bacapp.h b/bacnet-stack/bacapp.h index 81eca197..72b16337 100644 --- a/bacnet-stack/bacapp.h +++ b/bacnet-stack/bacapp.h @@ -36,6 +36,7 @@ #include #include +#include #include "bacdef.h" #include "bacstr.h" @@ -85,7 +86,12 @@ bool bacapp_parse_application_data( BACNET_APPLICATION_TAG tag_number, const char *argv, BACNET_APPLICATION_DATA_VALUE *value); - + +bool bacapp_print_value( + FILE *stream, + BACNET_APPLICATION_DATA_VALUE *value, + BACNET_PROPERTY_ID property); + #ifdef TEST #include "ctest.h" void testBACnetApplicationData(Test * pTest); diff --git a/bacnet-stack/bactext.c b/bacnet-stack/bactext.c index 87ca63e9..f0182416 100644 --- a/bacnet-stack/bactext.c +++ b/bacnet-stack/bactext.c @@ -360,8 +360,8 @@ const char *bactext_property_name(int index) unsigned bactext_property_id(const char* name) { return indtext_by_istring_default( - bacnet_property_names, - name, + bacnet_property_names, + name, 0); } @@ -551,7 +551,7 @@ INDTEXT_DATA bacnet_engineering_unit_names[] = { { UNITS_DEGREES_KELVIN_PER_MINUTE, "degrees-Kelvin-per-minute"}, { UNITS_JOULE_SECONDS, "joule-seconds"}, { UNITS_RADIANS_PER_SECOND, "radians-per-second"}, - { UNITS_SQUARE_METERS_PER_NEWTON, "square-meters-per-Newton"}, + { UNITS_SQUARE_METERS_PER_NEWTON, "square-meters-per-Newton"}, { UNITS_KILOGRAMS_PER_CUBIC_METER, "kilograms-per-cubic-meter"}, { UNITS_NEWTON_SECONDS, "newton-seconds"}, { UNITS_NEWTONS_PER_METER, "newtons-per-meter"}, @@ -701,3 +701,154 @@ const char *bactext_error_code_name(int index) Vendor_Proprietary_String); } +INDTEXT_DATA bacnet_month_names[] = { + {1, "January"}, + {2, "February"}, + {3, "March"}, + {4, "April"}, + {5, "May"}, + {6, "June"}, + {7, "July"}, + {8, "August"}, + {9, "September"}, + {10, "October"}, + {11, "November"}, + {12, "December"}, + {255,"Any Month"}, + {0,NULL} +}; + +const char *bactext_month_name(int index) +{ + return indtext_by_index_default( + bacnet_month_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_week_of_month_names[] = { + {1, "days numbered 1-7"}, + {2, "days numbered 8-14"}, + {3, "days numbered 15-21"}, + {4, "days numbered 22-28"}, + {5, "days numbered 29-31"}, + {6, "last 7 days of this month"}, + {255, "any week of this month"}, + {0,NULL} +}; + +const char *bactext_week_of_month_name(int index) +{ + return indtext_by_index_default( + bacnet_week_of_month_names, + index, + ASHRAE_Reserved_String); +} + +/* note: different than DaysOfWeek bit string where 0=monday */ +INDTEXT_DATA bacnet_day_of_week_names[] = { + {1, "Monday"}, + {2, "Tuesday"}, + {3, "Wednesday"}, + {4, "Thursday"}, + {5, "Friday"}, + {6, "Saturday"}, + {7, "Sunday"}, + {255, "any day of week"}, + {0,NULL} +}; + +const char *bactext_day_of_week_name(int index) +{ + return indtext_by_index_default( + bacnet_day_of_week_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_event_state_names[] = { + {EVENT_STATE_NORMAL, "normal"}, + {EVENT_STATE_FAULT, "fault"}, + {EVENT_STATE_OFFNORMAL, "offnormal"}, + {EVENT_STATE_HIGH_LIMIT, "high limit"}, + {EVENT_STATE_LOW_LIMIT, "low limit"}, + {0,NULL} +}; + +const char *bactext_event_state_name(int index) +{ + return indtext_by_index_default( + bacnet_event_state_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_binary_present_value_names[] = { + {BINARY_INACTIVE,"inactive"}, + {BINARY_ACTIVE,"active"}, + {0,NULL} +}; + +const char *bactext_binary_present_value_name(int index) +{ + return indtext_by_index_default( + bacnet_binary_present_value_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_reliability_names[] = { + {RELIABILITY_NO_FAULT_DETECTED,"no-fault-detected"}, + {RELIABILITY_NO_SENSOR,"no-sensor"}, + {RELIABILITY_OVER_RANGE,"over-range"}, + {RELIABILITY_UNDER_RANGE,"under-range"}, + {RELIABILITY_OPEN_LOOP,"open-loop"}, + {RELIABILITY_SHORTED_LOOP,"shorted-loop"}, + {RELIABILITY_NO_OUTPUT,"no-output"}, + {RELIABILITY_UNRELIABLE_OTHER,"unreliable-other"}, + {RELIABILITY_PROCESS_ERROR,"process-error"}, + {RELIABILITY_MULTI_STATE_FAULT,"mult-state-fault"}, + {RELIABILITY_CONFIGURATION_ERROR,"configuration-error"}, + {0,NULL} +}; + +const char *bactext_reliability_name(int index) +{ + return indtext_by_index_default( + bacnet_reliability_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_device_status_names[] = { + {STATUS_OPERATIONAL,"operational"}, + {STATUS_OPERATIONAL_READ_ONLY,"operational-read-only"}, + {STATUS_DOWNLOAD_REQUIRED,"download-required"}, + {STATUS_DOWNLOAD_IN_PROGRESS,"download-in-progress"}, + {STATUS_NON_OPERATIONAL,"non-operational"}, + {0,NULL} +}; + +const char *bactext_device_status_name(int index) +{ + return indtext_by_index_default( + bacnet_device_status_names, + index, + ASHRAE_Reserved_String); +} + +INDTEXT_DATA bacnet_segmentation_names[] = { + {SEGMENTATION_BOTH,"segmented-both"}, + {SEGMENTATION_TRANSMIT,"segmented-transmit"}, + {SEGMENTATION_RECEIVE,"segmented-receive"}, + {SEGMENTATION_NONE,"no-segmentation"}, + {0,NULL} +}; + +const char *bactext_segmentation_name(int index) +{ + return indtext_by_index_default( + bacnet_segmentation_names, + index, + ASHRAE_Reserved_String); +} diff --git a/bacnet-stack/bactext.h b/bacnet-stack/bactext.h index 1476ad17..67f547da 100644 --- a/bacnet-stack/bactext.h +++ b/bacnet-stack/bactext.h @@ -13,9 +13,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to + along with this program; if not, write to The Free Software Foundation, Inc. - 59 Temple Place - Suite 330 + 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA. As a special exception, if other files instantiate templates or @@ -53,6 +53,16 @@ const char *bactext_abort_reason_name(int index); const char *bactext_error_class_name(int index); const char *bactext_error_code_name(int index); unsigned bactext_property_id(const char* name); +const char *bactext_month_name(int index); +const char *bactext_week_of_month_name(int index); +const char *bactext_day_of_week_name(int index); +const char *bactext_event_state_name(int index); +const char *bactext_binary_present_value_name(int index); +const char *bactext_reliability_name(int index); +const char *bactext_device_status_name(int index); +const char *bactext_segmentation_name(int index); + + #ifdef __cplusplus } #endif /* __cplusplus */