Added DeviceCommunicationControl in the demos and into the stack.

This commit is contained in:
skarg
2006-02-10 22:44:34 +00:00
parent 6d8d5b83ca
commit 566749508c
28 changed files with 324 additions and 104 deletions
+12 -2
View File
@@ -1,13 +1,20 @@
all: readprop writeprop readfile writefile reinit server
all: readprop writeprop readfile writefile reinit server dcc
@echo "utilities are in demo/xx directories"
clean: demo/readprop/Makefile demo/writeprop/Makefile demo/readfile/Makefile demo/writefile/Makefile demo/server/Makefile
clean: \
demo/readprop/Makefile \
demo/writeprop/Makefile \
demo/readfile/Makefile \
demo/writefile/Makefile \
demo/server/Makefile \
demo/dcc/Makefile
( cd demo/readprop ; make clean )
( cd demo/writeprop ; make clean )
( cd demo/readfile ; make clean )
( cd demo/writefile ; make clean )
( cd demo/reinit ; make clean )
( cd demo/server ; make clean )
( cd demo/dcc ; make clean )
readprop: demo/readprop/Makefile
( cd demo/readprop ; make clean ; make )
@@ -27,3 +34,6 @@ reinit: demo/reinit/Makefile
server: demo/server/Makefile
( cd demo/server ; make clean ; make )
dcc: demo/dcc/Makefile
( cd demo/dcc ; make clean ; make )
+26 -21
View File
@@ -40,6 +40,7 @@
#include "bacdcode.h"
#include "bacenum.h"
#include "tsm.h"
#include "dcc.h"
#include "iam.h"
/* a simple table for crossing the services supported */
@@ -347,26 +348,30 @@ void apdu_handler(
&service_choice,
&service_request,
&service_request_len);
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE)
{
if (Confirmed_Function[service_choice])
Confirmed_Function[service_choice](
service_request,
service_request_len,
src,
&service_data);
else
{
if (Unrecognized_Service_Handler)
Unrecognized_Service_Handler(
service_request,
service_request_len,
src,
&service_data);
}
}
/* When network communications are completely disabled,
only DeviceCommunicationControl and ReinitializeDevice APDUs
shall be processed and no messages shall be initiated.*/
if (dcc_communication_disabled() &&
((service_choice != SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL) &&
(service_choice != SERVICE_CONFIRMED_REINITIALIZE_DEVICE)))
break;
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
(Confirmed_Function[service_choice]))
Confirmed_Function[service_choice](
service_request,
service_request_len,
src,
&service_data);
else if (Unrecognized_Service_Handler)
Unrecognized_Service_Handler(
service_request,
service_request_len,
src,
&service_data);
break;
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
if (dcc_communication_disabled())
break;
service_choice = apdu[1];
service_request = &apdu[2];
service_request_len = apdu_len - 2;
@@ -374,9 +379,9 @@ void apdu_handler(
{
if (Unconfirmed_Function[service_choice])
Unconfirmed_Function[service_choice](
service_request,
service_request_len,
src);
service_request,
service_request_len,
src);
}
break;
case PDU_TYPE_SIMPLE_ACK:
+2 -1
View File
@@ -932,7 +932,8 @@ typedef enum {
typedef enum {
COMMUNICATION_ENABLE = 0,
COMMUNICATION_DISABLE = 1,
COMMUNICATION_DISABLE_INITIATION = 2
COMMUNICATION_DISABLE_INITIATION = 2,
MAX_BACNET_COMMUNICATION_ENABLE_DISABLE = 3
} BACNET_COMMUNICATION_ENABLE_DISABLE;
typedef enum {
+38
View File
@@ -271,6 +271,44 @@ bool characterstring_same(
return same_status;
}
bool characterstring_ansi_same(
BACNET_CHARACTER_STRING *dest,
const char *src)
{
size_t i; /* counter */
bool same_status = false;
if (src && dest)
{
if ((dest->length == strlen(src)) &&
(dest->encoding == CHARACTER_ANSI_X34))
{
same_status = true;
for (i = 0; i < dest->length; i++)
{
if (src[i] != dest->value[i])
{
same_status = false;
break;
}
}
}
}
/* NULL matches an empty string in our world */
else if (src)
{
if (strlen(src) == 0)
same_status = true;
}
else if (dest)
{
if (dest->length == 0)
same_status = true;
}
return same_status;
}
/* returns false if the string exceeds capacity */
bool characterstring_append(
BACNET_CHARACTER_STRING *char_string,
+3
View File
@@ -106,6 +106,9 @@ bool characterstring_copy(
bool characterstring_same(
BACNET_CHARACTER_STRING *dest,
BACNET_CHARACTER_STRING *src);
bool characterstring_ansi_same(
BACNET_CHARACTER_STRING *dest,
const char *src);
/* returns false if the string exceeds capacity */
bool characterstring_append(
BACNET_CHARACTER_STRING *char_string,
+82
View File
@@ -37,6 +37,88 @@
#include "bacdef.h"
#include "dcc.h"
/* note: the disable and time are not expected to survive
over a power cycle or reinitialization. */
/* note: time duration is given in Minutes, but in order to be accurate,
we need to count down in seconds. */
static uint32_t DCC_Time_Duration_Seconds = 0;
static BACNET_COMMUNICATION_ENABLE_DISABLE DCC_Enable_Disable =
COMMUNICATION_ENABLE;
/* password is optionally supported */
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void)
{
return DCC_Enable_Disable;
}
bool dcc_communication_enabled(void)
{
return (DCC_Enable_Disable == COMMUNICATION_ENABLE);
}
/* When network communications are completely disabled,
only DeviceCommunicationControl and ReinitializeDevice APDUs
shall be processed and no messages shall be initiated.*/
bool dcc_communication_disabled(void)
{
return (DCC_Enable_Disable == COMMUNICATION_DISABLE);
}
/* When the initiation of communications is disabled,
all APDUs shall be processed and responses returned as
required and no messages shall be initiated with the
exception of I-Am requests, which shall be initiated only in
response to Who-Is messages. In this state, a device that
supports I-Am request initiation shall send one I-Am request
for any Who-Is request that is received if and only if
the Who-Is request does not contain an address range or
the device is included in the address range. */
bool dcc_communication_initiation_disabled(void)
{
return (DCC_Enable_Disable == COMMUNICATION_DISABLE_INITIATION);
}
uint32_t dcc_duration_seconds(void)
{
return DCC_Time_Duration_Seconds;
}
/* called every second or so. If more than one second,
then seconds should be the number of seconds to tick away */
void dcc_timer_seconds(uint32_t seconds)
{
if (DCC_Time_Duration_Seconds)
{
if (DCC_Time_Duration_Seconds > seconds)
DCC_Time_Duration_Seconds -= seconds;
else
DCC_Time_Duration_Seconds = 0;
/* just expired - do something */
if (DCC_Time_Duration_Seconds == 0)
DCC_Enable_Disable = COMMUNICATION_ENABLE;
}
}
bool dcc_set_status_duration(
BACNET_COMMUNICATION_ENABLE_DISABLE status,
uint16_t minutes)
{
bool valid = false;
/* valid? */
if (status < MAX_BACNET_COMMUNICATION_ENABLE_DISABLE)
{
DCC_Enable_Disable = status;
if (status == COMMUNICATION_ENABLE)
DCC_Time_Duration_Seconds = 0;
else
DCC_Time_Duration_Seconds = minutes * 60;
valid = true;
}
return valid;
}
/* encode service */
int dcc_encode_apdu(
uint8_t *apdu,
+18 -1
View File
@@ -36,14 +36,31 @@
#include <stdint.h>
#include <stdbool.h>
#include "bacenum.h"
#include "bacstr.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* return the status */
BACNET_COMMUNICATION_ENABLE_DISABLE dcc_enable_status(void);
bool dcc_communication_enabled(void);
bool dcc_communication_disabled(void);
bool dcc_communication_initiation_disabled(void);
/* return the time */
uint32_t dcc_duration_seconds(void);
/* called every second or so. If more than one second,
then seconds should be the number of seconds to tick away */
void dcc_timer_seconds(uint32_t seconds);
/* setup the communication values */
bool dcc_set_status_duration(
BACNET_COMMUNICATION_ENABLE_DISABLE status,
uint16_t minutes);
// encode service
int dcc_encode_apdu(
uint8_t *apdu,
uint8_t *apdu,
uint8_t invoke_id,
uint16_t timeDuration, /* 0=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE enable_disable,
+22 -8
View File
@@ -31,25 +31,26 @@
#include "bacdef.h"
#include "apdu.h"
#include "bacapp.h"
#include "bacenum.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* FIXME: probably should return the invoke ID for confirmed request */
bool Send_Read_Property_Request(
void Send_WhoIs(
int32_t low_limit,
int32_t high_limit);
/* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Read_Property_Request(
uint32_t device_id, /* destination device */
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
BACNET_PROPERTY_ID object_property,
int32_t array_index);
void Send_WhoIs(
int32_t low_limit,
int32_t high_limit);
/* FIXME: probably should return the invoke ID for confirmed request */
bool Send_Write_Property_Request(
/* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Write_Property_Request(
uint32_t device_id, // destination device
BACNET_OBJECT_TYPE object_type,
uint32_t object_instance,
@@ -58,6 +59,19 @@ bool Send_Write_Property_Request(
uint8_t priority,
int32_t array_index);
/* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Reinitialize_Device_Request(
uint32_t device_id,
BACNET_REINITIALIZED_STATE state,
char *password);
/* returns the invoke ID for confirmed request, or 0 if failed */
uint8_t Send_Device_Communication_Control_Request(
uint32_t device_id,
uint16_t timeDuration, /* 0=optional */
BACNET_COMMUNICATION_ENABLE_DISABLE state,
char *password); /* NULL=optional */
#ifdef __cplusplus
}
#endif /* __cplusplus */
+2
View File
@@ -112,6 +112,8 @@ void handler_reinitialize_device(
fprintf(stderr,"ReinitializeDevice: Sending Simple Ack!\n");
/* FIXME: now you can reboot, restart, quit, or something clever */
/* Note: you can use a mix of state and password to do specific stuff */
/* Note: if you don't do something clever like actually restart,
you probably should clear any DCC status and timeouts */
}
else
{
+6
View File
@@ -96,6 +96,12 @@ void handler_reinitialize_device(
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data);
void handler_device_communication_control(
uint8_t *service_request,
uint16_t service_len,
BACNET_ADDRESS *src,
BACNET_CONFIRMED_SERVICE_DATA *service_data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
+4
View File
@@ -36,6 +36,7 @@
#include "apdu.h"
#include "device.h"
#include "datalink.h"
#include "dcc.h"
#include "rp.h"
/* some demo stuff needed */
#include "handlers.h"
@@ -58,6 +59,9 @@ uint8_t Send_Read_Property_Request(
int bytes_sent = 0;
BACNET_READ_PROPERTY_DATA data;
if (!dcc_communication_enabled())
return 0;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
+4
View File
@@ -36,6 +36,7 @@
#include "apdu.h"
#include "device.h"
#include "datalink.h"
#include "dcc.h"
#include "whois.h"
/* some demo stuff needed */
#include "handlers.h"
@@ -50,6 +51,9 @@ void Send_WhoIs(
BACNET_ADDRESS dest;
int bytes_sent = 0;
if (!dcc_communication_enabled())
return;
// Who-Is is a global broadcast
datalink_get_broadcast_address(&dest);
+4
View File
@@ -36,6 +36,7 @@
#include "apdu.h"
#include "device.h"
#include "datalink.h"
#include "dcc.h"
#include "whois.h"
/* some demo stuff needed */
#include "handlers.h"
@@ -60,6 +61,9 @@ uint8_t Send_Write_Property_Request(
int bytes_sent = 0;
BACNET_WRITE_PROPERTY_DATA data;
if (!dcc_communication_enabled())
return 0;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
+2
View File
@@ -40,11 +40,13 @@ SRCS = readfile.c \
$(BACNET_ROOT)/tsm.c \
$(BACNET_ROOT)/datalink.c \
$(BACNET_ROOT)/address.c \
$(BACNET_ROOT)/filename.c \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
$(BACNET_OBJECT)/bacfile.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
+1
View File
@@ -36,6 +36,7 @@ SRCS = readfile.c \
..\..\wp.c \
..\..\arf.c \
..\..\awf.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
+3 -1
View File
@@ -44,6 +44,7 @@
#include "datalink.h"
#include "whois.h"
/* some demo stuff needed */
#include "filename.h"
#include "handlers.h"
#include "txbuf.h"
@@ -339,7 +340,8 @@ int main(int argc, char *argv[])
if (argc < 4)
{
/* FIXME: what about access method - record or stream? */
printf("%s device-instance file-instance local-name\r\n",argv[0]);
printf("%s device-instance file-instance local-name\r\n",
filename_remove_path(argv[0]));
return 0;
}
/* decode the command line parameters */
+1
View File
@@ -50,6 +50,7 @@ SRCS = readprop.c \
$(BACNET_ROOT)/datalink.c \
$(BACNET_ROOT)/address.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
+1
View File
@@ -41,6 +41,7 @@ SRCS = readprop.c \
..\..\wp.c \
..\..\arf.c \
..\..\awf.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
+2
View File
@@ -30,6 +30,7 @@ SRCS = main.c \
$(BACNET_HANDLER)/h_rp.c \
$(BACNET_HANDLER)/h_iam.c \
$(BACNET_HANDLER)/s_whois.c \
$(BACNET_HANDLER)/s_rd.c \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
@@ -50,6 +51,7 @@ SRCS = main.c \
$(BACNET_ROOT)/datalink.c \
$(BACNET_ROOT)/address.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
-66
View File
@@ -61,72 +61,6 @@ static char *Reinitialize_Password = NULL;
static bool Error_Detected = false;
static uint8_t Send_Reinitialize_Device_Request(
uint32_t device_id,
BACNET_REINITIALIZED_STATE state,
char *password)
{
BACNET_ADDRESS dest;
BACNET_ADDRESS my_address;
unsigned max_apdu = 0;
uint8_t invoke_id = 0;
bool status = false;
int pdu_len = 0;
int bytes_sent = 0;
BACNET_CHARACTER_STRING password_string;
/* is the device bound? */
status = address_get_by_device(device_id, &max_apdu, &dest);
/* is there a tsm available? */
if (status)
status = tsm_transaction_available();
if (status)
{
datalink_get_my_address(&my_address);
pdu_len = npdu_encode_apdu(
&Handler_Transmit_Buffer[0],
&dest,
&my_address,
true, // true for confirmed messages
MESSAGE_PRIORITY_NORMAL);
invoke_id = tsm_next_free_invokeID();
// load the data for the encoding
characterstring_init_ansi(&password_string,password);
pdu_len += rd_encode_apdu(
&Handler_Transmit_Buffer[pdu_len],
invoke_id,
state,
password?&password_string:NULL);
/* will it fit in the sender?
note: if there is a bottleneck router in between
us and the destination, we won't know unless
we have a way to check for that and update the
max_apdu in the address binding table. */
if ((unsigned)pdu_len < max_apdu)
{
tsm_set_confirmed_unsegmented_transaction(
invoke_id,
&dest,
&Handler_Transmit_Buffer[0],
pdu_len);
bytes_sent = datalink_send_pdu(
&dest, // destination address
&Handler_Transmit_Buffer[0],
pdu_len); // number of bytes of data
if (bytes_sent <= 0)
fprintf(stderr,"Failed to Send ReinitializeDevice Request (%s)!\n",
strerror(errno));
}
else
fprintf(stderr,"Failed to Send ReinitializeDevice Request "
"(exceeds destination maximum APDU)!\n");
}
return invoke_id;
}
static void MyErrorHandler(
BACNET_ADDRESS *src,
uint8_t invoke_id,
+1
View File
@@ -40,6 +40,7 @@ SRCS = main.c \
..\..\wp.c \
..\..\arf.c \
..\..\awf.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
+2
View File
@@ -30,6 +30,7 @@ SRCS = server.c \
$(BACNET_HANDLER)/h_wp.c \
$(BACNET_HANDLER)/h_arf.c \
$(BACNET_HANDLER)/h_rd.c \
$(BACNET_HANDLER)/h_dcc.c \
$(BACNET_OBJECT)/device.c \
$(BACNET_OBJECT)/ai.c \
$(BACNET_OBJECT)/ao.c \
@@ -49,6 +50,7 @@ SRCS = server.c \
$(BACNET_ROOT)/wp.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/rd.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
+2
View File
@@ -29,6 +29,7 @@ SRCS = server.c \
..\..\demo\handler\h_wp.c \
..\..\demo\handler\h_arf.c \
..\..\demo\handler\h_rd.c \
..\..\demo\handler\h_dcc.c \
..\..\bacdcode.c \
..\..\bacapp.c \
..\..\bacstr.c \
@@ -42,6 +43,7 @@ SRCS = server.c \
..\..\arf.c \
..\..\awf.c \
..\..\rd.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
+14 -2
View File
@@ -41,6 +41,7 @@
#include "device.h"
#include "bacfile.h"
#include "datalink.h"
#include "dcc.h"
#include "net.h"
#include "txbuf.h"
@@ -55,7 +56,6 @@ static void Init_Service_Handlers(void)
apdu_set_unconfirmed_handler(
SERVICE_UNCONFIRMED_WHO_IS,
handler_who_is);
/* set the handler for all the services we don't implement */
/* It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler(
@@ -74,6 +74,10 @@ static void Init_Service_Handlers(void)
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_reinitialize_device);
/* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
}
static void cleanup(void)
@@ -104,6 +108,8 @@ int main(int argc, char *argv[])
uint16_t pdu_len = 0;
unsigned timeout = 100; // milliseconds
BACNET_ADDRESS my_address, broadcast_address;
time_t last_seconds = 0;
time_t current_seconds = 0;
/* allow the device ID to be set */
if (argc > 1)
@@ -133,13 +139,15 @@ int main(int argc, char *argv[])
datalink_get_my_address(&my_address);
print_address("Address",&my_address);
atexit(cleanup);
/* configure the timeout values */
last_seconds = time(NULL);
/* broadcast an I-Am on startup */
I_Am_Request = true;
// loop forever
for (;;)
{
// input
current_seconds = time(NULL);
// returns 0 bytes on timeout
pdu_len = datalink_receive(
@@ -156,6 +164,10 @@ int main(int argc, char *argv[])
&Rx_Buf[0],
pdu_len);
}
/* at least one second has passed */
if (current_seconds != last_seconds)
dcc_timer_seconds(current_seconds - last_seconds);
/* send out the I-Am if requested */
if (I_Am_Request)
{
I_Am_Request = false;
+1
View File
@@ -46,6 +46,7 @@ SRCS = writefile.c \
$(BACNET_OBJECT)/bacfile.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/awf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
+1
View File
@@ -50,6 +50,7 @@ SRCS = writeprop.c \
$(BACNET_ROOT)/datalink.c \
$(BACNET_ROOT)/address.c \
$(BACNET_ROOT)/arf.c \
$(BACNET_ROOT)/dcc.c \
$(BACNET_ROOT)/abort.c \
$(BACNET_ROOT)/reject.c \
$(BACNET_ROOT)/bacerror.c \
+1
View File
@@ -40,6 +40,7 @@ SRCS = writeprop.c \
..\..\wp.c \
..\..\arf.c \
..\..\awf.c \
..\..\dcc.c \
..\..\demo\object\bacfile.c \
..\..\demo\object\device.c \
..\..\demo\object\ai.c \
+69 -2
View File
@@ -172,8 +172,75 @@ int main(int argc, char *argv[])
if (argc < 7)
{
/* note: priority 16 and 0 should produce the same end results... */
printf("%s device-instance object-type object-instance "
"property tag value [priority] [index]\r\n",
printf("Usage: %s device-instance object-type object-instance "
"property tag value [priority] [index]\r\n"
"\r\n"
"device-instance:\r\n"
"BACnet Device Object Instance number that you are trying to\r\n"
"communicate to. This number will be used to try and bind with\r\n"
"the device using Who-Is and I-Am services. For example, if you were\r\n"
"writing to Device Object 123, the device-instance would be 123.\r\n"
"\r\n"
"object-type:\r\n"
"The object type is the integer value of the enumeration\r\n"
"BACNET_OBJECT_TYPE in bacenum.h. It is the object that you are\r\n"
"writing to. For example if you were writing to Analog Output 2, \r\n"
"the object-type would be 1.\r\n"
"\r\n"
"object-instance:\r\n"
"This is the object instance number of the object that you are \r\n"
"writing to. For example, if you were writing to Analog Output 2, \r\n"
"the object-instance would be 2.\r\n"
"\r\n"
"property:\r\n"
"The property is an integer value of the enumeration \r\n"
"BACNET_PROPERTY_ID in bacenum.h. It is the property you are \r\n"
"writing to. For example, if you were writing to the Present Value\r\n"
"property, you would use 85 as the property.\r\n"
"\r\n"
"tag:\r\n"
"Tag is the integer value of the enumeration BACNET_APPLICATION_TAG \r\n"
"in bacenum.h. It is the data type of the value that you are\r\n"
"writing. For example, if you were writing a REAL value, you would \r\n"
"use a tag of 4."
"\r\n"
"value:\r\n"
"The value is an ASCII representation of some type of data that you\r\n"
"are writing. It is encoded using the tag information provided. For\r\n"
"example, if you were writing a REAL value of 100.0, you would use \r\n"
"100.0 as the value.\r\n"
"\r\n"
"[priority]:\r\n"
"This optional parameter is used for setting the priority of the\r\n"
"write. If no priority is given, none is sent, and the BACnet \r\n"
"standard requires that the value is written at the lowest \r\n"
"priority (16) if the object property supports priorities.\r\n"
"\r\n"
"[index]\r\n"
"This optional integer parameter is the index number of an array.\r\n"
"If the property is an array, individual elements can be written\r\n"
"to if supported.\r\n"
"\r\n"
"Here is a brief overview of BACnet property and tags:\r\n"
"Certain properties are expected to be written with certain \r\n"
"application tags, so you probably need to know which ones to use\r\n"
"with each property of each object. It is almost safe to say that\r\n"
"given a property and an object and a table, the tag could be looked\r\n"
"up automatically. There may be a few exceptions to this, such as\r\n"
"the Any property type in the schedule object and the Present Value\r\n"
"accepting REAL, BOOLEAN, NULL, etc. Perhaps it would be simpler for\r\n"
"the demo to use this kind of table - but I also wanted to be able\r\n"
"to do negative testing by passing the wrong tag and have the server\r\n"
"return a reject message.\r\n"
"\r\n"
"Example:\r\n"
"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"
"%s 123 1 0 85 4 100\r\n"
"You could also send a relinquish command:\r\n"
"%s 123 1 0 85 0 0\r\n",
filename_remove_path(argv[0]),
filename_remove_path(argv[0]),
filename_remove_path(argv[0]));
return 0;
}