adding BACnet application and context-specfic data parsing for WriteProperty.

This commit is contained in:
skarg
2007-01-18 19:32:31 +00:00
parent 176331270c
commit f48e6997ac
8 changed files with 330 additions and 24 deletions
+290 -4
View File
@@ -110,7 +110,7 @@ int bacapp_encode_application_data(uint8_t * apdu,
}
int bacapp_decode_application_data(uint8_t * apdu,
uint8_t apdu_len, BACNET_APPLICATION_DATA_VALUE * value)
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value)
{
int len = 0;
int tag_len = 0;
@@ -119,8 +119,8 @@ int bacapp_decode_application_data(uint8_t * apdu,
int object_type = 0;
uint32_t instance = 0;
/* FIXME: use apdu_len! */
(void) apdu_len;
/* FIXME: use max_apdu_len! */
(void) max_apdu_len;
if (apdu) {
tag_len = decode_tag_number_and_value(&apdu[0],
&tag_number, &len_value_type);
@@ -171,6 +171,84 @@ int bacapp_decode_application_data(uint8_t * apdu,
return len;
}
int bacapp_encode_context_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property)
{
int apdu_len = 0; /* total length of the apdu, return value */
if (value && apdu) {
switch (property) {
case PROP_REQUESTED_SHED_LEVEL:
switch (value->tag) {
case 0:
case 1:
apdu_len = encode_tagged_unsigned(&apdu[0],
value->type.Unsigned_Int);
break;
case 2:
apdu_len = encode_tagged_real(&apdu[0],
value->type.Real);
break;
default:
apdu_len = 0;
break;
}
break;
default:
break;
}
}
return apdu_len;
}
int bacapp_decode_context_data(uint8_t * apdu,
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property)
{
int len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int object_type = 0;
uint32_t instance = 0;
/* FIXME: use max_apdu_len! */
(void) max_apdu_len;
if (apdu) {
tag_len = decode_tag_number_and_value(&apdu[0],
&tag_number, &len_value_type);
if (tag_len) {
len += tag_len;
value->tag = tag_number;
switch (property) {
case PROP_REQUESTED_SHED_LEVEL:
switch (tag_number) {
case 0:
case 1:
len += decode_unsigned(&apdu[len],
len_value_type,
&(value->type.Unsigned_Int));
break;
case 2:
len += decode_real(&apdu[len],
&(value->type.Real));
break;
default:
len = 0;
break;
}
break;
default:
break;
}
}
}
return len;
}
bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
BACNET_APPLICATION_DATA_VALUE * src_value)
{
@@ -236,6 +314,63 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
return status;
}
/* returns the length of data between an opening tag and a closing tag.
Expects that the first octet contain the opening tag.
Include a value property identifier for context specific data
such as the value received in a WriteProperty request */
int bacapp_data_len(uint8_t *apdu, int max_apdu_len,
BACNET_PROPERTY_ID property)
{
int len = 0;
int total_len = 0;
int apdu_len = 0;
uint8_t tag_number = 0;
uint8_t opening_tag_number = 0;
uint8_t opening_tag_number_counter = 0;
uint32_t value = 0;
BACNET_APPLICATION_DATA_VALUE application_value;
if (decode_is_opening_tag(&apdu[0])) {
len = decode_tag_number_and_value(&apdu[apdu_len],
&tag_number, &value);
apdu_len += len;
opening_tag_number = tag_number;
opening_tag_number_counter = 1;
while (opening_tag_number_counter) {
if (decode_is_opening_tag(&apdu[apdu_len])) {
len = decode_tag_number_and_value(&apdu[apdu_len],
&tag_number, &value);
if (tag_number == opening_tag_number)
opening_tag_number_counter++;
} else if (decode_is_closing_tag(&apdu[apdu_len])) {
len = decode_tag_number_and_value(&apdu[apdu_len],
&tag_number, &value);
if (tag_number == opening_tag_number)
opening_tag_number_counter--;
} else if (decode_is_context_specific(&apdu[apdu_len])) {
/* context-specific tagged data */
len = bacapp_decode_context_data(&apdu[apdu_len],
max_apdu_len - apdu_len, &application_value, property);
} else {
/* application tagged data */
len = bacapp_decode_application_data(&apdu[apdu_len],
max_apdu_len - apdu_len, &application_value);
}
apdu_len += len;
if (opening_tag_number_counter)
total_len += len;
/* ERROR! */
if (apdu_len > max_apdu_len)
{
total_len = -1;
break;
}
}
}
return total_len;
}
#ifdef BACAPP_PRINT_ENABLED
bool bacapp_print_value(FILE * stream,
BACNET_APPLICATION_DATA_VALUE * value, BACNET_PROPERTY_ID property)
@@ -448,6 +583,156 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
#include <assert.h>
#include <string.h>
#include "ctest.h"
void testBACnetApplicationDataLength(Test * pTest)
{
int apdu_len = 0; /* total length of the apdu, return value */
int len = 0; /* total length of the apdu, return value */
int test_len = 0; /* length of the data */
uint8_t apdu[480] = { 0 };
BACNET_TIME local_time;
BACNET_DATE local_date;
/* create some constructed data */
/* 1. zero elements */
test_len = 0;
apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
/* verify the length of the data inside the opening/closing tags */
len = constructed_data_len(&apdu[0], apdu_len,
PROP_LIST_OF_OBJECT_PROPERTY_REFERENCES);
ct_test(pTest, test_len == len);
/* 2. application tagged data, one element */
test_len = 0;
apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len = encode_tagged_unsigned(&apdu[apdu_len], 4194303);
test_len += len;
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
/* verify the length of the data inside the opening/closing tags */
len = constructed_data_len(&apdu[0], apdu_len,
PROP_OBJECT_IDENTIFIER);
ct_test(pTest, test_len == len);
/* 3. application tagged data, multiple elements */
test_len = 0;
apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_unsigned(&apdu[apdu_len], 1);
test_len += len;
apdu_len += len;
len = encode_tagged_unsigned(&apdu[apdu_len], 42);
test_len += len;
apdu_len += len;
len = encode_tagged_unsigned(&apdu[apdu_len], 91);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_tagged_null(&apdu[apdu_len]);
test_len += len;
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
/* verify the length of the data inside the opening/closing tags */
len = constructed_data_len(&apdu[0], apdu_len,
PROP_PRIORITY_ARRAY);
ct_test(pTest, test_len == len);
/* 4. complex datatype - one element */
test_len = 0;
apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len = encode_opening_tag(&apdu[apdu_len], 3);
test_len += len;
apdu_len += len;
local_date.year = 2006; /* AD */
local_date.month = 4; /* 1=Jan */
local_date.day = 1; /* 1..31 */
local_date.wday = 6; /* 1=Monday */
len = encode_tagged_date(&apdu[apdu_len], &local_date);
test_len += len;
apdu_len += len;
local_time.hour = 7;
local_time.min = 0;
local_time.sec = 3;
local_time.hundredths = 1;
len = encode_tagged_time(&apdu[apdu_len], &local_time);
test_len += len;
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
test_len += len;
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
/* verify the length of the data inside the opening/closing tags */
len = constructed_data_len(&apdu[0], apdu_len,
PROP_START_TIME);
ct_test(pTest, test_len == len);
/* 5. complex datatype - multiple elements */
/* 6. context tagged data, one element */
test_len = 0;
apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len = encode_context_unsigned(&apdu[apdu_len], 1, 91);
test_len += len;
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
/* verify the length of the data inside the opening/closing tags */
len = constructed_data_len(&apdu[0], apdu_len,
PROP_REQUESTED_SHED_LEVEL);
ct_test(pTest, test_len == len);
}
/* returns true if matching or same, false if different */
bool bacapp_same_date(BACNET_DATE * date1, BACNET_DATE * date2)
{
@@ -722,7 +1007,8 @@ int main(void)
/* individual tests */
rc = ct_addTestFunction(pTest, testBACnetApplicationData);
assert(rc);
rc = ct_addTestFunction(pTest, testBACnetApplicationDataLength);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
+17 -1
View File
@@ -64,14 +64,29 @@ extern "C" {
#endif /* __cplusplus */
int bacapp_decode_application_data(uint8_t * apdu,
uint8_t apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
int bacapp_encode_application_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value);
int bacapp_decode_context_data(uint8_t * apdu,
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property);
int bacapp_encode_context_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property);
bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
BACNET_APPLICATION_DATA_VALUE * src_value);
/* returns the length of data between an opening tag and a closing tag.
Expects that the first octet contain the opening tag.
Include a value property identifier for context specific data
such as the value received in a WriteProperty request */
int bacapp_data_len(uint8_t *apdu, int max_apdu_len,
BACNET_PROPERTY_ID property);
#if PRINT_ENABLED
#define BACAPP_PRINT_ENABLED
#else
@@ -99,6 +114,7 @@ extern "C" {
bool bacapp_same_value(BACNET_APPLICATION_DATA_VALUE * value,
BACNET_APPLICATION_DATA_VALUE * test_value);
void testBACnetApplicationDataLength(Test * pTest);
void testBACnetApplicationData(Test * pTest);
#endif
+2 -4
View File
@@ -618,20 +618,18 @@ int decode_tag_number(uint8_t * apdu, uint8_t * tag_number)
return len;
}
static bool decode_is_opening_tag(uint8_t * apdu)
bool decode_is_opening_tag(uint8_t * apdu)
{
return ((apdu[0] & 0x07) == 6);
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
static bool decode_is_closing_tag(uint8_t * apdu)
bool decode_is_closing_tag(uint8_t * apdu)
{
return ((apdu[0] & 0x07) == 7);
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
int decode_tag_number_and_value(uint8_t * apdu,
+5
View File
@@ -53,6 +53,7 @@ extern "C" {
/* returns the number of apdu bytes consumed */
int encode_opening_tag(uint8_t * apdu, uint8_t tag_number);
int encode_closing_tag(uint8_t * apdu, uint8_t tag_number);
int decode_tag_number(uint8_t * apdu, uint8_t * tag_number);
int decode_tag_number_and_value(uint8_t * apdu, uint8_t * tag_number,
uint32_t * value);
/* returns true if the tag is context specific */
@@ -63,6 +64,10 @@ extern "C" {
bool decode_is_closing_tag_number(uint8_t * apdu, uint8_t tag_number);
/* returns true if the tag is context specific and matches */
bool decode_is_context_tag(uint8_t * apdu, uint8_t tag_number);
/* returns true if the tag is an opening tag */
bool decode_is_opening_tag(uint8_t * apdu);
/* returns true if the tag is a closing tag */
bool decode_is_closing_tag(uint8_t * apdu);
/* from clause 20.2.2 Encoding of a Null Value */
int encode_tagged_null(uint8_t * apdu);
+4 -9
View File
@@ -252,25 +252,20 @@ typedef enum {
PROP_STRUCTURED_OBJECT_LIST = 209,
PROP_SUBORDINATE_ANNOTATIONS = 210,
PROP_SUBORDINATE_LIST = 211,
/* enumerations 212-225 are used in Addendum e to
/* enumerations 212-225 are used in Addendum e to
ANSI/ASHRAE 135-2004 */
PROP_ACTUAL_SHED_LEVEL = 212,
PROP_DUTY_WINDOW = 213,
PROP_EXPECTED_SHED_LEVEL = 214,
PROP_FULL_DUTY_BASELINE = 215,
/* FIXME: is this the right enumeration? */
/* PROP_NODE_SUBTYPE = 216, */
/* PROP_NODE_TYPE = 217, */
/* note: missing enumerations for now */
PROP_REQUESTED_SHED_LEVEL = 218,
PROP_SHED_DURATION = 219,
PROP_SHED_LEVEL_DESCRIPTIONS = 220,
PROP_SHED_LEVELS = 221,
PROP_STATE_DESCRIPTION = 222,
/* FIXME: is this the right enumeration? */
/* PROP_STRUCTURED_OBJECT_LIST = 223, */
/* PROP_SUBORDINATE_ANNOTATIONS = 224, */
/* PROP_SUBORDINATE_LIST = 225, */
/* enumerations 226-235 are used in Addendum f to
/* note: missing enumerations for now */
/* enumerations 226-235 are used in Addendum f to
ANSI/ASHRAE 135-2004 */
PROP_LOG_DEVICE_OBJECT_PROPERTIES = 236,
PROP_LOG_MULTIPLE_BUFFER = 237,
+1 -1
View File
@@ -1,6 +1,6 @@
/**************************************************************************
*
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net>
* Copyright (C) 2007 Steve Karg <skarg@users.sourceforge.net>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
+7 -3
View File
@@ -67,8 +67,9 @@ int wp_encode_apdu(uint8_t * apdu,
/* propertyValue */
len = encode_opening_tag(&apdu[apdu_len], 3);
apdu_len += len;
len =
bacapp_encode_application_data(&apdu[apdu_len], &data->value);
for (len = 0; len < data->application_data_len; len++) {
apdu[apdu_len++] = data->application_data[len];
}
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], 3);
apdu_len += len;
@@ -127,10 +128,13 @@ int wp_decode_service_request(uint8_t * apdu,
return -1;
/* a tag number of 3 is not extended so only one octet */
len++;
/* determine the length of the data blob */
/* FIXME: decode the length of the context specific tag value */
if (decode_is_context_specific(&apdu[len]))
return -2;
/* FIXME: what if the length is more than 255 */
/* FIXME: what if the length is more than 255 */
len += bacapp_decode_application_data(&apdu[len],
(uint8_t)(apdu_len - len), &data->value);
/* FIXME: check the return value; abort if no valid data? */
+4 -2
View File
@@ -41,13 +41,15 @@
/* write property can have application tagged data, or context tagged data,
or even complex data types (i.e. opening and closing tag around data).
It could also have more than one value. */
It could also have more than one value or element. */
typedef struct BACnet_Write_Property_Data {
BACNET_OBJECT_TYPE object_type;
uint32_t object_instance;
BACNET_PROPERTY_ID object_property;
int32_t array_index; /* use BACNET_ARRAY_ALL when not setting */
BACNET_APPLICATION_DATA_VALUE value;
uint8_t *application_data;
int application_data_len;
uint8_t priority; /* use BACNET_NO_PRIORITY if no priority */
} BACNET_WRITE_PROPERTY_DATA;