diff --git a/bacnet-stack/demo/handler/h_rpm.c b/bacnet-stack/demo/handler/h_rpm.c index de3d7ff7..d91e7dcf 100644 --- a/bacnet-stack/demo/handler/h_rpm.c +++ b/bacnet-stack/demo/handler/h_rpm.c @@ -1,7 +1,7 @@ /************************************************************************** * -* Copyright (C) 2005 Steve Karg -* Enhanced by John Stachler for ReadPropertyMultiple +* Copyright (C) 2007 Steve Karg +* Inspired by John Stachler. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -37,37 +37,378 @@ #include "abort.h" #include "rpm.h" #include "handlers.h" +/* demo objects */ #include "device.h" #include "ai.h" #include "ao.h" +#include "av.h" #include "bi.h" +#include "bo.h" +#include "bv.h" +#include "lc.h" +#include "lsp.h" +#include "mso.h" +#if BACFILE +#include "bacfile.h" +#endif static uint8_t Temp_Buf[MAX_APDU] = { 0 }; +static uint8_t Application_Buf[MAX_APDU] = { 0 }; -/* copy encoded apdu data to tx buffer - this is needed to make sure we do not go past our apdu buffer size */ -bool copy_apdu_data_buffer(int *apdu_len, uint8 len, uint8 npdu_len) +struct property_list_t { - bool copy_status = false; - - if ((*apdu_len + len) <= MAX_APDU) { - memcpy(&Handler_Transmit_Buffer[*apdu_len + npdu_len], &Temp_Buf[0], len); - *apdu_len += len; - copy_status = true; + const int *pList; + unsigned count; +}; + +struct special_property_list_t +{ + struct property_list_t Required; + struct property_list_t Optional; + struct property_list_t Proprietary; +}; + +static unsigned property_list_count(const int *pList) +{ + unsigned property_count = 0; + + if (pList) { + while (*pList != -1) { + property_count++; + } } - - return copy_status; + + return property_count; } -void handler_read_property_multiple(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) +/* for a given object type, returns the special property list */ +static void RPM_Property_List( + BACNET_OBJECT_TYPE object_type, + struct special_property_list_t *pPropertyList) +{ + pPropertyList->Required.pList = NULL; + pPropertyList->Optional.pList = NULL; + pPropertyList->Proprietary.pList = NULL; + switch (object_type) { + case OBJECT_ANALOG_INPUT: + Analog_Input_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_ANALOG_OUTPUT: + Analog_Output_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_ANALOG_VALUE: + Analog_Value_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_BINARY_INPUT: + Binary_Input_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_BINARY_OUTPUT: + Binary_Output_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_BINARY_VALUE: + Binary_Value_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_LIFE_SAFETY_POINT: + Life_Safety_Point_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_LOAD_CONTROL: + Load_Control_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + case OBJECT_MULTI_STATE_OUTPUT: + break; +#if BACFILE + case OBJECT_FILE: + BACfile_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; +#endif + case OBJECT_DEVICE: + Device_Property_Lists( + &pPropertyList->Required.pList, + &pPropertyList->Optional.pList, + &pPropertyList->Proprietary.pList); + break; + default: + break; + } + /* fill the count */ + pPropertyList->Required.count = + property_list_count(pPropertyList->Required.pList); + pPropertyList->Optional.count = + property_list_count(pPropertyList->Optional.pList); + pPropertyList->Proprietary.count = + property_list_count(pPropertyList->Proprietary.pList); + + return; +} + +static int RPM_Object_Property( + struct special_property_list_t *pPropertyList, + BACNET_PROPERTY_ID special_property, + unsigned index) +{ + int property = -1; /* return value */ + unsigned required, optional, proprietary; + + required = pPropertyList->Required.count; + optional = pPropertyList->Optional.count; + proprietary = pPropertyList->Proprietary.count; + if (special_property == PROP_ALL) { + if (index < required) { + property = pPropertyList->Required.pList[index]; + } else if (index < (required + optional)) { + property = pPropertyList->Optional.pList[index]; + } else if (index < (required + optional + proprietary)) { + property = pPropertyList->Proprietary.pList[index]; + } + } else if (special_property == PROP_REQUIRED) { + if (index < required) { + property = pPropertyList->Required.pList[index]; + } + } else if (special_property == PROP_OPTIONAL) { + if (index < optional) { + property = pPropertyList->Optional.pList[index]; + } + } + + return property; +} + +static unsigned RPM_Object_Property_Count( + struct special_property_list_t *pPropertyList, + BACNET_PROPERTY_ID special_property) +{ + unsigned count = 0; /* return value */ + + if (special_property == PROP_ALL) { + count = pPropertyList->Required.count + + pPropertyList->Optional.count + + pPropertyList->Proprietary.count; + } else if (special_property == PROP_REQUIRED) { + count = pPropertyList->Required.count; + } else if (special_property == PROP_OPTIONAL) { + count = pPropertyList->Optional.count; + } + + return count; +} + +/* copy len bytes from src to offset of dest if there is enough space. */ +int apdu_copy(uint8_t *dest, uint8_t *src, int offset, int len, int max) +{ + int i; + int copy_len = 0; + + if (len <= (max-offset)) { + for (i = 0; i < len; i++) { + dest[offset+i] = src[i]; + copy_len++; + } + } + + return copy_len; +} + +/* Encodes the property APDU and returns the length, + or sets the error, and returns -1 */ +int Encode_Property_APDU( + uint8_t * apdu, + BACNET_OBJECT_TYPE object_type, + uint32_t object_instance, + BACNET_PROPERTY_ID property, + int32_t array_index, + BACNET_ERROR_CLASS * error_class, + BACNET_ERROR_CODE * error_code) +{ + int apdu_len = -1; + + switch(object_type) { + case OBJECT_DEVICE: + if ((object_instance == Device_Object_Instance_Number()) || + (object_instance == BACNET_MAX_INSTANCE)) { + apdu_len = Device_Encode_Property_APDU( + &apdu[0], + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_ANALOG_INPUT: + if (Analog_Input_Valid_Instance(object_instance)) { + apdu_len = Analog_Input_Encode_Property_APDU( + &apdu[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_ANALOG_OUTPUT: + if (!Analog_Output_Valid_Instance(object_instance)) { + apdu_len = Analog_Output_Encode_Property_APDU( + &apdu[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_ANALOG_VALUE: + if (Analog_Value_Valid_Instance(object_instance)) { + apdu_len = Analog_Value_Encode_Property_APDU(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_BINARY_INPUT: + if (Binary_Input_Valid_Instance(object_instance)) { + apdu_len = Binary_Input_Encode_Property_APDU( + &apdu[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_BINARY_OUTPUT: + if (Binary_Output_Valid_Instance(object_instance)) { + apdu_len = Binary_Output_Encode_Property_APDU( + &apdu[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_BINARY_VALUE: + if (Binary_Value_Valid_Instance(object_instance)) { + apdu_len = Binary_Value_Encode_Property_APDU(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_LIFE_SAFETY_POINT: + if (Life_Safety_Point_Valid_Instance(object_instance)) { + apdu_len = Life_Safety_Point_Encode_Property_APDU(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_LOAD_CONTROL: + if (Load_Control_Valid_Instance(object_instance)) { + apdu_len = Load_Control_Encode_Property_APDU(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; + case OBJECT_MULTI_STATE_OUTPUT: + if (Multistate_Output_Valid_Instance(object_instance)) { + apdu_len = Multistate_Output_Encode_Property_APDU(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; +#if BACFILE + case OBJECT_FILE: + if (bacfile_valid_instance(object_instance)) { + apdu_len = bacfile_encode_property_apdu(&Temp_Buf[0], + object_instance, + property, + array_index, + error_class, error_code); + } else { + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNKNOWN_OBJECT; + } + break; +#endif + default: + *error_class = ERROR_CLASS_OBJECT; + *error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; + break; + } + + return apdu_len; +} + +void handler_read_property_multiple( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data) { int len = 0; + int copy_len = 0; int decode_len = 0; + int application_data_len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; - bool error = false; - bool done; - bool property_found; int bytes_sent; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; @@ -78,8 +419,6 @@ void handler_read_property_multiple(uint8_t * service_request, uint16_t service_ int npdu_len; BACNET_PROPERTY_ID object_property, temp_object_property; int32_t array_index = 0; - uint8 index; - uint8 num_properties; /* jps_debug - see if we are utilizing all the buffer */ /* memset(&Handler_Transmit_Buffer[0], 0xff, MAX_MPDU);*/ @@ -87,7 +426,7 @@ void handler_read_property_multiple(uint8_t * service_request, uint16_t service_ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); npdu_len = npdu_encode_pdu( - &Handler_Transmit_Buffer[0], + &Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED if (service_len <= 0) @@ -123,7 +462,33 @@ void handler_read_property_multiple(uint8_t * service_request, uint16_t service_ &service_request[decode_len], service_len - decode_len, &object_type, &object_instance); + /* error - end of object? */ if (len < 0) { + len = rpm_ack_decode_object_end( + &service_request[decode_len], + service_len - decode_len); + if (len == 1) { + decode_len++; + len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]); + copy_len = apdu_copy( + &Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], + apdu_len, len, + sizeof(Handler_Transmit_Buffer)); + if (!copy_len) { + apdu_len = abort_encode_apdu( + &Handler_Transmit_Buffer[npdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); + goto RPM_ABORT; + } + } else { + apdu_len = abort_encode_apdu( + &Handler_Transmit_Buffer[npdu_len], + service_data->invoke_id, + ABORT_REASON_OTHER, true); + goto RPM_ABORT; + } break; } else { decode_len += len; @@ -131,282 +496,138 @@ void handler_read_property_multiple(uint8_t * service_request, uint16_t service_ len = rpm_ack_encode_apdu_object_begin( &Temp_Buf[0], object_type, object_instance); - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { + copy_len = apdu_copy( + &Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], + apdu_len, len, + sizeof(Handler_Transmit_Buffer)); + if (!copy_len) { apdu_len = abort_encode_apdu( &Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); - break; + goto RPM_ABORT; } /* do each property of this object of the RPM request */ - done = true; - num_properties = 0; - property_found = false; do { - if (done) { - len = rpm_decode_object_property( - &service_request[decode_len], - service_len - decode_len, - &object_property, - &array_index); - if (len < 0) { - break; - } else { - index = 0; - decode_len += len; - temp_object_property = object_property; - } + len = rpm_decode_object_property( + &service_request[decode_len], + service_len - decode_len, + &object_property, + &array_index); + /* error - end of property list? */ + if (len < 0) { + break; + } else { + decode_len += len; } /* handle the special properties */ if ((object_property == PROP_ALL) || (object_property == PROP_REQUIRED) || (object_property == PROP_OPTIONAL)) { - done = false; - switch(object_type) + struct special_property_list_t property_list; + unsigned property_count = 0; + unsigned index = 0; + RPM_Property_List(object_type, &property_list); + property_count = RPM_Object_Property_Count( + &property_list, + object_property); + for (index = 0; index < property_count; index++) { - case OBJECT_DEVICE: - property_found = Device_Property( - &index, &temp_object_property, - object_property); - break; - - case OBJECT_ANALOG_INPUT: - property_found = Analog_Input_Property( - &index, &temp_object_property, - object_property); - break; - - case OBJECT_BINARY_INPUT: - property_found = Binary_Input_Property( - &index, &temp_object_property, - object_property); - break; - - case OBJECT_ANALOG_OUTPUT: - property_found = Analog_Output_Property( - &index, &temp_object_property, - object_property); - break; - } - if (property_found) { - num_properties++; - } else { - if (num_properties > 0) { - done = true; - /* check for another property */ - len = rpm_decode_object_property( - &service_request[decode_len], - service_len - decode_len, - &object_property, - &array_index); - if (len < 0) { - /* check for closing tag */ - len = rpm_ack_decode_object_end( - &service_request[decode_len], - service_len - decode_len); - if (len == 1) { - decode_len++; - } - break; - } else { - decode_len += len; - temp_object_property = object_property; - property_found = true; - if ((object_property == PROP_ALL) || - (object_property == PROP_REQUIRED) || - (object_property == PROP_OPTIONAL)) - { - done = false; - index = 0; - switch(object_type) - { - case OBJECT_DEVICE: - property_found = - Device_Property(&index, - &temp_object_property, - object_property); - break; - - case OBJECT_ANALOG_INPUT: - property_found = - Analog_Input_Property(&index, - &temp_object_property, - object_property); - break; - - case OBJECT_BINARY_INPUT: - property_found = - Binary_Input_Property(&index, - &temp_object_property, - object_property); - break; - - case OBJECT_ANALOG_OUTPUT: - property_found = - Analog_Output_Property(&index, - &temp_object_property, - object_property); - break; - } - } - } + temp_object_property = RPM_Object_Property( + &property_list, + object_property, + index); + len = rpm_ack_encode_apdu_object_property( + &Temp_Buf[0], + temp_object_property, + array_index); + copy_len = apdu_copy( + &Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], + apdu_len, len, + sizeof(Handler_Transmit_Buffer)); + if (!copy_len) { + apdu_len = abort_encode_apdu( + &Handler_Transmit_Buffer[npdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); + goto RPM_ABORT; + } + application_data_len = Encode_Property_APDU( + &Application_Buf[0], + object_type, + object_instance, + temp_object_property, + array_index, + &error_class, &error_code); + if (application_data_len < 0) { + len = rpm_ack_encode_apdu_object_property_error( + &Temp_Buf[0], + error_class, error_code); } else { - error = true; - done = true; + len = rpm_ack_encode_apdu_object_property_value( + &Temp_Buf[0], + &Application_Buf[0], + application_data_len); + } + copy_len = apdu_copy( + &Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], + apdu_len, len, + sizeof(Handler_Transmit_Buffer)); + if (!copy_len) { + apdu_len = abort_encode_apdu( + &Handler_Transmit_Buffer[npdu_len], + service_data->invoke_id, + ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, + true); + goto RPM_ABORT; } } } else { - done = true; - property_found = true; - } - len = rpm_ack_encode_apdu_object_property( - &Temp_Buf[0], - temp_object_property, - array_index); - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { - apdu_len = abort_encode_apdu( - &Handler_Transmit_Buffer[npdu_len], - service_data->invoke_id, - ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); - break; - } - len = encode_opening_tag(&Temp_Buf[0], 4); - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { - apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); - break; - } - len = -1; - switch(object_type) { - case OBJECT_DEVICE: - if ((object_instance != Device_Object_Instance_Number()) && - ((object_instance != BACNET_MAX_INSTANCE) && - (temp_object_property != PROP_OBJECT_IDENTIFIER))) { - error_class = ERROR_CLASS_OBJECT; - error_code = ERROR_CODE_UNKNOWN_OBJECT; - } else if (!property_found) { - error_class = ERROR_CLASS_PROPERTY; - error_code = ERROR_CODE_UNKNOWN_PROPERTY; - } else { - len = Device_Encode_Property_APDU( - &Temp_Buf[0], - temp_object_property, - array_index, - &error_class, &error_code); - } - break; - case OBJECT_ANALOG_INPUT: - if (!Analog_Input_Valid_Instance(object_instance)) { - error_class = ERROR_CLASS_OBJECT; - error_code = ERROR_CODE_UNKNOWN_OBJECT; - } else if (!property_found) { - error_class = ERROR_CLASS_PROPERTY; - error_code = ERROR_CODE_UNKNOWN_PROPERTY; - } else { - len = Analog_Input_Encode_Property_APDU( - &Temp_Buf[0], - object_instance, - temp_object_property, - array_index, - &error_class, &error_code); - } - break; - case OBJECT_BINARY_INPUT: - if (!Binary_Input_Valid_Instance(object_instance)) { - error_class = ERROR_CLASS_OBJECT; - error_code = ERROR_CODE_UNKNOWN_OBJECT; - } else if (!property_found) { - error_class = ERROR_CLASS_PROPERTY; - error_code = ERROR_CODE_UNKNOWN_PROPERTY; - } else { - len = Binary_Input_Encode_Property_APDU( - &Temp_Buf[0], - object_instance, - temp_object_property, - array_index, - &error_class, &error_code); - } - break; - case OBJECT_ANALOG_OUTPUT: - if (!Analog_Output_Valid_Instance(object_instance)) { - error_class = ERROR_CLASS_OBJECT; - error_code = ERROR_CODE_UNKNOWN_OBJECT; - } else if (!property_found) { - error_class = ERROR_CLASS_PROPERTY; - error_code = ERROR_CODE_UNKNOWN_PROPERTY; - } else { - len = Analog_Output_Encode_Property_APDU( - &Temp_Buf[0], - object_instance, - temp_object_property, - array_index, - &error_class, &error_code); - } - break; - default: - len = -1; - error_class = ERROR_CLASS_OBJECT; - error_code = ERROR_CODE_UNSUPPORTED_OBJECT_TYPE; - break; - } - if (len < 0) { - len = rpm_ack_encode_apdu_object_property_error( - &Temp_Buf[0], - error_class, error_code); - apdu_len--; - error = true; - } - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { - apdu_len = abort_encode_apdu( - &Handler_Transmit_Buffer[npdu_len], - service_data->invoke_id, - ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, - true); - } - if (!error && property_found) { - len = encode_closing_tag(&Temp_Buf[0], 4); - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { + /* handle an individual property */ + application_data_len = Encode_Property_APDU( + &Application_Buf[0], + object_type, + object_instance, + object_property, + array_index, + &error_class, &error_code); + if (application_data_len < 0) { + len = rpm_ack_encode_apdu_object_property_error( + &Temp_Buf[0], + error_class, error_code); + } else { + len = rpm_ack_encode_apdu_object_property_value( + &Temp_Buf[0], + &Application_Buf[0], + application_data_len); + } + copy_len = apdu_copy( + &Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], + apdu_len, len, + sizeof(Handler_Transmit_Buffer)); + if (!copy_len) { apdu_len = abort_encode_apdu( &Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); - break; - } - } else { - error = false; - } - /* check for closing tag */ - if (done) { - len = rpm_ack_decode_object_end( - &service_request[decode_len], - service_len - decode_len); - if (len == 1) { - decode_len++; - break; + goto RPM_ABORT; } } } while(1); - len = encode_closing_tag(&Temp_Buf[0], 1); - if (!copy_apdu_data_buffer(&apdu_len, len, npdu_len)) { - apdu_len = abort_encode_apdu( - &Handler_Transmit_Buffer[npdu_len], - service_data->invoke_id, - ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, - true); - break; - } if (decode_len >= service_len) { break; } } while(1); } +RPM_ABORT: pdu_len = apdu_len + npdu_len; bytes_sent = datalink_send_pdu( - src, - &npdu_data, - &Handler_Transmit_Buffer[0], + src, + &npdu_data, + &Handler_Transmit_Buffer[0], pdu_len); } diff --git a/bacnet-stack/demo/handler/handlers.h b/bacnet-stack/demo/handler/handlers.h index 0ad74fc6..970d2409 100644 --- a/bacnet-stack/demo/handler/handlers.h +++ b/bacnet-stack/demo/handler/handlers.h @@ -77,10 +77,10 @@ extern "C" { uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data); - + void handler_atomic_write_file(uint8_t * service_request, uint16_t service_len, - BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data); + BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data); void handler_reinitialize_device(uint8_t * service_request, uint16_t service_len, @@ -101,6 +101,13 @@ extern "C" { void handler_timesync_utc(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src); + void handler_read_property_multiple( + uint8_t * service_request, + uint16_t service_len, + BACNET_ADDRESS * src, + BACNET_CONFIRMED_SERVICE_DATA * service_data); + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/demo/object/ai.c b/bacnet-stack/demo/object/ai.c index 308ecf60..af8dffcd 100644 --- a/bacnet-stack/demo/object/ai.c +++ b/bacnet-stack/demo/object/ai.c @@ -35,6 +35,49 @@ #define MAX_ANALOG_INPUTS 7 +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Analog_Input_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_UNITS, + -1 +}; + +static const int Analog_Input_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Analog_Input_Properties_Proprietary[] = +{ + 9997, + 9998, + 9999, + -1 +}; + +void Analog_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Analog_Input_Properties_Required; + if (*pOptional) + *pOptional = Analog_Input_Properties_Optional; + if (*pProprietary) + *pProprietary = Analog_Input_Properties_Proprietary; + + return; +} + /* we simply have 0-n object instances. Yours might be */ /* more complex, and then you need validate that the */ /* given instance exists */ diff --git a/bacnet-stack/demo/object/ai.h b/bacnet-stack/demo/object/ai.h index d940be71..5f4920f9 100644 --- a/bacnet-stack/demo/object/ai.h +++ b/bacnet-stack/demo/object/ai.h @@ -32,7 +32,10 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - + void Analog_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Analog_Input_Valid_Instance(uint32_t object_instance); unsigned Analog_Input_Count(void); uint32_t Analog_Input_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/ao.c b/bacnet-stack/demo/object/ao.c index 552d1600..421a1bfb 100644 --- a/bacnet-stack/demo/object/ao.c +++ b/bacnet-stack/demo/object/ao.c @@ -56,6 +56,48 @@ static bool Analog_Output_Out_Of_Service[MAX_ANALOG_OUTPUTS]; /* we need to have our arrays initialized before answering any calls */ static bool Analog_Output_Initialized = false; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Analog_Output_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_UNITS, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Analog_Output_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Analog_Output_Properties_Proprietary[] = +{ + -1 +}; + +void Analog_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Analog_Output_Properties_Required; + if (*pOptional) + *pOptional = Analog_Output_Properties_Optional; + if (*pProprietary) + *pProprietary = Analog_Output_Properties_Proprietary; + + return; +} + void Analog_Output_Init(void) { unsigned i, j; @@ -172,8 +214,8 @@ bool Analog_Output_Present_Value_Set(uint32_t object_instance, /* Note: you could set the physical output here to the next highest priority, or to the relinquish default if no priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } @@ -196,8 +238,8 @@ bool Analog_Output_Present_Value_Relinquish(uint32_t object_instance, /* Note: you could set the physical output here to the next highest priority, or to the relinquish default if no priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } diff --git a/bacnet-stack/demo/object/ao.h b/bacnet-stack/demo/object/ao.h index 1169ea21..d28ba410 100644 --- a/bacnet-stack/demo/object/ao.h +++ b/bacnet-stack/demo/object/ao.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Analog_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Analog_Output_Valid_Instance(uint32_t object_instance); unsigned Analog_Output_Count(void); uint32_t Analog_Output_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/av.c b/bacnet-stack/demo/object/av.c index 022ce72c..43bf2f05 100644 --- a/bacnet-stack/demo/object/av.c +++ b/bacnet-stack/demo/object/av.c @@ -55,6 +55,48 @@ static bool Analog_Value_Out_Of_Service[MAX_ANALOG_VALUES]; /* we need to have our arrays initialized before answering any calls */ static bool Analog_Value_Initialized = false; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Analog_Value_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_UNITS, + -1 +}; + +static const int Analog_Value_Properties_Optional[] = +{ + PROP_DESCRIPTION, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Analog_Value_Properties_Proprietary[] = +{ + -1 +}; + +void Analog_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Analog_Value_Properties_Required; + if (*pOptional) + *pOptional = Analog_Value_Properties_Optional; + if (*pProprietary) + *pProprietary = Analog_Value_Properties_Proprietary; + + return; +} + void Analog_Value_Init(void) { unsigned i, j; @@ -304,8 +346,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, Analog_Value_Level[object_index][priority] = level; /* Note: you could set the physical output here if we are the highest priority. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } else if (priority == 6) { @@ -329,8 +371,8 @@ bool Analog_Value_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, /* Note: you could set the physical output here to the next highest priority, or to the relinquish default if no priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } else { diff --git a/bacnet-stack/demo/object/av.h b/bacnet-stack/demo/object/av.h index d89a52d1..ffd978b2 100644 --- a/bacnet-stack/demo/object/av.h +++ b/bacnet-stack/demo/object/av.h @@ -34,7 +34,10 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - + void Analog_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Analog_Value_Valid_Instance(uint32_t object_instance); unsigned Analog_Value_Count(void); uint32_t Analog_Value_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/bacfile.c b/bacnet-stack/demo/object/bacfile.c index aa56a07b..ecdb3f20 100644 --- a/bacnet-stack/demo/object/bacfile.c +++ b/bacnet-stack/demo/object/bacfile.c @@ -52,6 +52,48 @@ static BACNET_FILE_LISTING BACnet_File_Listing[] = { {0, NULL} /* last file indication */ }; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int bacfile_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_FILE_TYPE, + PROP_FILE_SIZE, + PROP_MODIFICATION_DATE, + PROP_ARCHIVE, + PROP_READ_ONLY, + PROP_FILE_ACCESS_METHOD, + -1 +}; + +static const int bacfile_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int bacfile_Properties_Proprietary[] = +{ + -1 +}; + +void BACfile_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = bacfile_Properties_Required; + if (*pOptional) + *pOptional = bacfile_Properties_Optional; + if (*pProprietary) + *pProprietary = bacfile_Properties_Proprietary; + + return; +} + + char *bacfile_name(uint32_t instance) { uint32_t index = 0; @@ -393,7 +435,7 @@ bool bacfile_write_stream_data(BACNET_ATOMIC_WRITE_FILE_DATA * data) (void)fseek(pFile, data->type.stream.fileStartPosition, SEEK_SET); if (fwrite(octetstring_value(&data->fileData), octetstring_length(&data->fileData),1,pFile) != 1) { - + } fclose(pFile); } diff --git a/bacnet-stack/demo/object/bacfile.h b/bacnet-stack/demo/object/bacfile.h index 82cefe94..585b9ca9 100644 --- a/bacnet-stack/demo/object/bacfile.h +++ b/bacnet-stack/demo/object/bacfile.h @@ -46,6 +46,10 @@ extern "C" { #endif /* __cplusplus */ + void BACfile_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); char *bacfile_name(uint32_t instance); bool bacfile_valid_instance(uint32_t object_instance); uint32_t bacfile_count(void); diff --git a/bacnet-stack/demo/object/bi.c b/bacnet-stack/demo/object/bi.c index 8e7211bc..c5799b97 100644 --- a/bacnet-stack/demo/object/bi.c +++ b/bacnet-stack/demo/object/bi.c @@ -23,7 +23,7 @@ * *********************************************************************/ -/* Analog Input Objects customize for your use */ +/* Binary Input Objects customize for your use */ #include #include @@ -37,6 +37,46 @@ static BACNET_BINARY_PV Present_Value[MAX_BINARY_INPUTS]; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Binary_Input_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_POLARITY, + -1 +}; + +static const int Binary_Input_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Binary_Input_Properties_Proprietary[] = +{ + -1 +}; + +void Binary_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Binary_Input_Properties_Required; + if (*pOptional) + *pOptional = Binary_Input_Properties_Optional; + if (*pProprietary) + *pProprietary = Binary_Input_Properties_Proprietary; + + return; +} + /* we simply have 0-n object instances. Yours might be */ /* more complex, and then you need validate that the */ /* given instance exists */ diff --git a/bacnet-stack/demo/object/bi.h b/bacnet-stack/demo/object/bi.h index 9b5d5187..5725889f 100644 --- a/bacnet-stack/demo/object/bi.h +++ b/bacnet-stack/demo/object/bi.h @@ -33,6 +33,10 @@ extern "C" { #endif /* __cplusplus */ + void Binary_Input_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Binary_Input_Valid_Instance(uint32_t object_instance); unsigned Binary_Input_Count(void); uint32_t Binary_Input_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/bo.c b/bacnet-stack/demo/object/bo.c index 31054b09..dece631b 100644 --- a/bacnet-stack/demo/object/bo.c +++ b/bacnet-stack/demo/object/bo.c @@ -47,6 +47,48 @@ static BACNET_BINARY_PV /* without changing the physical output */ static bool Binary_Output_Out_Of_Service[MAX_BINARY_OUTPUTS]; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Binary_Output_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_POLARITY, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Binary_Output_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Binary_Output_Properties_Proprietary[] = +{ + -1 +}; + +void Binary_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Binary_Output_Properties_Required; + if (*pOptional) + *pOptional = Binary_Output_Properties_Optional; + if (*pProprietary) + *pProprietary = Binary_Output_Properties_Proprietary; + + return; +} + void Binary_Output_Init(void) { unsigned i, j; diff --git a/bacnet-stack/demo/object/bo.h b/bacnet-stack/demo/object/bo.h index 7898186e..2fd1117f 100644 --- a/bacnet-stack/demo/object/bo.h +++ b/bacnet-stack/demo/object/bo.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Binary_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Binary_Output_Valid_Instance(uint32_t object_instance); unsigned Binary_Output_Count(void); uint32_t Binary_Output_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/bv.c b/bacnet-stack/demo/object/bv.c index 7ebec87d..b55d77a8 100644 --- a/bacnet-stack/demo/object/bv.c +++ b/bacnet-stack/demo/object/bv.c @@ -47,6 +47,47 @@ static BACNET_BINARY_PV /* without changing the physical output */ static bool Binary_Value_Out_Of_Service[MAX_BINARY_VALUES]; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Binary_Value_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + -1 +}; + +static const int Binary_Value_Properties_Optional[] = +{ + PROP_DESCRIPTION, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Binary_Value_Properties_Proprietary[] = +{ + -1 +}; + +void Binary_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Binary_Value_Properties_Required; + if (*pOptional) + *pOptional = Binary_Value_Properties_Optional; + if (*pProprietary) + *pProprietary = Binary_Value_Properties_Proprietary; + + return; +} + void Binary_Value_Init(void) { unsigned i, j; @@ -195,9 +236,6 @@ int Binary_Value_Encode_Property_APDU(uint8_t * apdu, state = Binary_Value_Out_Of_Service[object_index]; apdu_len = encode_tagged_boolean(&apdu[0], state); break; - case PROP_POLARITY: - apdu_len = encode_tagged_enumerated(&apdu[0], polarity); - break; case PROP_PRIORITY_ARRAY: /* Array element zero is the number of elements in the array */ if (array_index == 0) diff --git a/bacnet-stack/demo/object/bv.h b/bacnet-stack/demo/object/bv.h index 30c0184d..b50a444e 100644 --- a/bacnet-stack/demo/object/bv.h +++ b/bacnet-stack/demo/object/bv.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Binary_Value_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Binary_Value_Valid_Instance(uint32_t object_instance); unsigned Binary_Value_Count(void); uint32_t Binary_Value_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/device.c b/bacnet-stack/demo/object/device.c index 1803be80..950759f6 100644 --- a/bacnet-stack/demo/object/device.c +++ b/bacnet-stack/demo/object/device.c @@ -48,7 +48,7 @@ #endif /* These three arrays are used by the ReadPropertyMultiple handler */ -static int Device_Properties_Required[] = +static const int Device_Properties_Required[] = { PROP_OBJECT_IDENTIFIER, PROP_OBJECT_NAME, @@ -76,7 +76,7 @@ static int Device_Properties_Required[] = -1 }; -static int Device_Properties_Optional[] = +static const int Device_Properties_Optional[] = { PROP_DESCRIPTION, PROP_LOCAL_TIME, @@ -87,11 +87,26 @@ static int Device_Properties_Optional[] = -1 }; -static int Device_Properties_Proprietary[] = +static const int Device_Properties_Proprietary[] = { -1 }; +void Device_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Device_Properties_Required; + if (*pOptional) + *pOptional = Device_Properties_Optional; + if (*pProprietary) + *pProprietary = Device_Properties_Proprietary; + + return; +} + /* note: you really only need to define variables for properties that are writable or that may change. The properties that are constant can be hard coded @@ -945,100 +960,6 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, return status; } -int int_list_count(const int *pList) -{ - int property_count = 0; - - while (*pList != -1) { - property_count++; - } - - return property_count; -} - -/* used to count the ALL, REQUIRED and OPTIONAL */ -int Device_Special_Property_Count(BACNET_PROPERTY_ID special_property) -{ - const int *pList = NULL; - int property_count = 0; - - if (special_property == PROP_ALL) { - property_count = - int_list_count(Device_Properties_Required); - property_count += - int_list_count(Device_Properties_Optional); - property_count += - int_list_count(Device_Properties_Proprietary); - } else if (special_property == PROP_REQUIRED) { - property_count = - int_list_count(Device_Properties_Required); - } else if (special_property == PROP_OPTIONAL) { - property_count = - int_list_count(Device_Properties_Optional); - } - - return property_count; -} - -/* returns the property ID given by the index into the list - or MAX_BACNET_PROPERTY_ID if not found or out of bounds */ -BACNET_PROPERTY_ID Device_Special_Property_By_Index( - BACNET_PROPERTY_ID special_property, /* ALL, OPTIONAL, REQUIRED */ - int index) -{ - BACNET_PROPERTY_ID property = MAX_BACNET_PROPERTY_ID; - int required = 0, optional = 0, proprietary = 0; - /* FIXME: we could use static vars to speed up access */ - - if (special_property == PROP_ALL) { - required = - property_list_count(Device_Properties_Required); - optional = - property_list_count(Device_Properties_Optional); - proprietary = - property_list_count(Device_Properties_Proprietary); - if (index < required) { - property = Device_Properties_Required[index]; - } else if (index < (required + optional)) { - property = Device_Properties_Optional[index]; - } else if (index < (required + optional + proprietary)) { - property = Device_Properties_Proprietary[index]; - } - } else if (special_property == PROP_REQUIRED) { - required = - property_list_count(Device_Properties_Required); - if (index < required) { - property = Device_Properties_Required[index]; - } - } else if (special_property == PROP_OPTIONAL) { - optional = - property_list_count(Device_Properties_Optional); - if (index < optional) { - property = Device_Properties_Optional[index]; - } - } - - return property; -} - -/* added for rpm service support when requesting prop_all, - prop_required, or prop_optional */ -bool Device_Property(uint8 *pIndex, BACNET_PROPERTY_ID *pProperty, BACNET_PROPERTY_ID special_property) -{ - bool result = false; - BACNET_PROPERTY_ID property; - - property = Device_Special_Property_By_Index( - special_property, *pIndex); - if (property != MAX_BACNET_PROPERTY_ID) { - (*pIndex)++; - *pProperty = property; - result = true; - } - - return result; -} - #ifdef TEST #include #include diff --git a/bacnet-stack/demo/object/device.h b/bacnet-stack/demo/object/device.h index 43c69cc4..957aa9a6 100644 --- a/bacnet-stack/demo/object/device.h +++ b/bacnet-stack/demo/object/device.h @@ -44,6 +44,11 @@ extern "C" { #endif /* __cplusplus */ + void Device_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); + uint32_t Device_Object_Instance_Number(void); bool Device_Set_Object_Instance_Number(uint32_t object_id); bool Device_Valid_Object_Instance_Number(uint32_t object_id); @@ -76,7 +81,7 @@ extern "C" { const char *Device_Location(void); bool Device_Set_Location(const char *name, size_t length); -/* some stack-centric constant values - no set methods */ + /* some stack-centric constant values - no set methods */ uint8_t Device_Protocol_Version(void); uint8_t Device_Protocol_Revision(void); uint16_t Device_Max_APDU_Length_Accepted(void); @@ -104,20 +109,6 @@ extern "C" { bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code); - /* support for RPM */ - - int Device_Special_Property_Count(BACNET_PROPERTY_ID special_property); - - /* returns the property ID given by the index into the list - or MAX_BACNET_PROPERTY_ID if not found or out of bounds */ - BACNET_PROPERTY_ID Device_Special_Property_By_Index( - BACNET_PROPERTY_ID special_property, /* ALL, OPTIONAL, REQUIRED */ - int index); - - bool Device_Property(uint8 *pIndex, BACNET_PROPERTY_ID *pProperty, - BACNET_PROPERTY_ID special_property); - - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/demo/object/lc.c b/bacnet-stack/demo/object/lc.c index 3b2e7c92..25d82c2c 100644 --- a/bacnet-stack/demo/object/lc.c +++ b/bacnet-stack/demo/object/lc.c @@ -24,6 +24,7 @@ *********************************************************************/ /* Load Control Objects - customize for your use */ +/* from 135-2004-Addendum e */ #include #include @@ -105,20 +106,20 @@ static bool Start_Time_Property_Written[MAX_LOAD_CONTROLS]; static float Full_Duty_Baseline[MAX_LOAD_CONTROLS]; #define MAX_SHED_LEVELS 3 -/* Represents the shed levels for the LEVEL choice of - BACnetShedLevel that have meaning for this particular +/* Represents the shed levels for the LEVEL choice of + BACnetShedLevel that have meaning for this particular Load Control object. */ -/* The elements of the array are required to be writable, - allowing local configuration of how this Load Control +/* The elements of the array are required to be writable, + allowing local configuration of how this Load Control object will participate in load shedding for the - facility. This array is not required to be resizable - through BACnet write services. The size of this array - shall be equal to the size of the Shed_Level_Descriptions - array. The behavior of this object when the Shed_Levels + facility. This array is not required to be resizable + through BACnet write services. The size of this array + shall be equal to the size of the Shed_Level_Descriptions + array. The behavior of this object when the Shed_Levels array contains duplicate entries is a local matter. */ static unsigned Shed_Levels[MAX_LOAD_CONTROLS][MAX_SHED_LEVELS]; -/* represents a description of the shed levels that the +/* represents a description of the shed levels that the Load Control object can take on. It is the same for all the load control objects in this example device. */ static char *Shed_Level_Descriptions[MAX_SHED_LEVELS] = { @@ -136,6 +137,54 @@ static float Shed_Level_Values[MAX_SHED_LEVELS] = { /* we need to have our arrays initialized before answering any calls */ static bool Load_Control_Initialized = false; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Load_Control_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_REQUESTED_SHED_LEVEL, + PROP_START_TIME, + PROP_SHED_DURATION, + PROP_DUTY_WINDOW, + PROP_ENABLE, + PROP_EXPECTED_SHED_LEVEL, + PROP_ACTUAL_SHED_LEVEL, + PROP_SHED_LEVELS, + PROP_SHED_LEVEL_DESCRIPTIONS, + -1 +}; + +static const int Load_Control_Properties_Optional[] = +{ + PROP_DESCRIPTION, + PROP_FULL_DUTY_BASELINE, + -1 +}; + +static const int Load_Control_Properties_Proprietary[] = +{ + -1 +}; + +void Load_Control_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Load_Control_Properties_Required; + if (*pOptional) + *pOptional = Load_Control_Properties_Optional; + if (*pProprietary) + *pProprietary = Load_Control_Properties_Proprietary; + + return; +} + void Load_Control_Init(void) { unsigned i, j; @@ -673,15 +722,15 @@ int Load_Control_Encode_Property_APDU(uint8_t * apdu, break; case PROP_STATUS_FLAGS: bitstring_init(&bit_string); - /* IN_ALARM - Logical FALSE (0) if the Event_State property + /* IN_ALARM - Logical FALSE (0) if the Event_State property has a value of NORMAL, otherwise logical TRUE (1). */ bitstring_set_bit(&bit_string, STATUS_FLAG_IN_ALARM, false); - /* FAULT - Logical TRUE (1) if the Reliability property is - present and does not have a value of NO_FAULT_DETECTED, + /* FAULT - Logical TRUE (1) if the Reliability property is + present and does not have a value of NO_FAULT_DETECTED, otherwise logical FALSE (0). */ bitstring_set_bit(&bit_string, STATUS_FLAG_FAULT, false); - /* OVERRIDDEN - Logical TRUE (1) if the point has been - overridden by some mechanism local to the BACnet Device, + /* OVERRIDDEN - Logical TRUE (1) if the point has been + overridden by some mechanism local to the BACnet Device, otherwise logical FALSE (0). */ bitstring_set_bit(&bit_string, STATUS_FLAG_OVERRIDDEN, false); /* OUT_OF_SERVICE - This bit shall always be Logical FALSE (0). */ diff --git a/bacnet-stack/demo/object/lc.h b/bacnet-stack/demo/object/lc.h index 532c76da..b8059919 100644 --- a/bacnet-stack/demo/object/lc.h +++ b/bacnet-stack/demo/object/lc.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Load_Control_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); void Load_Control_State_Machine_Handler(void); bool Load_Control_Valid_Instance(uint32_t object_instance); diff --git a/bacnet-stack/demo/object/lsp.c b/bacnet-stack/demo/object/lsp.c index 9d849d09..c3b3c8be 100644 --- a/bacnet-stack/demo/object/lsp.c +++ b/bacnet-stack/demo/object/lsp.c @@ -50,6 +50,50 @@ static BACNET_LIFE_SAFETY_OPERATION /* without changing the physical output */ static bool Life_Safety_Point_Out_Of_Service[MAX_LIFE_SAFETY_POINTS]; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Life_Safety_Point_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_RELIABILITY, + PROP_MODE, + PROP_ACCEPTED_MODES, + PROP_SILENCED, + PROP_OPERATION_EXPECTED, + -1 +}; + +static const int Life_Safety_Point_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Life_Safety_Point_Properties_Proprietary[] = +{ + -1 +}; + +void Life_Safety_Point_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Life_Safety_Point_Properties_Required; + if (*pOptional) + *pOptional = Life_Safety_Point_Properties_Optional; + if (*pProprietary) + *pProprietary = Life_Safety_Point_Properties_Proprietary; + + return; +} + void Life_Safety_Point_Init(void) { static bool initialized = false; @@ -159,7 +203,7 @@ int Life_Safety_Point_Encode_Property_APDU(uint8_t * apdu, unsigned object_index = 0; bool state = false; BACNET_RELIABILITY reliability = RELIABILITY_NO_FAULT_DETECTED; - + (void) array_index; /* currently not used */ Life_Safety_Point_Init(); switch (property) { diff --git a/bacnet-stack/demo/object/lsp.h b/bacnet-stack/demo/object/lsp.h index 4c3ef01f..42135f62 100644 --- a/bacnet-stack/demo/object/lsp.h +++ b/bacnet-stack/demo/object/lsp.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Life_Safety_Point_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Life_Safety_Point_Valid_Instance(uint32_t object_instance); unsigned Life_Safety_Point_Count(void); uint32_t Life_Safety_Point_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/object/mso.c b/bacnet-stack/demo/object/mso.c index 4c0395e9..73fef351 100644 --- a/bacnet-stack/demo/object/mso.c +++ b/bacnet-stack/demo/object/mso.c @@ -52,6 +52,48 @@ static uint8_t /* without changing the physical output */ static bool Multistate_Output_Out_Of_Service[MAX_MULTISTATE_OUTPUTS]; +/* These three arrays are used by the ReadPropertyMultiple handler */ +static const int Multistate_Output_Properties_Required[] = +{ + PROP_OBJECT_IDENTIFIER, + PROP_OBJECT_NAME, + PROP_OBJECT_TYPE, + PROP_PRESENT_VALUE, + PROP_STATUS_FLAGS, + PROP_EVENT_STATE, + PROP_OUT_OF_SERVICE, + PROP_NUMBER_OF_STATES, + PROP_PRIORITY_ARRAY, + PROP_RELINQUISH_DEFAULT, + -1 +}; + +static const int Multistate_Output_Properties_Optional[] = +{ + PROP_DESCRIPTION, + -1 +}; + +static const int Multistate_Output_Properties_Proprietary[] = +{ + -1 +}; + +void Multistate_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary) +{ + if (*pRequired) + *pRequired = Multistate_Output_Properties_Required; + if (*pOptional) + *pOptional = Multistate_Output_Properties_Optional; + if (*pProprietary) + *pProprietary = Multistate_Output_Properties_Proprietary; + + return; +} + void Multistate_Output_Init(void) { unsigned i, j; @@ -315,8 +357,8 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, (uint8_t) level; /* Note: you could set the physical output here if we are the highest priority. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } else if (priority == 6) { @@ -342,8 +384,8 @@ bool Multistate_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, /* Note: you could set the physical output here to the next highest priority, or to the relinquish default if no priorities are set. - However, if Out of Service is TRUE, then don't set the - physical output. This comment may apply to the + However, if Out of Service is TRUE, then don't set the + physical output. This comment may apply to the main loop (i.e. check out of service before changing output) */ status = true; } else { diff --git a/bacnet-stack/demo/object/mso.h b/bacnet-stack/demo/object/mso.h index d617ea8b..52043c1f 100644 --- a/bacnet-stack/demo/object/mso.h +++ b/bacnet-stack/demo/object/mso.h @@ -35,6 +35,10 @@ extern "C" { #endif /* __cplusplus */ + void Multistate_Output_Property_Lists( + const int **pRequired, + const int **pOptional, + const int **pProprietary); bool Multistate_Output_Valid_Instance(uint32_t object_instance); unsigned Multistate_Output_Count(void); uint32_t Multistate_Output_Index_To_Instance(unsigned index); diff --git a/bacnet-stack/demo/server/Makefile b/bacnet-stack/demo/server/Makefile index 24c384fa..04ab29ee 100644 --- a/bacnet-stack/demo/server/Makefile +++ b/bacnet-stack/demo/server/Makefile @@ -19,7 +19,7 @@ BACNET_PORT = ../../ports/linux BACNET_OBJECT = ../object BACNET_HANDLER = ../handler BACNET_ROOT = ../.. -INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER) +INCLUDES = -I$(BACNET_ROOT) -I$(BACNET_PORT) -I$(BACNET_OBJECT) -I$(BACNET_HANDLER) CFLAGS = -Wall -g $(INCLUDES) $(DEFINES) @@ -38,6 +38,7 @@ SRCS = main.c \ $(BACNET_HANDLER)/noserv.c \ $(BACNET_HANDLER)/h_whois.c \ $(BACNET_HANDLER)/h_rp.c \ + $(BACNET_HANDLER)/h_rpm.c \ $(BACNET_HANDLER)/h_wp.c \ $(BACNET_HANDLER)/h_arf.c \ $(BACNET_HANDLER)/h_awf.c \ @@ -71,6 +72,7 @@ SRCS = main.c \ $(BACNET_ROOT)/whohas.c \ $(BACNET_ROOT)/ihave.c \ $(BACNET_ROOT)/rp.c \ + $(BACNET_ROOT)/rpm.c \ $(BACNET_ROOT)/wp.c \ $(BACNET_ROOT)/arf.c \ $(BACNET_ROOT)/awf.c \ @@ -86,17 +88,17 @@ SRCS = main.c \ OBJS = ${SRCS:.c=.o} all: ${TARGET} - + ${TARGET}: ${OBJS} - ${CC} -pthread -o $@ ${OBJS} + ${CC} -pthread -o $@ ${OBJS} .c.o: ${CC} -c ${CFLAGS} $*.c -o $@ - + depend: rm -f .depend ${CC} -MM ${CFLAGS} *.c >> .depend - + clean: rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini diff --git a/bacnet-stack/demo/server/bacserv.cbp b/bacnet-stack/demo/server/bacserv.cbp index e6c14e93..6a32a71d 100644 --- a/bacnet-stack/demo/server/bacserv.cbp +++ b/bacnet-stack/demo/server/bacserv.cbp @@ -14,11 +14,6 @@ - - - - - @@ -54,7 +49,7 @@ - + @@ -138,6 +133,9 @@ + + @@ -150,6 +148,7 @@ + @@ -218,6 +217,9 @@ + + @@ -228,9 +230,6 @@ - - @@ -249,6 +248,10 @@ + + + diff --git a/bacnet-stack/demo/server/main.c b/bacnet-stack/demo/server/main.c index f270e725..6d9795b0 100644 --- a/bacnet-stack/demo/server/main.c +++ b/bacnet-stack/demo/server/main.c @@ -67,6 +67,8 @@ static void Init_Service_Handlers(void) /* We must implement read property - it's required! */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property); + apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE, + handler_read_property_multiple); apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property); apdu_set_confirmed_handler(SERVICE_CONFIRMED_ATOMIC_READ_FILE, diff --git a/bacnet-stack/demo/server/makefile.b32 b/bacnet-stack/demo/server/makefile.b32 index 134b6325..5d8c27de 100644 --- a/bacnet-stack/demo/server/makefile.b32 +++ b/bacnet-stack/demo/server/makefile.b32 @@ -32,6 +32,7 @@ SRCS = main.c \ ..\..\demo\handler\noserv.c \ ..\..\demo\handler\h_whois.c \ ..\..\demo\handler\h_rp.c \ + ..\..\demo\handler\h_rpm.c \ ..\..\demo\handler\h_wp.c \ ..\..\demo\handler\h_arf.c \ ..\..\demo\handler\h_awf.c \ @@ -52,6 +53,7 @@ SRCS = main.c \ ..\..\whohas.c \ ..\..\ihave.c \ ..\..\rp.c \ + ..\..\rpm.c \ ..\..\wp.c \ ..\..\arf.c \ ..\..\awf.c \ @@ -153,8 +155,8 @@ clean : # Compiler configuration file $(BCC_CFG) : Copy &&| -$(CFLAGS) --c +$(CFLAGS) +-c -y #include line numbers in OBJ's -v #include debug info -w+ #turn on all warnings diff --git a/bacnet-stack/rpm.c b/bacnet-stack/rpm.c index a242b97e..e4aa69fc 100644 --- a/bacnet-stack/rpm.c +++ b/bacnet-stack/rpm.c @@ -112,7 +112,7 @@ int rpm_decode_object_id(uint8_t * apdu, return -1; len += decode_object_id(&apdu[len], &type, object_instance); if (object_type) - *object_type = type; + *object_type = (BACNET_OBJECT_TYPE)type; /* Tag 1: sequence of ReadAccessSpecification */ if (!decode_is_opening_tag_number(&apdu[len], 1)) return -1; @@ -162,7 +162,7 @@ int rpm_decode_object_property(uint8_t * apdu, return -1; len += decode_enumerated(&apdu[len], len_value_type, &property); if (object_property) - *object_property = property; + *object_property = (BACNET_PROPERTY_ID)property; /* Tag 1: Optional propertyArrayIndex */ if (len < apdu_len) { option_len = @@ -317,7 +317,7 @@ int rpm_ack_decode_object_id(uint8_t * apdu, return -1; len += decode_object_id(&apdu[len], &type, object_instance); if (object_type) - *object_type = type; + *object_type = (BACNET_OBJECT_TYPE)type; /* Tag 1: listOfResults */ if (!decode_is_opening_tag_number(&apdu[len], 1)) return -1; @@ -360,7 +360,7 @@ int rpm_ack_decode_object_property(uint8_t * apdu, return -1; len += decode_enumerated(&apdu[len], len_value_type, &property); if (object_property) - *object_property = property; + *object_property = (BACNET_PROPERTY_ID)property; /* Tag 3: Optional propertyArrayIndex */ tag_len = decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type); diff --git a/bacnet-stack/rpm.h b/bacnet-stack/rpm.h index e868657d..f305213f 100644 --- a/bacnet-stack/rpm.h +++ b/bacnet-stack/rpm.h @@ -79,10 +79,15 @@ extern "C" { unsigned apdu_len, BACNET_PROPERTY_ID * object_property, int32_t * array_index); -/* RPM Ack */ +/* RPM Ack - reply from server */ + int rpm_ack_encode_apdu_init(uint8_t * apdu, uint8_t invoke_id); + int rpm_ack_encode_apdu_object_begin(uint8_t * apdu, BACNET_OBJECT_TYPE object_type, uint32_t object_instance); + int rpm_ack_encode_apdu_object_property(uint8_t * apdu, + BACNET_PROPERTY_ID object_property, int32_t array_index); + int rpm_ack_encode_apdu_object_property_value(uint8_t * apdu, uint8_t * application_data, unsigned application_data_len);