Enhanced the WriteProperty service demo to allow multiple tagged data elements and to allow context data.

This commit is contained in:
skarg
2007-02-20 20:56:08 +00:00
parent 2fed6fcf3b
commit b3d15b1f37
10 changed files with 760 additions and 472 deletions
+283 -103
View File
@@ -110,6 +110,77 @@ int bacapp_encode_application_data(uint8_t * apdu,
return apdu_len; return apdu_len;
} }
/* decode the data and store it into value.
Return the number of octets consumed. */
int bacapp_decode_data(uint8_t * apdu,
uint8_t tag_data_type,
uint32_t len_value_type,
BACNET_APPLICATION_DATA_VALUE * value)
{
int len = 0;
int object_type = 0;
uint32_t instance = 0;
if (apdu && value) {
switch (tag_data_type) {
case BACNET_APPLICATION_TAG_NULL:
/* nothing else to do */
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
value->type.Boolean = decode_boolean(len_value_type);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
len = decode_unsigned(&apdu[0],
len_value_type, &value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
len = decode_signed(&apdu[0],
len_value_type, &value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_REAL:
len = decode_real(&apdu[0], &(value->type.Real));
break;
#if 0
case BACNET_APPLICATION_TAG_DOUBLE:
len = decode_double(&apdu[0], &(value->type.Double));
break;
#endif
case BACNET_APPLICATION_TAG_ENUMERATED:
len = decode_enumerated(&apdu[0],
len_value_type, &value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
len = decode_date(&apdu[0], &value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
len = decode_bacnet_time(&apdu[0], &value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = decode_object_id(&apdu[0],
&object_type, &instance);
value->type.Object_Id.type = object_type;
value->type.Object_Id.instance = instance;
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
len = decode_octet_string(&apdu[0],
len_value_type, &value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
len = decode_character_string(&apdu[0],
len_value_type, &value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_BIT_STRING:
len = decode_bitstring(&apdu[0],
len_value_type, &value->type.Bit_String);
break;
default:
break;
}
}
return len;
}
int bacapp_decode_application_data(uint8_t * apdu, int bacapp_decode_application_data(uint8_t * apdu,
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value) int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value)
{ {
@@ -117,132 +188,239 @@ int bacapp_decode_application_data(uint8_t * apdu,
int tag_len = 0; int tag_len = 0;
uint8_t tag_number = 0; uint8_t tag_number = 0;
uint32_t len_value_type = 0; uint32_t len_value_type = 0;
/* FIXME: use max_apdu_len! */
(void) max_apdu_len;
if (apdu && value && !decode_is_context_specific(apdu)) {
value->context_specific = false;
tag_len = decode_tag_number_and_value(&apdu[0],
&tag_number, &len_value_type);
if (tag_len) {
len += tag_len;
value->tag = tag_number;
len += bacapp_decode_data(&apdu[len],
tag_number,
len_value_type,
value);
}
value->next = NULL;
}
return len;
}
int bacapp_encode_context_data_value(uint8_t * apdu, uint8_t context_tag_number,
BACNET_APPLICATION_DATA_VALUE * value)
{
int apdu_len = 0; /* total length of the apdu, return value */
if (value && apdu) {
switch (value->tag) {
case BACNET_APPLICATION_TAG_NULL:
apdu_len = encode_context_null(&apdu[0], context_tag_number);
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
apdu_len = encode_context_boolean(&apdu[0], context_tag_number,
value->type.Boolean);
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
apdu_len = encode_context_unsigned(&apdu[0], context_tag_number,
value->type.Unsigned_Int);
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
apdu_len = encode_context_signed(&apdu[0], context_tag_number,
value->type.Signed_Int);
break;
case BACNET_APPLICATION_TAG_REAL:
apdu_len = encode_context_real(&apdu[0], context_tag_number,
value->type.Real);
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
apdu_len = encode_context_enumerated(&apdu[0], context_tag_number,
value->type.Enumerated);
break;
case BACNET_APPLICATION_TAG_DATE:
apdu_len = encode_context_date(&apdu[0], context_tag_number,
&value->type.Date);
break;
case BACNET_APPLICATION_TAG_TIME:
apdu_len = encode_context_time(&apdu[0], context_tag_number,
&value->type.Time);
break;
case BACNET_APPLICATION_TAG_OBJECT_ID:
apdu_len = encode_context_object_id(&apdu[0], context_tag_number,
value->type.Object_Id.type,
value->type.Object_Id.instance);
break;
case BACNET_APPLICATION_TAG_OCTET_STRING:
apdu_len = encode_context_octet_string(&apdu[0], context_tag_number,
&value->type.Octet_String);
break;
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
apdu_len = encode_context_character_string(&apdu[0], context_tag_number,
&value->type.Character_String);
break;
case BACNET_APPLICATION_TAG_BIT_STRING:
apdu_len = encode_context_bitstring(&apdu[0], context_tag_number,
&value->type.Bit_String);
break;
#if 0
case BACNET_APPLICATION_TAG_DOUBLE:
/* FIXME: double is not implemented yet.*/
apdu_len = encode_context_double(&apdu[0], context_tag_number,
value->type.Double);
break;
#endif
default:
break;
}
}
return apdu_len;
}
/* returns the fixed tag type for certain context tagged properties */
BACNET_APPLICATION_TAG bacapp_context_tag_type(
BACNET_PROPERTY_ID property,
uint8_t tag_number)
{
BACNET_APPLICATION_TAG tag = MAX_BACNET_APPLICATION_TAG;
switch (property) {
case PROP_REQUESTED_SHED_LEVEL:
switch (tag_number) {
case 0:
case 1:
tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
break;
case 2:
tag = BACNET_APPLICATION_TAG_REAL;
break;
default:
break;
}
break;
case PROP_ACTION:
switch (tag_number) {
case 0:
case 1:
tag = BACNET_APPLICATION_TAG_OBJECT_ID;
break;
case 2:
tag = BACNET_APPLICATION_TAG_ENUMERATED;
break;
case 3:
case 5:
case 6:
tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
break;
case 7:
case 8:
tag = BACNET_APPLICATION_TAG_BOOLEAN;
break;
case 4: /* propertyValue: abstract syntax */
default:
break;
}
break;
case PROP_EXCEPTION_SCHEDULE:
switch (tag_number) {
case 1:
tag = BACNET_APPLICATION_TAG_OBJECT_ID;
break;
case 3:
tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
break;
case 0: /* calendarEntry: abstract syntax + context */
case 2: /* list of BACnetTimeValue: abstract syntax */
default:
break;
}
break;
default:
break;
}
return tag;
}
int bacapp_encode_context_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property)
{
int apdu_len = 0;
BACNET_APPLICATION_TAG tag_data_type;
if (value && apdu) {
tag_data_type = bacapp_context_tag_type(property, value->context_tag);
if (tag_data_type < MAX_BACNET_APPLICATION_TAG) {
apdu_len = bacapp_encode_context_data_value(&apdu[0],
value->context_tag, value);
} else {
/* FIXME: what now? */
apdu_len = 0;
}
value->next = NULL;
}
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 apdu_len = 0, len = 0;
int tag_len = 0;
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
int object_type = 0; int object_type = 0;
uint32_t instance = 0; uint32_t instance = 0;
/* FIXME: use max_apdu_len! */ /* FIXME: use max_apdu_len! */
(void) max_apdu_len; (void) max_apdu_len;
if (apdu && !decode_is_context_specific(apdu)) { if (apdu && value && decode_is_context_specific(apdu)) {
value->context_specific = true;
tag_len = decode_tag_number_and_value(&apdu[0], tag_len = decode_tag_number_and_value(&apdu[0],
&tag_number, &len_value_type); &tag_number, &len_value_type);
if (tag_len) { if (tag_len) {
len += tag_len; apdu_len = tag_len;
value->tag = tag_number; value->context_tag = tag_number;
if (tag_number == BACNET_APPLICATION_TAG_NULL) { value->tag = bacapp_context_tag_type(property, tag_number);
/* nothing else to do */ if (value->tag < MAX_BACNET_APPLICATION_TAG) {
} else if (tag_number == BACNET_APPLICATION_TAG_BOOLEAN) len = bacapp_decode_data(&apdu[apdu_len],
value->type.Boolean = decode_boolean(len_value_type); value->tag,
else if (tag_number == BACNET_APPLICATION_TAG_UNSIGNED_INT) len_value_type,
len += decode_unsigned(&apdu[len], value);
len_value_type, &value->type.Unsigned_Int); apdu_len += len;
else if (tag_number == BACNET_APPLICATION_TAG_SIGNED_INT) } else {
len += decode_signed(&apdu[len], /* FIXME: what now? */
len_value_type, &value->type.Signed_Int); apdu_len = 0;
else if (tag_number == BACNET_APPLICATION_TAG_REAL)
len += decode_real(&apdu[len], &(value->type.Real));
#if 0
else if (tag_number == BACNET_APPLICATION_TAG_DOUBLE)
len += decode_double(&apdu[len], &(value->type.Double));
#endif
else if (tag_number == BACNET_APPLICATION_TAG_OCTET_STRING)
len += decode_octet_string(&apdu[len],
len_value_type, &value->type.Octet_String);
else if (tag_number == BACNET_APPLICATION_TAG_CHARACTER_STRING)
len += decode_character_string(&apdu[len],
len_value_type, &value->type.Character_String);
else if (tag_number == BACNET_APPLICATION_TAG_BIT_STRING)
len += decode_bitstring(&apdu[len],
len_value_type, &value->type.Bit_String);
else if (tag_number == BACNET_APPLICATION_TAG_ENUMERATED)
len += decode_enumerated(&apdu[len],
len_value_type, &value->type.Enumerated);
else if (tag_number == BACNET_APPLICATION_TAG_DATE)
len += decode_date(&apdu[len], &value->type.Date);
else if (tag_number == BACNET_APPLICATION_TAG_TIME)
len += decode_bacnet_time(&apdu[len], &value->type.Time);
else if (tag_number == BACNET_APPLICATION_TAG_OBJECT_ID) {
len += decode_object_id(&apdu[len],
&object_type, &instance);
value->type.Object_Id.type = object_type;
value->type.Object_Id.instance = instance;
} }
} }
value->next = NULL;
} }
return len; return apdu_len;
} }
int bacapp_encode_context_data(uint8_t * apdu, int bacapp_encode_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value, BACNET_PROPERTY_ID property) BACNET_APPLICATION_DATA_VALUE * value)
{ {
int apdu_len = 0; /* total length of the apdu, return value */ int apdu_len = 0; /* total length of the apdu, return value */
if (value && apdu) { if (value && apdu) {
switch (property) { if (value->context_specific) {
case PROP_REQUESTED_SHED_LEVEL: apdu_len = bacapp_encode_context_data_value(&apdu[0],
switch (value->tag) { value->context_tag, value);
case 0: } else {
case 1: apdu_len = bacapp_encode_application_data(&apdu[0], value);
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; 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;
/* FIXME: use max_apdu_len! */
(void) max_apdu_len;
if (apdu && decode_is_context_specific(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, bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
BACNET_APPLICATION_DATA_VALUE * src_value) BACNET_APPLICATION_DATA_VALUE * src_value)
@@ -299,6 +477,7 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
status = false; status = false;
break; break;
} }
dest_value->next = src_value->next;
} }
return status; return status;
@@ -574,6 +753,7 @@ bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
} else } else
status = false; status = false;
} }
value->next = NULL;
} }
return status; return status;
+16 -2
View File
@@ -41,8 +41,11 @@
#include "bacstr.h" #include "bacstr.h"
#include "datetime.h" #include "datetime.h"
struct BACnet_Application_Data_Value;
typedef struct BACnet_Application_Data_Value { typedef struct BACnet_Application_Data_Value {
uint8_t tag; /* application or context-specific number */ bool context_specific; /* true if context specific data */
uint8_t context_tag; /* only used for context specific data */
uint8_t tag; /* application tag data type */
union { union {
/* NULL - not needed as it is encoded in the tag alone */ /* NULL - not needed as it is encoded in the tag alone */
bool Boolean; bool Boolean;
@@ -58,11 +61,15 @@ typedef struct BACnet_Application_Data_Value {
BACNET_TIME Time; BACNET_TIME Time;
BACNET_OBJECT_ID Object_Id; BACNET_OBJECT_ID Object_Id;
} type; } type;
/* simple linked list if needed */
struct BACnet_Application_Data_Value *next;
} BACNET_APPLICATION_DATA_VALUE; } BACNET_APPLICATION_DATA_VALUE;
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
int bacapp_encode_data(uint8_t * apdu,
BACNET_APPLICATION_DATA_VALUE * value);
int bacapp_decode_application_data(uint8_t * apdu, int bacapp_decode_application_data(uint8_t * apdu,
int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value); int max_apdu_len, BACNET_APPLICATION_DATA_VALUE * value);
@@ -78,6 +85,14 @@ extern "C" {
BACNET_APPLICATION_DATA_VALUE * value, BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property); BACNET_PROPERTY_ID property);
int bacapp_encode_context_data_value(uint8_t * apdu,
uint8_t context_tag_number,
BACNET_APPLICATION_DATA_VALUE * value);
BACNET_APPLICATION_TAG bacapp_context_tag_type(
BACNET_PROPERTY_ID property,
uint8_t tag_number);
bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value, bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE * dest_value,
BACNET_APPLICATION_DATA_VALUE * src_value); BACNET_APPLICATION_DATA_VALUE * src_value);
@@ -99,7 +114,6 @@ extern "C" {
#ifdef BACAPP_PRINT_ENABLED #ifdef BACAPP_PRINT_ENABLED
bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number, bool bacapp_parse_application_data(BACNET_APPLICATION_TAG tag_number,
const char *argv, BACNET_APPLICATION_DATA_VALUE * value); const char *argv, BACNET_APPLICATION_DATA_VALUE * value);
bool bacapp_print_value(FILE * stream, bool bacapp_print_value(FILE * stream,
BACNET_APPLICATION_DATA_VALUE * value, BACNET_APPLICATION_DATA_VALUE * value,
BACNET_PROPERTY_ID property); BACNET_PROPERTY_ID property);
+38 -7
View File
@@ -734,14 +734,11 @@ int encode_tagged_boolean(uint8_t * apdu, bool boolean_value)
int encode_context_boolean(uint8_t * apdu, int tag_number, int encode_context_boolean(uint8_t * apdu, int tag_number,
bool boolean_value) bool boolean_value)
{ {
int len = 1; /* return value */ int len = 0; /* return value */
apdu[1] = boolean_value ? 1 : 0; len = encode_tag(&apdu[0], (uint8_t) tag_number, true, 1);
/* we only reserved 1 byte for encoding the tag - check the limits */ apdu[len] = boolean_value ? 1 : 0;
if (tag_number <= 14) len++;
len += encode_tag(&apdu[0], (uint8_t) tag_number, true, 1);
else
len = 0;
return len; return len;
} }
@@ -777,6 +774,11 @@ int encode_tagged_null(uint8_t * apdu)
return encode_tag(&apdu[0], BACNET_APPLICATION_TAG_NULL, false, 0); return encode_tag(&apdu[0], BACNET_APPLICATION_TAG_NULL, false, 0);
} }
int encode_context_null(uint8_t * apdu, int tag_number)
{
return encode_tag(&apdu[0], tag_number, true, 0);
}
static uint8_t byte_reverse_bits(uint8_t in_byte) static uint8_t byte_reverse_bits(uint8_t in_byte)
{ {
uint8_t out_byte = 0; uint8_t out_byte = 0;
@@ -872,6 +874,20 @@ int encode_tagged_bitstring(uint8_t * apdu, BACNET_BIT_STRING * bit_string)
return len; return len;
} }
int encode_context_bitstring(uint8_t * apdu, int tag_number,
BACNET_BIT_STRING * bit_string)
{
int len = 0;
int bit_string_encoded_length = 1; /* 1 for the bits remaining octet */
/* bit string may use more than 1 octet for the tag, so find out how many */
bit_string_encoded_length += bitstring_bytes_used(bit_string);
len = encode_tag(&apdu[0], tag_number, true, bit_string_encoded_length);
len += encode_bitstring(&apdu[len], bit_string);
return len;
}
/* from clause 20.2.6 Encoding of a Real Number Value */ /* from clause 20.2.6 Encoding of a Real Number Value */
/* returns the number of apdu bytes consumed */ /* returns the number of apdu bytes consumed */
int decode_real(uint8_t * apdu, float *real_value) int decode_real(uint8_t * apdu, float *real_value)
@@ -1429,7 +1445,22 @@ int encode_tagged_time(uint8_t * apdu, BACNET_TIME * btime)
len += encode_tag(&apdu[0], BACNET_APPLICATION_TAG_TIME, false, len); len += encode_tag(&apdu[0], BACNET_APPLICATION_TAG_TIME, false, len);
return len; return len;
}
int encode_context_time(uint8_t * apdu, int tag_number,
BACNET_TIME * btime)
{
int len = 0; /* return value */
/* assumes that the tag only consumes 1 octet */
len = encode_bacnet_time(&apdu[1], btime);
/* we only reserved 1 byte for encoding the tag - check the limits */
if ((tag_number <= 14) && (len <= 4))
len += encode_tag(&apdu[0], (uint8_t) tag_number, true, len);
else
len = 0;
return len;
} }
/* from clause 20.2.13 Encoding of a Time Value */ /* from clause 20.2.13 Encoding of a Time Value */
+5
View File
@@ -72,6 +72,7 @@ extern "C" {
/* from clause 20.2.2 Encoding of a Null Value */ /* from clause 20.2.2 Encoding of a Null Value */
int encode_tagged_null(uint8_t * apdu); int encode_tagged_null(uint8_t * apdu);
int encode_context_null(uint8_t * apdu, int tag_number);
/* from clause 20.2.3 Encoding of a Boolean Value */ /* from clause 20.2.3 Encoding of a Boolean Value */
int encode_tagged_boolean(uint8_t * apdu, bool boolean_value); int encode_tagged_boolean(uint8_t * apdu, bool boolean_value);
@@ -88,6 +89,8 @@ extern "C" {
int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING * bit_string); int encode_bitstring(uint8_t * apdu, BACNET_BIT_STRING * bit_string);
int encode_tagged_bitstring(uint8_t * apdu, int encode_tagged_bitstring(uint8_t * apdu,
BACNET_BIT_STRING * bit_string); BACNET_BIT_STRING * bit_string);
int encode_context_bitstring(uint8_t * apdu, int tag_number,
BACNET_BIT_STRING * bit_string);
/* from clause 20.2.6 Encoding of a Real Number Value */ /* from clause 20.2.6 Encoding of a Real Number Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */ /* and 20.2.1 General Rules for Encoding BACnet Tags */
@@ -168,6 +171,8 @@ extern "C" {
int encode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime); int encode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime);
int encode_tagged_time(uint8_t * apdu, BACNET_TIME * btime); int encode_tagged_time(uint8_t * apdu, BACNET_TIME * btime);
int decode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime); int decode_bacnet_time(uint8_t * apdu, BACNET_TIME * btime);
int encode_context_time(uint8_t * apdu, int tag_number,
BACNET_TIME * btime);
/* BACnet Date */ /* BACnet Date */
/* year = years since 1900 */ /* year = years since 1900 */
+1 -1
View File
@@ -115,7 +115,7 @@ static void days_since_epoch_into_ymd(uint32_t days,
year++; year++;
} }
while (days >= month_days(year, month)) { while (days >= (uint32_t)month_days(year, month)) {
days -= month_days(year, month); days -= month_days(year, month);
month++; month++;
} }
+1 -1
View File
@@ -64,7 +64,7 @@ extern "C" {
BACNET_PROPERTY_ID object_property, BACNET_PROPERTY_ID object_property,
BACNET_APPLICATION_DATA_VALUE * object_value, BACNET_APPLICATION_DATA_VALUE * object_value,
uint8_t priority, int32_t array_index); uint8_t priority, int32_t array_index);
/* returns the invoke ID for confirmed request, or 0 if failed */ /* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Reinitialize_Device_Request(uint32_t device_id, uint8_t Send_Reinitialize_Device_Request(uint32_t device_id,
BACNET_REINITIALIZED_STATE state, char *password); BACNET_REINITIALIZED_STATE state, char *password);
+39 -5
View File
@@ -25,6 +25,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include "config.h" #include "config.h"
#include "config.h" #include "config.h"
#include "txbuf.h" #include "txbuf.h"
@@ -43,11 +44,12 @@
#include "txbuf.h" #include "txbuf.h"
/* returns the invoke ID for confirmed request, or zero on failure */ /* returns the invoke ID for confirmed request, or zero on failure */
uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */ uint8_t Send_Write_Property_Request_Data(uint32_t device_id,
BACNET_OBJECT_TYPE object_type, BACNET_OBJECT_TYPE object_type,
uint32_t object_instance, uint32_t object_instance,
BACNET_PROPERTY_ID object_property, BACNET_PROPERTY_ID object_property,
BACNET_APPLICATION_DATA_VALUE * object_value, uint8_t *application_data,
int application_data_len,
uint8_t priority, int32_t array_index) uint8_t priority, int32_t array_index)
{ {
BACNET_ADDRESS dest; BACNET_ADDRESS dest;
@@ -80,9 +82,8 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
data.object_instance = object_instance; data.object_instance = object_instance;
data.object_property = object_property; data.object_property = object_property;
data.array_index = array_index; data.array_index = array_index;
data.application_data_len = data.application_data_len = application_data_len;
bacapp_encode_application_data(&data.application_data[0], memcpy(&data.application_data[0],&application_data[0], application_data_len);
object_value);
data.priority = priority; data.priority = priority;
len = wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len], len = wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len],
invoke_id, &data); invoke_id, &data);
@@ -117,3 +118,36 @@ uint8_t Send_Write_Property_Request(uint32_t device_id, /* destination device */
return invoke_id; return invoke_id;
} }
uint8_t Send_Write_Property_Request(uint32_t device_id,
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
BACNET_APPLICATION_DATA_VALUE * object_value,
uint8_t priority, int32_t array_index)
{
uint8_t application_data[MAX_APDU] = {0};
int apdu_len = 0, len = 0;
while (object_value) {
len = bacapp_encode_data(
&application_data[apdu_len],
object_value);
if ((len + apdu_len) < MAX_APDU) {
apdu_len += len;
} else {
return 0;
}
object_value = object_value->next;
}
return Send_Write_Property_Request_Data(
device_id,
object_type,
object_instance,
object_property,
&application_data[0],
apdu_len,
priority,
array_index);
}
+1 -2
View File
@@ -20,7 +20,7 @@ CFLAGS = -Wall -g $(INCLUDES) $(DEFINES)
TARGET = bacwp TARGET = bacwp
SRCS = writeprop.c \ SRCS = main.c \
$(BACNET_PORT)/bip-init.c \ $(BACNET_PORT)/bip-init.c \
$(BACNET_ROOT)/bip.c \ $(BACNET_ROOT)/bip.c \
$(BACNET_HANDLER)/txbuf.c \ $(BACNET_HANDLER)/txbuf.c \
@@ -51,7 +51,6 @@ SRCS = writeprop.c \
$(BACNET_ROOT)/bactext.c \ $(BACNET_ROOT)/bactext.c \
$(BACNET_ROOT)/datetime.c \ $(BACNET_ROOT)/datetime.c \
$(BACNET_ROOT)/indtext.c \ $(BACNET_ROOT)/indtext.c \
$(BACNET_ROOT)/bigend.c \
$(BACNET_ROOT)/whois.c \ $(BACNET_ROOT)/whois.c \
$(BACNET_ROOT)/iam.c \ $(BACNET_ROOT)/iam.c \
$(BACNET_ROOT)/tsm.c \ $(BACNET_ROOT)/tsm.c \
@@ -1,349 +1,375 @@
/************************************************************************** /**************************************************************************
* *
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net> * Copyright (C) 2006-2007 Steve Karg <skarg@users.sourceforge.net>
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including * "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, * without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to * distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to * permit persons to whom the Software is furnished to do so, subject to
* the following conditions: * the following conditions:
* *
* The above copyright notice and this permission notice shall be included * The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software. * in all copies or substantial portions of the Software.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*********************************************************************/ *********************************************************************/
/* command line tool that sends a BACnet service, and displays the reply */ /* command line tool that sends a BACnet service, and displays the response */
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> /* for time */ #include <time.h> /* for time */
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "bactext.h" #include "bactext.h"
#include "iam.h" #include "iam.h"
#include "arf.h" #include "arf.h"
#include "tsm.h" #include "tsm.h"
#include "address.h" #include "address.h"
#include "config.h" #include "config.h"
#include "bacdef.h" #include "bacdef.h"
#include "npdu.h" #include "npdu.h"
#include "apdu.h" #include "apdu.h"
#include "device.h" #include "device.h"
#include "net.h" #include "net.h"
#include "datalink.h" #include "datalink.h"
#include "whois.h" #include "whois.h"
/* some demo stuff needed */ /* some demo stuff needed */
#include "filename.h" #include "filename.h"
#include "handlers.h" #include "handlers.h"
#include "client.h" #include "client.h"
#include "txbuf.h" #include "txbuf.h"
/* buffer used for receive */ /* buffer used for receive */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */ /* global variables used in this file */
static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Device_Object_Instance = BACNET_MAX_INSTANCE;
static uint32_t Target_Object_Instance = BACNET_MAX_INSTANCE; static uint32_t Target_Object_Instance = BACNET_MAX_INSTANCE;
static BACNET_OBJECT_TYPE Target_Object_Type = OBJECT_ANALOG_INPUT; static BACNET_OBJECT_TYPE Target_Object_Type = OBJECT_ANALOG_INPUT;
static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS; static BACNET_PROPERTY_ID Target_Object_Property = PROP_ACKED_TRANSITIONS;
/* array index value or BACNET_ARRAY_ALL */ /* array index value or BACNET_ARRAY_ALL */
static int32_t Target_Object_Property_Index = BACNET_ARRAY_ALL; static int32_t Target_Object_Property_Index = BACNET_ARRAY_ALL;
static BACNET_APPLICATION_TAG Target_Object_Property_Tag = #define MAX_PROPERTY_VALUES 16
BACNET_APPLICATION_TAG_NULL; static BACNET_APPLICATION_DATA_VALUE Target_Object_Property_Value[MAX_PROPERTY_VALUES];
static BACNET_APPLICATION_DATA_VALUE Target_Object_Property_Value = { 0 };
/* 0 if not set, 1..16 if set */
/* 0 if not set, 1..16 if set */ static uint8_t Target_Object_Property_Priority = 0;
static uint8_t Target_Object_Property_Priority = 0;
static BACNET_ADDRESS Target_Address;
static BACNET_ADDRESS Target_Address; static bool Error_Detected = false;
static bool Error_Detected = false;
static void MyErrorHandler(BACNET_ADDRESS * src,
static void MyErrorHandler(BACNET_ADDRESS * src, uint8_t invoke_id,
uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code)
BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code) {
{ /* FIXME: verify src and invoke id */
/* FIXME: verify src and invoke id */ (void) src;
(void) src; (void) invoke_id;
(void) invoke_id; printf("\r\nBACnet Error!\r\n");
printf("\r\nBACnet Error!\r\n"); printf("Error Class: %s\r\n", bactext_error_class_name(error_class));
printf("Error Class: %s\r\n", bactext_error_class_name(error_class)); printf("Error Code: %s\r\n", bactext_error_code_name(error_code));
printf("Error Code: %s\r\n", bactext_error_code_name(error_code)); Error_Detected = true;
Error_Detected = true; }
}
void MyAbortHandler(BACNET_ADDRESS * src,
void MyAbortHandler(BACNET_ADDRESS * src, uint8_t invoke_id, uint8_t abort_reason, bool server)
uint8_t invoke_id, uint8_t abort_reason, bool server) {
{ /* FIXME: verify src and invoke id */
/* FIXME: verify src and invoke id */ (void) src;
(void) src; (void) invoke_id;
(void) invoke_id; (void) server;
(void) server; printf("\r\nBACnet Abort!\r\n");
printf("\r\nBACnet Abort!\r\n"); printf("Abort Reason: %s\r\n",
printf("Abort Reason: %s\r\n", bactext_abort_reason_name(abort_reason));
bactext_abort_reason_name(abort_reason)); Error_Detected = true;
Error_Detected = true; }
}
void MyRejectHandler(BACNET_ADDRESS * src,
void MyRejectHandler(BACNET_ADDRESS * src, uint8_t invoke_id, uint8_t reject_reason)
uint8_t invoke_id, uint8_t reject_reason) {
{ /* FIXME: verify src and invoke id */
/* FIXME: verify src and invoke id */ (void) src;
(void) src; (void) invoke_id;
(void) invoke_id; printf("\r\nBACnet Reject!\r\n");
printf("\r\nBACnet Reject!\r\n"); printf("Reject Reason: %s\r\n",
printf("Reject Reason: %s\r\n", bactext_reject_reason_name(reject_reason));
bactext_reject_reason_name(reject_reason)); Error_Detected = true;
Error_Detected = true; }
}
void MyWritePropertySimpleAckHandler(BACNET_ADDRESS * src,
void MyWritePropertySimpleAckHandler(BACNET_ADDRESS * src, uint8_t invoke_id)
uint8_t invoke_id) {
{ (void) src;
(void) src; (void) invoke_id;
(void) invoke_id; printf("\r\nWriteProperty Acknowledged!\r\n");
printf("\r\nWriteProperty Acknowledged!\r\n"); }
}
static void Init_Service_Handlers(void)
static void Init_Service_Handlers(void) {
{ /* we need to handle who-is
/* we need to handle who-is to support dynamic device binding to us */
to support dynamic device binding to us */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
handler_who_is); /* handle i-am to support binding to other devices */
/* handle i-am to support binding to other devices */ apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM,
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_bind);
handler_i_am_bind); /* set the handler for all the services we don't implement
/* set the handler for all the services we don't implement It is required to send the proper reject message... */
It is required to send the proper reject message... */ apdu_set_unrecognized_service_handler_handler
apdu_set_unrecognized_service_handler_handler (handler_unrecognized_service);
(handler_unrecognized_service); /* we must implement read property - it's required! */
/* we must implement read property - it's required! */ apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
handler_read_property); /* handle the ack coming back */
/* handle the ack coming back */ apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, MyWritePropertySimpleAckHandler);
MyWritePropertySimpleAckHandler); /* handle any errors coming back */
/* handle any errors coming back */ apdu_set_error_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
apdu_set_error_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, MyErrorHandler);
MyErrorHandler); apdu_set_abort_handler(MyAbortHandler);
apdu_set_abort_handler(MyAbortHandler); apdu_set_reject_handler(MyRejectHandler);
apdu_set_reject_handler(MyRejectHandler); }
}
int main(int argc, char *argv[])
int main(int argc, char *argv[]) {
{ BACNET_ADDRESS src = { 0 }; /* address where message came from */
BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0;
uint16_t pdu_len = 0; unsigned timeout = 100; /* milliseconds */
unsigned timeout = 100; /* milliseconds */ unsigned max_apdu = 0;
unsigned max_apdu = 0; time_t elapsed_seconds = 0;
time_t elapsed_seconds = 0; time_t last_seconds = 0;
time_t last_seconds = 0; time_t current_seconds = 0;
time_t current_seconds = 0; time_t timeout_seconds = 0;
time_t timeout_seconds = 0; uint8_t invoke_id = 0;
uint8_t invoke_id = 0; bool found = false;
bool found = false; char *value_string = NULL;
char *value_string = NULL; bool status = false;
bool status = false; int args_remaining = 0, tag_value_arg = 0, i = 0;
BACNET_APPLICATION_TAG property_tag;
if (argc < 7) { uint8_t context_tag = 0;
/* note: priority 16 and 0 should produce the same end results... */ bool context_tagged = false;
printf("Usage: %s device-instance object-type object-instance "
"property tag value [priority] [index]\r\n", if (argc < 9) {
filename_remove_path(argv[0])); /* note: priority 16 and 0 should produce the same end results... */
if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) { printf("Usage: %s device-instance object-type object-instance "
printf("device-instance:\r\n" "property priority index tag value [tag value...]\r\n",
"BACnet Device Object Instance number that you are trying to\r\n" filename_remove_path(argv[0]));
"communicate to. This number will be used to try and bind with\r\n" if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) {
"the device using Who-Is and I-Am services. For example, if you were\r\n" printf("device-instance:\r\n"
"writing to Device Object 123, the device-instance would be 123.\r\n" "BACnet Device Object Instance number that you are trying to\r\n"
"\r\n" "communicate to. This number will be used to try and bind with\r\n"
"object-type:\r\n" "the device using Who-Is and I-Am services. For example, if you were\r\n"
"The object type is the integer value of the enumeration\r\n" "writing to Device Object 123, the device-instance would be 123.\r\n"
"BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n" "\r\n"
"writing to. For example if you were writing to Analog Output 2, \r\n" "object-type:\r\n"
"the object-type would be 1.\r\n" "The object type is the integer value of the enumeration\r\n"
"\r\n" "BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n"
"object-instance:\r\n" "writing to. For example if you were writing to Analog Output 2, \r\n"
"This is the object instance number of the object that you are \r\n" "the object-type would be 1.\r\n"
"writing to. For example, if you were writing to Analog Output 2, \r\n" "\r\n"
"the object-instance would be 2.\r\n" "object-instance:\r\n"
"\r\n" "This is the object instance number of the object that you are \r\n"
"property:\r\n" "writing to. For example, if you were writing to Analog Output 2, \r\n"
"The property is an integer value of the enumeration \r\n" "the object-instance would be 2.\r\n"
"BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n" "\r\n"
"writing to. For example, if you were writing to the Present Value\r\n" "property:\r\n"
"property, you would use 85 as the property.\r\n" "The property is an integer value of the enumeration \r\n"
"\r\n" "BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n"
"tag:\r\n" "writing to. For example, if you were writing to the Present Value\r\n"
"Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n" "property, you would use 85 as the property.\r\n"
"in bacenum.h. It is the data type of the value that you are\r\n" "\r\n"
"writing. For example, if you were writing a REAL value, you would \r\n" "priority:\r\n"
"use a tag of 4." "This parameter is used for setting the priority of the\r\n"
"\r\n" "write. If Priority 0 is given, no priority is sent. The BACnet \r\n"
"value:\r\n" "standard states that the value is written at the lowest \r\n"
"The value is an ASCII representation of some type of data that you\r\n" "priority (16) if the object property supports priorities\r\n"
"are writing. It is encoded using the tag information provided. For\r\n" "when no priority is sent.\r\n"
"example, if you were writing a REAL value of 100.0, you would use \r\n" "\r\n"
"100.0 as the value.\r\n" "index\r\n"
"\r\n" "This integer parameter is the index number of an array.\r\n"
"[priority]:\r\n" "If the property is an array, individual elements can be written\r\n"
"This optional parameter is used for setting the priority of the\r\n" "to if supported. If this parameter is -1, the index is ignored.\r\n"
"write. If no priority is given, none is sent, and the BACnet \r\n" "\r\n"
"standard requires that the value is written at the lowest \r\n" "tag:\r\n"
"priority (16) if the object property supports priorities.\r\n" "Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n"
"\r\n" "in bacenum.h. It is the data type of the value that you are\r\n"
"[index]\r\n" "writing. For example, if you were writing a REAL value, you would \r\n"
"This optional integer parameter is the index number of an array.\r\n" "use a tag of 4.\r\n"
"If the property is an array, individual elements can be written\r\n" "Context tags are created using two tags in a row. The context tag\r\n"
"to if supported.\r\n" "is preceded by a C. Ctag tag. C2 4 creates a context 2 tagged REAL.\r\n"
"\r\n" "\r\n"
"Here is a brief overview of BACnet property and tags:\r\n" "value:\r\n"
"Certain properties are expected to be written with certain \r\n" "The value is an ASCII representation of some type of data that you\r\n"
"application tags, so you probably need to know which ones to use\r\n" "are writing. It is encoded using the tag information provided. For\r\n"
"with each property of each object. It is almost safe to say that\r\n" "example, if you were writing a REAL value of 100.0, you would use \r\n"
"given a property and an object and a table, the tag could be looked\r\n" "100.0 as the value.\r\n"
"up automatically. There may be a few exceptions to this, such as\r\n" "\r\n"
"the Any property type in the schedule object and the Present Value\r\n" "Here is a brief overview of BACnet property and tags:\r\n"
"accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n" "Certain properties are expected to be written with certain \r\n"
"the demo to use this kind of table - but I also wanted to be able\r\n" "application tags, so you probably need to know which ones to use\r\n"
"to do negative testing by passing the wrong tag and have the server\r\n" "with each property of each object. It is almost safe to say that\r\n"
"return a reject message.\r\n" "given a property and an object and a table, the tag could be looked\r\n"
"\r\n" "up automatically. There may be a few exceptions to this, such as\r\n"
"Example:\r\n" "the Any property type in the schedule object and the Present Value\r\n"
"If you want send a 100 to the Present-Value in the Analog Output\r\n" "accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n"
"at priority 16, you could send the following command:\r\n" "the demo to use this kind of table - but I also wanted to be able\r\n"
"%s 123 1 0 85 4 100\r\n" "to do negative testing by passing the wrong tag and have the server\r\n"
"You could also send a relinquish command:\r\n" "return a reject message.\r\n"
"%s 123 1 0 85 0 0\r\n", "\r\n"
filename_remove_path(argv[0]), "Example:\r\n"
filename_remove_path(argv[0])); "If you want send a 100 to the Present-Value in the Analog Output\r\n"
} "at priority 16, you could send the following command:\r\n"
return 0; "%s 123 1 0 85 4 100\r\n"
} "You could also send a relinquish command:\r\n"
/* decode the command line parameters */ "%s 123 1 0 85 0 0\r\n",
Target_Device_Object_Instance = strtol(argv[1], NULL, 0); filename_remove_path(argv[0]),
Target_Object_Type = strtol(argv[2], NULL, 0); filename_remove_path(argv[0]));
Target_Object_Instance = strtol(argv[3], NULL, 0); }
Target_Object_Property = strtol(argv[4], NULL, 0); return 0;
Target_Object_Property_Tag = strtol(argv[5], NULL, 0); }
value_string = argv[6]; /* decode the command line parameters */
/* optional priority */ Target_Device_Object_Instance = strtol(argv[1], NULL, 0);
if (argc > 7) Target_Object_Type = strtol(argv[2], NULL, 0);
Target_Object_Property_Priority = strtol(argv[7], NULL, 0); Target_Object_Instance = strtol(argv[3], NULL, 0);
/* optional index */ Target_Object_Property = strtol(argv[4], NULL, 0);
if (argc > 8) Target_Object_Property_Priority = strtol(argv[5], NULL, 0);
Target_Object_Property_Index = strtol(argv[8], NULL, 0); Target_Object_Property_Index = strtol(argv[6], NULL, 0);
if (Target_Object_Property_Index == -1)
if (Target_Device_Object_Instance > BACNET_MAX_INSTANCE) { Target_Object_Property_Index = BACNET_ARRAY_ALL;
fprintf(stderr, "device-instance=%u - it must be less than %u\r\n", if (Target_Device_Object_Instance > BACNET_MAX_INSTANCE) {
Target_Device_Object_Instance, BACNET_MAX_INSTANCE + 1); fprintf(stderr, "device-instance=%u - it must be less than %u\r\n",
return 1; Target_Device_Object_Instance, BACNET_MAX_INSTANCE + 1);
} return 1;
if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) { }
fprintf(stderr, "object-type=%u - it must be less than %u\r\n", if (Target_Object_Type > MAX_BACNET_OBJECT_TYPE) {
Target_Object_Type, MAX_BACNET_OBJECT_TYPE + 1); fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
return 1; Target_Object_Type, MAX_BACNET_OBJECT_TYPE + 1);
} return 1;
if (Target_Object_Instance > BACNET_MAX_INSTANCE) { }
fprintf(stderr, "object-instance=%u - it must be less than %u\r\n", if (Target_Object_Instance > BACNET_MAX_INSTANCE) {
Target_Object_Instance, BACNET_MAX_INSTANCE + 1); fprintf(stderr, "object-instance=%u - it must be less than %u\r\n",
return 1; Target_Object_Instance, BACNET_MAX_INSTANCE + 1);
} return 1;
if (Target_Object_Property > MAX_BACNET_PROPERTY_ID) { }
fprintf(stderr, "object-type=%u - it must be less than %u\r\n", if (Target_Object_Property > MAX_BACNET_PROPERTY_ID) {
Target_Object_Property, MAX_BACNET_PROPERTY_ID + 1); fprintf(stderr, "object-type=%u - it must be less than %u\r\n",
return 1; Target_Object_Property, MAX_BACNET_PROPERTY_ID + 1);
} return 1;
if (Target_Object_Property_Tag >= MAX_BACNET_APPLICATION_TAG) { }
fprintf(stderr, "tag=%u - it must be less than %u\r\n", args_remaining = (argc - 7);
Target_Object_Property_Tag, MAX_BACNET_APPLICATION_TAG); for (i = 0; i < MAX_PROPERTY_VALUES; i++) {
return 1; tag_value_arg = 7+(i*2);
} /* special case for context tagged values */
status = bacapp_parse_application_data(Target_Object_Property_Tag, if (toupper(argv[tag_value_arg][0]) == 'C') {
value_string, &Target_Object_Property_Value); context_tag = strtol(&argv[tag_value_arg][1], NULL, 0);
if (!status) { tag_value_arg++;
/* FIXME: show the expected entry format for the tag */ args_remaining--;
fprintf(stderr, "unable to parse the tag value\r\n"); Target_Object_Property_Value[i].context_tag = context_tag;
return 1; Target_Object_Property_Value[i].context_specific = true;
} } else {
Target_Object_Property_Value[i].context_specific = false;
/* setup my info */ }
Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); property_tag = strtol(argv[tag_value_arg], NULL, 0);
address_init(); value_string = argv[tag_value_arg+1];
Init_Service_Handlers(); args_remaining -= 2;
/* configure standard BACnet/IP port */ /* printf("tag[%d]=%u value[%d]=%s\r\n",
bip_set_interface("eth0"); /* for linux */ i, property_tag, i, value_string); */
bip_set_port(0xBAC0); if (property_tag >= MAX_BACNET_APPLICATION_TAG) {
if (!bip_init()) fprintf(stderr, "tag=%u - it must be less than %u\r\n",
return 1; property_tag, MAX_BACNET_APPLICATION_TAG);
/* configure the timeout values */ return 1;
last_seconds = time(NULL); }
timeout_seconds = (Device_APDU_Timeout() / 1000) * status = bacapp_parse_application_data(property_tag,
Device_Number_Of_APDU_Retries(); value_string, &Target_Object_Property_Value[i]);
/* try to bind with the device */ if (!status) {
Send_WhoIs(Target_Device_Object_Instance, /* FIXME: show the expected entry format for the tag */
Target_Device_Object_Instance); fprintf(stderr, "unable to parse the tag value\r\n");
/* loop forever */ return 1;
for (;;) { }
/* increment timer - exit if timed out */ Target_Object_Property_Value[i].next = NULL;
current_seconds = time(NULL); if (i > 0) {
Target_Object_Property_Value[i-1].next =
/* returns 0 bytes on timeout */ &Target_Object_Property_Value[i];
pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); }
if (args_remaining <= 0)
/* process */ break;
if (pdu_len) { }
npdu_handler(&src, &Rx_Buf[0], pdu_len); /* setup my info */
} Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE);
/* at least one second has passed */ address_init();
if (current_seconds != last_seconds) Init_Service_Handlers();
tsm_timer_milliseconds(((current_seconds - /* configure standard BACnet/IP port */
last_seconds) * 1000)); bip_set_interface("eth0"); /* for linux */
if (Error_Detected) bip_set_port(0xBAC0);
break; if (!bip_init())
/* wait until the device is bound, or timeout and quit */ return 1;
found = address_bind_request(Target_Device_Object_Instance, /* configure the timeout values */
&max_apdu, &Target_Address); last_seconds = time(NULL);
if (found) { timeout_seconds = (Device_APDU_Timeout() / 1000) *
if (invoke_id == 0) { Device_Number_Of_APDU_Retries();
invoke_id = /* try to bind with the device */
Send_Write_Property_Request Send_WhoIs(Target_Device_Object_Instance,
(Target_Device_Object_Instance, Target_Object_Type, Target_Device_Object_Instance);
Target_Object_Instance, Target_Object_Property, /* loop forever */
&Target_Object_Property_Value, for (;;) {
Target_Object_Property_Priority, /* increment timer - exit if timed out */
Target_Object_Property_Index); current_seconds = time(NULL);
} else if (tsm_invoke_id_free(invoke_id))
break; /* returns 0 bytes on timeout */
else if (tsm_invoke_id_failed(invoke_id)) { pdu_len = bip_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id); /* process */
/* try again or abort? */ if (pdu_len) {
break; npdu_handler(&src, &Rx_Buf[0], pdu_len);
} }
} else { /* at least one second has passed */
/* increment timer - exit if timed out */ if (current_seconds != last_seconds)
elapsed_seconds += (current_seconds - last_seconds); tsm_timer_milliseconds(((current_seconds -
if (elapsed_seconds > timeout_seconds) { last_seconds) * 1000));
printf("\rError: APDU Timeout!\r\n"); if (Error_Detected)
break; break;
} /* wait until the device is bound, or timeout and quit */
} found = address_bind_request(Target_Device_Object_Instance,
/* keep track of time for next check */ &max_apdu, &Target_Address);
last_seconds = current_seconds; if (found) {
} if (invoke_id == 0) {
invoke_id =
return 0; Send_Write_Property_Request(
} Target_Device_Object_Instance, Target_Object_Type,
Target_Object_Instance, Target_Object_Property,
&Target_Object_Property_Value[0],
Target_Object_Property_Priority,
Target_Object_Property_Index);
} else if (tsm_invoke_id_free(invoke_id))
break;
else if (tsm_invoke_id_failed(invoke_id)) {
fprintf(stderr, "\rError: TSM Timeout!\r\n");
tsm_free_invoke_id(invoke_id);
/* try again or abort? */
break;
}
} else {
/* increment timer - exit if timed out */
elapsed_seconds += (current_seconds - last_seconds);
if (elapsed_seconds > timeout_seconds) {
printf("\rError: APDU Timeout!\r\n");
break;
}
}
/* keep track of time for next check */
last_seconds = current_seconds;
}
return 0;
}
+1 -2
View File
@@ -17,7 +17,7 @@ PRODUCT_EXE = $(PRODUCT).exe
# Choose the Data Link Layer to Enable # Choose the Data Link Layer to Enable
DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1;BIG_ENDIAN=0;PRINT_ENABLED=1 DEFINES = -DBACDL_BIP=1;TSM_ENABLED=1;BIG_ENDIAN=0;PRINT_ENABLED=1
SRCS = writeprop.c \ SRCS = main.c \
..\..\ports\win32\bip-init.c \ ..\..\ports\win32\bip-init.c \
..\..\filename.c \ ..\..\filename.c \
..\..\bip.c \ ..\..\bip.c \
@@ -34,7 +34,6 @@ SRCS = writeprop.c \
..\..\bactext.c \ ..\..\bactext.c \
..\..\datetime.c \ ..\..\datetime.c \
..\..\indtext.c \ ..\..\indtext.c \
..\..\bigend.c \
..\..\whois.c \ ..\..\whois.c \
..\..\iam.c \ ..\..\iam.c \
..\..\rp.c \ ..\..\rp.c \