Corrected ReadPropertyMultiple handler. Tested using VTS with demo/server running under linux.
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
/* 50 is the minimum; adjust to your memory and physical layer constraints */
|
||||
/* Lon=206, MS/TP=480, ARCNET=480, Ethernet=1476 */
|
||||
#ifndef MAX_APDU
|
||||
#define MAX_APDU 50
|
||||
/* #define MAX_APDU 480 */
|
||||
/* #define MAX_APDU 50 */
|
||||
#define MAX_APDU 480
|
||||
/* #define MAX_APDU 1476 */
|
||||
#endif
|
||||
/* for confirmed messages, this is the number of transactions */
|
||||
|
||||
@@ -75,6 +75,7 @@ static unsigned property_list_count(const int *pList)
|
||||
if (pList) {
|
||||
while (*pList != -1) {
|
||||
property_count++;
|
||||
pList++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,8 +184,10 @@ static int RPM_Object_Property(
|
||||
if (index < required) {
|
||||
property = pPropertyList->Required.pList[index];
|
||||
} else if (index < (required + optional)) {
|
||||
index -= required;
|
||||
property = pPropertyList->Optional.pList[index];
|
||||
} else if (index < (required + optional + proprietary)) {
|
||||
index -= (required + optional);
|
||||
property = pPropertyList->Proprietary.pList[index];
|
||||
}
|
||||
} else if (special_property == PROP_REQUIRED) {
|
||||
@@ -458,13 +461,15 @@ void handler_read_property_multiple(
|
||||
service_data->invoke_id);
|
||||
do
|
||||
{
|
||||
len = rpm_ack_decode_object_id(
|
||||
len = rpm_decode_object_id(
|
||||
&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(
|
||||
/* end of object? */
|
||||
if (len > 0) {
|
||||
decode_len += len;
|
||||
} else {
|
||||
len = rpm_decode_object_end(
|
||||
&service_request[decode_len],
|
||||
service_len - decode_len);
|
||||
if (len == 1) {
|
||||
@@ -481,6 +486,8 @@ void handler_read_property_multiple(
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RPM_ABORT;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
} else {
|
||||
apdu_len = abort_encode_apdu(
|
||||
@@ -490,8 +497,6 @@ void handler_read_property_multiple(
|
||||
goto RPM_ABORT;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
decode_len += len;
|
||||
}
|
||||
len = rpm_ack_encode_apdu_object_begin(
|
||||
&Temp_Buf[0],
|
||||
@@ -507,6 +512,8 @@ void handler_read_property_multiple(
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RPM_ABORT;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
/* do each property of this object of the RPM request */
|
||||
do
|
||||
@@ -516,11 +523,39 @@ void handler_read_property_multiple(
|
||||
service_len - decode_len,
|
||||
&object_property,
|
||||
&array_index);
|
||||
/* error - end of property list? */
|
||||
if (len < 0) {
|
||||
break;
|
||||
} else {
|
||||
/* end of property list? */
|
||||
if (len > 0) {
|
||||
decode_len += len;
|
||||
} else {
|
||||
len = rpm_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 += copy_len;
|
||||
}
|
||||
} else {
|
||||
apdu_len = abort_encode_apdu(
|
||||
&Handler_Transmit_Buffer[npdu_len],
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_OTHER, true);
|
||||
goto RPM_ABORT;
|
||||
}
|
||||
/* stop decoding properties */
|
||||
break;
|
||||
}
|
||||
/* handle the special properties */
|
||||
if ((object_property == PROP_ALL) ||
|
||||
@@ -554,6 +589,8 @@ void handler_read_property_multiple(
|
||||
service_data->invoke_id,
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true);
|
||||
goto RPM_ABORT;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
application_data_len = Encode_Property_APDU(
|
||||
&Application_Buf[0],
|
||||
@@ -583,10 +620,29 @@ void handler_read_property_multiple(
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RPM_ABORT;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* handle an individual property */
|
||||
len = rpm_ack_encode_apdu_object_property(
|
||||
&Temp_Buf[0],
|
||||
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;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
application_data_len = Encode_Property_APDU(
|
||||
&Application_Buf[0],
|
||||
object_type,
|
||||
@@ -615,6 +671,8 @@ void handler_read_property_multiple(
|
||||
ABORT_REASON_SEGMENTATION_NOT_SUPPORTED,
|
||||
true);
|
||||
goto RPM_ABORT;
|
||||
} else {
|
||||
apdu_len += copy_len;
|
||||
}
|
||||
}
|
||||
} while(1);
|
||||
|
||||
@@ -68,11 +68,11 @@ void Analog_Input_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Analog_Input_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Analog_Input_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Analog_Input_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -88,11 +88,11 @@ void Analog_Output_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Analog_Output_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Analog_Output_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Analog_Output_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -87,11 +87,11 @@ void Analog_Value_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Analog_Value_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Analog_Value_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Analog_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -83,11 +83,11 @@ void BACfile_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = bacfile_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = bacfile_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = bacfile_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -67,11 +67,11 @@ void Binary_Input_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Input_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Binary_Input_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Binary_Input_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -79,11 +79,11 @@ void Binary_Output_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Output_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Binary_Output_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Binary_Output_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -78,11 +78,11 @@ void Binary_Value_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Binary_Value_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Binary_Value_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Binary_Value_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -97,11 +97,11 @@ void Device_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Device_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Device_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Device_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -175,11 +175,11 @@ void Load_Control_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Load_Control_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Load_Control_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Load_Control_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -84,11 +84,11 @@ void Life_Safety_Point_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Life_Safety_Point_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Life_Safety_Point_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Life_Safety_Point_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
@@ -84,11 +84,11 @@ void Multistate_Output_Property_Lists(
|
||||
const int **pOptional,
|
||||
const int **pProprietary)
|
||||
{
|
||||
if (*pRequired)
|
||||
if (pRequired)
|
||||
*pRequired = Multistate_Output_Properties_Required;
|
||||
if (*pOptional)
|
||||
if (pOptional)
|
||||
*pOptional = Multistate_Output_Properties_Optional;
|
||||
if (*pProprietary)
|
||||
if (pProprietary)
|
||||
*pProprietary = Multistate_Output_Properties_Proprietary;
|
||||
|
||||
return;
|
||||
|
||||
+54
-41
@@ -156,6 +156,8 @@ int rpm_decode_object_property(uint8_t * apdu,
|
||||
/* check for valid pointers */
|
||||
if (apdu && apdu_len && object_property && array_index) {
|
||||
/* Tag 0: propertyIdentifier */
|
||||
if (!decode_is_context_specific(&apdu[len]))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 0)
|
||||
@@ -164,7 +166,9 @@ int rpm_decode_object_property(uint8_t * apdu,
|
||||
if (object_property)
|
||||
*object_property = (BACNET_PROPERTY_ID)property;
|
||||
/* Tag 1: Optional propertyArrayIndex */
|
||||
if (len < apdu_len) {
|
||||
if ((len < apdu_len) &&
|
||||
decode_is_context_specific(&apdu[len]) &&
|
||||
(!decode_is_closing_tag(&apdu[len]))) {
|
||||
option_len =
|
||||
decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
@@ -182,34 +186,6 @@ int rpm_decode_object_property(uint8_t * apdu,
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
int rpm_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint8_t ** service_request, unsigned *service_request_len)
|
||||
{
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
if (service_request)
|
||||
*service_request = &apdu[offset];
|
||||
if (service_request_len)
|
||||
*service_request_len = apdu_len - offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int rpm_ack_encode_apdu_init(uint8_t * apdu, uint8_t invoke_id)
|
||||
{
|
||||
int apdu_len = 0; /* total length of the apdu, return value */
|
||||
@@ -354,6 +330,8 @@ int rpm_ack_decode_object_property(uint8_t * apdu,
|
||||
/* check for valid pointers */
|
||||
if (apdu && apdu_len && object_property && array_index) {
|
||||
/* Tag 2: propertyIdentifier */
|
||||
if (!decode_is_context_specific(&apdu[len]))
|
||||
return -1;
|
||||
len += decode_tag_number_and_value(&apdu[len],
|
||||
&tag_number, &len_value_type);
|
||||
if (tag_number != 2)
|
||||
@@ -362,20 +340,32 @@ int rpm_ack_decode_object_property(uint8_t * apdu,
|
||||
if (object_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);
|
||||
if (tag_number == 3) {
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&array_value);
|
||||
*array_index = array_value;
|
||||
} else
|
||||
if ((len < apdu_len) &&
|
||||
decode_is_context_specific(&apdu[len]) &&
|
||||
(!decode_is_closing_tag(&apdu[len]))) {
|
||||
tag_len = decode_tag_number_and_value(&apdu[len], &tag_number,
|
||||
&len_value_type);
|
||||
if (tag_number == 3) {
|
||||
len += tag_len;
|
||||
len += decode_unsigned(&apdu[len], len_value_type,
|
||||
&array_value);
|
||||
*array_index = array_value;
|
||||
} else {
|
||||
*array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
} else {
|
||||
*array_index = BACNET_ARRAY_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return (int) len;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
|
||||
int rpm_ack_decode_apdu(uint8_t * apdu, int apdu_len, /* total length of the apdu */
|
||||
uint8_t * invoke_id,
|
||||
uint8_t ** service_request, unsigned *service_request_len)
|
||||
@@ -401,10 +391,33 @@ int rpm_ack_decode_apdu(uint8_t * apdu, int apdu_len, /* total length of the a
|
||||
return offset;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "ctest.h"
|
||||
int rpm_decode_apdu(uint8_t * apdu,
|
||||
unsigned apdu_len,
|
||||
uint8_t * invoke_id,
|
||||
uint8_t ** service_request, unsigned *service_request_len)
|
||||
{
|
||||
unsigned offset = 0;
|
||||
|
||||
if (!apdu)
|
||||
return -1;
|
||||
/* optional checking - most likely was already done prior to this call */
|
||||
if (apdu[0] != PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
|
||||
return -1;
|
||||
/* apdu[1] = encode_max_segs_max_apdu(0, Device_Max_APDU_Length_Accepted()); */
|
||||
*invoke_id = apdu[2]; /* invoke id - filled in by net layer */
|
||||
if (apdu[3] != SERVICE_CONFIRMED_READ_PROPERTY_MULTIPLE)
|
||||
return -1;
|
||||
offset = 4;
|
||||
|
||||
if (apdu_len > offset) {
|
||||
if (service_request)
|
||||
*service_request = &apdu[offset];
|
||||
if (service_request_len)
|
||||
*service_request_len = apdu_len - offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void testReadPropertyMultiple(Test * pTest)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user