Add RGB pixel and brightness APIs, update Blinkt example (#1210)
* Added API to get the RGB pixel and brightness values from the blinkt interface. * Fixed Channel object for Color object present-value which does not use coercion. * Added API to the color-RGB library to convert from ASCII CSS color name to X,Y and brightness. * Converted the Blinkt example app to use the basic-server. Added a default color name command line option --color that accepts CSS color names. Set the color and brightness at startup. * Added vacancy timer for lights using timer object defaulted to 30m and started at startup.
This commit is contained in:
@@ -32,6 +32,11 @@ The git repositories are hosted at the following sites:
|
||||
|
||||
### Added
|
||||
|
||||
* Added API to get the RGB pixel and brightness values from the blinkt
|
||||
interface. Added API to the color-RGB library to convert from ASCII
|
||||
CSS color name to X,Y and brightness. Added a default color name command
|
||||
line option. Set the color and brightness at startup. Changed the Blinkt
|
||||
example app to use the basic-server framework. (#1210)
|
||||
* Added enumeration text lookup for BACnetAuthenticationStatus,
|
||||
BACnetAuthorizationMode, BACnetAccessCredentialDisable,
|
||||
BACnetAccessCredentialDisableReason, BACnetAccessUserType,
|
||||
@@ -108,6 +113,8 @@ The git repositories are hosted at the following sites:
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed Channel object for Color object present-value which does not
|
||||
use coercion. (#1210)
|
||||
* Fixed lighting output object lighting-command last-on-value to only
|
||||
be updated with the last value of the Present_Value property that
|
||||
was greater than or equal to 1.0%, keeping in mind that the Present_Value
|
||||
|
||||
+38
-3
@@ -1,6 +1,8 @@
|
||||
###############################################################################
|
||||
# Makefile for Project - BACnet Blinkt!
|
||||
# sudo apt install libpigpio-dev libpigpiod-if-dev pigpiod
|
||||
# note: start pigpio daemon with the command 'sudo pigpiod'
|
||||
# note: Blinkt! pigpio library is not supported on Raspberry Pi 5 at this time
|
||||
###############################################################################
|
||||
|
||||
## General Flags
|
||||
@@ -8,13 +10,46 @@ TARGET = bacblinkt
|
||||
|
||||
# BACnet objects that are used with this app
|
||||
BACNET_OBJECT_DIR = $(BACNET_SRC_DIR)/bacnet/basic/object
|
||||
SRC = main.c blinkt.c device.c \
|
||||
$(BACNET_OBJECT_DIR)/netport.c \
|
||||
BACNET_SERVER_DIR = $(BACNET_SRC_DIR)/bacnet/basic/server
|
||||
SRC = main.c blinkt.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_basic.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_device.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_port.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_port_ipv4.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_port_ipv6.c \
|
||||
$(BACNET_SERVER_DIR)/bacnet_port_mstp.c \
|
||||
$(BACNET_OBJECT_DIR)/ai.c \
|
||||
$(BACNET_OBJECT_DIR)/ao.c \
|
||||
$(BACNET_OBJECT_DIR)/av.c \
|
||||
$(BACNET_OBJECT_DIR)/auditlog.c \
|
||||
$(BACNET_OBJECT_DIR)/bacfile.c \
|
||||
$(BACNET_OBJECT_DIR)/bi.c \
|
||||
$(BACNET_OBJECT_DIR)/bitstring_value.c \
|
||||
$(BACNET_OBJECT_DIR)/blo.c \
|
||||
$(BACNET_OBJECT_DIR)/bo.c \
|
||||
$(BACNET_OBJECT_DIR)/bv.c \
|
||||
$(BACNET_OBJECT_DIR)/calendar.c \
|
||||
$(BACNET_OBJECT_DIR)/channel.c \
|
||||
$(BACNET_OBJECT_DIR)/color_object.c \
|
||||
$(BACNET_OBJECT_DIR)/color_temperature.c \
|
||||
$(BACNET_OBJECT_DIR)/command.c \
|
||||
$(BACNET_OBJECT_DIR)/csv.c \
|
||||
$(BACNET_OBJECT_DIR)/iv.c \
|
||||
$(BACNET_OBJECT_DIR)/lc.c \
|
||||
$(BACNET_OBJECT_DIR)/lo.c
|
||||
$(BACNET_OBJECT_DIR)/lo.c \
|
||||
$(BACNET_OBJECT_DIR)/loop.c \
|
||||
$(BACNET_OBJECT_DIR)/lsp.c \
|
||||
$(BACNET_OBJECT_DIR)/lsz.c \
|
||||
$(BACNET_OBJECT_DIR)/ms-input.c \
|
||||
$(BACNET_OBJECT_DIR)/mso.c \
|
||||
$(BACNET_OBJECT_DIR)/msv.c \
|
||||
$(BACNET_OBJECT_DIR)/nc.c \
|
||||
$(BACNET_OBJECT_DIR)/netport.c \
|
||||
$(BACNET_OBJECT_DIR)/osv.c \
|
||||
$(BACNET_OBJECT_DIR)/program.c \
|
||||
$(BACNET_OBJECT_DIR)/structured_view.c \
|
||||
$(BACNET_OBJECT_DIR)/timer.c \
|
||||
$(BACNET_OBJECT_DIR)/time_value.c
|
||||
|
||||
CFLAGS += -DMAX_TSM_TRANSACTIONS=1
|
||||
|
||||
|
||||
@@ -69,6 +69,29 @@ void blinkt_set_pixel(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
|
||||
Blinkt_LED[led] = blinkt_rgbb(r, g, b, Blinkt_LED[led] & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current RGB color of one LED
|
||||
* @param led index 0..#BLINKT_NUM_LEDS
|
||||
* @param r pointer to store the red component (0..255), may be NULL
|
||||
* @param g pointer to store the green component (0..255), may be NULL
|
||||
* @param b pointer to store the blue component (0..255), may be NULL
|
||||
*/
|
||||
void blinkt_get_pixel(uint8_t led, uint8_t *r, uint8_t *g, uint8_t *b)
|
||||
{
|
||||
if (led >= BLINKT_NUM_LEDS) {
|
||||
return;
|
||||
}
|
||||
if (r) {
|
||||
*r = (Blinkt_LED[led] >> 24) & 0xFF;
|
||||
}
|
||||
if (g) {
|
||||
*g = (Blinkt_LED[led] >> 16) & 0xFF;
|
||||
}
|
||||
if (b) {
|
||||
*b = (Blinkt_LED[led] >> 8) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set one LED to specific intensity
|
||||
* @param led index 0..#BLINKT_NUM_LEDS
|
||||
@@ -83,6 +106,20 @@ void blinkt_set_pixel_brightness(uint8_t led, uint8_t brightness)
|
||||
Blinkt_LED[led] = (Blinkt_LED[led] & 0xFFFFFF00) | (brightness & 0x1F);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the brightness of one LED
|
||||
* @param led index 0..#BLINKT_NUM_LEDS
|
||||
* @return brightness intensity from 0..31, 0=OFF, 1=dimmest, 31=brightest
|
||||
*/
|
||||
uint8_t blinkt_get_pixel_brightness(uint8_t led)
|
||||
{
|
||||
if (led >= BLINKT_NUM_LEDS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Blinkt_LED[led] & 0x1F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set one LED to RGB color and brightness
|
||||
* @param led index 0..#BLINKT_NUM_LEDS
|
||||
|
||||
@@ -9,8 +9,13 @@
|
||||
|
||||
void blinkt_clear(void);
|
||||
void blinkt_set_pixel_uint32(uint8_t led, uint32_t color);
|
||||
|
||||
void blinkt_set_pixel(uint8_t led, uint8_t r, uint8_t g, uint8_t b);
|
||||
void blinkt_get_pixel(uint8_t led, uint8_t *r, uint8_t *g, uint8_t *b);
|
||||
|
||||
uint8_t blinkt_get_pixel_brightness(uint8_t led);
|
||||
void blinkt_set_pixel_brightness(uint8_t led, uint8_t brightness);
|
||||
|
||||
uint32_t blinkt_rgbb(uint8_t r, uint8_t g, uint8_t b, uint8_t brightness);
|
||||
uint32_t blinkt_rgb(uint8_t r, uint8_t g, uint8_t b);
|
||||
void blinkt_stop(void);
|
||||
|
||||
+192
-181
@@ -14,104 +14,50 @@
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/bactext.h"
|
||||
#include "bacnet/version.h"
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/npdu.h"
|
||||
#include "bacnet/apdu.h"
|
||||
#include "bacnet/iam.h"
|
||||
#include "bacnet/dcc.h"
|
||||
#include "bacnet/getevent.h"
|
||||
#include "bacnet/lighting.h"
|
||||
/* demo services */
|
||||
#include "bacnet/basic/binding/address.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
#include "bacnet/datalink/dlenv.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
#include "bacnet/basic/sys/mstimer.h"
|
||||
/* BACnet System API */
|
||||
#include "bacnet/basic/sys/color_rgb.h"
|
||||
#include "bacnet/basic/sys/debug.h"
|
||||
#include "bacnet/basic/sys/filename.h"
|
||||
#include "bacnet/basic/sys/linear.h"
|
||||
#include "bacnet/basic/tsm/tsm.h"
|
||||
#include "bacnet/version.h"
|
||||
/* include the device object */
|
||||
#include "bacnet/basic/sys/mstimer.h"
|
||||
/* BACnet basic server & services API */
|
||||
#include "bacnet/basic/server/bacnet_basic.h"
|
||||
#include "bacnet/basic/server/bacnet_port.h"
|
||||
#include "bacnet/basic/services.h"
|
||||
/* BACnet basic datalink API */
|
||||
#include "bacnet/datalink/dlenv.h"
|
||||
#include "bacnet/datalink/datalink.h"
|
||||
/* BACnet basic object */
|
||||
#include "bacnet/basic/object/device.h"
|
||||
#include "bacnet/basic/object/bacfile.h"
|
||||
#include "bacnet/basic/object/lo.h"
|
||||
#include "bacnet/basic/object/channel.h"
|
||||
#include "bacnet/basic/object/color_object.h"
|
||||
#include "bacnet/basic/object/color_temperature.h"
|
||||
#include "bacnet/basic/object/timer.h"
|
||||
/* local includes */
|
||||
#include "bacport.h"
|
||||
#include "blinkt.h"
|
||||
|
||||
/* (Doxygen note: The next two lines pull all the following Javadoc
|
||||
* into the ServerDemo module.) */
|
||||
/** @addtogroup ServerDemo */
|
||||
/*@{*/
|
||||
|
||||
/** Buffer used for receiving */
|
||||
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
|
||||
/* current version of the BACnet stack */
|
||||
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;
|
||||
/* some device customization */
|
||||
static const char *Device_Name = "Blinkt! Server";
|
||||
static uint32_t Device_ID = 260001;
|
||||
/* task timer for Blinkt! RGB LED display */
|
||||
static struct mstimer Blinkt_Task;
|
||||
/* flag to enable the Blinkt! test */
|
||||
static bool Blinkt_Test = false;
|
||||
/* observer for WriteGroup notifications */
|
||||
static BACNET_WRITE_GROUP_NOTIFICATION Write_Group_Notification;
|
||||
|
||||
/** Initialize the handlers we will utilize.
|
||||
* @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler
|
||||
*/
|
||||
static void Init_Service_Handlers(void)
|
||||
{
|
||||
Device_Init(NULL);
|
||||
/* 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_HAS, handler_who_has);
|
||||
/* handle i-am to support binding to other devices */
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_bind);
|
||||
/* set the handler for all the services we don't implement */
|
||||
/* It is required to send the proper reject message... */
|
||||
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
|
||||
/* Set the handlers for any confirmed services that we support. */
|
||||
/* We must implement read property - it's required! */
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_READ_PROP_MULTIPLE, handler_read_property_multiple);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE, handler_write_property_multiple);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_READ_RANGE, handler_read_range);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_REINITIALIZE_DEVICE, handler_reinitialize_device);
|
||||
apdu_set_unconfirmed_handler(
|
||||
SERVICE_UNCONFIRMED_UTC_TIME_SYNCHRONIZATION, handler_timesync_utc);
|
||||
apdu_set_unconfirmed_handler(
|
||||
SERVICE_UNCONFIRMED_TIME_SYNCHRONIZATION, handler_timesync);
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_SUBSCRIBE_COV, handler_cov_subscribe);
|
||||
apdu_set_unconfirmed_handler(
|
||||
SERVICE_UNCONFIRMED_WRITE_GROUP, handler_write_group);
|
||||
/* handle communication so we can shutup when asked */
|
||||
apdu_set_confirmed_handler(
|
||||
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
|
||||
handler_device_communication_control);
|
||||
/* configure the cyclic timers */
|
||||
mstimer_set(&BACnet_Task_Timer, 1000UL);
|
||||
mstimer_set(&BACnet_TSM_Timer, 50UL);
|
||||
mstimer_set(&BACnet_Address_Timer, 60UL * 1000UL);
|
||||
mstimer_set(&BACnet_Object_Timer, 100UL);
|
||||
}
|
||||
|
||||
/* object instances */
|
||||
static uint32_t Light_Channel_Instance = 1;
|
||||
static uint32_t Color_Channel_Instance = 2;
|
||||
static uint32_t CCT_Channel_Instance = 3;
|
||||
static uint32_t Vacancy_Timer_Instance = 1;
|
||||
static unsigned Default_Priority = 16;
|
||||
/**
|
||||
* Clean up the Blinkt! interface
|
||||
*/
|
||||
@@ -209,30 +155,63 @@ static void Color_Write_Value_Handler(
|
||||
/**
|
||||
* @brief Create the objects and configure the callbacks for BACnet objects
|
||||
*/
|
||||
static void bacnet_output_init(void)
|
||||
static void BACnet_Object_Table_Init(void *context)
|
||||
{
|
||||
unsigned i = 0;
|
||||
uint8_t led_max;
|
||||
uint32_t object_instance = 0, member_element = 0;
|
||||
uint32_t object_instance = 0, member_element = 0, device_instance = 0;
|
||||
BACNET_COLOR_COMMAND command = { 0 };
|
||||
BACNET_OBJECT_ID object_id;
|
||||
uint32_t light_channel_instance = 1;
|
||||
uint32_t color_channel_instance = 2;
|
||||
uint32_t temp_channel_instance = 3;
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE member;
|
||||
BACNET_OBJECT_ID object_id = { 0 };
|
||||
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE member = { 0 };
|
||||
BACNET_TIMER_STATE_CHANGE_VALUE timer_transition = { 0 };
|
||||
|
||||
Channel_Create(light_channel_instance);
|
||||
Channel_Name_Set(light_channel_instance, "Lights");
|
||||
Channel_Number_Set(light_channel_instance, 1);
|
||||
Channel_Control_Groups_Element_Set(light_channel_instance, 1, 1);
|
||||
Channel_Create(color_channel_instance);
|
||||
Channel_Name_Set(color_channel_instance, "Colors");
|
||||
Channel_Number_Set(color_channel_instance, 2);
|
||||
Channel_Control_Groups_Element_Set(color_channel_instance, 1, 2);
|
||||
Channel_Create(temp_channel_instance);
|
||||
Channel_Name_Set(temp_channel_instance, "Color-Temperatures");
|
||||
Channel_Number_Set(temp_channel_instance, 3);
|
||||
Channel_Control_Groups_Element_Set(temp_channel_instance, 1, 3);
|
||||
(void)context;
|
||||
device_instance = Device_Object_Instance_Number();
|
||||
/* create the objects */
|
||||
Channel_Create(Light_Channel_Instance);
|
||||
Channel_Name_Set(Light_Channel_Instance, "Lights");
|
||||
Channel_Number_Set(Light_Channel_Instance, 1);
|
||||
Channel_Control_Groups_Element_Set(Light_Channel_Instance, 1, 1);
|
||||
Channel_Create(Color_Channel_Instance);
|
||||
Channel_Name_Set(Color_Channel_Instance, "Colors");
|
||||
Channel_Number_Set(Color_Channel_Instance, 2);
|
||||
Channel_Control_Groups_Element_Set(Color_Channel_Instance, 1, 2);
|
||||
Channel_Create(CCT_Channel_Instance);
|
||||
Channel_Name_Set(CCT_Channel_Instance, "Color-Temperatures");
|
||||
Channel_Number_Set(CCT_Channel_Instance, 3);
|
||||
Channel_Control_Groups_Element_Set(CCT_Channel_Instance, 1, 3);
|
||||
/* timer to automatically turn off the lights */
|
||||
Timer_Create(Vacancy_Timer_Instance);
|
||||
Timer_Name_Set(Vacancy_Timer_Instance, "Vacancy-Timer");
|
||||
Timer_Default_Timeout_Set(Vacancy_Timer_Instance, 30UL * 60UL * 1000UL);
|
||||
/* to running */
|
||||
timer_transition.next = NULL;
|
||||
timer_transition.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
timer_transition.type.Real = BACNET_LIGHTING_SPECIAL_VALUE_RESTORE_ON;
|
||||
Timer_State_Change_Value_Set(
|
||||
Vacancy_Timer_Instance, TIMER_TRANSITION_IDLE_TO_RUNNING,
|
||||
&timer_transition);
|
||||
Timer_State_Change_Value_Set(
|
||||
Vacancy_Timer_Instance, TIMER_TRANSITION_RUNNING_TO_RUNNING,
|
||||
&timer_transition);
|
||||
Timer_State_Change_Value_Set(
|
||||
Vacancy_Timer_Instance, TIMER_TRANSITION_EXPIRED_TO_RUNNING,
|
||||
&timer_transition);
|
||||
/* to expired */
|
||||
timer_transition.next = NULL;
|
||||
timer_transition.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
timer_transition.type.Real = BACNET_LIGHTING_SPECIAL_VALUE_WARN_RELINQUISH;
|
||||
Timer_State_Change_Value_Set(
|
||||
Vacancy_Timer_Instance, TIMER_TRANSITION_RUNNING_TO_EXPIRED,
|
||||
&timer_transition);
|
||||
member.objectIdentifier.type = OBJECT_CHANNEL;
|
||||
member.objectIdentifier.instance = Light_Channel_Instance;
|
||||
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||
member.arrayIndex = BACNET_ARRAY_ALL;
|
||||
member.deviceIdentifier.type = OBJECT_DEVICE;
|
||||
member.deviceIdentifier.instance = device_instance;
|
||||
Timer_Reference_List_Member_Element_Add(Vacancy_Timer_Instance, &member);
|
||||
Timer_Priority_For_Writing_Set(Vacancy_Timer_Instance, Default_Priority);
|
||||
/* configure outputs and bindings */
|
||||
led_max = blinkt_led_count();
|
||||
for (i = 0; i < led_max; i++) {
|
||||
@@ -255,9 +234,9 @@ static void bacnet_output_init(void)
|
||||
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||
member.arrayIndex = BACNET_ARRAY_ALL;
|
||||
member.deviceIdentifier.type = OBJECT_DEVICE;
|
||||
member.deviceIdentifier.instance = Device_Object_Instance_Number();
|
||||
member.deviceIdentifier.instance = device_instance;
|
||||
Channel_Reference_List_Member_Element_Set(
|
||||
color_channel_instance, member_element, &member);
|
||||
Color_Channel_Instance, member_element, &member);
|
||||
|
||||
/* color temperature */
|
||||
Color_Temperature_Create(object_instance);
|
||||
@@ -273,9 +252,9 @@ static void bacnet_output_init(void)
|
||||
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||
member.arrayIndex = BACNET_ARRAY_ALL;
|
||||
member.deviceIdentifier.type = OBJECT_DEVICE;
|
||||
member.deviceIdentifier.instance = Device_Object_Instance_Number();
|
||||
member.deviceIdentifier.instance = device_instance;
|
||||
Channel_Reference_List_Member_Element_Set(
|
||||
temp_channel_instance, member_element, &member);
|
||||
CCT_Channel_Instance, member_element, &member);
|
||||
|
||||
/* lighting output */
|
||||
Lighting_Output_Create(object_instance);
|
||||
@@ -291,10 +270,11 @@ static void bacnet_output_init(void)
|
||||
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
||||
member.arrayIndex = BACNET_ARRAY_ALL;
|
||||
member.deviceIdentifier.type = OBJECT_DEVICE;
|
||||
member.deviceIdentifier.instance = Device_Object_Instance_Number();
|
||||
member.deviceIdentifier.instance = device_instance;
|
||||
Channel_Reference_List_Member_Element_Set(
|
||||
light_channel_instance, member_element, &member);
|
||||
Light_Channel_Instance, member_element, &member);
|
||||
}
|
||||
/* enable the callbacks for control */
|
||||
Color_Write_Present_Value_Callback_Set(Color_Write_Value_Handler);
|
||||
Color_Temperature_Write_Present_Value_Callback_Set(
|
||||
Color_Temperature_Write_Value_Handler);
|
||||
@@ -302,6 +282,59 @@ static void bacnet_output_init(void)
|
||||
Lighting_Output_Write_Value_Handler);
|
||||
Write_Group_Notification.callback = Channel_Write_Group;
|
||||
handler_write_group_notification_add(&Write_Group_Notification);
|
||||
/* LEDs run at 0.1s intervals */
|
||||
bacnet_basic_task_object_timer_set(100);
|
||||
mstimer_set(&Blinkt_Task, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief BACnet object value initialization
|
||||
* @param color_name - color name string
|
||||
*/
|
||||
static void BACnet_Object_Value_Init(const char *color_name)
|
||||
{
|
||||
BACNET_CHANNEL_VALUE value = { 0 };
|
||||
float x_coordinate = 1.0f, y_coordinate = 1.0f;
|
||||
uint8_t brightness = 0;
|
||||
|
||||
/* update the lighting-output and color-temperature */
|
||||
if (color_rgb_xy_from_ascii(
|
||||
&x_coordinate, &y_coordinate, &brightness, color_name)) {
|
||||
printf(
|
||||
"Initial color: %s x=%.2f y=%.2f brightness=%u/255\n", color_name,
|
||||
x_coordinate, y_coordinate, (unsigned)brightness);
|
||||
/* Set the Color */
|
||||
value.tag = BACNET_APPLICATION_TAG_XY_COLOR;
|
||||
value.type.XY_Color.x_coordinate = x_coordinate;
|
||||
value.type.XY_Color.y_coordinate = y_coordinate;
|
||||
Channel_Present_Value_Set(Color_Channel_Instance, 16, &value);
|
||||
/* Set the Brightness */
|
||||
value.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
value.type.Real =
|
||||
linear_interpolate(0.0f, brightness, 255.0f, 0.0f, 100.0f);
|
||||
Channel_Present_Value_Set(
|
||||
Light_Channel_Instance, Default_Priority, &value);
|
||||
/* start the vacancy timer */
|
||||
Timer_Running_Set(Vacancy_Timer_Instance, true);
|
||||
} else {
|
||||
printf("Initial color: %s unknown\n", color_name);
|
||||
}
|
||||
}
|
||||
|
||||
static void BACnet_Object_Task(void *context)
|
||||
{
|
||||
(void)context;
|
||||
/* input/process/output */
|
||||
if (Blinkt_Test) {
|
||||
blinkt_test_task();
|
||||
}
|
||||
if (mstimer_expired(&Blinkt_Task)) {
|
||||
mstimer_restart(&Blinkt_Task);
|
||||
/* run at the same interval as the BACnet basic objects */
|
||||
if (!Blinkt_Test) {
|
||||
blinkt_show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,6 +362,10 @@ static void print_help(const char *filename)
|
||||
"try and bind with this device using Who-Is and\n"
|
||||
"I-Am services.\n");
|
||||
printf("\n");
|
||||
printf(
|
||||
"--color:\n"
|
||||
"Default CSS color name from W3C, such as black, red, green, etc.\n");
|
||||
printf("\n");
|
||||
printf("--test:\n"
|
||||
"Test the Blinkt! RGB LEDs with a cycling pattern.\n");
|
||||
printf("\n");
|
||||
@@ -339,29 +376,17 @@ static void print_help(const char *filename)
|
||||
}
|
||||
|
||||
/** Main function of server demo.
|
||||
*
|
||||
* @see Device_Set_Object_Instance_Number, dlenv_init, Send_I_Am,
|
||||
* datalink_receive, npdu_handler,
|
||||
* dcc_timer_seconds, datalink_maintenance_timer,
|
||||
* handler_cov_task,
|
||||
* tsm_timer_milliseconds
|
||||
*
|
||||
* @param argc [in] Arg count.
|
||||
* @param argv [in] Takes one argument: the Device Instance #.
|
||||
* @param argv [in] Argument list.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BACNET_ADDRESS src = { 0 }; /* address where message came from */
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout_ms = 1;
|
||||
unsigned long seconds = 0;
|
||||
unsigned long milliseconds;
|
||||
bool blinkt_test = false;
|
||||
unsigned int target_args = 0;
|
||||
uint32_t device_id = BACNET_MAX_INSTANCE;
|
||||
int argi = 0;
|
||||
const char *filename = NULL;
|
||||
const char *color_name = "darkred";
|
||||
|
||||
filename = filename_remove_path(argv[0]);
|
||||
for (argi = 1; argi < argc; argi++) {
|
||||
@@ -380,92 +405,78 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[argi], "--device") == 0) {
|
||||
/* allow the device ID to be set */
|
||||
if (++argi < argc) {
|
||||
if (!bacnet_string_to_uint32(argv[argi], &device_id)) {
|
||||
fprintf(stderr, "device-instance=%s invalid\n", argv[argi]);
|
||||
return 1;
|
||||
}
|
||||
if (device_id > BACNET_MAX_INSTANCE) {
|
||||
fprintf(stderr, "device-instance=%s invalid\n", argv[argi]);
|
||||
return 1;
|
||||
} else {
|
||||
Device_ID = device_id;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(argv[argi], "--test") == 0) {
|
||||
blinkt_test = true;
|
||||
/* test the hardware */
|
||||
Blinkt_Test = true;
|
||||
} else if (strcmp(argv[argi], "--color") == 0) {
|
||||
/* initial color */
|
||||
if (++argi < argc) {
|
||||
color_name = argv[argi];
|
||||
} else {
|
||||
fprintf(stderr, "Missing color name after --color\n");
|
||||
print_usage(filename);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (target_args == 0) {
|
||||
/* allow the device ID to be set */
|
||||
if (!bacnet_string_to_uint32(argv[argi], &device_id)) {
|
||||
fprintf(stderr, "device-instance=%s invalid\n", argv[argi]);
|
||||
return 1;
|
||||
}
|
||||
if (device_id > BACNET_MAX_INSTANCE) {
|
||||
fprintf(stderr, "device-instance=%s invalid\n", argv[argi]);
|
||||
return 1;
|
||||
} else {
|
||||
Device_ID = device_id;
|
||||
}
|
||||
target_args++;
|
||||
} else if (target_args == 1) {
|
||||
/* allow the device name to be set */
|
||||
Device_Name = argv[argi];
|
||||
target_args++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (device_id > BACNET_MAX_INSTANCE) {
|
||||
fprintf(
|
||||
stderr, "device=%u - not greater than %u\n", device_id,
|
||||
BACNET_MAX_INSTANCE);
|
||||
return 1;
|
||||
}
|
||||
Device_Set_Object_Instance_Number(device_id);
|
||||
Device_Set_Object_Instance_Number(Device_ID);
|
||||
Device_Object_Name_ANSI_Init(Device_Name);
|
||||
printf(
|
||||
"BACnet Raspberry Pi Blinkt! Demo\n"
|
||||
"BACnet Raspberry Pi Blinkt! Demo %s\n"
|
||||
"BACnet Stack Version %s\n"
|
||||
"BACnet Device ID: %u\n"
|
||||
"Max APDU: %d\n",
|
||||
BACnet_Version, Device_Object_Instance_Number(), MAX_APDU);
|
||||
/* load any static address bindings to show up
|
||||
in our device bindings list */
|
||||
address_init();
|
||||
Init_Service_Handlers();
|
||||
dlenv_init();
|
||||
atexit(datalink_cleanup);
|
||||
Device_Application_Software_Version(), Device_Firmware_Revision(),
|
||||
Device_Object_Instance_Number(), MAX_APDU);
|
||||
blinkt_init();
|
||||
atexit(blinkt_cleanup);
|
||||
bacnet_output_init();
|
||||
/* configure the timeout values */
|
||||
/* broadcast an I-Am on startup */
|
||||
Send_I_Am(&Handler_Transmit_Buffer[0]);
|
||||
/* loop forever */
|
||||
debug_printf_stdout("Blinkt! initialized\n");
|
||||
bacnet_basic_init_callback_set(BACnet_Object_Table_Init, NULL);
|
||||
bacnet_basic_task_callback_set(BACnet_Object_Task, NULL);
|
||||
bacnet_basic_init();
|
||||
if (bacnet_port_init()) {
|
||||
/* OS based apps use DLENV for environment variables */
|
||||
dlenv_init();
|
||||
atexit(datalink_cleanup);
|
||||
}
|
||||
debug_printf_stdout("Server: BACnet initialized\n");
|
||||
BACnet_Object_Value_Init(color_name);
|
||||
for (;;) {
|
||||
/* input */
|
||||
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout_ms);
|
||||
/* process */
|
||||
if (pdu_len) {
|
||||
npdu_handler(&src, &Rx_Buf[0], pdu_len);
|
||||
}
|
||||
if (mstimer_expired(&BACnet_Task_Timer)) {
|
||||
mstimer_reset(&BACnet_Task_Timer);
|
||||
/* 1 second tasks */
|
||||
dcc_timer_seconds(1);
|
||||
datalink_maintenance_timer(1);
|
||||
dlenv_maintenance_timer(1);
|
||||
handler_cov_timer_seconds(1);
|
||||
}
|
||||
if (mstimer_expired(&BACnet_TSM_Timer)) {
|
||||
mstimer_reset(&BACnet_TSM_Timer);
|
||||
tsm_timer_milliseconds(mstimer_interval(&BACnet_TSM_Timer));
|
||||
}
|
||||
handler_cov_task();
|
||||
if (mstimer_expired(&BACnet_Address_Timer)) {
|
||||
mstimer_reset(&BACnet_Address_Timer);
|
||||
/* address cache */
|
||||
seconds = mstimer_interval(&BACnet_Address_Timer) / 1000;
|
||||
address_cache_timer(seconds);
|
||||
}
|
||||
/* output/input */
|
||||
if (blinkt_test) {
|
||||
blinkt_test_task();
|
||||
} else {
|
||||
if (mstimer_expired(&BACnet_Object_Timer)) {
|
||||
mstimer_reset(&BACnet_Object_Timer);
|
||||
milliseconds = mstimer_interval(&BACnet_Object_Timer);
|
||||
Device_Timer(milliseconds);
|
||||
blinkt_show();
|
||||
}
|
||||
}
|
||||
bacnet_basic_task();
|
||||
bacnet_port_task();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @} */
|
||||
|
||||
/* End group ServerDemo */
|
||||
|
||||
@@ -662,18 +662,6 @@ bool Channel_Write_Member_Value(
|
||||
wp_data->application_data_len = apdu_len;
|
||||
status = true;
|
||||
}
|
||||
} else if (
|
||||
(wp_data->object_type == OBJECT_COLOR) &&
|
||||
((wp_data->object_property == PROP_PRESENT_VALUE) ||
|
||||
(wp_data->object_property == PROP_DEFAULT_COLOR)) &&
|
||||
(wp_data->array_index == BACNET_ARRAY_ALL)) {
|
||||
apdu_len = bacnet_channel_value_coerce_data_encode(
|
||||
wp_data->application_data, wp_data->application_data_len, value,
|
||||
BACNET_APPLICATION_TAG_XY_COLOR);
|
||||
if (apdu_len != BACNET_STATUS_ERROR) {
|
||||
wp_data->application_data_len = apdu_len;
|
||||
status = true;
|
||||
}
|
||||
} else if (
|
||||
(wp_data->object_type == OBJECT_COLOR_TEMPERATURE) &&
|
||||
((wp_data->object_property == PROP_PRESENT_VALUE) ||
|
||||
@@ -761,8 +749,11 @@ static bool Channel_Write_Members(
|
||||
}
|
||||
debug_printf(
|
||||
"channel[%lu].Channel_Write_Member[%u] "
|
||||
"%s\n",
|
||||
"%s-%u %s %s\n",
|
||||
(unsigned long)object_instance, m,
|
||||
bactext_object_type_name(wp_data.object_type),
|
||||
wp_data.object_instance,
|
||||
bactext_property_name(wp_data.object_property),
|
||||
bactext_error_code_name(wp_data.error_code));
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -490,6 +490,33 @@ unsigned color_rgb_from_ascii(
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert CSS color name to CIE xy coordinates and brightness
|
||||
* @param x_coordinate - return x of CIE xy 0.0..1.0
|
||||
* @param y_coordinate - return y of CIE xy 0.0..1.0
|
||||
* @param brightness - return brightness of the CIE xy color 0..255
|
||||
* @param name - CSS color name from W3C
|
||||
* @return true if color name was found, false if not found
|
||||
*/
|
||||
bool color_rgb_xy_from_ascii(
|
||||
float *x_coordinate,
|
||||
float *y_coordinate,
|
||||
uint8_t *brightness,
|
||||
const char *name)
|
||||
{
|
||||
bool status = false;
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
unsigned index;
|
||||
|
||||
index = color_rgb_from_ascii(&r, &g, &b, name);
|
||||
if (index < color_rgb_count()) {
|
||||
color_rgb_to_xy(r, g, b, x_coordinate, y_coordinate, brightness);
|
||||
status = true;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert sRGB from CIE xy and brightness
|
||||
* @param red - return R value of sRGB
|
||||
|
||||
@@ -59,6 +59,13 @@ BACNET_STACK_EXPORT
|
||||
unsigned color_rgb_from_ascii(
|
||||
uint8_t *red, uint8_t *green, uint8_t *blue, const char *name);
|
||||
BACNET_STACK_EXPORT
|
||||
bool color_rgb_xy_from_ascii(
|
||||
float *x_coordinate,
|
||||
float *y_coordinate,
|
||||
uint8_t *brightness,
|
||||
const char *name);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
const char *color_rgb_from_index(
|
||||
unsigned target_index, uint8_t *red, uint8_t *green, uint8_t *blue);
|
||||
BACNET_STACK_EXPORT
|
||||
|
||||
Reference in New Issue
Block a user