Bugfix/special event read property write property (#1291)
* Fixed special-event to print priority for the RP and RPM and EPICS example apps. * Improved error message for tag value parsing in WP example app. * Added BACnet property array parsing function to handle property string name in RPM example app. * Added unit test to validate BACnet special event with multiple time-value pairs
This commit is contained in:
@@ -53,6 +53,9 @@ The git repositories are hosted at the following sites:
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
* Added parsing for property name and optional array in ReadPropertyMultiple
|
||||||
|
example application. Added the priority value when printing special-event
|
||||||
|
property types, specificially for exception-schedule property. (#1291)
|
||||||
* Added parsing for BACnetSpecialEvent in bacapp for use in apps/writeproperty
|
* Added parsing for BACnetSpecialEvent in bacapp for use in apps/writeproperty
|
||||||
and add unit tests. (#1290)
|
and add unit tests. (#1290)
|
||||||
* Added multi-device support for BACnet gateway routing. Expanded Object_List
|
* Added multi-device support for BACnet gateway routing. Expanded Object_List
|
||||||
|
|||||||
+83
-14
@@ -11,6 +11,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <time.h> /* for time */
|
#include <time.h> /* for time */
|
||||||
#if (__STDC_VERSION__ >= 199901L) && defined(__STDC_ISO_10646__)
|
#if (__STDC_VERSION__ >= 199901L) && defined(__STDC_ISO_10646__)
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
@@ -337,6 +338,76 @@ static void print_help(const char *filename)
|
|||||||
filename, filename);
|
filename, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parse a BACnet property array string.
|
||||||
|
* The property array string can be either a property name or a
|
||||||
|
* property number, with an optional array index in square brackets.
|
||||||
|
* For example, "present-value" or "85" would parse the Present Value
|
||||||
|
* property with no array index, while "priority-array[3]" or "87[3]"
|
||||||
|
* would parse the Priority Array property with an array index of 3.
|
||||||
|
*
|
||||||
|
* @param argv [in] The property array string to parse.
|
||||||
|
* @param property_id [out] The parsed property ID, if the string is valid.
|
||||||
|
* @param array_index [out] The parsed array index, or 0 if no array index is
|
||||||
|
* specified.
|
||||||
|
* @return true if the string was successfully parsed, false if it was invalid
|
||||||
|
*/
|
||||||
|
static bool bacnet_property_array_parse(
|
||||||
|
char *argv, uint32_t *property_id, uint32_t *array_index)
|
||||||
|
{
|
||||||
|
long unsigned int unsigned_value = 0;
|
||||||
|
unsigned int array_value = 0;
|
||||||
|
uint32_t found_index = 0;
|
||||||
|
char name[80] = "";
|
||||||
|
int scan_count = 0;
|
||||||
|
|
||||||
|
if (isalpha(argv[0])) {
|
||||||
|
/* choose a property by name with optional [] to denote array */
|
||||||
|
scan_count = sscanf(argv, "%79[^[][%u]", name, &array_value);
|
||||||
|
if (scan_count < 1) {
|
||||||
|
fprintf(stderr, "parse: missing property: %s.", argv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!bactext_property_strtol(name, &found_index)) {
|
||||||
|
fprintf(stderr, "parse: invalid property name: %s.", argv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (property_id) {
|
||||||
|
*property_id = found_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* choose a property by number */
|
||||||
|
scan_count = sscanf(argv, "%lu[%u]", &unsigned_value, &array_value);
|
||||||
|
if (scan_count < 1) {
|
||||||
|
fprintf(stderr, "parse: missing property: %s.", argv);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (unsigned_value > UINT32_MAX) {
|
||||||
|
fprintf(
|
||||||
|
stderr, "parse: Invalid property: %s. Must be 0-%u.", argv,
|
||||||
|
UINT32_MAX);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (property_id) {
|
||||||
|
*property_id = (uint32_t)unsigned_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scan_count >= 2) {
|
||||||
|
if (array_value > UINT32_MAX) {
|
||||||
|
fprintf(
|
||||||
|
stderr, "parse: Invalid array index: %s. Must be 0-%u.", argv,
|
||||||
|
UINT32_MAX);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (array_index) {
|
||||||
|
*array_index = (uint32_t)array_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
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 */
|
||||||
@@ -353,9 +424,8 @@ int main(int argc, char *argv[])
|
|||||||
BACNET_READ_ACCESS_DATA *rpm_object = NULL;
|
BACNET_READ_ACCESS_DATA *rpm_object = NULL;
|
||||||
BACNET_PROPERTY_REFERENCE *rpm_property = NULL;
|
BACNET_PROPERTY_REFERENCE *rpm_property = NULL;
|
||||||
char *property_token = NULL;
|
char *property_token = NULL;
|
||||||
unsigned property_id = 0;
|
uint32_t property_id = 0;
|
||||||
unsigned property_array_index = 0;
|
uint32_t property_array_index = 0;
|
||||||
int scan_count = 0;
|
|
||||||
int argi = 0;
|
int argi = 0;
|
||||||
long dnet = -1;
|
long dnet = -1;
|
||||||
unsigned object_type = 0;
|
unsigned object_type = 0;
|
||||||
@@ -460,10 +530,15 @@ int main(int argc, char *argv[])
|
|||||||
property_token = strtok(argv[argi], ",");
|
property_token = strtok(argv[argi], ",");
|
||||||
/* add all the properties and optional index to our list */
|
/* add all the properties and optional index to our list */
|
||||||
while (rpm_property) {
|
while (rpm_property) {
|
||||||
scan_count = sscanf(
|
property_array_index = BACNET_ARRAY_ALL;
|
||||||
property_token, "%u[%u]", &property_id,
|
if (!bacnet_property_array_parse(
|
||||||
&property_array_index);
|
property_token, &property_id,
|
||||||
if (scan_count > 0) {
|
&property_array_index)) {
|
||||||
|
fprintf(
|
||||||
|
stderr, "Error: property=%s invalid\n",
|
||||||
|
property_token);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
rpm_property->propertyIdentifier = property_id;
|
rpm_property->propertyIdentifier = property_id;
|
||||||
if (rpm_property->propertyIdentifier >
|
if (rpm_property->propertyIdentifier >
|
||||||
MAX_BACNET_PROPERTY_ID) {
|
MAX_BACNET_PROPERTY_ID) {
|
||||||
@@ -474,13 +549,7 @@ int main(int argc, char *argv[])
|
|||||||
MAX_BACNET_PROPERTY_ID + 1);
|
MAX_BACNET_PROPERTY_ID + 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
rpm_property->propertyArrayIndex = property_array_index;
|
||||||
if (scan_count > 1) {
|
|
||||||
rpm_property->propertyArrayIndex =
|
|
||||||
property_array_index;
|
|
||||||
} else {
|
|
||||||
rpm_property->propertyArrayIndex = BACNET_ARRAY_ALL;
|
|
||||||
}
|
|
||||||
/* is there another property? */
|
/* is there another property? */
|
||||||
property_token = strtok(NULL, ",");
|
property_token = strtok(NULL, ",");
|
||||||
if (property_token) {
|
if (property_token) {
|
||||||
|
|||||||
@@ -401,7 +401,8 @@ int main(int argc, char *argv[])
|
|||||||
*/
|
*/
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"Error: unable to parse the tag value\n");
|
"Error: unable to parse tag=%ld value=%s\n",
|
||||||
|
property_tag, value_string);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -3613,7 +3613,7 @@ static int bacapp_snprintf_special_event(
|
|||||||
}
|
}
|
||||||
slen = bacapp_snprintf_daily_schedule(str, str_len, &value->timeValues);
|
slen = bacapp_snprintf_daily_schedule(str, str_len, &value->timeValues);
|
||||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||||
slen = bacapp_snprintf(str, str_len, "}");
|
slen = bacapp_snprintf(str, str_len, ",%u}", (unsigned)value->priority);
|
||||||
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
|||||||
@@ -1282,6 +1282,44 @@ static void testBACnetApplicationData(void)
|
|||||||
bacapp_encode_application_data(apdu_special, &value), special_len,
|
bacapp_encode_application_data(apdu_special, &value), special_len,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
/* Test: date entry with two numeric time-value pairs (from header comment
|
||||||
|
* example). Verifies that sched_str is "{12:30:00.00,100,14:00:00.00,50}"
|
||||||
|
* and not just the first token "12:30:00.00". */
|
||||||
|
char special_event_date_multi[] =
|
||||||
|
"2023/10/24,{12:30:00.00,100,14:00:00.00,50},5";
|
||||||
|
status = bacapp_parse_application_data(
|
||||||
|
BACNET_APPLICATION_TAG_SPECIAL_EVENT, special_event_date_multi, &value);
|
||||||
|
zassert_true(status, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.periodTag,
|
||||||
|
BACNET_SPECIAL_EVENT_PERIOD_CALENDAR_ENTRY, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.period.calendarEntry.tag, BACNET_CALENDAR_DATE,
|
||||||
|
NULL);
|
||||||
|
zassert_equal(value.type.Special_Event.timeValues.TV_Count, 2, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[0].Time.hour, 12, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[0].Time.min, 30, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[0].Value.tag,
|
||||||
|
BACNET_APPLICATION_TAG_UNSIGNED_INT, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[0]
|
||||||
|
.Value.type.Unsigned_Int,
|
||||||
|
100, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[1].Time.hour, 14, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[1].Value.tag,
|
||||||
|
BACNET_APPLICATION_TAG_UNSIGNED_INT, NULL);
|
||||||
|
zassert_equal(
|
||||||
|
value.type.Special_Event.timeValues.Time_Values[1]
|
||||||
|
.Value.type.Unsigned_Int,
|
||||||
|
50, NULL);
|
||||||
|
zassert_equal(value.type.Special_Event.priority, 5, NULL);
|
||||||
|
verifyBACnetComplexDataValue(
|
||||||
|
&value, OBJECT_SCHEDULE, PROP_EXCEPTION_SCHEDULE);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user