Bugfix/read range trend log buffer (#947)

* Fixed ReadRange app to read and pretty-print a Trend Log log-buffer
This commit is contained in:
Steve Karg
2025-03-25 10:32:11 -05:00
committed by GitHub
parent 0c45b50574
commit 6f7f3649a5
88 changed files with 1637 additions and 69 deletions
+225 -16
View File
@@ -23,6 +23,7 @@
#include "bacnet/access_rule.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/baclog.h"
#include "bacnet/bacreal.h"
#include "bacnet/bacapp.h"
#include "bacnet/bactext.h"
@@ -527,6 +528,13 @@ int bacapp_encode_application_data(
apdu, &value->type.Channel_Value);
break;
#endif
#if defined(BACAPP_LOG_RECORD)
case BACNET_APPLICATION_TAG_LOG_RECORD:
/* BACnetLogRecord */
apdu_len = bacnet_log_record_value_encode(
apdu, &value->type.Log_Record);
break;
#endif
#if defined(BACAPP_SECURE_CONNECT)
case BACNET_APPLICATION_TAG_SC_FAILED_CONNECTION_REQUEST:
apdu_len = bacapp_encode_SCFailedConnectionRequest(
@@ -960,6 +968,7 @@ int bacapp_encode_context_data_value(
case BACNET_APPLICATION_TAG_BDT_ENTRY:
case BACNET_APPLICATION_TAG_FDT_ENTRY:
case BACNET_APPLICATION_TAG_ACTION_COMMAND:
case BACNET_APPLICATION_TAG_LOG_RECORD:
case BACNET_APPLICATION_TAG_SCALE:
case BACNET_APPLICATION_TAG_SHED_LEVEL:
case BACNET_APPLICATION_TAG_ACCESS_RULE:
@@ -1165,6 +1174,8 @@ static int decode_priority_array_value(
}
apdu_len += len;
} else
#else
(void)object_type;
#endif
{
apdu_len = bacapp_decode_application_data(apdu, apdu_size, value);
@@ -1319,6 +1330,9 @@ int bacapp_known_property_tag(
/* FIXME: BACnetAddressBinding */
return -1;
case PROP_LOG_BUFFER:
/* BACnetLogRecord */
return BACNET_APPLICATION_TAG_LOG_RECORD;
case PROP_ACTION:
/* BACnetActionCommand */
return BACNET_APPLICATION_TAG_ACTION_COMMAND;
@@ -1364,6 +1378,8 @@ int bacapp_known_property_tag(
return -1;
}
#else
(void)object_type;
(void)property;
return -1;
#endif
}
@@ -1670,6 +1686,13 @@ int bacapp_decode_application_tag_value(
apdu, apdu_size, &value->type.Channel_Value);
break;
#endif
#if defined(BACAPP_LOG_RECORD)
case BACNET_APPLICATION_TAG_LOG_RECORD:
/* BACnetLogRecord */
apdu_len = bacnet_log_record_decode(
apdu, apdu_size, &value->type.Log_Record);
break;
#endif
#if defined(BACAPP_SECURE_CONNECT)
case BACNET_APPLICATION_TAG_SC_FAILED_CONNECTION_REQUEST:
apdu_len = bacapp_decode_SCFailedConnectionRequest(
@@ -2161,6 +2184,42 @@ static int bacapp_snprintf_double(char *str, size_t str_len, double value)
}
#endif
#if defined(BACAPP_BIT_STRING)
/**
* @brief Print a bit string 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 - bit string value to print
* @return number of characters written
*/
static int bacapp_snprintf_bit_string(
char *str, size_t str_len, const BACNET_BIT_STRING *value)
{
int ret_val = 0;
int len = 0;
int slen = 0;
int i = 0;
len = bitstring_bits_used(value);
slen = bacapp_snprintf(str, str_len, "{");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (i = 0; i < len; i++) {
bool bit;
bit = bitstring_bit(value, (uint8_t)i);
slen = bacapp_snprintf(str, str_len, "%s", bit ? "true" : "false");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (i < (len - 1)) {
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);
return ret_val;
}
#endif
#if defined(BACAPP_ENUMERATED)
/**
* @brief Print an enumerated value to a string for EPICS
@@ -2311,6 +2370,44 @@ bacapp_snprintf_date(char *str, size_t str_len, const BACNET_DATE *bdate)
}
#endif
#if defined(BACAPP_LOG_RECORD)
/**
* @brief Print a date value to a string as numeric
* @param str - destination string, or NULL for length only
* @param str_len - length of the destination string, or 0 for length only
* @param bdate - date value to print
* @return number of characters written
* @note Numeric will be in the format: yyyy-mm-dd
*/
static int bacapp_snprintf_date_numeric(
char *str, size_t str_len, const BACNET_DATE *bdate)
{
int ret_val = 0;
int slen = 0;
if (bdate->year == 2155) {
slen = bacapp_snprintf(str, str_len, "****-");
} else {
slen = bacapp_snprintf(str, str_len, "%04u-", (unsigned)bdate->year);
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (bdate->month == 255) {
slen = bacapp_snprintf(str, str_len, "**-");
} else {
slen = bacapp_snprintf(str, str_len, "%02u-", (unsigned)bdate->month);
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (bdate->day == 255) {
slen = bacapp_snprintf(str, str_len, "**");
} else {
slen = bacapp_snprintf(str, str_len, "%02u", (unsigned)bdate->day);
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
return ret_val;
}
#endif
#if defined(BACAPP_TIME)
/**
* @brief Print a time value to a string for EPICS
@@ -2422,6 +2519,34 @@ static int bacapp_snprintf_datetime(
}
#endif
#if defined(BACAPP_LOG_RECORD)
/**
* @brief Print a value to a string as numeric
* @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 print
* @return number of characters written
*/
static int bacapp_snprintf_datetime_numeric(
char *str, size_t str_len, const BACNET_DATE_TIME *value)
{
int ret_val = 0;
int slen = 0;
slen = bacapp_snprintf(str, str_len, "{");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = bacapp_snprintf_date_numeric(str, str_len, &value->date);
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_time(str, str_len, &value->time);
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
ret_val += bacapp_snprintf(str, str_len, "}");
return ret_val;
}
#endif
#if defined(BACAPP_DATERANGE) || defined(BACAPP_CALENDAR_ENTRY)
/**
* @brief Print a value to a string for EPICS
@@ -2924,6 +3049,86 @@ bool bacapp_channel_value_copy(
}
#endif
#if defined(BACAPP_LOG_RECORD)
/**
* @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_log_record(
char *str, size_t str_len, const BACNET_LOG_RECORD *value)
{
int ret_val = 0, slen;
BACNET_BIT_STRING bitstring;
slen = bacapp_snprintf(str, str_len, "{");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
slen = bacapp_snprintf_datetime_numeric(str, str_len, &value->timestamp);
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (value->tag < BACNET_LOG_DATUM_MAX) {
slen = bacapp_snprintf(
str, str_len, ", %s:", bactext_log_datum_name(value->tag));
} else {
slen =
bacapp_snprintf(str, str_len, ", <tag=%u>:", (unsigned)value->tag);
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
switch (value->tag) {
case BACNET_LOG_DATUM_STATUS:
bitstring_init(&bitstring);
bitstring_set_bits_used(&bitstring, 1, 8 - 3);
bitstring_set_octet(&bitstring, 0, value->log_datum.log_status);
slen = bacapp_snprintf_bit_string(str, str_len, &bitstring);
break;
case BACNET_LOG_DATUM_BOOLEAN:
slen = bacapp_snprintf_boolean(
str, str_len, value->log_datum.boolean_value);
break;
case BACNET_LOG_DATUM_REAL:
slen =
bacapp_snprintf_real(str, str_len, value->log_datum.real_value);
break;
case BACNET_LOG_DATUM_ENUMERATED:
slen = bacapp_snprintf(
str, str_len, "%lu",
(unsigned long)value->log_datum.enumerated_value);
break;
case BACNET_LOG_DATUM_UNSIGNED:
slen = bacapp_snprintf_unsigned_integer(
str, str_len, value->log_datum.unsigned_value);
break;
case BACNET_LOG_DATUM_SIGNED:
slen = bacapp_snprintf_signed_integer(
str, str_len, value->log_datum.integer_value);
break;
case BACNET_LOG_DATUM_NULL:
slen = bacapp_snprintf_null(str, str_len);
break;
case BACNET_LOG_DATUM_FAILURE:
slen = bacapp_snprintf(
str, str_len, "%s,%s",
bactext_error_class_name(value->log_datum.failure.error_class),
bactext_error_code_name(value->log_datum.failure.error_code));
break;
case BACNET_LOG_DATUM_TIME_CHANGE:
slen = bacapp_snprintf_real(
str, str_len, value->log_datum.time_change);
break;
default:
slen = 0;
break;
}
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
/* FIXME: optional status flags */
slen = bacapp_snprintf(str, str_len, "}");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
return ret_val;
}
#endif
#if defined(BACAPP_WEEKLY_SCHEDULE)
/**
* @brief Print a weekly schedule value to a string for EPICS
@@ -3520,22 +3725,8 @@ int bacapp_snprintf_value(
#endif
#if defined(BACAPP_BIT_STRING)
case BACNET_APPLICATION_TAG_BIT_STRING:
len = bitstring_bits_used(&value->type.Bit_String);
slen = bacapp_snprintf(str, str_len, "{");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
for (i = 0; i < len; i++) {
bool bit;
bit = bitstring_bit(&value->type.Bit_String, (uint8_t)i);
slen = bacapp_snprintf(
str, str_len, "%s", bit ? "true" : "false");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
if (i < (len - 1)) {
slen = bacapp_snprintf(str, str_len, ",");
ret_val += bacapp_snprintf_shift(slen, &str, &str_len);
}
}
slen = bacapp_snprintf(str, str_len, "}");
ret_val += slen;
ret_val = bacapp_snprintf_bit_string(
str, str_len, &value->type.Bit_String);
break;
#endif
#if defined(BACAPP_ENUMERATED)
@@ -3731,6 +3922,12 @@ int bacapp_snprintf_value(
ret_val = bacapp_snprintf_channel_value(
str, str_len, &value->type.Channel_Value);
break;
#endif
#if defined(BACAPP_LOG_RECORD)
case BACNET_APPLICATION_TAG_LOG_RECORD:
ret_val = bacapp_snprintf_log_record(
str, str_len, &value->type.Log_Record);
break;
#endif
case BACNET_APPLICATION_TAG_EMPTYLIST:
ret_val = bacapp_snprintf(str, str_len, "{}");
@@ -4495,6 +4692,12 @@ bool bacapp_parse_application_data(
bacnet_channel_value_from_ascii(
&value->type.Channel_Value, argv);
break;
#endif
#if defined(BACAPP_LOG_RECORD)
case BACNET_APPLICATION_TAG_LOG_RECORD:
status = bacnet_log_record_datum_from_ascii(
&value->type.Log_Record, argv);
break;
#endif
default:
break;
@@ -5060,6 +5263,12 @@ bool bacapp_same_value(
&value->type.Channel_Value,
&test_value->type.Channel_Value);
break;
#endif
#if defined(BACAPP_LOG_RECORD)
case BACNET_APPLICATION_TAG_LOG_RECORD:
status = bacnet_log_record_same(
&value->type.Log_Record, &test_value->type.Log_Record);
break;
#endif
case BACNET_APPLICATION_TAG_EMPTYLIST:
status = true;