Adding ReadPropertyMultiple handler (thank you to John Stachler for this contribution!). Untested and not finished integrating with the demos.

This commit is contained in:
skarg
2007-07-17 00:21:31 +00:00
parent 5e68e165f5
commit b952a54966
3 changed files with 547 additions and 0 deletions
+400
View File
@@ -0,0 +1,400 @@
/**************************************************************************
*
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
* Enhanced by John Stachler for ReadPropertyMultiple
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "config.h"
#include "txbuf.h"
#include "bacdef.h"
#include "bacdcode.h"
#include "apdu.h"
#include "npdu.h"
#include "abort.h"
#include "rpm.h"
#include "handlers.h"
#include "device.h"
#include "ai.h"
#include "ao.h"
#include "bi.h"
static uint8_t Temp_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)
{
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;
}
return copy_status;
}
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 decode_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;
BACNET_ADDRESS my_address;
BACNET_OBJECT_TYPE object_type;
uint32_t object_instance = 0;
int apdu_len = 0;
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);*/
/* encode the NPDU portion of the packet */
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],
src, &my_address, &npdu_data);
#if PRINT_ENABLED
if (service_len <= 0)
printf("RPM: Unable to decode request!\r\n");
#endif
/* bad decoding - send an abort */
if (service_len == 0)
{
apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true);
#if PRINT_ENABLED
printf("RPM: Sending Abort!\r\n");
#endif
} else if (service_data->segmented_message) {
apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
#if PRINT_ENABLED
printf("RPM: Sending Abort!\r\n");
#endif
} else {
/* decode apdu request & encode apdu reply
encode complex ack, invoke id, service choice */
apdu_len = rpm_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id);
do
{
len = rpm_ack_decode_object_id(
&service_request[decode_len],
service_len - decode_len,
&object_type, &object_instance);
if (len < 0) {
break;
} else {
decode_len += len;
}
len = rpm_ack_encode_apdu_object_begin(
&Temp_Buf[0],
object_type, object_instance);
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;
}
/* 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;
}
}
/* handle the special properties */
if ((object_property == PROP_ALL) ||
(object_property == PROP_REQUIRED) ||
(object_property == PROP_OPTIONAL))
{
done = false;
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;
}
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;
}
}
}
} else {
error = true;
done = true;
}
}
} 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)) {
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;
}
}
} 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);
}
pdu_len = apdu_len + npdu_len;
bytes_sent = datalink_send_pdu(
src,
&npdu_data,
&Handler_Transmit_Buffer[0],
pdu_len);
}
+133
View File
@@ -47,6 +47,45 @@
#include "bacfile.h" /* object list dependency */ #include "bacfile.h" /* object list dependency */
#endif #endif
/* These three arrays are used by the ReadPropertyMultiple handler */
static int Device_Properties_Required[] =
{
PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME,
PROP_OBJECT_TYPE,
PROP_SYSTEM_STATUS,
PROP_VENDOR_NAME,
PROP_VENDOR_IDENTIFIER,
PROP_MODEL_NAME,
PROP_FIRMWARE_REVISION,
PROP_APPLICATION_SOFTWARE_VERSION,
PROP_DESCRIPTION,
PROP_PROTOCOL_VERSION,
PROP_PROTOCOL_REVISION,
PROP_PROTOCOL_SERVICES_SUPPORTED,
PROP_PROTOCOL_OBJECT_TYPES_SUPPORTED,
PROP_OBJECT_LIST,
PROP_MAX_APDU_LENGTH_ACCEPTED,
PROP_SEGMENTATION_SUPPORTED,
PROP_APDU_TIMEOUT,
PROP_NUMBER_OF_APDU_RETRIES,
PROP_MAX_MASTER,
PROP_MAX_INFO_FRAMES,
PROP_DEVICE_ADDRESS_BINDING,
PROP_DATABASE_REVISION,
-1
};
static int Device_Properties_Optional[] =
{
-1
};
static int Device_Properties_Proprietary[] =
{
-1
};
/* note: you really only need to define variables for /* note: you really only need to define variables for
properties that are writable or that may change. properties that are writable or that may change.
The properties that are constant can be hard coded The properties that are constant can be hard coded
@@ -900,6 +939,100 @@ bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
return status; 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 #ifdef TEST
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
+14
View File
@@ -104,6 +104,20 @@ extern "C" {
bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data, bool Device_Write_Property(BACNET_WRITE_PROPERTY_DATA * wp_data,
BACNET_ERROR_CLASS * error_class, BACNET_ERROR_CODE * error_code); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */