Added WriteGroup service and Channel object interfaces (#829)
This commit is contained in:
+417
-11
@@ -33,6 +33,7 @@
|
||||
#include "bacnet/weeklyschedule.h"
|
||||
#include "bacnet/calendar_entry.h"
|
||||
#include "bacnet/special_event.h"
|
||||
#include "bacnet/channel_value.h"
|
||||
#include "bacnet/basic/sys/platform.h"
|
||||
|
||||
#if defined(BACAPP_SCALE)
|
||||
@@ -510,6 +511,13 @@ int bacapp_encode_application_data(
|
||||
apdu_len =
|
||||
bacapp_encode_access_rule(apdu, &value->type.Access_Rule);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
case BACNET_APPLICATION_TAG_CHANNEL_VALUE:
|
||||
/* BACnetChannelValue */
|
||||
apdu_len = bacnet_channel_value_type_encode(
|
||||
apdu, &value->type.Channel_Value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
@@ -1221,6 +1229,9 @@ int bacapp_known_property_tag(
|
||||
(object_type == OBJECT_DATETIME_VALUE)) {
|
||||
/* Properties using BACnetDateTime */
|
||||
return BACNET_APPLICATION_TAG_DATETIME;
|
||||
} else if (object_type == OBJECT_CHANNEL) {
|
||||
/* Properties using BACnetChannelValue */
|
||||
return BACNET_APPLICATION_TAG_CHANNEL_VALUE;
|
||||
}
|
||||
/* note: primitive application tagged present-values return '-1' */
|
||||
return -1;
|
||||
@@ -1607,6 +1618,13 @@ int bacapp_decode_application_tag_value(
|
||||
apdu_len = bacnet_access_rule_decode(
|
||||
apdu, apdu_size, &value->type.Access_Rule);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
case BACNET_APPLICATION_TAG_CHANNEL_VALUE:
|
||||
/* BACnetChannelValue */
|
||||
apdu_len = bacnet_channel_value_decode(
|
||||
apdu, apdu_size, &value->type.Channel_Value);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
@@ -2565,6 +2583,255 @@ static int bacapp_snprintf_access_rule(
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_COLOR_COMMAND)
|
||||
/**
|
||||
* @brief Print a value to a string for EPICS
|
||||
* @param str - destination string, or NULL for length only
|
||||
* @param str_len - length of the destination string, or 0 for length only
|
||||
* @param value - value to be printed
|
||||
* @return number of characters written to the string
|
||||
*/
|
||||
static int bacapp_snprintf_color_command(
|
||||
char *str, size_t str_len, const BACNET_COLOR_COMMAND *value)
|
||||
{
|
||||
int slen;
|
||||
int ret_val = 0;
|
||||
|
||||
slen = bacapp_snprintf(str, str_len, "{");
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
slen = bacapp_snprintf(str, str_len, "(");
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
slen = bacapp_snprintf(
|
||||
str, str_len, "%s", bactext_color_operation_name(value->operation));
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
slen = bacapp_snprintf(str, str_len, ")");
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
|
||||
/* FIXME: add the Color Command optional values */
|
||||
|
||||
slen = bacapp_snprintf(str, str_len, "}");
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
/**
|
||||
* @brief Print a value to a string for EPICS
|
||||
* @param str - destination string, or NULL for length only
|
||||
* @param str_len - length of the destination string, or 0 for length only
|
||||
* @param value - value to be printed
|
||||
* @return number of characters written to the string
|
||||
*/
|
||||
static int bacapp_snprintf_channel_value(
|
||||
char *str, size_t str_len, const BACNET_CHANNEL_VALUE *value)
|
||||
{
|
||||
int ret_val = 0;
|
||||
|
||||
switch (value->tag) {
|
||||
case BACNET_APPLICATION_TAG_NULL:
|
||||
ret_val = bacapp_snprintf_null(str, str_len);
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
#if defined(CHANNEL_BOOLEAN)
|
||||
ret_val =
|
||||
bacapp_snprintf_boolean(str, str_len, value->type.Boolean);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
#if defined(CHANNEL_UNSIGNED)
|
||||
ret_val = bacapp_snprintf_unsigned_integer(
|
||||
str, str_len, value->type.Unsigned_Int);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
#if defined(CHANNEL_SIGNED)
|
||||
ret_val = bacapp_snprintf_signed_integer(
|
||||
str, str_len, value->type.Signed_Int);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
#if defined(CHANNEL_REAL)
|
||||
ret_val = bacapp_snprintf_real(str, str_len, value->type.Real);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_DOUBLE:
|
||||
#if defined(CHANNEL_DOUBLE)
|
||||
ret_val = bacapp_snprintf_double(str, str_len, value->type.Double);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_ENUMERATED:
|
||||
#if defined(CHANNEL_ENUMERATED)
|
||||
ret_val = bacapp_snprintf_enumerated(
|
||||
str, str_len, OBJECT_COMMAND, PROP_ACTION,
|
||||
value->type.Enumerated);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_LIGHTING_COMMAND:
|
||||
#if defined(CHANNEL_LIGHTING_COMMAND)
|
||||
ret_val = lighting_command_to_ascii(
|
||||
&value->type.Lighting_Command, str, str_len);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
|
||||
#if defined(CHANNEL_COLOR_COMMAND)
|
||||
ret_val = bacapp_snprintf_color_command(
|
||||
str, str_len, &value->type.Color_Command);
|
||||
#endif
|
||||
break;
|
||||
case BACNET_APPLICATION_TAG_XY_COLOR:
|
||||
#if defined(CHANNEL_XY_COLOR)
|
||||
ret_val = xy_color_to_ascii(&value->type.XY_Color, str, str_len);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_CHANNEL)
|
||||
/**
|
||||
* @brief For a given application value, copy to the channel value
|
||||
* @param cvalue - BACNET_CHANNEL_VALUE value
|
||||
* @param value - BACNET_APPLICATION_DATA_VALUE value
|
||||
* @return true if values are able to be copied
|
||||
*/
|
||||
bool bacapp_channel_value_copy(
|
||||
BACNET_CHANNEL_VALUE *cvalue, const BACNET_APPLICATION_DATA_VALUE *value)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (!value || !cvalue) {
|
||||
return false;
|
||||
}
|
||||
switch (value->tag) {
|
||||
#if defined(BACAPP_NULL)
|
||||
case BACNET_APPLICATION_TAG_NULL:
|
||||
cvalue->tag = value->tag;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_BOOLEAN) && defined(CHANNEL_BOOLEAN)
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Boolean = value->type.Boolean;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_UNSIGNED) && defined(CHANNEL_UNSIGNED)
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Unsigned_Int = value->type.Unsigned_Int;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_SIGNED) && defined(CHANNEL_SIGNED)
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Signed_Int = value->type.Signed_Int;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_REAL) && defined(CHANNEL_REAL)
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Real = value->type.Real;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_DOUBLE) && defined(CHANNEL_DOUBLE)
|
||||
case BACNET_APPLICATION_TAG_DOUBLE:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Double = value->type.Double;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_OCTET_STRING) && defined(CHANNEL_OCTET_STRING)
|
||||
case BACNET_APPLICATION_TAG_OCTET_STRING:
|
||||
cvalue->tag = value->tag;
|
||||
octetstring_copy(
|
||||
&cvalue->type.Octet_String, &value->type.Octet_String);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHARACTER_STRING) && defined(CHANNEL_CHARACTER_STRING)
|
||||
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
|
||||
cvalue->tag = value->tag;
|
||||
characterstring_copy(
|
||||
&cvalue->type.Character_String, &value->type.Character_String);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_BIT_STRING) && defined(CHANNEL_BIT_STRING)
|
||||
case BACNET_APPLICATION_TAG_BIT_STRING:
|
||||
cvalue->tag = value->tag;
|
||||
bitstring_copy(&cvalue->type.Bit_String, &value->type.Bit_String);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_ENUMERATED) && defined(CHANNEL_ENUMERATED)
|
||||
case BACNET_APPLICATION_TAG_ENUMERATED:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Enumerated = value->type.Enumerated;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_DATE) && defined(CHANNEL_DATE)
|
||||
case BACNET_APPLICATION_TAG_DATE:
|
||||
cvalue->tag = value->tag;
|
||||
datetime_date_copy(&cvalue->type.Date, &value->type.Date);
|
||||
apdu_len = encode_application_date(apdu, &value->type.Date);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_TIME) && defined(CHANNEL_TIME)
|
||||
case BACNET_APPLICATION_TAG_TIME:
|
||||
cvalue->tag = value->tag;
|
||||
datetime_time_copy(&cvalue->type.Time, &value->type.Time);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_OBJECT_ID) && defined(CHANNEL_OBJECT_ID)
|
||||
case BACNET_APPLICATION_TAG_OBJECT_ID:
|
||||
cvalue->tag = value->tag;
|
||||
cvalue->type.Object_Id.type = value->type.Object_Id.type;
|
||||
cvalue->type.Object_Id.instance = value->type.Object_Id.instance;
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_LIGHTING_COMMAND) && defined(CHANNEL_LIGHTING_COMMAND)
|
||||
case BACNET_APPLICATION_TAG_LIGHTING_COMMAND:
|
||||
cvalue->tag = value->tag;
|
||||
lighting_command_copy(
|
||||
&cvalue->type.Lighting_Command, &value->type.Lighting_Command);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_COLOR_COMMAND) && defined(CHANNEL_COLOR_COMMAND)
|
||||
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
|
||||
cvalue->tag = value->tag;
|
||||
color_command_copy(
|
||||
&cvalue->type.Color_Command, &value->type.Color_Command);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_COLOR_COMMAND) && defined(CHANNEL_XY_COLOR)
|
||||
case BACNET_APPLICATION_TAG_XY_COLOR:
|
||||
cvalue->tag = value->tag;
|
||||
xy_color_copy(&cvalue->type.XY_Color, &value->type.XY_Color);
|
||||
status = true;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_WEEKLY_SCHEDULE)
|
||||
/**
|
||||
* @brief Print a weekly schedule value to a string for EPICS
|
||||
@@ -3235,16 +3502,8 @@ int bacapp_snprintf_value(
|
||||
#if defined(BACAPP_COLOR_COMMAND)
|
||||
case BACNET_APPLICATION_TAG_COLOR_COMMAND:
|
||||
/* BACnetColorCommand */
|
||||
slen = bacapp_snprintf(str, str_len, "(");
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
slen = bacapp_snprintf(
|
||||
str, str_len, "%s",
|
||||
bactext_color_operation_name(
|
||||
value->type.Color_Command.operation));
|
||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||
/* FIXME: add the Lighting Command optional values */
|
||||
slen = bacapp_snprintf(str, str_len, ")");
|
||||
ret_val += slen;
|
||||
ret_val = bacapp_snprintf_color_command(
|
||||
str, str_len, &value->type.Color_Command);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_WEEKLY_SCHEDULE)
|
||||
@@ -3350,6 +3609,12 @@ int bacapp_snprintf_value(
|
||||
ret_val = bacapp_snprintf_access_rule(
|
||||
str, str_len, &value->type.Access_Rule);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
case BACNET_APPLICATION_TAG_CHANNEL_VALUE:
|
||||
ret_val = bacapp_snprintf_channel_value(
|
||||
str, str_len, &value->type.Channel_Value);
|
||||
break;
|
||||
#endif
|
||||
case BACNET_APPLICATION_TAG_EMPTYLIST:
|
||||
ret_val = bacapp_snprintf(str, str_len, "{}");
|
||||
@@ -3722,6 +3987,117 @@ bacnet_shed_level_from_ascii(BACNET_SHED_LEVEL *value, const char *argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE)
|
||||
/**
|
||||
* @brief Parse a string into a BACnetDeviceObjectPropertyReference value
|
||||
* @param value [out] The BACnetObjectPropertyReference value
|
||||
* @param argv [in] The string to parse
|
||||
* @return true on success, else false
|
||||
*/
|
||||
static bool device_object_property_reference_from_ascii(
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value, const char *argv)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned long object_type, object_instance;
|
||||
unsigned long property_id;
|
||||
long array_index;
|
||||
unsigned long device_type, device_instance;
|
||||
int count;
|
||||
|
||||
if (!value || !argv) {
|
||||
return false;
|
||||
}
|
||||
/* analog-output:4194303,present-value,-1,device:4194303 */
|
||||
count = sscanf(
|
||||
argv, "%4lu:%7lu,%lu,%ld,%4lu:%7lu", &object_type, &object_instance,
|
||||
&property_id, &array_index, &device_type, &device_instance);
|
||||
if (count == 6) {
|
||||
value->objectIdentifier.type = object_type;
|
||||
value->objectIdentifier.instance = object_instance;
|
||||
value->propertyIdentifier = property_id;
|
||||
if (array_index < 0) {
|
||||
value->arrayIndex = BACNET_ARRAY_ALL;
|
||||
} else {
|
||||
value->arrayIndex = array_index;
|
||||
}
|
||||
value->arrayIndex = array_index;
|
||||
value->deviceIdentifier.type = device_type;
|
||||
value->deviceIdentifier.instance = device_instance;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
#if defined(BACAPP_DEVICE_OBJECT_REFERENCE)
|
||||
/**
|
||||
* @brief Parse a string into a BACnetDeviceObjectReference value
|
||||
* @param value [out] The BACnetObjectPropertyReference value
|
||||
* @param argv [in] The string to parse
|
||||
* @return true on success, else false
|
||||
*/
|
||||
static bool device_object_reference_from_ascii(
|
||||
BACNET_DEVICE_OBJECT_REFERENCE *value, const char *argv)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned long object_type, object_instance;
|
||||
unsigned long device_type, device_instance;
|
||||
int count;
|
||||
|
||||
if (!value || !argv) {
|
||||
return false;
|
||||
}
|
||||
/* analog-output:4194303,device:4194303 */
|
||||
count = sscanf(
|
||||
argv, "%4lu:%7lu,%4lu:%7lu", &object_type, &object_instance,
|
||||
&device_type, &device_instance);
|
||||
if (count == 4) {
|
||||
value->objectIdentifier.type = object_type;
|
||||
value->objectIdentifier.instance = object_instance;
|
||||
value->deviceIdentifier.type = device_type;
|
||||
value->deviceIdentifier.instance = device_instance;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BACAPP_OBJECT_PROPERTY_REFERENCE)
|
||||
/**
|
||||
* @brief Parse a string into a BACnetObjectPropertyReference value
|
||||
* @param value [out] The BACnetObjectPropertyReference value
|
||||
* @param argv [in] The string to parse
|
||||
* @return true on success, else false
|
||||
*/
|
||||
static bool object_property_reference_from_ascii(
|
||||
BACNET_OBJECT_PROPERTY_REFERENCE *value, const char *argv)
|
||||
{
|
||||
bool status = false;
|
||||
unsigned long object_type, object_instance;
|
||||
unsigned long property_id;
|
||||
long array_index;
|
||||
int count;
|
||||
|
||||
if (!value || !argv) {
|
||||
return false;
|
||||
}
|
||||
/* analog-output:4194303,present-value,-1,device:4194303 */
|
||||
count = sscanf(
|
||||
argv, "%4lu:%7lu,%lu,%ld", &object_type, &object_instance, &property_id,
|
||||
&array_index);
|
||||
if (count == 4) {
|
||||
value->object_identifier.type = object_type;
|
||||
value->object_identifier.instance = object_instance;
|
||||
value->property_identifier = property_id;
|
||||
value->property_array_index = array_index;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* used to load the app data struct with the proper data
|
||||
converted from a command line argument.
|
||||
"argv" is not const to allow using strtok internally. It MAY be modified. */
|
||||
@@ -3930,6 +4306,24 @@ bool bacapp_parse_application_data(
|
||||
host_n_port_from_ascii(&value->type.Host_Address, argv);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_DEVICE_OBJECT_PROPERTY_REFERENCE)
|
||||
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_PROPERTY_REFERENCE:
|
||||
status = device_object_property_reference_from_ascii(
|
||||
&value->type.Device_Object_Property_Reference, argv);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_DEVICE_OBJECT_REFERENCE)
|
||||
case BACNET_APPLICATION_TAG_DEVICE_OBJECT_REFERENCE:
|
||||
status = device_object_reference_from_ascii(
|
||||
&value->type.Device_Object_Reference, argv);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_OBJECT_PROPERTY_REFERENCE)
|
||||
case BACNET_APPLICATION_TAG_OBJECT_PROPERTY_REFERENCE:
|
||||
status = object_property_reference_from_ascii(
|
||||
&value->type.Object_Property_Reference, argv);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_DESTINATION)
|
||||
case BACNET_APPLICATION_TAG_DESTINATION:
|
||||
status = bacnet_destination_from_ascii(
|
||||
@@ -3966,9 +4360,14 @@ bool bacapp_parse_application_data(
|
||||
#endif
|
||||
#if defined(BACAPP_ACCESS_RULE)
|
||||
case BACNET_APPLICATION_TAG_ACCESS_RULE:
|
||||
/* BACnetAccessRule - not implemented */
|
||||
bacnet_access_rule_from_ascii(&value->type.Access_Rule, argv);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
case BACNET_APPLICATION_TAG_CHANNEL_VALUE:
|
||||
bacnet_channel_value_from_ascii(
|
||||
&value->type.Channel_Value, argv);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
@@ -4527,6 +4926,13 @@ bool bacapp_same_value(
|
||||
status = bacnet_access_rule_same(
|
||||
&value->type.Access_Rule, &test_value->type.Access_Rule);
|
||||
break;
|
||||
#endif
|
||||
#if defined(BACAPP_CHANNEL_VALUE)
|
||||
case BACNET_APPLICATION_TAG_CHANNEL_VALUE:
|
||||
status = bacnet_channel_value_same(
|
||||
&value->type.Channel_Value,
|
||||
&test_value->type.Channel_Value);
|
||||
break;
|
||||
#endif
|
||||
case BACNET_APPLICATION_TAG_EMPTYLIST:
|
||||
status = true;
|
||||
|
||||
Reference in New Issue
Block a user