Feature/add bacnet binary lighting object (#522)

* Added Binary Lighting Output object example.

* Changed piface example app to support binary-lighting-output object type and blink warn

* Changed example device object to not create objects when device object-table is overridden

* Fixed unit testing for device object
This commit is contained in:
Steve Karg
2024-01-29 09:41:40 -06:00
committed by GitHub
parent 34b1d24bb7
commit 6cb875aae6
20 changed files with 2342 additions and 91 deletions
+2
View File
@@ -188,6 +188,8 @@ add_library(${PROJECT_NAME}
src/bacnet/basic/object/bacfile.h src/bacnet/basic/object/bacfile.h
src/bacnet/basic/object/bi.c src/bacnet/basic/object/bi.c
src/bacnet/basic/object/bi.h src/bacnet/basic/object/bi.h
src/bacnet/basic/object/blo.c
src/bacnet/basic/object/blo.h
src/bacnet/basic/object/bo.c src/bacnet/basic/object/bo.c
src/bacnet/basic/object/bo.h src/bacnet/basic/object/bo.h
src/bacnet/basic/object/bv.c src/bacnet/basic/object/bv.c
+1 -4
View File
@@ -118,9 +118,6 @@ static void Init_Service_Handlers(void)
/* handle communication so we can shutup when asked */ /* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control); handler_device_communication_control);
/* handle the data coming back from private requests */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_PRIVATE_TRANSFER,
handler_unconfirmed_private_transfer);
/* configure the cyclic timers */ /* configure the cyclic timers */
mstimer_set(&BACnet_Task_Timer, 1000UL); mstimer_set(&BACnet_Task_Timer, 1000UL);
mstimer_set(&BACnet_TSM_Timer, 50UL); mstimer_set(&BACnet_TSM_Timer, 50UL);
@@ -297,7 +294,7 @@ static void bacnet_output_init(void)
Channel_Reference_List_Member_Element_Set( Channel_Reference_List_Member_Element_Set(
light_channel_instance, 1 + i, &member); light_channel_instance, 1 + i, &member);
object_instance++; object_instance = 1 + i;
} }
Color_Write_Present_Value_Callback_Set(Color_Write_Value_Handler); Color_Write_Present_Value_Callback_Set(Color_Write_Value_Handler);
Color_Temperature_Write_Present_Value_Callback_Set( Color_Temperature_Write_Present_Value_Callback_Set(
+1
View File
@@ -15,6 +15,7 @@ BACNET_OBJECT_SRC := \
$(BACNET_OBJECT_DIR)/ao.c \ $(BACNET_OBJECT_DIR)/ao.c \
$(BACNET_OBJECT_DIR)/av.c \ $(BACNET_OBJECT_DIR)/av.c \
$(BACNET_OBJECT_DIR)/bi.c \ $(BACNET_OBJECT_DIR)/bi.c \
$(BACNET_OBJECT_DIR)/blo.c \
$(BACNET_OBJECT_DIR)/bo.c \ $(BACNET_OBJECT_DIR)/bo.c \
$(BACNET_OBJECT_DIR)/bv.c \ $(BACNET_OBJECT_DIR)/bv.c \
$(BACNET_OBJECT_DIR)/channel.c \ $(BACNET_OBJECT_DIR)/channel.c \
+1
View File
@@ -10,6 +10,7 @@ SRC = main.c \
device.c \ device.c \
$(BACNET_OBJECT_DIR)/netport.c \ $(BACNET_OBJECT_DIR)/netport.c \
$(BACNET_OBJECT_DIR)/bi.c \ $(BACNET_OBJECT_DIR)/bi.c \
$(BACNET_OBJECT_DIR)/blo.c \
$(BACNET_OBJECT_DIR)/bo.c $(BACNET_OBJECT_DIR)/bo.c
CFLAGS += -DMAX_TSM_TRANSACTIONS=1 CFLAGS += -DMAX_TSM_TRANSACTIONS=1
+40
View File
@@ -47,6 +47,7 @@
/* include the OS specific */ /* include the OS specific */
#include "bacnet/basic/object/device.h" #include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/bi.h" #include "bacnet/basic/object/bi.h"
#include "bacnet/basic/object/blo.h"
#include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bo.h"
#if (BACNET_PROTOCOL_REVISION >= 17) #if (BACNET_PROTOCOL_REVISION >= 17)
#include "bacnet/basic/object/netport.h" #include "bacnet/basic/object/netport.h"
@@ -88,6 +89,18 @@ static object_functions_t My_Object_Table[] = {
Binary_Input_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */, Binary_Input_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
NULL /* Create */, NULL /* Delete */, NULL /* Timer */ }, NULL /* Create */, NULL /* Delete */, NULL /* Timer */ },
{ OBJECT_BINARY_LIGHTING_OUTPUT, Binary_Lighting_Output_Init,
Binary_Lighting_Output_Count, Binary_Lighting_Output_Index_To_Instance,
Binary_Lighting_Output_Valid_Instance,
Binary_Lighting_Output_Object_Name,
Binary_Lighting_Output_Read_Property,
Binary_Lighting_Output_Write_Property,
Binary_Lighting_Output_Property_Lists, NULL /* ReadRangeInfo */,
NULL /* Iterator */, NULL /* Value_Lists */, NULL /* COV */,
NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Binary_Lighting_Output_Create, Binary_Lighting_Output_Delete,
Binary_Lighting_Output_Timer },
{ OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count, { OBJECT_BINARY_OUTPUT, Binary_Output_Init, Binary_Output_Count,
Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance, Binary_Output_Index_To_Instance, Binary_Output_Valid_Instance,
Binary_Output_Object_Name, Binary_Output_Read_Property, Binary_Output_Object_Name, Binary_Output_Read_Property,
@@ -1979,3 +1992,30 @@ bool DeviceGetRRInfo(BACNET_READ_RANGE_DATA *pRequest, /* Info on the request */
return status; return status;
} }
/**
* @brief Updates all the object timers with elapsed milliseconds
* @param milliseconds - number of milliseconds elapsed
*/
void Device_Timer(uint16_t milliseconds)
{
struct object_functions *pObject;
unsigned count = 0;
uint32_t instance;
pObject = Object_Table;
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
if (pObject->Object_Count) {
count = pObject->Object_Count();
}
while (count) {
count--;
if ((pObject->Object_Timer) &&
(pObject->Object_Index_To_Instance)) {
instance = pObject->Object_Index_To_Instance(count);
pObject->Object_Timer(instance, milliseconds);
}
}
pObject++;
}
}
+150 -67
View File
@@ -1,33 +1,17 @@
/************************************************************************** /**
* @file
* @brief
* @author Steve Karg <skarg@users.sourceforge.net>
* @date January 2023
* *
* Copyright (C) 2006 Steve Karg <skarg@users.sourceforge.net> * SPDX-License-Identifier: MIT
* *
* Permission is hereby granted, free of charge, to any person obtaining */
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <time.h>
#include "bacnet/config.h" #include "bacnet/config.h"
#include "bacnet/basic/binding/address.h" #include "bacnet/basic/binding/address.h"
@@ -39,40 +23,117 @@
#include "bacnet/npdu.h" #include "bacnet/npdu.h"
#include "bacnet/apdu.h" #include "bacnet/apdu.h"
#include "bacnet/iam.h" #include "bacnet/iam.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/basic/object/device.h" #include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/bacfile.h" #include "bacnet/basic/object/bacfile.h"
#include "bacnet/datalink/datalink.h" #include "bacnet/datalink/datalink.h"
#include "bacnet/dcc.h" #include "bacnet/dcc.h"
#include "bacnet/getevent.h" #include "bacnet/getevent.h"
#include "bacport.h" #include "bacport.h"
#include "bacnet/basic/tsm/tsm.h" #include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/tsm/tsm.h" #include "bacnet/basic/tsm/tsm.h"
#include "bacnet/version.h" #include "bacnet/version.h"
/* include the device object */ /* include the device object */
#include "bacnet/basic/object/device.h" #include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/bi.h" #include "bacnet/basic/object/bi.h"
#include "bacnet/basic/object/blo.h"
#include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bo.h"
#include "pifacedigital.h" #include "pifacedigital.h"
/** @file server/main.c Example server application using the BACnet Stack. */ /** @file server/main.c Example server application using the BACnet Stack. */
/* (Doxygen note: The next two lines pull all the following Javadoc /* number of binary outputs on the PiFace card */
* into the ServerDemo module.) */ #define PIFACE_OUTPUTS_MAX 8
/** @addtogroup ServerDemo */
/*@{*/
/** Buffer used for receiving */ /** Buffer used for receiving */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 }; static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* current version of the BACnet stack */ /* current version of the BACnet stack */
static const char *BACnet_Version = BACNET_VERSION_TEXT; static const char *BACnet_Version = BACNET_VERSION_TEXT;
/* task timer for various BACnet timeouts */
static struct mstimer BACnet_Task_Timer;
/* task timer for TSM timeouts */
static struct mstimer BACnet_TSM_Timer;
/* task timer for address binding timeouts */
static struct mstimer BACnet_Address_Timer;
/* task timer for object functionality */
static struct mstimer BACnet_Object_Timer;
/* track the state of of the output */
static bool PiFace_Output_State[PIFACE_OUTPUTS_MAX];
/**
* @brief output write value request
* @param index - 0..N index of the output
* @param value - value of the write ON or OFF
*/
static void piface_write_output(int index, BACNET_BINARY_LIGHTING_PV value)
{
if (index < PIFACE_OUTPUTS_MAX) {
if (value == BINARY_LIGHTING_PV_OFF) {
pifacedigital_digital_write(index, 0);
PiFace_Output_State[index] = false;
printf("OUTPUT[%u]=OFF\n", index);
} else if (value == BINARY_LIGHTING_PV_ON) {
pifacedigital_digital_write(index, 1);
PiFace_Output_State[index] = true;
printf("OUTPUT[%u]=ON\n", index);
}
}
}
/**
* @brief Callback for write value request
* @param object_instance - object-instance number of the object
* @param old_value - value prior to write
* @param value - value of the write
*/
static void Binary_Lighting_Output_Write_Value_Handler(uint32_t object_instance,
BACNET_BINARY_LIGHTING_PV old_value,
BACNET_BINARY_LIGHTING_PV value)
{
unsigned index;
index = Binary_Lighting_Output_Instance_To_Index(object_instance);
if (index < PIFACE_OUTPUTS_MAX) {
printf("BLO-WRITE: OUTPUT[%u]=%d present=%d feedback=%d target=%d\n",
index, (int)value,
(int)Binary_Lighting_Output_Present_Value(object_instance),
(int)old_value,
(int)Binary_Lighting_Output_Lighting_Command_Target_Value(
object_instance));
piface_write_output(index, value);
}
}
/**
* @brief Callback for blink warning notification
* @param object_instance - object-instance number of the object
*/
static void Binary_Lighting_Output_Blink_Warn_Handler(uint32_t object_instance)
{
unsigned index;
index = Binary_Lighting_Output_Instance_To_Index(object_instance);
if (index < PIFACE_OUTPUTS_MAX) {
/* blink is just toggle on/off every one second */
if (PiFace_Output_State[index]) {
printf("BLO-BLINK: OUTPUT[%u]=%d\n", index,
BINARY_LIGHTING_PV_OFF);
piface_write_output(index, BINARY_LIGHTING_PV_OFF);
} else {
printf(
"BLO-BLINK: OUTPUT[%u]=%d\n", index, BINARY_LIGHTING_PV_ON);
piface_write_output(index, BINARY_LIGHTING_PV_ON);
}
}
}
/** Initialize the handlers we will utilize. /** Initialize the handlers we will utilize.
* @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler * @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler
*/ */
static void Init_Service_Handlers(void) static void Init_Service_Handlers(void)
{ {
uint32_t i = 0;
uint32_t object_instance;
Device_Init(NULL); Device_Init(NULL);
/* we need to handle who-is to support dynamic device binding */ /* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
@@ -107,9 +168,21 @@ static void Init_Service_Handlers(void)
/* handle communication so we can shutup when asked */ /* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, apdu_set_confirmed_handler(SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control); handler_device_communication_control);
/* handle the data coming back from private requests */ /* configure the cyclic timers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_PRIVATE_TRANSFER, mstimer_set(&BACnet_Task_Timer, 1000UL);
handler_unconfirmed_private_transfer); mstimer_set(&BACnet_TSM_Timer, 50UL);
mstimer_set(&BACnet_Address_Timer, 60UL * 1000UL);
mstimer_set(&BACnet_Object_Timer, 1000UL);
/* create some objects */
for (i = 0; i < PIFACE_OUTPUTS_MAX; i++) {
object_instance = 1 + i;
Binary_Lighting_Output_Create(object_instance);
Binary_Output_Create(object_instance);
}
Binary_Lighting_Output_Write_Value_Callback_Set(
Binary_Lighting_Output_Write_Value_Handler);
Binary_Lighting_Output_Blink_Warn_Callback_Set(
Binary_Lighting_Output_Blink_Warn_Handler);
} }
static void piface_init(void) static void piface_init(void)
@@ -159,6 +232,7 @@ static void piface_task(void)
unsigned i = 0; unsigned i = 0;
BACNET_BINARY_PV present_value = BINARY_INACTIVE; BACNET_BINARY_PV present_value = BINARY_INACTIVE;
bool pin_status = false; bool pin_status = false;
uint32_t object_instance;
for (i = 0; i < MAX_BINARY_INPUTS; i++) { for (i = 0; i < MAX_BINARY_INPUTS; i++) {
if (!Binary_Input_Out_Of_Service(i)) { if (!Binary_Input_Out_Of_Service(i)) {
@@ -181,13 +255,24 @@ static void piface_task(void)
} }
} }
} }
for (i = 0; i < MAX_BINARY_OUTPUTS; i++) { for (i = 0; i < PIFACE_OUTPUTS_MAX; i++) {
if (!Binary_Output_Out_Of_Service(i)) { object_instance = Binary_Output_Index_To_Instance(i);
present_value = Binary_Output_Present_Value(i); if (Binary_Output_Valid_Instance(object_instance)) {
if (present_value == BINARY_INACTIVE) { if (!Binary_Output_Out_Of_Service(object_instance)) {
pifacedigital_digital_write(i, 0); present_value = Binary_Output_Present_Value(object_instance);
} else { if (present_value == BINARY_INACTIVE) {
pifacedigital_digital_write(i, 1); if (PiFace_Output_State[i]) {
printf("BO-WRITE: OUTPUT[%u]=%d\n", i,
BINARY_LIGHTING_PV_OFF);
piface_write_output(i, BINARY_LIGHTING_PV_OFF);
}
} else {
if (!PiFace_Output_State[i]) {
printf("BO-WRITE: OUTPUT[%u]=%d\n", i,
BINARY_LIGHTING_PV_OFF);
piface_write_output(i, BINARY_LIGHTING_PV_ON);
}
}
} }
} }
} }
@@ -209,12 +294,9 @@ int main(int argc, char *argv[])
{ {
BACNET_ADDRESS src = { 0 }; /* address where message came from */ BACNET_ADDRESS src = { 0 }; /* address where message came from */
uint16_t pdu_len = 0; uint16_t pdu_len = 0;
unsigned timeout = 1; /* milliseconds */ unsigned timeout_ms = 1; /* milliseconds */
time_t last_seconds = 0; unsigned long seconds = 0;
time_t current_seconds = 0; unsigned long milliseconds;
uint32_t elapsed_seconds = 0;
uint32_t elapsed_milliseconds = 0;
uint32_t address_binding_tmr = 0;
/* allow the device ID to be set */ /* allow the device ID to be set */
if (argc > 1) { if (argc > 1) {
@@ -233,41 +315,42 @@ int main(int argc, char *argv[])
atexit(datalink_cleanup); atexit(datalink_cleanup);
piface_init(); piface_init();
atexit(piface_cleanup); atexit(piface_cleanup);
/* configure the timeout values */
last_seconds = time(NULL);
/* broadcast an I-Am on startup */ /* broadcast an I-Am on startup */
Send_I_Am(&Handler_Transmit_Buffer[0]); Send_I_Am(&Handler_Transmit_Buffer[0]);
/* loop forever */ /* loop forever */
for (;;) { for (;;) {
/* input */ /* input */
current_seconds = time(NULL);
/* returns 0 bytes on timeout */ /* returns 0 bytes on timeout */
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout_ms);
/* process */ /* process */
if (pdu_len) { if (pdu_len) {
npdu_handler(&src, &Rx_Buf[0], pdu_len); npdu_handler(&src, &Rx_Buf[0], pdu_len);
} }
/* at least one second has passed */ if (mstimer_expired(&BACnet_Task_Timer)) {
elapsed_seconds = (uint32_t)(current_seconds - last_seconds); mstimer_reset(&BACnet_Task_Timer);
if (elapsed_seconds) { /* 1 second tasks */
last_seconds = current_seconds; dcc_timer_seconds(1);
dcc_timer_seconds(elapsed_seconds); datalink_maintenance_timer(1);
datalink_maintenance_timer(elapsed_seconds); dlenv_maintenance_timer(1);
dlenv_maintenance_timer(elapsed_seconds); handler_cov_timer_seconds(1);
elapsed_milliseconds = elapsed_seconds * 1000; }
handler_cov_timer_seconds(elapsed_seconds); if (mstimer_expired(&BACnet_TSM_Timer)) {
tsm_timer_milliseconds(elapsed_milliseconds); mstimer_reset(&BACnet_TSM_Timer);
tsm_timer_milliseconds(mstimer_interval(&BACnet_TSM_Timer));
} }
handler_cov_task(); handler_cov_task();
/* scan cache address */ if (mstimer_expired(&BACnet_Address_Timer)) {
address_binding_tmr += elapsed_seconds; mstimer_reset(&BACnet_Address_Timer);
if (address_binding_tmr >= 60) { /* address cache */
address_cache_timer(address_binding_tmr); seconds = mstimer_interval(&BACnet_Address_Timer) / 1000;
address_binding_tmr = 0; address_cache_timer(seconds);
} }
/* output/input */ /* output/input */
if (mstimer_expired(&BACnet_Object_Timer)) {
mstimer_reset(&BACnet_Object_Timer);
milliseconds = mstimer_interval(&BACnet_Object_Timer);
Device_Timer(milliseconds);
}
piface_task(); piface_task();
} }
+1
View File
@@ -11,6 +11,7 @@ SRC = main.c \
$(BACNET_OBJECT_DIR)/av.c \ $(BACNET_OBJECT_DIR)/av.c \
$(BACNET_OBJECT_DIR)/bi.c \ $(BACNET_OBJECT_DIR)/bi.c \
$(BACNET_OBJECT_DIR)/bo.c \ $(BACNET_OBJECT_DIR)/bo.c \
$(BACNET_OBJECT_DIR)/blo.c \
$(BACNET_OBJECT_DIR)/bv.c \ $(BACNET_OBJECT_DIR)/bv.c \
$(BACNET_OBJECT_DIR)/channel.c \ $(BACNET_OBJECT_DIR)/channel.c \
$(BACNET_OBJECT_DIR)/color_object.c \ $(BACNET_OBJECT_DIR)/color_object.c \
+17 -7
View File
@@ -2206,13 +2206,23 @@ int bacapp_snprintf_value(
break; break;
case PROP_PRESENT_VALUE: case PROP_PRESENT_VALUE:
case PROP_RELINQUISH_DEFAULT: case PROP_RELINQUISH_DEFAULT:
if (object_type < OBJECT_PROPRIETARY_MIN) { switch (object_type) {
ret_val = snprintf(str, str_len, "%s", case OBJECT_BINARY_INPUT:
bactext_binary_present_value_name( case OBJECT_BINARY_OUTPUT:
value->type.Enumerated)); case OBJECT_BINARY_VALUE:
} else { ret_val = snprintf(str, str_len, "%s",
ret_val = snprintf(str, str_len, "%lu", bactext_binary_present_value_name(
(unsigned long)value->type.Enumerated); value->type.Enumerated));
break;
case OBJECT_BINARY_LIGHTING_OUTPUT:
ret_val = snprintf(str, str_len, "%s",
bactext_binary_lighting_pv_name(
value->type.Enumerated));
break;
default:
ret_val = snprintf(str, str_len, "%lu",
(unsigned long)value->type.Enumerated);
break;
} }
break; break;
case PROP_RELIABILITY: case PROP_RELIABILITY:
+2 -1
View File
@@ -1079,7 +1079,7 @@ typedef enum {
PROP_STATE_EXAMPLE_TWO = 257 PROP_STATE_EXAMPLE_TWO = 257
} BACNET_PROPERTY_STATES; } BACNET_PROPERTY_STATES;
typedef enum { typedef enum BACnetReliability {
RELIABILITY_NO_FAULT_DETECTED = 0, RELIABILITY_NO_FAULT_DETECTED = 0,
RELIABILITY_NO_SENSOR = 1, RELIABILITY_NO_SENSOR = 1,
RELIABILITY_OVER_RANGE = 2, RELIABILITY_OVER_RANGE = 2,
@@ -2106,6 +2106,7 @@ typedef enum BACnetBinaryLightingPV {
BINARY_LIGHTING_PV_WARN_OFF = 3, BINARY_LIGHTING_PV_WARN_OFF = 3,
BINARY_LIGHTING_PV_WARN_RELINQUISH = 4, BINARY_LIGHTING_PV_WARN_RELINQUISH = 4,
BINARY_LIGHTING_PV_STOP = 5, BINARY_LIGHTING_PV_STOP = 5,
BINARY_LIGHTING_PV_MAX = 6,
/* -- Enumerated values 0-63 are reserved for definition by ASHRAE. /* -- Enumerated values 0-63 are reserved for definition by ASHRAE.
-- Enumerated values 64-255 may be used by others -- Enumerated values 64-255 may be used by others
-- subject to the procedures and constraints described in Clause 23. */ -- subject to the procedures and constraints described in Clause 23. */
+30 -1
View File
@@ -1750,12 +1750,41 @@ const char *bactext_lighting_operation_name(unsigned index)
} }
} }
bool bactext_bactext_lighting_operation_strtol(const char *search_name, unsigned *found_index) bool bactext_lighting_operation_strtol(const char *search_name, unsigned *found_index)
{ {
return bactext_strtol_index( return bactext_strtol_index(
bacnet_lighting_operation_names, search_name, found_index); bacnet_lighting_operation_names, search_name, found_index);
} }
INDTEXT_DATA bacnet_binary_lighting_pv_names[] = {
{ BINARY_LIGHTING_PV_OFF, "off" },
{ BINARY_LIGHTING_PV_ON, "on" },
{ BINARY_LIGHTING_PV_WARN, "warn" },
{ BINARY_LIGHTING_PV_WARN_OFF, "warn-off" },
{ BINARY_LIGHTING_PV_WARN_RELINQUISH, "warn-relinquish" },
{ BINARY_LIGHTING_PV_STOP, "stop" },
{ 0, NULL }
};
const char *bactext_binary_lighting_pv_name(unsigned index)
{
if (index < BINARY_LIGHTING_PV_PROPRIETARY_MIN) {
return indtext_by_index_default(
bacnet_binary_lighting_pv_names, index, ASHRAE_Reserved_String);
} else if (index <= BINARY_LIGHTING_PV_PROPRIETARY_MAX) {
return Vendor_Proprietary_String;
} else {
return "Invalid BACnetBinaryLightingPV";
}
}
bool bactext_binary_lighting_pv_names_strtol(const char *search_name,
unsigned *found_index)
{
return bactext_strtol_index(
bacnet_binary_lighting_pv_names, search_name, found_index);
}
INDTEXT_DATA bacnet_color_operation_names[] = { { BACNET_COLOR_OPERATION_NONE, INDTEXT_DATA bacnet_color_operation_names[] = { { BACNET_COLOR_OPERATION_NONE,
"none" }, "none" },
{ BACNET_COLOR_OPERATION_FADE_TO_COLOR, "fade-to-color" }, { BACNET_COLOR_OPERATION_FADE_TO_COLOR, "fade-to-color" },
+10 -1
View File
@@ -201,7 +201,16 @@ extern "C" {
unsigned index); unsigned index);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool bactext_bactext_lighting_operation_strtol( bool bactext_lighting_operation_strtol(
const char *search_name,
unsigned *found_index);
BACNET_STACK_EXPORT
const char *bactext_binary_lighting_pv_name(
unsigned index);
BACNET_STACK_EXPORT
bool bactext_binary_lighting_pv_names_strtol(
const char *search_name, const char *search_name,
unsigned *found_index); unsigned *found_index);
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
/**
* @file
* @author Steve Karg
* @date 2023
* @brief Binary Lighting Output object
*
* SPDX-License-Identifier: MIT
*/
#ifndef BINARY_LIGHTING_OUTPUT_H
#define BINARY_LIGHTING_OUTPUT_H
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/bacnet_stack_exports.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacerror.h"
#include "bacnet/rp.h"
#include "bacnet/wp.h"
/**
* @brief Callback for write value request
* @param object_instance - object-instance number of the object
* @param old_value - value prior to write
* @param value - value of the write
*/
typedef void (*binary_lighting_output_write_value_callback)(
uint32_t object_instance,
BACNET_BINARY_LIGHTING_PV old_value,
BACNET_BINARY_LIGHTING_PV value);
/**
* @brief Callback for blink warning notification
* @param object_instance - object-instance number of the object
*/
typedef void (*binary_lighting_output_blink_warn_callback)(
uint32_t object_instance);
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Property_Lists(
const int **pRequired, const int **pOptional, const int **pProprietary);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Valid_Instance(uint32_t object_instance);
BACNET_STACK_EXPORT
unsigned Binary_Lighting_Output_Count(void);
BACNET_STACK_EXPORT
uint32_t Binary_Lighting_Output_Index_To_Instance(unsigned index);
BACNET_STACK_EXPORT
unsigned Binary_Lighting_Output_Instance_To_Index(uint32_t instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Object_Instance_Add(uint32_t instance);
BACNET_STACK_EXPORT
BACNET_BINARY_LIGHTING_PV Binary_Lighting_Output_Present_Value(
uint32_t object_instance);
BACNET_STACK_EXPORT
unsigned Binary_Lighting_Output_Present_Value_Priority(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Present_Value_Set(uint32_t object_instance,
BACNET_BINARY_LIGHTING_PV value,
unsigned priority);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Present_Value_Relinquish(
uint32_t object_instance, unsigned priority);
BACNET_STACK_EXPORT
BACNET_BINARY_LIGHTING_PV Binary_Lighting_Output_Relinquish_Default(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Relinquish_Default_Set(
uint32_t object_instance, BACNET_BINARY_LIGHTING_PV value);
BACNET_STACK_EXPORT
BACNET_RELIABILITY Binary_Lighting_Output_Reliability(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Reliability_Set(
uint32_t object_instance, BACNET_RELIABILITY value);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Object_Name(
uint32_t object_instance, BACNET_CHARACTER_STRING *object_name);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Name_Set(uint32_t object_instance, char *new_name);
BACNET_STACK_EXPORT
char *Binary_Lighting_Output_Description(uint32_t instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Description_Set(uint32_t instance, char *new_name);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Out_Of_Service(uint32_t instance);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Out_Of_Service_Set(
uint32_t instance, bool oos_flag);
BACNET_STACK_EXPORT
BACNET_BINARY_LIGHTING_PV Binary_Lighting_Output_Lighting_Command_Target_Value(
uint32_t object_instance);
BACNET_STACK_EXPORT
unsigned Binary_Lighting_Output_Lighting_Command_Target_Priority(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Lighting_Command_Set(
uint32_t object_instance, BACNET_BINARY_LIGHTING_PV value, unsigned priority);
BACNET_STACK_EXPORT
BACNET_BINARY_LIGHTING_PV Binary_Lighting_Output_Feedback_Value(
uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Feedback_Value_Set(
uint32_t object_instance, BACNET_BINARY_LIGHTING_PV value);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Blink_Warn_Enable(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Blink_Warn_Enable_Set(
uint32_t object_instance, bool enable);
BACNET_STACK_EXPORT
uint32_t Binary_Lighting_Output_Egress_Time(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Egress_Time_Set(
uint32_t object_instance, uint32_t seconds);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Egress_Active(uint32_t object_instance);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Timer(
uint32_t object_instance, uint16_t milliseconds);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Write_Value_Callback_Set(
binary_lighting_output_write_value_callback cb);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Blink_Warn_Callback_Set(
binary_lighting_output_blink_warn_callback cb);
BACNET_STACK_EXPORT
uint32_t Binary_Lighting_Output_Create(uint32_t object_instance);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Delete(uint32_t object_instance);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Cleanup(void);
BACNET_STACK_EXPORT
void Binary_Lighting_Output_Init(void);
BACNET_STACK_EXPORT
int Binary_Lighting_Output_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata);
BACNET_STACK_EXPORT
bool Binary_Lighting_Output_Write_Property(BACNET_WRITE_PROPERTY_DATA *wp_data);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
+24 -5
View File
@@ -51,6 +51,9 @@
#include "bacnet/basic/object/ao.h" #include "bacnet/basic/object/ao.h"
#include "bacnet/basic/object/av.h" #include "bacnet/basic/object/av.h"
#include "bacnet/basic/object/bi.h" #include "bacnet/basic/object/bi.h"
#if (BACNET_PROTOCOL_REVISION >= 16)
#include "bacnet/basic/object/blo.h"
#endif
#include "bacnet/basic/object/bo.h" #include "bacnet/basic/object/bo.h"
#include "bacnet/basic/object/bv.h" #include "bacnet/basic/object/bv.h"
#include "bacnet/basic/object/channel.h" #include "bacnet/basic/object/channel.h"
@@ -267,6 +270,20 @@ static object_functions_t My_Object_Table[] = {
NULL /* Add_List_Element */, NULL /* Remove_List_Element */, NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Channel_Create, Channel_Delete, NULL /* Timer */ }, Channel_Create, Channel_Delete, NULL /* Timer */ },
#endif #endif
#if (BACNET_PROTOCOL_REVISION >= 16)
{ OBJECT_BINARY_LIGHTING_OUTPUT, Binary_Lighting_Output_Init,
Binary_Lighting_Output_Count, Binary_Lighting_Output_Index_To_Instance,
Binary_Lighting_Output_Valid_Instance,
Binary_Lighting_Output_Object_Name,
Binary_Lighting_Output_Read_Property,
Binary_Lighting_Output_Write_Property,
Binary_Lighting_Output_Property_Lists, NULL /* ReadRangeInfo */,
NULL /* Iterator */, NULL /* Value_Lists */, NULL /* COV */,
NULL /* COV Clear */, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Binary_Lighting_Output_Create, Binary_Lighting_Output_Delete,
Binary_Lighting_Output_Timer },
#endif
#if (BACNET_PROTOCOL_REVISION >= 24) #if (BACNET_PROTOCOL_REVISION >= 24)
{ OBJECT_COLOR, Color_Init, Color_Count, Color_Index_To_Instance, { OBJECT_COLOR, Color_Init, Color_Count, Color_Index_To_Instance,
Color_Valid_Instance, Color_Object_Name, Color_Read_Property, Color_Valid_Instance, Color_Object_Name, Color_Read_Property,
@@ -2201,12 +2218,14 @@ void Device_Init(object_functions_t *object_table)
pObject++; pObject++;
} }
/* create some dynamically created objects as examples */ /* create some dynamically created objects as examples */
pObject = Object_Table; if (!object_table) {
while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) { pObject = Object_Table;
if (pObject->Object_Create) { while (pObject->Object_Type < MAX_BACNET_OBJECT_TYPE) {
pObject->Object_Create(BACNET_MAX_INSTANCE); if (pObject->Object_Create) {
pObject->Object_Create(BACNET_MAX_INSTANCE);
}
pObject++;
} }
pObject++;
} }
#if (BACNET_PROTOCOL_REVISION >= 14) #if (BACNET_PROTOCOL_REVISION >= 14)
Channel_Write_Property_Internal_Callback_Set(Device_Write_Property); Channel_Write_Property_Internal_Callback_Set(Device_Write_Property);
-4
View File
@@ -48,10 +48,6 @@
/* me! */ /* me! */
#include "bacnet/basic/object/lo.h" #include "bacnet/basic/object/lo.h"
#ifndef MAX_LIGHTING_OUTPUTS
#define MAX_LIGHTING_OUTPUTS 8
#endif
struct object_data { struct object_data {
float Present_Value; float Present_Value;
float Tracking_Value; float Tracking_Value;
+1 -1
View File
@@ -25,7 +25,7 @@
#define KEYLIST_H #define KEYLIST_H
#include "bacnet/bacnet_stack_exports.h" #include "bacnet/bacnet_stack_exports.h"
#include "key.h" #include "bacnet/basic/sys/key.h"
/* This is a key sorted linked list data library that */ /* This is a key sorted linked list data library that */
/* uses a key or index to access the data. */ /* uses a key or index to access the data. */
+1
View File
@@ -113,6 +113,7 @@ list(APPEND testdirs
bacnet/basic/object/av bacnet/basic/object/av
bacnet/basic/object/bacfile bacnet/basic/object/bacfile
bacnet/basic/object/bi bacnet/basic/object/bi
bacnet/basic/object/blo
bacnet/basic/object/bo bacnet/basic/object/bo
bacnet/basic/object/bv bacnet/basic/object/bv
bacnet/basic/object/channel bacnet/basic/object/channel
@@ -0,0 +1,68 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(test_${basename}
VERSION 1.0.0
LANGUAGES C)
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/src"
SRC_DIR
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/test/bacnet/[a-zA-Z_/-]*$"
"/test"
TST_DIR
${CMAKE_CURRENT_SOURCE_DIR})
set(ZTST_DIR "${TST_DIR}/ztest/src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
# File(s) under test
${SRC_DIR}/bacnet/basic/object/blo.c
# Support files and stubs (pathname alphabetical)
${SRC_DIR}/bacnet/bacaddr.c
${SRC_DIR}/bacnet/bacapp.c
${SRC_DIR}/bacnet/bacdcode.c
${SRC_DIR}/bacnet/bacdest.c
${SRC_DIR}/bacnet/bacdevobjpropref.c
${SRC_DIR}/bacnet/bacerror.c
${SRC_DIR}/bacnet/bacint.c
${SRC_DIR}/bacnet/bacreal.c
${SRC_DIR}/bacnet/bacstr.c
${SRC_DIR}/bacnet/bactext.c
${SRC_DIR}/bacnet/basic/sys/bigend.c
${SRC_DIR}/bacnet/basic/sys/days.c
${SRC_DIR}/bacnet/basic/sys/keylist.c
${SRC_DIR}/bacnet/basic/sys/linear.c
${SRC_DIR}/bacnet/datetime.c
${SRC_DIR}/bacnet/indtext.c
${SRC_DIR}/bacnet/hostnport.c
${SRC_DIR}/bacnet/lighting.c
${SRC_DIR}/bacnet/timestamp.c
${SRC_DIR}/bacnet/wp.c
${SRC_DIR}/bacnet/weeklyschedule.c
${SRC_DIR}/bacnet/bactimevalue.c
${SRC_DIR}/bacnet/dailyschedule.c
# Test and test library files
./src/main.c
../mock/device_mock.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
target_link_libraries(${PROJECT_NAME} PRIVATE
m)
+277
View File
@@ -0,0 +1,277 @@
/**
* @file
* @brief Unit test for object
* @author Steve Karg <skarg@users.sourceforge.net>
* @date September 2023
*
* SPDX-License-Identifier: MIT
*/
#include <zephyr/ztest.h>
#include <bacnet/bactext.h>
#include <bacnet/basic/object/blo.h>
/**
* @addtogroup bacnet_tests
* @{
*/
/**
* @brief Test
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(lo_tests, testBinaryLightingOutput)
#else
static void testBinaryLightingOutput(void)
#endif
{
uint8_t apdu[MAX_APDU] = { 0 };
int len = 0, test_len = 0;
BACNET_READ_PROPERTY_DATA rpdata;
BACNET_APPLICATION_DATA_VALUE value = { 0 };
const int *pRequired = NULL;
const int *pOptional = NULL;
const int *pProprietary = NULL;
const uint32_t instance = 123;
BACNET_WRITE_PROPERTY_DATA wpdata = { 0 };
bool status = false;
unsigned index;
Binary_Lighting_Output_Init();
Binary_Lighting_Output_Create(instance);
status = Binary_Lighting_Output_Valid_Instance(instance);
zassert_true(status, NULL);
index = Binary_Lighting_Output_Instance_To_Index(instance);
zassert_equal(index, 0, NULL);
rpdata.application_data = &apdu[0];
rpdata.application_data_len = sizeof(apdu);
rpdata.object_type = OBJECT_BINARY_LIGHTING_OUTPUT;
rpdata.object_instance = instance;
rpdata.array_index = BACNET_ARRAY_ALL;
Binary_Lighting_Output_Property_Lists(
&pRequired, &pOptional, &pProprietary);
while ((*pRequired) >= 0) {
rpdata.object_property = *pRequired;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Lighting_Output_Read_Property(&rpdata);
zassert_not_equal(len, BACNET_STATUS_ERROR,
"property '%s': failed to ReadProperty!\n",
bactext_property_name(rpdata.object_property));
if (len >= 0) {
test_len = bacapp_decode_known_property(rpdata.application_data,
len, &value, rpdata.object_type, rpdata.object_property);
if (rpdata.object_property != PROP_PRIORITY_ARRAY) {
zassert_equal(len, test_len,
"property '%s': failed to decode!\n",
bactext_property_name(rpdata.object_property));
}
/* check WriteProperty properties */
wpdata.object_type = rpdata.object_type;
wpdata.object_instance = rpdata.object_instance;
wpdata.object_property = rpdata.object_property;
wpdata.array_index = rpdata.array_index;
memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU);
wpdata.application_data_len = len;
wpdata.error_code = ERROR_CODE_SUCCESS;
status = Binary_Lighting_Output_Write_Property(&wpdata);
if (!status) {
/* verify WriteProperty property is known */
zassert_not_equal(wpdata.error_code,
ERROR_CODE_UNKNOWN_PROPERTY,
"property '%s': WriteProperty Unknown!\n",
bactext_property_name(rpdata.object_property));
}
}
pRequired++;
}
while ((*pOptional) != -1) {
rpdata.object_property = *pOptional;
rpdata.array_index = BACNET_ARRAY_ALL;
len = Binary_Lighting_Output_Read_Property(&rpdata);
zassert_not_equal(len, BACNET_STATUS_ERROR,
"property '%s': failed to ReadProperty!\n",
bactext_property_name(rpdata.object_property));
if (len > 0) {
test_len = bacapp_decode_application_data(rpdata.application_data,
(uint8_t)rpdata.application_data_len, &value);
zassert_equal(len, test_len, "property '%s': failed to decode!\n",
bactext_property_name(rpdata.object_property));
/* check WriteProperty properties */
wpdata.object_type = rpdata.object_type;
wpdata.object_instance = rpdata.object_instance;
wpdata.object_property = rpdata.object_property;
wpdata.array_index = rpdata.array_index;
memcpy(&wpdata.application_data, rpdata.application_data, MAX_APDU);
wpdata.application_data_len = len;
wpdata.error_code = ERROR_CODE_SUCCESS;
status = Binary_Lighting_Output_Write_Property(&wpdata);
if (!status) {
/* verify WriteProperty property is known */
zassert_not_equal(wpdata.error_code,
ERROR_CODE_UNKNOWN_PROPERTY,
"property '%s': WriteProperty Unknown!\n",
bactext_property_name(rpdata.object_property));
}
}
pOptional++;
}
/* check for unsupported property - use ALL */
rpdata.object_property = PROP_ALL;
len = Binary_Lighting_Output_Read_Property(&rpdata);
zassert_equal(len, BACNET_STATUS_ERROR, NULL);
status = Binary_Lighting_Output_Write_Property(&wpdata);
zassert_false(status, NULL);
/* check the delete function */
status = Binary_Lighting_Output_Delete(instance);
zassert_true(status, NULL);
return;
}
static struct {
uint32_t object_instance;
BACNET_BINARY_LIGHTING_PV old_pv;
BACNET_BINARY_LIGHTING_PV pv;
uint32_t count;
} BLO_Value;
static void Binary_Lighting_Output_Write_Value_Handler(uint32_t object_instance,
BACNET_BINARY_LIGHTING_PV old_value,
BACNET_BINARY_LIGHTING_PV value)
{
BLO_Value.object_instance = object_instance;
BLO_Value.old_pv = old_value;
BLO_Value.pv = value;
BLO_Value.count++;
}
static struct {
uint32_t object_instance;
uint32_t count;
} BLO_Blink;
static void Binary_Lighting_Output_Blink_Warn_Handler(uint32_t object_instance)
{
BLO_Blink.object_instance = object_instance;
BLO_Blink.count++;
}
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST(lo_tests, testBinaryLightingOutputBlink)
#else
static void testBinaryLightingOutputBlink(void)
#endif
{
const uint32_t object_instance = 123;
bool status = false;
uint16_t milliseconds, milliseconds_elapsed;
BACNET_BINARY_LIGHTING_PV pv, test_pv, expect_pv;
unsigned test_priority;
BACNET_WRITE_PROPERTY_DATA wpdata = { 0 };
BACNET_APPLICATION_DATA_VALUE value = { 0 };
Binary_Lighting_Output_Init();
Binary_Lighting_Output_Create(object_instance);
status = Binary_Lighting_Output_Valid_Instance(object_instance);
zassert_true(status, NULL);
Binary_Lighting_Output_Write_Value_Callback_Set(
Binary_Lighting_Output_Write_Value_Handler);
Binary_Lighting_Output_Blink_Warn_Callback_Set(
Binary_Lighting_Output_Blink_Warn_Handler);
/* check the blink warning engine at defaults */
milliseconds_elapsed = 100;
expect_pv = BINARY_LIGHTING_PV_OFF;
Binary_Lighting_Output_Timer(object_instance, milliseconds_elapsed);
zassert_equal(BLO_Blink.count, 0, "count=%u", BLO_Blink.count);
zassert_equal(BLO_Value.count, 0, "count=%u", BLO_Value.count);
zassert_equal(BLO_Value.pv, expect_pv, "value=%u", BLO_Value.pv);
/* check WriteProperty properties */
wpdata.object_type = OBJECT_BINARY_LIGHTING_OUTPUT;
wpdata.object_instance = object_instance;
wpdata.object_property = PROP_PRESENT_VALUE;
wpdata.priority = BACNET_MAX_PRIORITY;
wpdata.array_index = BACNET_ARRAY_ALL;
wpdata.error_class = ERROR_CLASS_PROPERTY;
wpdata.error_code = ERROR_CODE_SUCCESS;
/* ON */
pv = BINARY_LIGHTING_PV_ON;
expect_pv = BINARY_LIGHTING_PV_ON;
wpdata.application_data_len =
encode_application_enumerated(wpdata.application_data, pv);
status = Binary_Lighting_Output_Write_Property(&wpdata);
zassert_true(status, NULL);
milliseconds = 2000;
milliseconds_elapsed = 100;
while (milliseconds) {
Binary_Lighting_Output_Timer(object_instance, milliseconds_elapsed);
test_pv = Binary_Lighting_Output_Present_Value(object_instance);
zassert_equal(expect_pv, test_pv, NULL);
test_priority =
Binary_Lighting_Output_Present_Value_Priority(object_instance);
zassert_equal(wpdata.priority, test_priority,
"priority=%u test_priority=%u", wpdata.priority, test_priority);
zassert_equal(BLO_Blink.count, 0, NULL);
zassert_equal(BLO_Value.count, 1, "count=%u", BLO_Value.count);
zassert_equal(BLO_Value.pv, expect_pv, NULL);
milliseconds -= milliseconds_elapsed;
}
/* OFF */
pv = BINARY_LIGHTING_PV_OFF;
expect_pv = BINARY_LIGHTING_PV_OFF;
wpdata.application_data_len =
encode_application_enumerated(wpdata.application_data, pv);
status = Binary_Lighting_Output_Write_Property(&wpdata);
zassert_true(status, NULL);
milliseconds = 2000;
milliseconds_elapsed = 100;
while (milliseconds) {
Binary_Lighting_Output_Timer(object_instance, milliseconds_elapsed);
test_pv = Binary_Lighting_Output_Present_Value(object_instance);
zassert_equal(expect_pv, test_pv, NULL);
test_priority =
Binary_Lighting_Output_Present_Value_Priority(object_instance);
zassert_equal(wpdata.priority, test_priority,
"priority=%u test_priority=%u", wpdata.priority, test_priority);
zassert_equal(BLO_Blink.count, 0, NULL);
zassert_equal(BLO_Value.count, 2, "count=%u", BLO_Value.count);
zassert_equal(BLO_Value.pv, expect_pv, NULL);
milliseconds -= milliseconds_elapsed;
}
/* WARN - already off */
pv = BINARY_LIGHTING_PV_WARN;
expect_pv = BINARY_LIGHTING_PV_OFF;
wpdata.application_data_len =
encode_application_enumerated(wpdata.application_data, pv);
status = Binary_Lighting_Output_Write_Property(&wpdata);
zassert_true(status, NULL);
milliseconds = 2000;
milliseconds_elapsed = 100;
while (milliseconds) {
Binary_Lighting_Output_Timer(object_instance, milliseconds_elapsed);
test_pv = Binary_Lighting_Output_Present_Value(object_instance);
zassert_equal(expect_pv, test_pv, "pv=%u", test_pv);
test_priority =
Binary_Lighting_Output_Present_Value_Priority(object_instance);
zassert_equal(wpdata.priority, test_priority,
"priority=%u test_priority=%u", wpdata.priority, test_priority);
zassert_equal(BLO_Blink.count, 0, NULL);
zassert_equal(BLO_Value.count, 2, "count=%u", BLO_Value.count);
zassert_equal(BLO_Value.pv, expect_pv, NULL);
milliseconds -= milliseconds_elapsed;
}
}
/**
* @}
*/
#if defined(CONFIG_ZTEST_NEW_API)
ZTEST_SUITE(blo_tests, NULL, NULL, NULL, NULL, NULL);
#else
void test_main(void)
{
ztest_test_suite(blo_tests, ztest_unit_test(testBinaryLightingOutput),
ztest_unit_test(testBinaryLightingOutputBlink));
ztest_run_test_suite(blo_tests);
}
#endif
@@ -52,6 +52,7 @@ add_executable(${PROJECT_NAME}
${SRC_DIR}/bacnet/basic/object/ao.c ${SRC_DIR}/bacnet/basic/object/ao.c
${SRC_DIR}/bacnet/basic/object/av.c ${SRC_DIR}/bacnet/basic/object/av.c
${SRC_DIR}/bacnet/basic/object/bi.c ${SRC_DIR}/bacnet/basic/object/bi.c
${SRC_DIR}/bacnet/basic/object/blo.c
${SRC_DIR}/bacnet/basic/object/bo.c ${SRC_DIR}/bacnet/basic/object/bo.c
${SRC_DIR}/bacnet/basic/object/bv.c ${SRC_DIR}/bacnet/basic/object/bv.c
${SRC_DIR}/bacnet/basic/object/channel.c ${SRC_DIR}/bacnet/basic/object/channel.c