Feature/raspberry pi blinkt color objects (#503)
* fixed BACnetXYcolor and BACnetColorCommand encode and decoding and improved unit test coverage. Refactored BACnetXYcolor to/from ascii into lighting module. * added to the color, color temperature, and lighting output objects a fade/ramp/step engine. Added color and color command coercion into the channel object and enabled color temperature object coercion. Added CreateObject and DeleteObject service handling to the color, color temperature, lighting output, and channel objects. * added blinkt demo app for Raspberry Pi [WIP] * updated gitignore to simplify handling of apps folder contents * fixed piface demo build * added RaspiOS to pipeline for piface and blinkt! demo builds * added device object timer function for child object types into example Device object. Refactored device object to increment database revision for create or delete object services. Refactored example app/server to use mstimer library and device child object timers. --------- Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+332
-261
@@ -25,6 +25,18 @@
|
||||
/**
|
||||
* Encodes into bytes from the lighting-command structure
|
||||
*
|
||||
* BACnetLightingCommand ::= SEQUENCE {
|
||||
* operation [0] BACnetLightingOperation,
|
||||
* target-level [1] REAL (0.0..100.0) OPTIONAL,
|
||||
* ramp-rate [2] REAL (0.1..100.0) OPTIONAL,
|
||||
* step-increment [3] REAL (0.1..100.0) OPTIONAL,
|
||||
* fade-time [4] Unsigned (100..86400000) OPTIONAL,
|
||||
* priority [5] Unsigned (1..16) OPTIONAL
|
||||
* }
|
||||
* -- Note that the combination of level, ramp-rate,
|
||||
* -- step-increment, and fade-time fields is
|
||||
* -- dependent on the specific lighting operation.
|
||||
*
|
||||
* @param apdu - buffer to hold the bytes, or null for length
|
||||
* @param value - lighting command value to encode
|
||||
*
|
||||
@@ -86,6 +98,18 @@ int lighting_command_encode(uint8_t *apdu, BACNET_LIGHTING_COMMAND *data)
|
||||
* Encodes into bytes from the lighting-command structure
|
||||
* a context tagged chunk (opening and closing tag)
|
||||
*
|
||||
* BACnetLightingCommand ::= SEQUENCE {
|
||||
* operation [0] BACnetLightingOperation,
|
||||
* target-level [1] REAL (0.0..100.0) OPTIONAL,
|
||||
* ramp-rate [2] REAL (0.1..100.0) OPTIONAL,
|
||||
* step-increment [3] REAL (0.1..100.0) OPTIONAL,
|
||||
* fade-time [4] Unsigned (100..86400000) OPTIONAL,
|
||||
* priority [5] Unsigned (1..16) OPTIONAL
|
||||
* }
|
||||
* -- Note that the combination of level, ramp-rate,
|
||||
* -- step-increment, and fade-time fields is
|
||||
* -- dependent on the specific lighting operation.
|
||||
*
|
||||
* @param apdu - buffer to hold the bytes
|
||||
* @param tag_number - tag number to encode this chunk
|
||||
* @param value - lighting command value to encode
|
||||
@@ -114,58 +138,64 @@ int lighting_command_encode_context(
|
||||
/**
|
||||
* Decodes from bytes into the lighting-command structure
|
||||
*
|
||||
* BACnetLightingCommand ::= SEQUENCE {
|
||||
* operation [0] BACnetLightingOperation,
|
||||
* target-level [1] REAL (0.0..100.0) OPTIONAL,
|
||||
* ramp-rate [2] REAL (0.1..100.0) OPTIONAL,
|
||||
* step-increment [3] REAL (0.1..100.0) OPTIONAL,
|
||||
* fade-time [4] Unsigned (100..86400000) OPTIONAL,
|
||||
* priority [5] Unsigned (1..16) OPTIONAL
|
||||
* }
|
||||
* -- Note that the combination of level, ramp-rate,
|
||||
* -- step-increment, and fade-time fields is
|
||||
* -- dependent on the specific lighting operation.
|
||||
*
|
||||
* @param apdu - buffer to hold the bytes
|
||||
* @param apdu_max_len - number of bytes in the buffer to decode
|
||||
* @param apdu_size - number of bytes in the buffer to decode
|
||||
* @param value - lighting command value to place the decoded values
|
||||
*
|
||||
* @return number of bytes decoded
|
||||
* @return number of bytes decoded, or BACNET_STATUS_ERROR
|
||||
*/
|
||||
int lighting_command_decode(
|
||||
uint8_t *apdu, unsigned apdu_max_len, BACNET_LIGHTING_COMMAND *data)
|
||||
uint8_t *apdu, unsigned apdu_size, BACNET_LIGHTING_COMMAND *data)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t tag_number = 0;
|
||||
uint32_t len_value_type = 0;
|
||||
uint32_t enum_value = 0;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
|
||||
BACNET_LIGHTING_OPERATION operation = BACNET_LIGHTS_NONE;
|
||||
float real_value = 0.0;
|
||||
|
||||
/* check for value pointers */
|
||||
if (apdu_max_len) {
|
||||
/* Tag 0: operation */
|
||||
if (!decode_is_context_tag(&apdu[apdu_len], 0)) {
|
||||
if (!apdu) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
/* operation [0] BACnetLightingOperation */
|
||||
len = bacnet_enumerated_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0, &enum_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (unsigned_value <= BACNET_LIGHTS_PROPRIETARY_LAST) {
|
||||
if (data) {
|
||||
data->operation = (BACNET_LIGHTING_OPERATION)enum_value;
|
||||
}
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_enumerated(&apdu[apdu_len], len_value_type, &enum_value);
|
||||
if (len > 0) {
|
||||
if (unsigned_value <= BACNET_LIGHTS_PROPRIETARY_LAST) {
|
||||
if (data) {
|
||||
data->operation = (BACNET_LIGHTING_OPERATION)enum_value;
|
||||
}
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
switch (operation) {
|
||||
case BACNET_LIGHTS_NONE:
|
||||
break;
|
||||
case BACNET_LIGHTS_FADE_TO:
|
||||
if ((apdu_max_len - apdu_len) == 0) {
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* Tag 1: target-level */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_real(&apdu[apdu_len], &real_value);
|
||||
/* target-level [1] REAL (0.0..100.0) OPTIONAL */
|
||||
len = bacnet_real_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 1, &real_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->target_level = real_value;
|
||||
@@ -176,33 +206,29 @@ int lighting_command_decode(
|
||||
data->use_target_level = false;
|
||||
}
|
||||
}
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* Tag 4: fade-time - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_unsigned(
|
||||
&apdu[apdu_len], len_value_type, &unsigned_value);
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 4, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->fade_time = (uint32_t)unsigned_value;
|
||||
data->use_fade_time = true;
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_fade_time = false;
|
||||
}
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_fade_time = false;
|
||||
}
|
||||
}
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 5: priority - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_unsigned(
|
||||
&apdu[apdu_len], len_value_type, &unsigned_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* priority [5] Unsigned (1..16) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 5, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->priority = (uint8_t)unsigned_value;
|
||||
@@ -213,18 +239,20 @@ int lighting_command_decode(
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BACNET_LIGHTS_RAMP_TO:
|
||||
if ((apdu_max_len - apdu_len) == 0) {
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* Tag 1: target-level */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 1)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_real(&apdu[apdu_len], &real_value);
|
||||
/* target-level [1] REAL (0.0..100.0) OPTIONAL */
|
||||
len = bacnet_real_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 1, &real_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->target_level = real_value;
|
||||
@@ -235,13 +263,11 @@ int lighting_command_decode(
|
||||
data->use_target_level = false;
|
||||
}
|
||||
}
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 2: ramp-rate - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 2)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_real(&apdu[apdu_len], &real_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* ramp-rate [2] REAL (0.1..100.0) OPTIONAL */
|
||||
len = bacnet_real_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 2, &real_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->ramp_rate = real_value;
|
||||
@@ -252,15 +278,16 @@ int lighting_command_decode(
|
||||
data->use_ramp_rate = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_ramp_rate = false;
|
||||
}
|
||||
}
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 5: priority - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_unsigned(
|
||||
&apdu[apdu_len], len_value_type, &unsigned_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* priority [5] Unsigned (1..16) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 5, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->priority = (uint8_t)unsigned_value;
|
||||
@@ -271,19 +298,21 @@ int lighting_command_decode(
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BACNET_LIGHTS_STEP_UP:
|
||||
case BACNET_LIGHTS_STEP_DOWN:
|
||||
case BACNET_LIGHTS_STEP_ON:
|
||||
case BACNET_LIGHTS_STEP_OFF:
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 3: step-increment - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 3)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_real(&apdu[apdu_len], &real_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* step-increment [3] REAL (0.1..100.0) OPTIONAL */
|
||||
len = bacnet_real_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 3, &real_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->step_increment = real_value;
|
||||
@@ -294,15 +323,16 @@ int lighting_command_decode(
|
||||
data->use_step_increment = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_step_increment = false;
|
||||
}
|
||||
}
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 5: priority - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_unsigned(
|
||||
&apdu[apdu_len], len_value_type, &unsigned_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* priority [5] Unsigned (1..16) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 5, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->priority = (uint8_t)unsigned_value;
|
||||
@@ -313,20 +343,21 @@ int lighting_command_decode(
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BACNET_LIGHTS_WARN:
|
||||
case BACNET_LIGHTS_WARN_OFF:
|
||||
case BACNET_LIGHTS_WARN_RELINQUISH:
|
||||
case BACNET_LIGHTS_STOP:
|
||||
if ((apdu_max_len - apdu_len) != 0) {
|
||||
/* Tag 5: priority - OPTIONAL */
|
||||
if (decode_is_context_tag(&apdu[apdu_len], 4)) {
|
||||
len = decode_tag_number_and_value(
|
||||
&apdu[apdu_len], &tag_number, &len_value_type);
|
||||
apdu_len += len;
|
||||
len = decode_unsigned(
|
||||
&apdu[apdu_len], len_value_type, &unsigned_value);
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* priority [5] Unsigned (1..16) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size, 5, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (data) {
|
||||
data->priority = (uint8_t)unsigned_value;
|
||||
@@ -337,6 +368,10 @@ int lighting_command_decode(
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (data) {
|
||||
data->use_priority = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -437,20 +472,16 @@ int xy_color_encode(uint8_t *apdu, BACNET_XY_COLOR *value)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
|
||||
if (value) {
|
||||
/* x-coordinate REAL */
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_bacnet_real(value->x_coordinate, apdu_offset);
|
||||
len = encode_application_real(apdu, value->x_coordinate);
|
||||
apdu_len += len;
|
||||
/* y-coordinate REAL */
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
apdu += len;
|
||||
}
|
||||
len = encode_bacnet_real(value->y_coordinate, apdu_offset);
|
||||
/* y-coordinate REAL */
|
||||
len = encode_application_real(apdu, value->y_coordinate);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
@@ -497,7 +528,7 @@ int xy_color_context_encode(
|
||||
* @param apdu_size - the size of the data buffer
|
||||
* @param value - decoded BACnetxyColor, if decoded
|
||||
*
|
||||
* @return the number of apdu bytes consumed
|
||||
* @return the number of apdu bytes consumed, or BACNET_STATUS_ERROR
|
||||
*/
|
||||
int xy_color_decode(uint8_t *apdu, uint32_t apdu_size, BACNET_XY_COLOR *value)
|
||||
{
|
||||
@@ -505,21 +536,26 @@ int xy_color_decode(uint8_t *apdu, uint32_t apdu_size, BACNET_XY_COLOR *value)
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
|
||||
if (apdu && value && (apdu_size >= 8)) {
|
||||
/* each REAL is encoded in 4 octets */
|
||||
len = decode_real(&apdu[0], &real_value);
|
||||
if (len == 4) {
|
||||
if (apdu) {
|
||||
len = bacnet_real_application_decode(
|
||||
&apdu[apdu_len], apdu_size, &real_value);
|
||||
if (len > 0) {
|
||||
if (value) {
|
||||
value->x_coordinate = real_value;
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
len = decode_real(&apdu[4], &real_value);
|
||||
if (len == 4) {
|
||||
len = bacnet_real_application_decode(
|
||||
&apdu[apdu_len], apdu_size, &real_value);
|
||||
if (len > 0) {
|
||||
if (value) {
|
||||
value->y_coordinate = real_value;
|
||||
}
|
||||
apdu_len += len;
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,7 +569,7 @@ int xy_color_decode(uint8_t *apdu, uint32_t apdu_size, BACNET_XY_COLOR *value)
|
||||
* @param apdu_size - the size of the data buffer
|
||||
* @param value - decoded BACnetxyColor, if decoded
|
||||
*
|
||||
* @return the number of apdu bytes consumed
|
||||
* @return the number of apdu bytes consumed, or BACNET_STATUS_ERROR
|
||||
*/
|
||||
int xy_color_context_decode(uint8_t *apdu,
|
||||
uint32_t apdu_size,
|
||||
@@ -541,33 +577,45 @@ int xy_color_context_decode(uint8_t *apdu,
|
||||
BACNET_XY_COLOR *value)
|
||||
{
|
||||
int len = 0;
|
||||
int rlen = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_XY_COLOR color = { 0.0, 0.0 };
|
||||
|
||||
if (apdu_size > 0) {
|
||||
if (decode_is_opening_tag_number(&apdu[apdu_len], tag_number)) {
|
||||
apdu_len += 1;
|
||||
len =
|
||||
xy_color_decode(&apdu[apdu_len], apdu_size - apdu_len, &color);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (value) {
|
||||
value->x_coordinate = color.x_coordinate;
|
||||
value->y_coordinate = color.y_coordinate;
|
||||
}
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
if (decode_is_closing_tag_number(
|
||||
&apdu[apdu_len], tag_number)) {
|
||||
apdu_len += 1;
|
||||
rlen = apdu_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bacnet_is_opening_tag_number(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
apdu_len += len;
|
||||
len = xy_color_decode(&apdu[apdu_len], apdu_size - apdu_len, &color);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
if (value) {
|
||||
value->x_coordinate = color.x_coordinate;
|
||||
value->y_coordinate = color.y_coordinate;
|
||||
}
|
||||
} else {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
if (!bacnet_is_closing_tag_number(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, tag_number, &len)) {
|
||||
return BACNET_STATUS_ERROR;
|
||||
}
|
||||
apdu_len += len;
|
||||
|
||||
return rlen;
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnetxyColor complex data for x and y coordinates
|
||||
* @param dst - destination BACNET_XY_COLOR structure
|
||||
* @param x - x coordinate
|
||||
* @param x - y coordinate
|
||||
*/
|
||||
void xy_color_set(BACNET_XY_COLOR *dst, float x, float y)
|
||||
{
|
||||
if (dst) {
|
||||
dst->x_coordinate = x;
|
||||
dst->y_coordinate = y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -609,6 +657,64 @@ bool xy_color_same(BACNET_XY_COLOR *value1, BACNET_XY_COLOR *value2)
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert BACnetXYcolor to ASCII for printing
|
||||
*
|
||||
* @param value - struct to convert to ASCII
|
||||
* @param buf - ASCII output buffer (or NULL for size)
|
||||
* @param buf_size - ASCII output buffer capacity (or 0 for size)
|
||||
*
|
||||
* @return the number of characters which would be generated for the given
|
||||
* input, excluding the trailing null. negative is returned if the
|
||||
* capacity was not sufficient.
|
||||
*
|
||||
* @note buf and buf_size may be null and zero to return only the size
|
||||
*/
|
||||
int xy_color_to_ascii(
|
||||
const BACNET_XY_COLOR *value,
|
||||
char *buf,
|
||||
size_t buf_size)
|
||||
{
|
||||
return snprintf(buf, buf_size, "(%f,%f)", value->x_coordinate,
|
||||
value->x_coordinate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Parse an ASCII string for a BACnetXYcolor
|
||||
* @param mac [out] BACNET_XY_COLOR structure to store the results
|
||||
* @param arg [in] nul terminated ASCII string to parse
|
||||
* @return true if the address was parsed
|
||||
*/
|
||||
bool xy_color_from_ascii(BACNET_XY_COLOR *value, const char *argv)
|
||||
{
|
||||
bool status = false;
|
||||
int count;
|
||||
float x,y;
|
||||
|
||||
count = sscanf(argv, "%f,%f", &x, &y);
|
||||
if (count == 2) {
|
||||
value->x_coordinate = x;
|
||||
value->y_coordinate = y;
|
||||
status = true;
|
||||
} else {
|
||||
#if defined(BACAPP_COLOR_RGB_CONVERSION_ENABLED)
|
||||
uint8_t red, green, blue;
|
||||
unsigned rgb_max;
|
||||
|
||||
rgb_max = color_rgb_count();
|
||||
count = color_rgb_from_ascii(&red, &green, &blue, argv);
|
||||
if (count < rgb_max) {
|
||||
color_rgb_to_xy(red, green, blue, &x, &y, NULL);
|
||||
value->x_coordinate = x;
|
||||
value->y_coordinate = y;
|
||||
status = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a BACnetColorCommand complex data type
|
||||
*
|
||||
@@ -629,82 +735,62 @@ int color_command_encode(uint8_t *apdu, BACNET_COLOR_COMMAND *value)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value;
|
||||
|
||||
if (value) {
|
||||
/* operation [0] BACnetColorOperation */
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_context_enumerated(apdu_offset, 0, value->operation);
|
||||
len = encode_context_enumerated(apdu, 0, value->operation);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
switch (value->operation) {
|
||||
case BACNET_COLOR_OPERATION_NONE:
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_COLOR:
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
/* target-color [1] BACnetxyColor */
|
||||
len = xy_color_context_encode(
|
||||
apdu_offset, 1, &value->target.color);
|
||||
len = xy_color_context_encode(apdu, 1, &value->target.color);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
if ((value->transit.fade_time >= BACNET_COLOR_FADE_TIME_MIN) &&
|
||||
(value->transit.fade_time <= BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
/* fade-time [3] Unsigned (100.. 86400000) */
|
||||
/* fade-time [3] Unsigned (100.. 86400000) OPTIONAL */
|
||||
unsigned_value = value->transit.fade_time;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 3, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 3, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_CCT:
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
/* target-color-temperature [2] Unsigned */
|
||||
unsigned_value = value->target.color_temperature;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_context_unsigned(apdu_offset, 2, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 2, unsigned_value);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
if ((value->transit.fade_time >= BACNET_COLOR_FADE_TIME_MIN) &&
|
||||
(value->transit.fade_time <= BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
/* fade-time [3] Unsigned (100.. 86400000) */
|
||||
/* fade-time [3] Unsigned (100.. 86400000) OPTIONAL */
|
||||
unsigned_value = value->transit.fade_time;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 3, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 3, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_RAMP_TO_CCT:
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
/* target-color-temperature [2] Unsigned */
|
||||
unsigned_value = value->target.color_temperature;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_context_unsigned(apdu_offset, 2, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 2, unsigned_value);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu += len;
|
||||
}
|
||||
if ((value->transit.ramp_rate >= BACNET_COLOR_RAMP_RATE_MIN) &&
|
||||
(value->transit.ramp_rate <= BACNET_COLOR_RAMP_RATE_MAX)) {
|
||||
/* ramp-rate [4] Unsigned (1..30000) */
|
||||
/* ramp-rate [4] Unsigned (1..30000) OPTIONAL */
|
||||
unsigned_value = value->transit.ramp_rate;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 4, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 4, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
@@ -714,16 +800,9 @@ int color_command_encode(uint8_t *apdu, BACNET_COLOR_COMMAND *value)
|
||||
BACNET_COLOR_STEP_INCREMENT_MIN) &&
|
||||
(value->transit.step_increment <=
|
||||
BACNET_COLOR_STEP_INCREMENT_MAX)) {
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
/* step-increment [5] Unsigned (1..30000) */
|
||||
/* step-increment [5] Unsigned (1..30000) OPTIONAL */
|
||||
unsigned_value = value->transit.step_increment;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 5, unsigned_value);
|
||||
len = encode_context_unsigned(apdu, 5, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
@@ -749,21 +828,19 @@ int color_command_context_encode(
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
uint8_t *apdu_offset = NULL;
|
||||
|
||||
if (value) {
|
||||
apdu_offset = apdu;
|
||||
len = encode_opening_tag(apdu_offset, tag_number);
|
||||
len = encode_opening_tag(apdu, tag_number);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
apdu += len;
|
||||
}
|
||||
len = color_command_encode(apdu_offset, value);
|
||||
len = color_command_encode(apdu, value);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
apdu += len;
|
||||
}
|
||||
len = encode_closing_tag(apdu_offset, tag_number);
|
||||
len = encode_closing_tag(apdu, tag_number);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
@@ -808,8 +885,10 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
/* operation [0] BACnetColorOperation */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
apdu, apdu_size - apdu_len, 0, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 0, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -821,7 +900,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value >= BACNET_COLOR_OPERATION_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
@@ -837,30 +915,27 @@ int color_command_decode(uint8_t *apdu,
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_COLOR:
|
||||
/* target-color [1] BACnetxyColor */
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
len = xy_color_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 1, &color);
|
||||
if (len == 0) {
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (value) {
|
||||
value->target.color.x_coordinate = color.x_coordinate;
|
||||
value->target.color.y_coordinate = color.y_coordinate;
|
||||
}
|
||||
if ((apdu_size - apdu_len) != 0) {
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* fade-time [3] Unsigned (100.. 86400000) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 3, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -873,7 +948,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_FADE_TIME_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
if (error_code) {
|
||||
@@ -881,22 +955,20 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.fade_time = unsigned_value;
|
||||
}
|
||||
} else {
|
||||
unsigned_value = 0;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.fade_time = unsigned_value;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_CCT:
|
||||
/* target-color-temperature [2] Unsigned */
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
len = bacnet_unsigned_context_decode(
|
||||
apdu, apdu_size - apdu_len, 2, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -909,7 +981,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value > UINT16_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
@@ -919,11 +990,13 @@ int color_command_decode(uint8_t *apdu,
|
||||
if (value) {
|
||||
value->target.color_temperature = unsigned_value;
|
||||
}
|
||||
if ((apdu_size - apdu_len) != 0) {
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* fade-time [3] Unsigned (100.. 86400000) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 3, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -936,7 +1009,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_FADE_TIME_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
if (error_code) {
|
||||
@@ -944,22 +1016,20 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.fade_time = unsigned_value;
|
||||
}
|
||||
} else {
|
||||
unsigned_value = 0;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.fade_time = unsigned_value;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_RAMP_TO_CCT:
|
||||
/* target-color-temperature [2] Unsigned */
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
len = bacnet_unsigned_context_decode(
|
||||
apdu, apdu_size - apdu_len, 2, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 2, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -972,7 +1042,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value > UINT16_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
@@ -982,11 +1051,13 @@ int color_command_decode(uint8_t *apdu,
|
||||
if (value) {
|
||||
value->target.color_temperature = unsigned_value;
|
||||
}
|
||||
if ((apdu_size - apdu_len) != 0) {
|
||||
/* ramp-rate [4] Unsigned (1..30000) */
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* ramp-rate [4] Unsigned (1..30000) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 4, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
@@ -999,7 +1070,6 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_RAMP_RATE_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_RAMP_RATE_MAX)) {
|
||||
if (error_code) {
|
||||
@@ -1007,42 +1077,43 @@ int color_command_decode(uint8_t *apdu,
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.ramp_rate = unsigned_value;
|
||||
}
|
||||
} else {
|
||||
unsigned_value = 0;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.ramp_rate = unsigned_value;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STEP_UP_CCT:
|
||||
case BACNET_COLOR_OPERATION_STEP_DOWN_CCT:
|
||||
/* step-increment [5] Unsigned (1..30000) */
|
||||
if ((apdu_size - apdu_len) == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
len = bacnet_unsigned_context_decode(
|
||||
apdu, apdu_size - apdu_len, 3, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
if ((apdu_size - apdu_len) > 0) {
|
||||
/* step-increment [5] Unsigned (1..30000) OPTIONAL */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 5, &unsigned_value);
|
||||
if (len > 0) {
|
||||
apdu_len += len;
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code =
|
||||
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
if (len == 0) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_INVALID_TAG;
|
||||
}
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code =
|
||||
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_STEP_INCREMENT_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_STEP_INCREMENT_MAX)) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
if ((unsigned_value < BACNET_COLOR_STEP_INCREMENT_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_STEP_INCREMENT_MAX)) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
} else {
|
||||
unsigned_value = 0;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.step_increment = unsigned_value;
|
||||
|
||||
Reference in New Issue
Block a user