From bd7f0b3ad430d02a21a2f72ce0a188989675ed30 Mon Sep 17 00:00:00 2001 From: bigjohngoulah Date: Fri, 16 Dec 2005 21:39:57 +0000 Subject: [PATCH] added a sendWriteRequest, writeAckHandler, wp decode service request, struct and library to map property to tag --- bacnet-stack/bactext.c | 41 +++++++++++++++++ bacnet-stack/bactext.h | 2 + bacnet-stack/device.c | 53 ++++++++++++++++++++++ bacnet-stack/handlers.c | 98 +++++++++++++++++++++++++++++++++++++++++ bacnet-stack/handlers.h | 17 +++++++ bacnet-stack/indtext.c | 23 ++++++++++ bacnet-stack/indtext.h | 11 +++++ bacnet-stack/wp.c | 62 ++++++++++++++++++++++++++ bacnet-stack/wp.h | 5 +++ 9 files changed, 312 insertions(+) diff --git a/bacnet-stack/bactext.c b/bacnet-stack/bactext.c index 1396d47f..f1469947 100644 --- a/bacnet-stack/bactext.c +++ b/bacnet-stack/bactext.c @@ -32,12 +32,53 @@ ------------------------------------------- ####COPYRIGHTEND####*/ +#include #include "indtext.h" #include "bacenum.h" static const char *ASHRAE_Reserved_String = "Reserved for Use by ASHRAE"; static const char *Vendor_Proprietary_String = "Vendor Proprietary Value"; + +PROP_TAG_DATA bacnet_object_device_property_tag_map[] = { + {PROP_OBJECT_IDENTIFIER, BACNET_APPLICATION_TAG_OBJECT_ID}, + {PROP_OBJECT_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, + {PROP_OBJECT_TYPE, BACNET_APPLICATION_TAG_ENUMERATED}, + {PROP_SYSTEM_STATUS, BACNET_APPLICATION_TAG_ENUMERATED}, + {PROP_VENDOR_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, + {PROP_VENDOR_IDENTIFIER, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + {PROP_MODEL_NAME, BACNET_APPLICATION_TAG_CHARACTER_STRING}, + {PROP_FIRMWARE_REVISION, BACNET_APPLICATION_TAG_CHARACTER_STRING}, + {PROP_APPLICATION_SOFTWARE_VERSION, BACNET_APPLICATION_TAG_CHARACTER_STRING}, + {PROP_PROTOCOL_VERSION, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + {PROP_PROTOCOL_CONFORMANCE_CLASS, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + {PROP_PROTOCOL_SERVICES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING}, + {PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED, BACNET_APPLICATION_TAG_BIT_STRING}, + {PROP_MAX_APDU_LENGTH_ACCEPTED, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + {PROP_SEGMENTATION_SUPPORTED, BACNET_APPLICATION_TAG_ENUMERATED}, + {PROP_APDU_TIMEOUT, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + {PROP_NUMBER_OF_APDU_RETRIES, BACNET_APPLICATION_TAG_UNSIGNED_INT}, + { 0, 0 } +}; + +unsigned bactext_property_tag(BACNET_OBJECT_TYPE type, unsigned prop) +{ + switch (type) + { + case OBJECT_DEVICE: + return indtext_tag_by_index_default( + bacnet_object_device_property_tag_map, + prop, + 0); + break; + default: + fprintf(stderr, "Unsupported object type"); + break; + } + + return 0; +} + INDTEXT_DATA bacnet_confirmed_service_names[] = { { SERVICE_CONFIRMED_ACKNOWLEDGE_ALARM, "Acknowledge-Alarm" }, { SERVICE_CONFIRMED_COV_NOTIFICATION, "COV-Notification" }, diff --git a/bacnet-stack/bactext.h b/bacnet-stack/bactext.h index 600e137f..146fc036 100644 --- a/bacnet-stack/bactext.h +++ b/bacnet-stack/bactext.h @@ -55,6 +55,8 @@ const char *bactext_error_code_name(int index); unsigned bactext_property_id(const char* name); +unsigned bactext_property_tag(BACNET_OBJECT_TYPE type, unsigned prop); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/device.c b/bacnet-stack/device.c index c1092598..46d69f27 100644 --- a/bacnet-stack/device.c +++ b/bacnet-stack/device.c @@ -509,6 +509,59 @@ bool Device_Write_Property( *error_code = ERROR_CODE_INVALID_DATA_TYPE; } break; + + case PROP_NUMBER_OF_APDU_RETRIES: + if (wp_data->value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) + { + Device_Set_Number_Of_APDU_Retries(wp_data->value.type.Unsigned_Int); + status = true; + } + else + { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + + case PROP_APDU_TIMEOUT: + if (wp_data->value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) + { + Device_Set_APDU_Timeout(wp_data->value.type.Unsigned_Int); + status = true; + } + else + { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + + case PROP_VENDOR_IDENTIFIER: + if (wp_data->value.tag == BACNET_APPLICATION_TAG_UNSIGNED_INT) + { + Device_Set_Vendor_Identifier(wp_data->value.type.Unsigned_Int); + status = true; + } + else + { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + + case PROP_SYSTEM_STATUS: + if (wp_data->value.tag == BACNET_APPLICATION_TAG_ENUMERATED) + { + Device_Set_System_Status(wp_data->value.type.Enumerated); + status = true; + } + else + { + *error_class = ERROR_CLASS_PROPERTY; + *error_code = ERROR_CODE_INVALID_DATA_TYPE; + } + break; + default: *error_class = ERROR_CLASS_PROPERTY; *error_code = ERROR_CODE_WRITE_ACCESS_DENIED; diff --git a/bacnet-stack/handlers.c b/bacnet-stack/handlers.c index 5819d6f9..1f61550e 100644 --- a/bacnet-stack/handlers.c +++ b/bacnet-stack/handlers.c @@ -50,6 +50,8 @@ #if BACFILE #include "bacfile.h" #endif +#include "indtext.h" +#include "bactext.h" // Example handlers of services // flag to send an I-Am @@ -208,6 +210,83 @@ bool Send_Read_Property_Request( return status; } + + +bool Send_Write_Property_Request( + uint32_t device_id, // destination device + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property, + BACNET_APPLICATION_DATA_VALUE object_value, + uint8_t priority, + int32_t array_index) +{ + BACNET_ADDRESS dest; + BACNET_ADDRESS my_address; + unsigned max_apdu = 0; + uint8_t invoke_id = 0; + bool status = false; + int pdu_len = 0; + int bytes_sent = 0; + BACNET_WRITE_PROPERTY_DATA data; + + /* is the device bound? */ + status = address_get_by_device(device_id, &max_apdu, &dest); + /* is there a tsm available? */ + if (status) + status = tsm_transaction_available(); + if (status) + { + datalink_get_my_address(&my_address); + pdu_len = npdu_encode_apdu( + &Tx_Buf[0], + &dest, + &my_address, + true, // true for confirmed messages + MESSAGE_PRIORITY_NORMAL); + + invoke_id = tsm_next_free_invokeID(); + // load the data for the encoding + data.object_type = object_type; + data.object_instance = object_instance; + data.object_property = object_property; + data.array_index = array_index; + data.value = object_value; + data.priority = priority; + pdu_len += wp_encode_apdu( + &Tx_Buf[pdu_len], + invoke_id, + &data); + /* will it fit in the sender? + note: if there is a bottleneck router in between + us and the destination, we won't know unless + we have a way to check for that and update the + max_apdu in the address binding table. */ + if ((unsigned)pdu_len < max_apdu) + { + tsm_set_confirmed_unsegmented_transaction( + invoke_id, + &dest, + &Tx_Buf[0], + pdu_len); + bytes_sent = datalink_send_pdu( + &dest, // destination address + &Tx_Buf[0], + pdu_len); // number of bytes of data + if (bytes_sent > 0);// fprintf(stderr,"Sent ReadProperty Request!\n"); + else + fprintf(stderr,"Failed to Send WriteProperty Request (%s)!\n", + strerror(errno)); + } + else + fprintf(stderr,"Failed to Send WriteProperty Request " + "(exceeds destination maximum APDU)!\n"); + } + + return status; +} + + void WhoIsHandler( uint8_t *service_request, uint16_t service_len, @@ -479,6 +558,25 @@ void ReadPropertyHandler( return; } + +void WritePropertyAckHandler( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data) +{ + int len = 0; + BACNET_WRITE_PROPERTY_DATA data; + + (void)src; + tsm_free_invoke_id(service_data->invoke_id); + len = wp_ack_decode_service_request( + service_request, + service_len, + &data); + fprintf(stderr,"Received Write-Property Ack!\n"); +} + void WritePropertyHandler( uint8_t *service_request, uint16_t service_len, diff --git a/bacnet-stack/handlers.h b/bacnet-stack/handlers.h index f00451fa..6192da1f 100644 --- a/bacnet-stack/handlers.h +++ b/bacnet-stack/handlers.h @@ -30,6 +30,7 @@ #include #include "bacdef.h" #include "apdu.h" +#include "bacapp.h" // flag to send an I-Am extern bool I_Am_Request; @@ -66,6 +67,12 @@ void ReadPropertyHandler( BACNET_ADDRESS *src, BACNET_CONFIRMED_SERVICE_DATA *service_data); +void WritePropertyAckHandler( + uint8_t *service_request, + uint16_t service_len, + BACNET_ADDRESS *src, + BACNET_CONFIRMED_SERVICE_ACK_DATA *service_data); + void WritePropertyHandler( uint8_t *service_request, uint16_t service_len, @@ -79,6 +86,16 @@ bool Send_Read_Property_Request( uint32_t object_instance, BACNET_PROPERTY_ID object_property, int32_t array_index); + +// returns false if device is not bound +bool Send_Write_Property_Request( + uint32_t device_id, // destination device + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID object_property, + BACNET_APPLICATION_DATA_VALUE object_value, + uint8_t priority, + int32_t array_index); void AtomicReadFileHandler( uint8_t *service_request, diff --git a/bacnet-stack/indtext.c b/bacnet-stack/indtext.c index 2c64d82c..7d5321a9 100644 --- a/bacnet-stack/indtext.c +++ b/bacnet-stack/indtext.c @@ -145,6 +145,29 @@ const char *indtext_by_index_default( return pString?pString:default_string; } +unsigned indtext_tag_by_index_default( + PROP_TAG_DATA *data_list, + unsigned index, + unsigned default_ret) +{ + unsigned pUnsigned = 0; + + if (data_list) + { + while (data_list->prop_id) + { + if (data_list->prop_id == index) + { + pUnsigned = data_list->tag_id; + break; + } + data_list++; + } + } + + return pUnsigned?pUnsigned:default_ret; +} + const char *indtext_by_index_split_default( INDTEXT_DATA *data_list, int index, diff --git a/bacnet-stack/indtext.h b/bacnet-stack/indtext.h index 3e9596ef..3c5d0d71 100644 --- a/bacnet-stack/indtext.h +++ b/bacnet-stack/indtext.h @@ -45,10 +45,21 @@ typedef struct const char *pString; /* text pair - use NULL to end the list */ } INDTEXT_DATA; +typedef struct +{ + unsigned prop_id; /* index number that matches the text */ + unsigned tag_id; /* text pair - use NULL to end the list */ +} PROP_TAG_DATA; + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +unsigned indtext_tag_by_index_default( + PROP_TAG_DATA *data_list, + unsigned index, + unsigned default_ret); + /* Searches for a matching string and returns the index to the string in the parameter found_index. If the string is not found, false is returned diff --git a/bacnet-stack/wp.c b/bacnet-stack/wp.c index 1cf35c26..c4d027ac 100644 --- a/bacnet-stack/wp.c +++ b/bacnet-stack/wp.c @@ -182,6 +182,68 @@ int wp_decode_apdu( return len; } + +int wp_ack_decode_service_request( + uint8_t *apdu, + int apdu_len, // total length of the apdu + BACNET_WRITE_PROPERTY_DATA *data) +{ + uint8_t tag_number = 0; + uint32_t len_value_type = 0; + int tag_len = 0; // length of tag decode + int len = 0; // total length of decodes + int object = 0, property = 0; // for decoding + unsigned array_value = 0; // for decoding + + // FIXME: check apdu_len against the len during decode + // Tag 0: Object ID + if (!decode_is_context_tag(&apdu[0], 0)) + return -1; + len = 1; + len += decode_object_id(&apdu[len], + &object, &data->object_instance); + data->object_type = object; + // Tag 1: Property ID + len += decode_tag_number_and_value(&apdu[len], + &tag_number, &len_value_type); + if (tag_number != 1) + return -1; + len += decode_enumerated(&apdu[len], + len_value_type, + &property); + data->object_property = property; + // Tag 2: Optional Array Index + tag_len = decode_tag_number_and_value(&apdu[len], + &tag_number, &len_value_type); + if (tag_number == 2) + { + len += tag_len; + len += decode_unsigned(&apdu[len], + len_value_type, &array_value); + data->array_index = array_value; + } + else + data->array_index = BACNET_ARRAY_ALL; + + // Tag 3: opening context tag */ + /* + if (decode_is_opening_tag_number(&apdu[len], 3)) + { + // a tag number of 3 is not extended so only one octet + len++; + // don't decode the application tag number or its data here + data->application_data = &apdu[len]; + data->application_data_len = apdu_len - len - 1; //closing tag + } + else + return -1; + */ + + return len; +} + + + #ifdef TEST #include #include diff --git a/bacnet-stack/wp.h b/bacnet-stack/wp.h index 0c59de42..704546bb 100644 --- a/bacnet-stack/wp.h +++ b/bacnet-stack/wp.h @@ -71,6 +71,11 @@ int wp_decode_apdu( uint8_t *invoke_id, BACNET_WRITE_PROPERTY_DATA *data); +int wp_ack_decode_service_request( + uint8_t *apdu, + int apdu_len, // total length of the apdu + BACNET_WRITE_PROPERTY_DATA *data); + #ifdef TEST #include "ctest.h"