299 lines
8.2 KiB
C
299 lines
8.2 KiB
C
/**
|
|
* @file
|
|
* @brief BACnetShedLevel complex data type encode and decode
|
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
|
* @date December 2025
|
|
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include "bacnet/bacdcode.h"
|
|
#include "bacnet/shed_level.h"
|
|
|
|
/**
|
|
* @brief Encode a BACnetShedLevel value.
|
|
*
|
|
* BACnetShedLevel ::= CHOICE {
|
|
* percent[0] Unsigned,
|
|
* level[1] Unsigned,
|
|
* amount[2] Real
|
|
* }
|
|
*
|
|
* @param apdu - buffer to encode to
|
|
* @param value - value to encode
|
|
* @return number of bytes encoded
|
|
*/
|
|
int bacnet_shed_level_encode(uint8_t *apdu, const BACNET_SHED_LEVEL *value)
|
|
{
|
|
int apdu_len = 0;
|
|
|
|
if (!value) {
|
|
return 0;
|
|
}
|
|
switch (value->type) {
|
|
case BACNET_SHED_TYPE_PERCENT:
|
|
apdu_len = encode_context_unsigned(apdu, 0, value->value.percent);
|
|
break;
|
|
case BACNET_SHED_TYPE_LEVEL:
|
|
apdu_len = encode_context_unsigned(apdu, 1, value->value.level);
|
|
break;
|
|
case BACNET_SHED_TYPE_AMOUNT:
|
|
apdu_len = encode_context_real(apdu, 2, value->value.amount);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return apdu_len;
|
|
}
|
|
|
|
/**
|
|
* @brief Decode a BACnetShedLevel value.
|
|
*
|
|
* BACnetShedLevel ::= CHOICE {
|
|
* percent[0] Unsigned,
|
|
* level[1] Unsigned,
|
|
* amount[2] Real
|
|
* }
|
|
*
|
|
* @param apdu - buffer to decode to
|
|
* @param apdu_size - size of the buffer
|
|
* @param value - value to encode, or NULL for size only
|
|
* @return number of bytes decoded, or BACNET_STATUS_ERROR on error
|
|
*/
|
|
int bacnet_shed_level_decode(
|
|
const uint8_t *apdu, size_t apdu_size, BACNET_SHED_LEVEL *value)
|
|
{
|
|
int apdu_len = 0;
|
|
BACNET_TAG tag = { 0 };
|
|
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
|
|
float real_value = 0.0f;
|
|
|
|
if (!apdu) {
|
|
return BACNET_STATUS_ERROR;
|
|
}
|
|
apdu_len = bacnet_tag_decode(apdu, apdu_size, &tag);
|
|
if (apdu_len <= 0) {
|
|
return BACNET_STATUS_ERROR;
|
|
}
|
|
switch (tag.number) {
|
|
case 0:
|
|
/* percent - Unsigned */
|
|
apdu_len = bacnet_unsigned_context_decode(
|
|
apdu, apdu_size, tag.number, &unsigned_value);
|
|
if (apdu_len > 0) {
|
|
if (value) {
|
|
value->value.percent = unsigned_value;
|
|
value->type = BACNET_SHED_TYPE_PERCENT;
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
/* level - Unsigned */
|
|
apdu_len = bacnet_unsigned_context_decode(
|
|
apdu, apdu_size, tag.number, &unsigned_value);
|
|
if (apdu_len > 0) {
|
|
if (value) {
|
|
value->value.level = unsigned_value;
|
|
value->type = BACNET_SHED_TYPE_LEVEL;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
apdu_len = bacnet_real_context_decode(
|
|
apdu, apdu_size, tag.number, &real_value);
|
|
if (apdu_len > 0) {
|
|
if (value) {
|
|
value->type = BACNET_SHED_TYPE_AMOUNT;
|
|
value->value.amount = real_value;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return BACNET_STATUS_ERROR;
|
|
}
|
|
|
|
return apdu_len;
|
|
}
|
|
|
|
/**
|
|
* @brief Compare the BACnetShedLevel complex data
|
|
* @param value1 - BACNET_SHED_LEVEL structure
|
|
* @param value2 - BACNET_SHED_LEVEL structure
|
|
* @return true if the same
|
|
*/
|
|
bool bacnet_shed_level_same(
|
|
const BACNET_SHED_LEVEL *value1, const BACNET_SHED_LEVEL *value2)
|
|
{
|
|
bool status = false;
|
|
|
|
if (value1 && value2) {
|
|
status = true;
|
|
if (value1->type != value2->type) {
|
|
status = false;
|
|
} else {
|
|
switch (value1->type) {
|
|
case BACNET_SHED_TYPE_PERCENT:
|
|
if (value1->value.percent != value2->value.percent) {
|
|
status = false;
|
|
}
|
|
break;
|
|
case BACNET_SHED_TYPE_LEVEL:
|
|
if (value1->value.level != value2->value.level) {
|
|
status = false;
|
|
}
|
|
break;
|
|
case BACNET_SHED_TYPE_AMOUNT:
|
|
if (islessgreater(
|
|
value1->value.amount, value2->value.amount)) {
|
|
status = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Compare the BACnetShedLevel complex data
|
|
* @param value1 - BACNET_SHED_LEVEL structure
|
|
* @param value2 - BACNET_SHED_LEVEL structure
|
|
* @return true if the same
|
|
*/
|
|
bool bacnet_shed_level_copy(
|
|
BACNET_SHED_LEVEL *dest, const BACNET_SHED_LEVEL *src)
|
|
{
|
|
if (!dest || !src) {
|
|
return false;
|
|
}
|
|
|
|
memcpy(dest, src, sizeof(BACNET_SHED_LEVEL));
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
int bacapp_snprintf_shed_level(
|
|
char *str, size_t str_len, const BACNET_SHED_LEVEL *value)
|
|
{
|
|
int length = 0;
|
|
|
|
switch (value->type) {
|
|
case BACNET_SHED_TYPE_PERCENT:
|
|
length = bacnet_snprintf(
|
|
str, str_len, length, "%u%%", (unsigned)value->value.percent);
|
|
break;
|
|
case BACNET_SHED_TYPE_LEVEL:
|
|
length = bacnet_snprintf(
|
|
str, str_len, length, "%u", (unsigned)value->value.level);
|
|
break;
|
|
case BACNET_SHED_TYPE_AMOUNT:
|
|
length = bacnet_snprintf(
|
|
str, str_len, length, "%f", (double)value->value.amount);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
/**
|
|
* @brief Parse a string into a BACnet Shed Level value
|
|
* @param value [out] The BACnet Shed Level value
|
|
* @param argv [in] The string to parse
|
|
* @return True on success, else False
|
|
*/
|
|
bool bacnet_shed_level_from_ascii(BACNET_SHED_LEVEL *value, const char *argv)
|
|
{
|
|
bool status = false;
|
|
int count;
|
|
unsigned percent, level;
|
|
float amount;
|
|
const char *percentage;
|
|
const char *decimal_point;
|
|
|
|
if (!status) {
|
|
percentage = strchr(argv, '%');
|
|
if (percentage) {
|
|
count = sscanf(argv, "%u", &percent);
|
|
if (count == 1) {
|
|
value->type = BACNET_SHED_TYPE_PERCENT;
|
|
value->value.percent = percent;
|
|
status = true;
|
|
}
|
|
}
|
|
}
|
|
if (!status) {
|
|
decimal_point = strchr(argv, '.');
|
|
if (decimal_point) {
|
|
count = sscanf(argv, "%f", &amount);
|
|
if (count == 1) {
|
|
value->type = BACNET_SHED_TYPE_AMOUNT;
|
|
value->value.amount = amount;
|
|
status = true;
|
|
}
|
|
}
|
|
}
|
|
if (!status) {
|
|
count = sscanf(argv, "%u", &level);
|
|
if (count == 1) {
|
|
value->type = BACNET_SHED_TYPE_LEVEL;
|
|
value->value.level = level;
|
|
status = true;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Initialize a BACnetShedLevel structure
|
|
* @param value - pointer to the BACNET_SHED_LEVEL structure
|
|
* @param type - type of shed level
|
|
* @param level - level value as float
|
|
* @return true on success, else false
|
|
*/
|
|
bool bacnet_shed_level_init(
|
|
BACNET_SHED_LEVEL *value, BACNET_SHED_LEVEL_TYPE type, float level)
|
|
{
|
|
if (!value) {
|
|
return false;
|
|
}
|
|
value->type = type;
|
|
switch (type) {
|
|
case BACNET_SHED_TYPE_PERCENT:
|
|
if (level < 0.0f || level > 100.0f) {
|
|
return false;
|
|
}
|
|
value->value.percent = (BACNET_UNSIGNED_INTEGER)level;
|
|
break;
|
|
case BACNET_SHED_TYPE_LEVEL:
|
|
if (level < 0.0f) {
|
|
return false;
|
|
}
|
|
value->value.level = (BACNET_UNSIGNED_INTEGER)level;
|
|
break;
|
|
case BACNET_SHED_TYPE_AMOUNT:
|
|
if (level < 0.0f) {
|
|
return false;
|
|
}
|
|
value->value.amount = level;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|