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:
Steve Karg
2022-07-13 09:54:36 -05:00
committed by GitHub
parent 085de3c385
commit 38d213b47c
80 changed files with 5369 additions and 347 deletions
+917
View File
@@ -0,0 +1,917 @@
/**
* @file
* @author Steve Karg
* @date June 2022
* @brief Color objects, customize for your use
*
* @section DESCRIPTION
*
* The Color object is an object with a present-value that
* uses an x,y color single precision floating point data type.
*
* @section LICENSE
*
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacenum.h"
#include "bacnet/bacerror.h"
#include "bacnet/bacapp.h"
#include "bacnet/bactext.h"
#include "bacnet/cov.h"
#include "bacnet/apdu.h"
#include "bacnet/npdu.h"
#include "bacnet/abort.h"
#include "bacnet/lighting.h"
#include "bacnet/reject.h"
#include "bacnet/rp.h"
#include "bacnet/wp.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/sys/keylist.h"
/* me! */
#include "color_object.h"
struct object_data {
bool Changed : 1;
bool Write_Enabled : 1;
BACNET_XY_COLOR Present_Value;
BACNET_XY_COLOR Tracking_Value;
BACNET_COLOR_COMMAND Color_Command;
BACNET_COLOR_OPERATION_IN_PROGRESS In_Progress;
BACNET_XY_COLOR Default_Color;
uint32_t Default_Fade_Time;
BACNET_COLOR_TRANSITION Transition;
const char *Object_Name;
const char *Description;
};
/* Key List for storing the object data sorted by instance number */
static OS_Keylist Object_List;
/* callback for present value writes */
static color_write_present_value_callback Color_Write_Present_Value_Callback;
/* These three arrays are used by the ReadPropertyMultiple handler */
static const int Color_Properties_Required[] = { PROP_OBJECT_IDENTIFIER,
PROP_OBJECT_NAME, PROP_OBJECT_TYPE, PROP_PRESENT_VALUE, PROP_TRACKING_VALUE,
PROP_COLOR_COMMAND, PROP_IN_PROGRESS, PROP_DEFAULT_COLOR,
PROP_DEFAULT_FADE_TIME, -1 };
static const int Color_Properties_Optional[] = { PROP_DESCRIPTION,
PROP_TRANSITION, -1 };
static const int Color_Properties_Proprietary[] = { -1 };
/**
* Returns the list of required, optional, and proprietary properties.
* Used by ReadPropertyMultiple service.
*
* @param pRequired - pointer to list of int terminated by -1, of
* BACnet required properties for this object.
* @param pOptional - pointer to list of int terminated by -1, of
* BACnet optkional properties for this object.
* @param pProprietary - pointer to list of int terminated by -1, of
* BACnet proprietary properties for this object.
*/
void Color_Property_Lists(
const int **pRequired, const int **pOptional, const int **pProprietary)
{
if (pRequired) {
*pRequired = Color_Properties_Required;
}
if (pOptional) {
*pOptional = Color_Properties_Optional;
}
if (pProprietary) {
*pProprietary = Color_Properties_Proprietary;
}
return;
}
/**
* Determines if a given Color instance is valid
*
* @param object_instance - object-instance number of the object
*
* @return true if the instance is valid, and false if not
*/
bool Color_Valid_Instance(uint32_t object_instance)
{
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
return true;
}
return false;
}
/**
* Determines the number of Color objects
*
* @return Number of Color objects
*/
unsigned Color_Count(void)
{
return Keylist_Count(Object_List);
}
/**
* Determines the object instance-number for a given 0..N index
* of Color objects where N is Color_Count().
*
* @param index - 0..N where N is Color_Count()
*
* @return object instance-number for the given index
*/
uint32_t Color_Index_To_Instance(unsigned index)
{
return Keylist_Key(Object_List, index);
}
/**
* For a given object instance-number, determines a 0..N index
* of Color objects where N is Color_Count().
*
* @param object_instance - object-instance number of the object
*
* @return index for the given instance-number, or Color_Count()
* if not valid.
*/
unsigned Color_Instance_To_Index(uint32_t object_instance)
{
return Keylist_Index(Object_List, object_instance);
}
/**
* For a given object instance-number, determines the present-value
*
* @param object_instance - object-instance number of the object
*
* @return present-value of the object
*/
bool Color_Present_Value(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(value, &pObject->Present_Value);
status = true;
}
return status;
}
/**
* For a given object instance-number, sets the present-value
*
* @param object_instance - object-instance number of the object
* @param value - floating point Color
*
* @return true if values are within range and present-value is set.
*/
bool Color_Present_Value_Set(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(&pObject->Present_Value, value);
status = true;
}
return status;
}
/**
* For a given object instance-number, sets the present-value
*
* @param object_instance - object-instance number of the object
* @param value - floating point Color
* @param priority - priority-array index value 1..16
* @param error_class - the BACnet error class
* @param error_code - BACnet Error code
*
* @return true if values are within range and present-value is set.
*/
static bool Color_Present_Value_Write(uint32_t object_instance,
BACNET_XY_COLOR *value,
uint8_t priority,
BACNET_ERROR_CLASS *error_class,
BACNET_ERROR_CODE *error_code)
{
bool status = false;
struct object_data *pObject;
BACNET_XY_COLOR old_value = { 0.0, 0.0 };
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
(void)priority;
if (pObject->Write_Enabled) {
xy_color_copy(&old_value, &pObject->Present_Value);
xy_color_copy(&pObject->Present_Value, value);
if (Color_Write_Present_Value_Callback) {
Color_Write_Present_Value_Callback(
object_instance, &old_value, value);
}
status = true;
} else {
*error_class = ERROR_CLASS_PROPERTY;
*error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
}
} else {
*error_class = ERROR_CLASS_OBJECT;
*error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
return status;
}
/**
* For a given object instance-number, determines the present-value
*
* @param object_instance - object-instance number of the object
*
* @return present-value of the object
*/
bool Color_Tracking_Value(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(value, &pObject->Tracking_Value);
status = true;
}
return status;
}
/**
* For a given object instance-number, sets the present-value
*
* @param object_instance - object-instance number of the object
* @param value - floating point Color
*
* @return true if values are within range and present-value is set.
*/
bool Color_Tracking_Value_Set(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(&pObject->Tracking_Value, value);
status = true;
}
return status;
}
/**
* For a given object instance-number, gets the property value
*
* @param object_instance - object-instance number of the object
* @param value - color command data
* @return true if the property value is copied
*/
bool Color_Command(uint32_t object_instance, BACNET_COLOR_COMMAND *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject && value) {
color_command_copy(value, &pObject->Color_Command);
status = true;
}
return status;
}
/**
* For a given object instance-number, sets the property value
*
* @param object_instance - object-instance number of the object
* @param value - color command data
* @return true if values are within range and value is set.
*/
bool Color_Command_Set(uint32_t object_instance, BACNET_COLOR_COMMAND *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject && value) {
color_command_copy(&pObject->Color_Command, value);
status = true;
}
return status;
}
/**
* For a given object instance-number, gets the property value
*
* @param object_instance - object-instance number of the object
* @return property value
*/
BACNET_COLOR_OPERATION_IN_PROGRESS Color_In_Progress(uint32_t object_instance)
{
BACNET_COLOR_OPERATION_IN_PROGRESS value =
BACNET_COLOR_OPERATION_IN_PROGRESS_MAX;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->In_Progress;
}
return value;
}
/**
* For a given object instance-number, sets the property value
*
* @param object_instance - object-instance number of the object
* @param value - BACNET_COLOR_OPERATION_IN_PROGRESS
* @return true if values are within range and value is set.
*/
bool Color_In_Progress_Set(
uint32_t object_instance, BACNET_COLOR_OPERATION_IN_PROGRESS value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value < BACNET_COLOR_OPERATION_IN_PROGRESS_MAX) {
pObject->In_Progress = value;
status = true;
}
}
return status;
}
/**
* For a given object instance-number, determines the present-value
*
* @param object_instance - object-instance number of the object
*
* @return present-value of the object
*/
bool Color_Default_Color(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(value, &pObject->Default_Color);
status = true;
}
return status;
}
/**
* For a given object instance-number, sets the present-value
*
* @param object_instance - object-instance number of the object
* @param value - floating point Color
*
* @return true if values are within range and present-value is set.
*/
bool Color_Default_Color_Set(uint32_t object_instance, BACNET_XY_COLOR *value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
xy_color_copy(&pObject->Default_Color, value);
status = true;
}
return status;
}
/**
* For a given object instance-number, gets the property value
*
* @param object_instance - object-instance number of the object
* @return property value
*/
uint32_t Color_Default_Fade_Time(uint32_t object_instance)
{
uint32_t value = 0;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Default_Fade_Time;
}
return value;
}
/**
* For a given object instance-number, sets the property value
*
* @param object_instance - object-instance number of the object
* @param value - BACNET_COLOR_OPERATION_IN_PROGRESS
* @return true if values are within range and value is set.
*/
bool Color_Default_Fade_Time_Set(uint32_t object_instance, uint32_t value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if ((value == 0) ||
((value >= BACNET_COLOR_FADE_TIME_MIN) &&
(value <= BACNET_COLOR_FADE_TIME_MAX))) {
pObject->Default_Fade_Time = value;
}
status = true;
}
return status;
}
/**
* For a given object instance-number, gets the property value
*
* @param object_instance - object-instance number of the object
* @return property value
*/
BACNET_COLOR_TRANSITION Color_Transition(uint32_t object_instance)
{
BACNET_COLOR_TRANSITION value = BACNET_COLOR_OPERATION_IN_PROGRESS_MAX;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Transition;
}
return value;
}
/**
* For a given object instance-number, sets the property value
*
* @param object_instance - object-instance number of the object
* @param value - BACNET_COLOR_TRANSITION
* @return true if values are within range and value is set.
*/
bool Color_Transition_Set(
uint32_t object_instance, BACNET_COLOR_TRANSITION value)
{
bool status = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (value < BACNET_COLOR_TRANSITION_MAX) {
pObject->Transition = value;
status = true;
}
}
return status;
}
/**
* For a given object instance-number, loads the object-name into
* a characterstring. Note that the object name must be unique
* within this device.
*
* @param object_instance - object-instance number of the object
* @param object_name - holds the object-name retrieved
*
* @return true if object-name was retrieved
*/
bool Color_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name)
{
bool status = false;
struct object_data *pObject;
char name_text[16] = "COLOR-4194303";
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Object_Name) {
status =
characterstring_init_ansi(object_name, pObject->Object_Name);
} else {
snprintf(name_text, sizeof(name_text), "COLOR-%u", object_instance);
status = characterstring_init_ansi(object_name, name_text);
}
}
return status;
}
/**
* For a given object instance-number, sets the object-name
* Note that the object name must be unique within this device.
*
* @param object_instance - object-instance number of the object
* @param new_name - holds the object-name to be set
*
* @return true if object-name was set
*/
bool Color_Name_Set(uint32_t object_instance, char *new_name)
{
bool status = false; /* return value */
BACNET_CHARACTER_STRING object_name;
BACNET_OBJECT_TYPE found_type = 0;
uint32_t found_instance = 0;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject && new_name) {
/* All the object names in a device must be unique */
characterstring_init_ansi(&object_name, new_name);
if (Device_Valid_Object_Name(
&object_name, &found_type, &found_instance)) {
if ((found_type == OBJECT_COLOR) &&
(found_instance == object_instance)) {
/* writing same name to same object */
status = true;
} else {
/* duplicate name! */
status = false;
}
} else {
status = true;
pObject->Object_Name = new_name;
Device_Inc_Database_Revision();
}
}
return status;
}
/**
* For a given object instance-number, returns the description
*
* @param object_instance - object-instance number of the object
*
* @return description text or NULL if not found
*/
char *Color_Description(uint32_t object_instance)
{
char *name = NULL;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
if (pObject->Description) {
name = (char *)pObject->Description;
} else {
name = "";
}
}
return name;
}
/**
* For a given object instance-number, sets the description
*
* @param object_instance - object-instance number of the object
* @param new_name - holds the description to be set
*
* @return true if object-name was set
*/
bool Color_Description_Set(uint32_t object_instance, char *new_name)
{
bool status = false; /* return value */
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject && new_name) {
status = true;
pObject->Description = new_name;
}
return status;
}
/**
* ReadProperty handler for this object. For the given ReadProperty
* data, the application_data is loaded or the error flags are set.
*
* @param rpdata - BACNET_READ_PROPERTY_DATA data, including
* requested data and space for the reply, or error response.
*
* @return number of APDU bytes in the response, or
* BACNET_STATUS_ERROR on error.
*/
int Color_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = 0; /* return value */
BACNET_CHARACTER_STRING char_string;
uint8_t *apdu = NULL;
BACNET_XY_COLOR color_value = { 0.0, 0.0 };
BACNET_COLOR_COMMAND color_command = { 0 };
if ((rpdata == NULL) || (rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
apdu_len = encode_application_object_id(
&apdu[0], rpdata->object_type, rpdata->object_instance);
break;
case PROP_OBJECT_NAME:
Color_Object_Name(rpdata->object_instance, &char_string);
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
break;
case PROP_OBJECT_TYPE:
apdu_len =
encode_application_enumerated(&apdu[0], rpdata->object_type);
break;
case PROP_PRESENT_VALUE:
if (Color_Present_Value(rpdata->object_instance, &color_value)) {
apdu_len = xy_color_encode(apdu, &color_value);
}
break;
case PROP_TRACKING_VALUE:
if (Color_Tracking_Value(rpdata->object_instance, &color_value)) {
apdu_len = xy_color_encode(apdu, &color_value);
}
break;
case PROP_COLOR_COMMAND:
if (Color_Command(rpdata->object_instance, &color_command)) {
apdu_len = color_command_encode(apdu, &color_command);
}
break;
case PROP_IN_PROGRESS:
apdu_len = encode_application_enumerated(
apdu, Color_In_Progress(rpdata->object_instance));
break;
case PROP_DEFAULT_COLOR:
if (Color_Default_Color(rpdata->object_instance, &color_value)) {
apdu_len = xy_color_encode(apdu, &color_value);
}
break;
case PROP_DEFAULT_FADE_TIME:
apdu_len = encode_application_unsigned(
apdu, Color_Default_Fade_Time(rpdata->object_instance));
break;
case PROP_TRANSITION:
apdu_len = encode_application_enumerated(
apdu, Color_Transition(rpdata->object_instance));
break;
case PROP_DESCRIPTION:
characterstring_init_ansi(
&char_string, Color_Description(rpdata->object_instance));
apdu_len = encode_application_character_string(apdu, &char_string);
break;
default:
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
apdu_len = BACNET_STATUS_ERROR;
break;
}
/* only array properties can have array options */
if ((apdu_len >= 0) && (rpdata->object_property != PROP_PRIORITY_ARRAY) &&
(rpdata->object_property != PROP_EVENT_TIME_STAMPS) &&
(rpdata->array_index != BACNET_ARRAY_ALL)) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
}
return apdu_len;
}
/**
* WriteProperty handler for this object. For the given WriteProperty
* data, the application_data is loaded or the error flags are set.
*
* @param wp_data - BACNET_WRITE_PROPERTY_DATA data, including
* requested data and space for the reply, or error response.
*
* @return false if an error is loaded, true if no errors
*/
bool Color_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data)
{
bool status = false; /* return value */
int len = 0;
BACNET_APPLICATION_DATA_VALUE value;
/* decode the some of the request */
len = bacapp_decode_application_data(
wp_data->application_data, wp_data->application_data_len, &value);
/* FIXME: len < application_data_len: more data? */
if (len < 0) {
/* error while decoding - a value larger than we can handle */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_VALUE_OUT_OF_RANGE;
return false;
}
if ((wp_data->object_property != PROP_PRIORITY_ARRAY) &&
(wp_data->object_property != PROP_EVENT_TIME_STAMPS) &&
(wp_data->array_index != BACNET_ARRAY_ALL)) {
/* only array properties can have array options */
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
return false;
}
switch (wp_data->object_property) {
case PROP_PRESENT_VALUE:
status = write_property_type_valid(
wp_data, &value, BACNET_APPLICATION_TAG_REAL);
if (status) {
status = Color_Present_Value_Write(wp_data->object_instance,
&value.type.XY_Color, wp_data->priority,
&wp_data->error_class, &wp_data->error_code);
}
break;
case PROP_OBJECT_IDENTIFIER:
case PROP_OBJECT_TYPE:
case PROP_OBJECT_NAME:
case PROP_DESCRIPTION:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_WRITE_ACCESS_DENIED;
break;
default:
wp_data->error_class = ERROR_CLASS_PROPERTY;
wp_data->error_code = ERROR_CODE_UNKNOWN_PROPERTY;
break;
}
return status;
}
/**
* @brief Sets a callback used when present-value is written from BACnet
* @param cb - callback used to provide indications
*/
void Color_Write_Present_Value_Callback_Set(
color_write_present_value_callback cb)
{
Color_Write_Present_Value_Callback = cb;
}
/**
* @brief Determines a object write-enabled flag state
* @param object_instance - object-instance number of the object
* @return write-enabled status flag
*/
bool Color_Write_Enabled(uint32_t object_instance)
{
bool value = false;
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
value = pObject->Write_Enabled;
}
return value;
}
/**
* @brief For a given object instance-number, sets the write-enabled flag
* @param object_instance - object-instance number of the object
*/
void Color_Write_Enable(uint32_t object_instance)
{
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
pObject->Write_Enabled = true;
}
}
/**
* @brief For a given object instance-number, clears the write-enabled flag
* @param object_instance - object-instance number of the object
*/
void Color_Write_Disable(uint32_t object_instance)
{
struct object_data *pObject;
pObject = Keylist_Data(Object_List, object_instance);
if (pObject) {
pObject->Write_Enabled = false;
}
}
/**
* Creates a Color object
* @param object_instance - object-instance number of the object
*/
bool Color_Create(uint32_t object_instance)
{
bool status = false;
struct object_data *pObject = NULL;
int index = 0;
pObject = Keylist_Data(Object_List, object_instance);
if (!pObject) {
pObject = calloc(1, sizeof(struct object_data));
if (pObject) {
pObject->Object_Name = NULL;
pObject->Present_Value.x_coordinate = 0.0;
pObject->Present_Value.y_coordinate = 0.0;
pObject->Tracking_Value.x_coordinate = 0.0;
pObject->Tracking_Value.y_coordinate = 0.0;
pObject->Color_Command.operation = BACNET_COLOR_OPERATION_NONE;
pObject->In_Progress = BACNET_COLOR_OPERATION_IN_PROGRESS_IDLE;
pObject->Default_Color.x_coordinate = 1.0;
pObject->Default_Color.y_coordinate = 1.0;
pObject->Default_Fade_Time = 0;
pObject->Transition = BACNET_COLOR_TRANSITION_NONE;
pObject->Changed = false;
pObject->Write_Enabled = false;
/* add to list */
index = Keylist_Data_Add(Object_List, object_instance, pObject);
if (index >= 0) {
status = true;
Device_Inc_Database_Revision();
}
}
}
return status;
}
/**
* Deletes an Color object
* @param object_instance - object-instance number of the object
* @return true if the object is deleted
*/
bool Color_Delete(uint32_t object_instance)
{
bool status = false;
struct object_data *pObject = NULL;
pObject = Keylist_Data_Delete(Object_List, object_instance);
if (pObject) {
free(pObject);
status = true;
Device_Inc_Database_Revision();
}
return status;
}
/**
* Deletes all the Colors and their data
*/
void Color_Cleanup(void)
{
struct object_data *pObject;
if (Object_List) {
do {
pObject = Keylist_Data_Pop(Object_List);
if (pObject) {
free(pObject);
Device_Inc_Database_Revision();
}
} while (pObject);
Keylist_Delete(Object_List);
Object_List = NULL;
}
}
/**
* Initializes the Color object data
*/
void Color_Init(void)
{
Object_List = Keylist_Create();
if (Object_List) {
atexit(Color_Cleanup);
}
}
+133
View File
@@ -0,0 +1,133 @@
/**
* @file
* @author Steve Karg
* @date June 2022
* @brief Color object, customize for your use
*
* @section DESCRIPTION
*
* The Color object is an object with a present-value that
* uses an x,y color single precision floating point data type.
*
* @section LICENSE
*
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
*
* SPDX-License-Identifier: MIT
*/
#ifndef BACNET_COLOR_OBJECT_H
#define BACNET_COLOR_OBJECT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacenum.h"
#include "bacnet/bacerror.h"
#include "bacnet/rp.h"
#include "bacnet/wp.h"
/**
* @brief Callback for gateway write present value request
* @param object_instance - object-instance number of the object
* @param old_value - BACnetXYColor value prior to write
* @param value - BACnetXYColor value of the write
*/
typedef void (*color_write_present_value_callback)(uint32_t object_instance,
BACNET_XY_COLOR *old_value,
BACNET_XY_COLOR *value);
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
void Color_Property_Lists(
const int **pRequired, const int **pOptional, const int **pProprietary);
BACNET_STACK_EXPORT
bool Color_Valid_Instance(uint32_t object_instance);
BACNET_STACK_EXPORT
unsigned Color_Count(void);
BACNET_STACK_EXPORT
uint32_t Color_Index_To_Instance(unsigned index);
BACNET_STACK_EXPORT
unsigned Color_Instance_To_Index(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name);
BACNET_STACK_EXPORT
bool Color_Name_Set(uint32_t object_instance, char *new_name);
BACNET_STACK_EXPORT
int Color_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata);
BACNET_STACK_EXPORT
bool Color_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
bool Color_Present_Value_Set(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
bool Color_Present_Value(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
void Color_Write_Present_Value_Callback_Set(
color_write_present_value_callback cb);
BACNET_STACK_EXPORT
bool Color_Tracking_Value_Set(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
bool Color_Tracking_Value(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
bool Color_Command(uint32_t object_instance, BACNET_COLOR_COMMAND *value);
BACNET_STACK_EXPORT
bool Color_Command_Set(uint32_t object_instance, BACNET_COLOR_COMMAND *value);
BACNET_STACK_EXPORT
bool Color_Default_Color_Set(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
bool Color_Default_Color(uint32_t object_instance, BACNET_XY_COLOR *value);
BACNET_STACK_EXPORT
uint32_t Color_Default_Fade_Time(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Default_Fade_Time_Set(uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
BACNET_COLOR_OPERATION_IN_PROGRESS Color_In_Progress(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_In_Progress_Set(
uint32_t object_instance, BACNET_COLOR_OPERATION_IN_PROGRESS value);
BACNET_STACK_EXPORT
BACNET_COLOR_TRANSITION Color_Transition(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Transition_Set(
uint32_t object_instance, BACNET_COLOR_TRANSITION value);
BACNET_STACK_EXPORT
char *Color_Description(uint32_t instance);
BACNET_STACK_EXPORT
bool Color_Description_Set(uint32_t instance, char *new_name);
BACNET_STACK_EXPORT
bool Color_Write_Enabled(uint32_t instance);
BACNET_STACK_EXPORT
void Color_Write_Enable(uint32_t instance);
BACNET_STACK_EXPORT
void Color_Write_Disable(uint32_t instance);
BACNET_STACK_EXPORT
bool Color_Create(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Delete(uint32_t object_instance);
BACNET_STACK_EXPORT
void Color_Cleanup(void);
BACNET_STACK_EXPORT
void Color_Init(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
File diff suppressed because it is too large Load Diff
+165
View File
@@ -0,0 +1,165 @@
/**
* @file
* @author Steve Karg
* @date July 2022
* @brief Color Temperature object, customize for your use
*
* @section DESCRIPTION
*
* The Color Temperature object is an object with a present-value that
* uses an Color Temperature INTEGER type
*
* @section LICENSE
*
* Copyright (C) 2022 Steve Karg <skarg@users.sourceforge.net>
*
* SPDX-License-Identifier: MIT
*/
#ifndef BACNET_COLOR_TEMPERATURE_H
#define BACNET_COLOR_TEMPERATURE_H
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacenum.h"
#include "bacnet/bacerror.h"
#include "bacnet/rp.h"
#include "bacnet/wp.h"
/**
* @brief Callback for gateway write present value request
* @param object_instance - object-instance number of the object
* @param old_value - 32-bit value prior to write
* @param value - 32-bit value of the write
*/
typedef void (*color_temperature_write_present_value_callback)(
uint32_t object_instance, uint32_t old_value, uint32_t value);
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
void Color_Temperature_Property_Lists(
const int **pRequired, const int **pOptional, const int **pProprietary);
BACNET_STACK_EXPORT
bool Color_Temperature_Valid_Instance(uint32_t object_instance);
BACNET_STACK_EXPORT
unsigned Color_Temperature_Count(void);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Index_To_Instance(unsigned index);
BACNET_STACK_EXPORT
unsigned Color_Temperature_Instance_To_Index(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name);
BACNET_STACK_EXPORT
bool Color_Temperature_Name_Set(uint32_t object_instance, char *new_name);
BACNET_STACK_EXPORT
int Color_Temperature_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata);
BACNET_STACK_EXPORT
bool Color_Temperature_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data);
BACNET_STACK_EXPORT
bool Color_Temperature_Present_Value_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Present_Value(uint32_t object_instance);
BACNET_STACK_EXPORT
void Color_Temperature_Write_Present_Value_Callback_Set(
color_temperature_write_present_value_callback cb);
BACNET_STACK_EXPORT
bool Color_Temperature_Tracking_Value_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Tracking_Value(uint32_t object_instance);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Min_Pres_Value(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Min_Pres_Value_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Max_Pres_Value(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Max_Pres_Value_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
bool Color_Temperature_Command(
uint32_t object_instance, BACNET_COLOR_COMMAND *value);
BACNET_STACK_EXPORT
bool Color_Temperature_Command_Set(
uint32_t object_instance, BACNET_COLOR_COMMAND *value);
BACNET_STACK_EXPORT
bool Color_Temperature_Default_Color_Temperature_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Default_Color_Temperature(uint32_t object_instance);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Default_Fade_Time(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Default_Fade_Time_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Default_Ramp_Rate(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Default_Ramp_Rate_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
uint32_t Color_Temperature_Default_Step_Increment(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Default_Step_Increment_Set(
uint32_t object_instance, uint32_t value);
BACNET_STACK_EXPORT
BACNET_COLOR_OPERATION_IN_PROGRESS Color_Temperature_In_Progress(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_In_Progress_Set(
uint32_t object_instance, BACNET_COLOR_OPERATION_IN_PROGRESS value);
BACNET_STACK_EXPORT
BACNET_COLOR_TRANSITION Color_Temperature_Transition(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Transition_Set(
uint32_t object_instance, BACNET_COLOR_TRANSITION value);
BACNET_STACK_EXPORT
char *Color_Temperature_Description(uint32_t instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Description_Set(uint32_t instance, char *new_name);
BACNET_STACK_EXPORT
bool Color_Temperature_Write_Enabled(uint32_t instance);
BACNET_STACK_EXPORT
void Color_Temperature_Write_Enable(uint32_t instance);
BACNET_STACK_EXPORT
void Color_Temperature_Write_Disable(uint32_t instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Create(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Color_Temperature_Delete(uint32_t object_instance);
BACNET_STACK_EXPORT
void Color_Temperature_Cleanup(void);
BACNET_STACK_EXPORT
void Color_Temperature_Init(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+113 -18
View File
@@ -75,6 +75,10 @@
#if defined(BACFILE)
#include "bacnet/basic/object/bacfile.h"
#endif /* defined(BACFILE) */
#if (BACNET_PROTOCOL_REVISION >= 24)
#include "bacnet/basic/object/color_object.h"
#include "bacnet/basic/object/color_temperature.h"
#endif
/* local forward (semi-private) and external prototypes */
int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata);
@@ -223,6 +227,20 @@ static object_functions_t My_Object_Table[] = {
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */ },
#endif
#if (BACNET_PROTOCOL_REVISION >= 24)
{ OBJECT_COLOR, Color_Init, Color_Count,
Color_Index_To_Instance, Color_Valid_Instance,
Color_Object_Name, Color_Read_Property,
Color_Write_Property, Color_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */ },
{ OBJECT_COLOR_TEMPERATURE, Color_Temperature_Init, Color_Temperature_Count,
Color_Temperature_Index_To_Instance, Color_Temperature_Valid_Instance,
Color_Temperature_Object_Name, Color_Temperature_Read_Property,
Color_Temperature_Write_Property, Color_Temperature_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */,
NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */ },
#endif
#if defined(BACFILE)
{ OBJECT_FILE, bacfile_init, bacfile_count, bacfile_index_to_instance,
bacfile_valid_instance, bacfile_object_name, bacfile_read_property,
@@ -1312,6 +1330,91 @@ int Device_Read_Property_Local(BACNET_READ_PROPERTY_DATA *rpdata)
return apdu_len;
}
/** Looks up the common Object and Property, and encodes its Value in an
* APDU. Sets the error class and code if request is not appropriate.
* @param pObject - object table
* @param rpdata [in,out] Structure with the requested Object & Property info
* on entry, and APDU message on return.
* @return The length of the APDU on success, else BACNET_STATUS_ERROR
*/
static int Read_Property_Common(
struct object_functions *pObject, BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = BACNET_STATUS_ERROR;
BACNET_CHARACTER_STRING char_string;
uint8_t *apdu = NULL;
#if (BACNET_PROTOCOL_REVISION >= 14)
struct special_property_list_t property_list;
#endif
if ((rpdata->application_data == NULL) ||
(rpdata->application_data_len == 0)) {
return 0;
}
apdu = rpdata->application_data;
switch (rpdata->object_property) {
case PROP_OBJECT_IDENTIFIER:
/* only array properties can have array options */
if (rpdata->array_index != BACNET_ARRAY_ALL) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
} else {
/* Device Object exception: requested instance
may not match our instance if a wildcard */
if (rpdata->object_type == OBJECT_DEVICE) {
rpdata->object_instance = Object_Instance_Number;
}
apdu_len = encode_application_object_id(
&apdu[0], rpdata->object_type, rpdata->object_instance);
}
break;
case PROP_OBJECT_NAME:
/* only array properties can have array options */
if (rpdata->array_index != BACNET_ARRAY_ALL) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
} else {
characterstring_init_ansi(&char_string, "");
if (pObject->Object_Name) {
(void)pObject->Object_Name(
rpdata->object_instance, &char_string);
}
apdu_len =
encode_application_character_string(&apdu[0], &char_string);
}
break;
case PROP_OBJECT_TYPE:
/* only array properties can have array options */
if (rpdata->array_index != BACNET_ARRAY_ALL) {
rpdata->error_class = ERROR_CLASS_PROPERTY;
rpdata->error_code = ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY;
apdu_len = BACNET_STATUS_ERROR;
} else {
apdu_len = encode_application_enumerated(
&apdu[0], rpdata->object_type);
}
break;
#if (BACNET_PROTOCOL_REVISION >= 14)
case PROP_PROPERTY_LIST:
Device_Objects_Property_List(
rpdata->object_type, rpdata->object_instance, &property_list);
apdu_len = property_list_encode(rpdata,
property_list.Required.pList, property_list.Optional.pList,
property_list.Proprietary.pList);
break;
#endif
default:
if (pObject->Object_Read_Property) {
apdu_len = pObject->Object_Read_Property(rpdata);
}
break;
}
return apdu_len;
}
/** Looks up the requested Object and Property, and encodes its Value in an
* APDU.
* @ingroup ObjIntf
@@ -1325,9 +1428,6 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
{
int apdu_len = BACNET_STATUS_ERROR;
struct object_functions *pObject = NULL;
#if (BACNET_PROTOCOL_REVISION >= 14)
struct special_property_list_t property_list;
#endif
/* initialize the default return values */
rpdata->error_class = ERROR_CLASS_OBJECT;
@@ -1336,22 +1436,14 @@ int Device_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata)
if (pObject != NULL) {
if (pObject->Object_Valid_Instance &&
pObject->Object_Valid_Instance(rpdata->object_instance)) {
if (pObject->Object_Read_Property) {
#if (BACNET_PROTOCOL_REVISION >= 14)
if ((int)rpdata->object_property == PROP_PROPERTY_LIST) {
Device_Objects_Property_List(rpdata->object_type,
rpdata->object_instance, &property_list);
apdu_len = property_list_encode(rpdata,
property_list.Required.pList,
property_list.Optional.pList,
property_list.Proprietary.pList);
} else
#endif
{
apdu_len = pObject->Object_Read_Property(rpdata);
}
}
apdu_len = Read_Property_Common(pObject, rpdata);
} else {
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
} else {
rpdata->error_class = ERROR_CLASS_OBJECT;
rpdata->error_code = ERROR_CODE_UNKNOWN_OBJECT;
}
return apdu_len;
@@ -1816,6 +1908,9 @@ void Device_Init(object_functions_t *object_table)
}
pObject++;
}
#if (BACNET_PROTOCOL_REVISION >= 24)
Color_Create(1);
#endif
}
bool DeviceGetRRInfo(BACNET_READ_RANGE_DATA *pRequest, /* Info on the request */