Feature/color objects color command (#302)
* added BACnetColorCommand and BACnetxyColor encoding and unit testing * Added Color object and unit testing. * Added Color Temperature object and Unit test * Fix BVLC unit test warning. * add port Makefile for extra types * added RGB to and from CIE xy utility in sys folder, and add unit tests. * added cmake-win32 target * Change RP and RPM to use known property decoder. Add color object RP and RPM decoding and printing Fix RPM print for new reserved range above 4194303 Change default protocol-revision to 24 for Color object * Integrate Color and Color Temperature objects into demo apps Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
+724
-35
@@ -1,36 +1,14 @@
|
||||
/*####COPYRIGHTBEGIN####
|
||||
-------------------------------------------
|
||||
Copyright (C) 2013 Steve Karg <skarg@users.sourceforge.net>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to:
|
||||
The Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330
|
||||
Boston, MA 02111-1307, USA.
|
||||
|
||||
As a special exception, if other files instantiate templates or
|
||||
use macros or inline functions from this file, or you compile
|
||||
this file and link it with other works to produce a work based
|
||||
on this file, this file does not by itself cause the resulting
|
||||
work to be covered by the GNU General Public License. However
|
||||
the source code for this file must still be made available in
|
||||
accordance with section (3) of the GNU General Public License.
|
||||
|
||||
This exception does not invalidate any other reasons why a work
|
||||
based on this file might be covered by the GNU General Public
|
||||
License.
|
||||
-------------------------------------------
|
||||
####COPYRIGHTEND####*/
|
||||
/**
|
||||
* @file
|
||||
* @brief API for BACnetLightingCommand and BACnetColorCommand
|
||||
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||
* @date June 2022
|
||||
* @section LICENSE
|
||||
*
|
||||
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
@@ -38,11 +16,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "bacnet/lighting.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacreal.h"
|
||||
#include "bacnet/lighting.h"
|
||||
|
||||
#ifndef islessgreater
|
||||
#define islessgreater( x, y) ((x) < (y) || (x) > (y))
|
||||
#define islessgreater(x, y) ((x) < (y) || (x) > (y))
|
||||
#endif
|
||||
|
||||
/** @file lighting.c Manipulate BACnet lighting command values */
|
||||
@@ -313,3 +292,713 @@ bool lighting_command_same(
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a BACnetxyColor complex data type
|
||||
*
|
||||
* BACnetxyColor::= SEQUENCE {
|
||||
* x-coordinate REAL, --(0.0 to 1.0)
|
||||
* y-coordinate REAL --(0.0 to 1.0)
|
||||
* }
|
||||
* @param apdu - the APDU buffer, or NULL for length
|
||||
* @param value - BACnetxyColor structure
|
||||
* @return length of the encoded APDU buffer
|
||||
*/
|
||||
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);
|
||||
apdu_len += len;
|
||||
/* y-coordinate REAL */
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_bacnet_real(value->y_coordinate, apdu_offset);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a context tagged BACnetxyColor complex data type
|
||||
* @param apdu - the APDU buffer
|
||||
* @param tag_number - the APDU buffer size
|
||||
* @param value - BACnetxyColor structure
|
||||
* @return length of the APDU buffer, or 0 if not able to encode
|
||||
*/
|
||||
int xy_color_context_encode(
|
||||
uint8_t *apdu, uint8_t tag_number, BACNET_XY_COLOR *value)
|
||||
{
|
||||
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);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = xy_color_encode(apdu_offset, value);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_closing_tag(apdu_offset, tag_number);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the BACnetxyColor complex data type Value
|
||||
*
|
||||
* @param apdu - buffer of data to be decoded
|
||||
* @param apdu_size - the size of the data buffer
|
||||
* @param value - decoded BACnetxyColor, if decoded
|
||||
*
|
||||
* @return the number of apdu bytes consumed
|
||||
*/
|
||||
int xy_color_decode(uint8_t *apdu, uint32_t apdu_size, BACNET_XY_COLOR *value)
|
||||
{
|
||||
float real_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 (value) {
|
||||
value->x_coordinate = real_value;
|
||||
}
|
||||
apdu_len += len;
|
||||
}
|
||||
len = decode_real(&apdu[4], &real_value);
|
||||
if (len == 4) {
|
||||
if (value) {
|
||||
value->y_coordinate = real_value;
|
||||
}
|
||||
apdu_len += len;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the BACnetxyColor complex data type Value
|
||||
*
|
||||
* @param apdu - buffer of data to be decoded
|
||||
* @param apdu_size - the size of the data buffer
|
||||
* @param value - decoded BACnetxyColor, if decoded
|
||||
*
|
||||
* @return the number of apdu bytes consumed
|
||||
*/
|
||||
int xy_color_context_decode(uint8_t *apdu,
|
||||
uint32_t apdu_size,
|
||||
uint8_t tag_number,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy the BACnetxyColor complex data from src to dst
|
||||
* @param dst - destination BACNET_XY_COLOR structure
|
||||
* @param src - source BACNET_XY_COLOR structure
|
||||
* @return true if successfully copied
|
||||
*/
|
||||
int xy_color_copy(BACNET_XY_COLOR *dst, BACNET_XY_COLOR *src)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dst && src) {
|
||||
dst->x_coordinate = src->x_coordinate;
|
||||
dst->y_coordinate = src->y_coordinate;
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the BACnetxyColor complex data
|
||||
* @param value1 - BACNET_XY_COLOR structure
|
||||
* @param value2 - BACNET_XY_COLOR structure
|
||||
* @return true if the same
|
||||
*/
|
||||
bool xy_color_same(BACNET_XY_COLOR *value1, BACNET_XY_COLOR *value2)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (value1 && value2) {
|
||||
if ((value1->x_coordinate == value2->x_coordinate) &&
|
||||
(value1->y_coordinate == value2->y_coordinate)) {
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a BACnetColorCommand complex data type
|
||||
*
|
||||
* BACnetColorCommand structure ::= SEQUENCE {
|
||||
* operation [0] BACnetColorOperation,
|
||||
* target-color [1] BACnetxyColor OPTIONAL,
|
||||
* target-color-temperature [2] Unsigned OPTIONAL,
|
||||
* fade-time [3] Unsigned (100.. 86400000) OPTIONAL,
|
||||
* ramp-rate [4] Unsigned (1..30000) OPTIONAL,
|
||||
* step-increment [5] Unsigned (1..30000) OPTIONAL
|
||||
* }
|
||||
*
|
||||
* @param apdu - the APDU buffer, or NULL for length
|
||||
* @param value - BACnetColorCommand structure
|
||||
* @return length of the encoded APDU buffer
|
||||
*/
|
||||
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);
|
||||
apdu_len += 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);
|
||||
apdu_len += 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) */
|
||||
unsigned_value = value->transit.fade_time;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 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);
|
||||
apdu_len += 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) */
|
||||
unsigned_value = value->transit.fade_time;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 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);
|
||||
apdu_len += 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) */
|
||||
unsigned_value = value->transit.ramp_rate;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 4, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STEP_UP_CCT:
|
||||
case BACNET_COLOR_OPERATION_STEP_DOWN_CCT:
|
||||
if ((value->transit.step_increment >=
|
||||
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) */
|
||||
unsigned_value = value->transit.step_increment;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len =
|
||||
encode_context_unsigned(apdu_offset, 5, unsigned_value);
|
||||
apdu_len += len;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STOP:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a context tagged BACnetColorCommand complex data type
|
||||
* @param apdu - the APDU buffer
|
||||
* @param tag_number - the APDU buffer size
|
||||
* @param address - IP address and port number
|
||||
* @return length of the APDU buffer, or 0 if not able to encode
|
||||
*/
|
||||
int color_command_context_encode(
|
||||
uint8_t *apdu, uint8_t tag_number, BACNET_COLOR_COMMAND *value)
|
||||
{
|
||||
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);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = color_command_encode(apdu_offset, value);
|
||||
apdu_len += len;
|
||||
if (apdu) {
|
||||
apdu_offset = &apdu[apdu_len];
|
||||
}
|
||||
len = encode_closing_tag(apdu_offset, tag_number);
|
||||
apdu_len += len;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode the BACnetColorCommand complex data
|
||||
*
|
||||
* BACnetColorCommand ::= SEQUENCE {
|
||||
* operation [0] BACnetColorOperation,
|
||||
* target-color [1] BACnetxyColor OPTIONAL,
|
||||
* target-color-temperature [2] Unsigned OPTIONAL,
|
||||
* fade-time [3] Unsigned (100.. 86400000) OPTIONAL,
|
||||
* ramp-rate [4] Unsigned (1..30000) OPTIONAL,
|
||||
* step-increment [5] Unsigned (1..30000) OPTIONAL
|
||||
* }
|
||||
*
|
||||
* @param apdu - the APDU buffer
|
||||
* @param apdu_len - the APDU buffer length
|
||||
* @param value - BACnetColorCommand structure values
|
||||
* @return length of the APDU buffer decoded, or ERROR, REJECT, or ABORT
|
||||
*/
|
||||
int color_command_decode(uint8_t *apdu,
|
||||
uint16_t apdu_size,
|
||||
BACNET_ERROR_CODE *error_code,
|
||||
BACNET_COLOR_COMMAND *value)
|
||||
{
|
||||
int len = 0;
|
||||
int apdu_len = 0;
|
||||
BACNET_UNSIGNED_INTEGER unsigned_value = 0;
|
||||
BACNET_COLOR_OPERATION operation = BACNET_COLOR_OPERATION_NONE;
|
||||
BACNET_XY_COLOR color;
|
||||
|
||||
/* default reject code */
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
/* check for value pointers */
|
||||
if ((apdu_size == 0) || (!apdu)) {
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
/* operation [0] BACnetColorOperation */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
apdu, apdu_size - apdu_len, 0, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value >= BACNET_COLOR_OPERATION_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
operation = (BACNET_COLOR_OPERATION)unsigned_value;
|
||||
if (value) {
|
||||
value->operation = operation;
|
||||
}
|
||||
switch (operation) {
|
||||
case BACNET_COLOR_OPERATION_NONE:
|
||||
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 (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) {
|
||||
/* 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) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_FADE_TIME_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value > UINT16_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->target.color_temperature = unsigned_value;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_FADE_TIME_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_FADE_TIME_MAX)) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if (unsigned_value > UINT16_MAX) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->target.color_temperature = unsigned_value;
|
||||
}
|
||||
if ((apdu_size - apdu_len) != 0) {
|
||||
/* ramp-rate [4] Unsigned (1..30000) */
|
||||
len = bacnet_unsigned_context_decode(
|
||||
&apdu[apdu_len], apdu_size - apdu_len, 4, &unsigned_value);
|
||||
if (len <= 0) {
|
||||
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;
|
||||
}
|
||||
apdu_len += len;
|
||||
if ((unsigned_value < BACNET_COLOR_RAMP_RATE_MIN) ||
|
||||
(unsigned_value > BACNET_COLOR_RAMP_RATE_MAX)) {
|
||||
if (error_code) {
|
||||
*error_code = ERROR_CODE_REJECT_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (error_code) {
|
||||
*error_code =
|
||||
ERROR_CODE_REJECT_MISSING_REQUIRED_PARAMETER;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
return BACNET_STATUS_REJECT;
|
||||
}
|
||||
if (value) {
|
||||
value->transit.step_increment = unsigned_value;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STOP:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return apdu_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy the BACnetColorCommand complex data from src to dst
|
||||
* @param dst - destination structure
|
||||
* @param src - source structure
|
||||
* @return true if successfully copied
|
||||
*/
|
||||
bool color_command_copy(BACNET_COLOR_COMMAND *dst, BACNET_COLOR_COMMAND *src)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (dst && src) {
|
||||
memcpy(dst, src, sizeof(BACNET_COLOR_COMMAND));
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare the BACnetColorCommand complex data
|
||||
* @param value1 - BACNET_COLOR_COMMAND structure
|
||||
* @param value2 - BACNET_COLOR_COMMAND structure
|
||||
* @return true if the same
|
||||
*/
|
||||
bool color_command_same(
|
||||
BACNET_COLOR_COMMAND *value1, BACNET_COLOR_COMMAND *value2)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (value1 && value2 && (value1->operation == value2->operation)) {
|
||||
switch (value1->operation) {
|
||||
case BACNET_COLOR_OPERATION_NONE:
|
||||
status = true;
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_COLOR:
|
||||
if ((value1->target.color.x_coordinate ==
|
||||
value2->target.color.x_coordinate) &&
|
||||
(value1->target.color.y_coordinate ==
|
||||
value2->target.color.y_coordinate) &&
|
||||
(value1->transit.fade_time == value2->transit.fade_time)) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_FADE_TO_CCT:
|
||||
if ((value1->target.color_temperature ==
|
||||
value2->target.color_temperature) &&
|
||||
(value1->transit.fade_time == value2->transit.fade_time)) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_RAMP_TO_CCT:
|
||||
if ((value1->target.color_temperature ==
|
||||
value2->target.color_temperature) &&
|
||||
(value1->transit.ramp_rate == value2->transit.ramp_rate)) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STEP_UP_CCT:
|
||||
case BACNET_COLOR_OPERATION_STEP_DOWN_CCT:
|
||||
if (value1->transit.step_increment ==
|
||||
value2->transit.step_increment) {
|
||||
status = true;
|
||||
}
|
||||
break;
|
||||
case BACNET_COLOR_OPERATION_STOP:
|
||||
status = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user