20f402f5b6
* Fixed lighting output object lighting-commands for warn-off and warn-relinquish when blink-warn notification shall not occur. * Fixed timer object task to initiate a write-request at expiration. * Added channel and timer object write-property observers in blinkt app to monitor internal writes. * Added vacancy timer command line argument in blinkt app for testing initial timer object vacancy time for lights channel.
579 lines
21 KiB
C
579 lines
21 KiB
C
/**
|
|
* @file
|
|
* @brief Example application using the BACnet Stack on a Raspberry Pi
|
|
* with Blinkt! LEDs.
|
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
|
* @date 2023
|
|
* @copyright SPDX-License-Identifier: MIT
|
|
*/
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
/* 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/lighting.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/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"
|
|
|
|
/* 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;
|
|
/* observers for internal object to object writes */
|
|
static struct channel_write_property_notification
|
|
Channel_Write_Property_Observer;
|
|
static struct timer_write_property_notification Timer_Write_Property_Observer;
|
|
|
|
/* 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 uint32_t Vacancy_Timeout_Milliseconds = 30UL * 60UL * 1000UL;
|
|
static unsigned Default_Priority = 16;
|
|
/**
|
|
* Clean up the Blinkt! interface
|
|
*/
|
|
static void blinkt_cleanup(void)
|
|
{
|
|
blinkt_stop();
|
|
}
|
|
|
|
/**
|
|
* @brief Log internal object to object WriteProperty calls
|
|
* @param object_type The object type being written to
|
|
* @param instance The object instance being written to
|
|
* @param status The status of the WriteProperty
|
|
* @param wp_data The WriteProperty data
|
|
*/
|
|
static void write_property_observer(
|
|
BACNET_OBJECT_TYPE object_type,
|
|
uint32_t instance,
|
|
bool status,
|
|
BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|
{
|
|
unsigned i;
|
|
char value_string[64 + 1] = { 0 };
|
|
|
|
if (status) {
|
|
printf(
|
|
"WriteProperty: %s-%d to %s-%u %s@%u\n",
|
|
bactext_object_type_name(object_type), instance,
|
|
bactext_object_type_name(wp_data->object_type),
|
|
wp_data->object_instance,
|
|
bactext_property_name(wp_data->object_property), wp_data->priority);
|
|
} else {
|
|
for (i = 0; i < wp_data->application_data_len &&
|
|
(i * 2) < sizeof(value_string) - 1;
|
|
i++) {
|
|
snprintf(
|
|
&value_string[i * 2], 3, "%02X", wp_data->application_data[i]);
|
|
}
|
|
printf(
|
|
"WriteProperty: %s-%d to %s-%u %s@%u %s %s-%s\n",
|
|
bactext_object_type_name(object_type), instance,
|
|
bactext_object_type_name(wp_data->object_type),
|
|
wp_data->object_instance,
|
|
bactext_property_name(wp_data->object_property), wp_data->priority,
|
|
value_string, bactext_error_class_name(wp_data->error_class),
|
|
bactext_error_code_name(wp_data->error_code));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Log internal object to object WriteProperty calls
|
|
* @param instance The object instance being written to
|
|
* @param status The status of the WriteProperty
|
|
* @param wp_data The WriteProperty data
|
|
*/
|
|
static void channel_write_property_observer(
|
|
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|
{
|
|
write_property_observer(OBJECT_CHANNEL, instance, status, wp_data);
|
|
}
|
|
|
|
/**
|
|
* @brief Log internal object to object WriteProperty calls
|
|
* @param instance The object instance being written to
|
|
* @param status The status of the WriteProperty
|
|
* @param wp_data The WriteProperty data
|
|
*/
|
|
static void timer_write_property_observer(
|
|
uint32_t instance, bool status, BACNET_WRITE_PROPERTY_DATA *wp_data)
|
|
{
|
|
write_property_observer(OBJECT_TIMER, instance, status, wp_data);
|
|
}
|
|
|
|
/**
|
|
* @brief Callback for tracking value
|
|
* @param object_instance - object-instance number of the object
|
|
* @param old_value - Color temperature value prior to write
|
|
* @param value - Color temperature value of the write
|
|
*/
|
|
static void Lighting_Output_Write_Value_Handler(
|
|
uint32_t object_instance, float old_value, float value)
|
|
{
|
|
uint8_t index = 255;
|
|
uint8_t brightness;
|
|
|
|
(void)old_value;
|
|
if (object_instance > 0) {
|
|
index = object_instance - 1;
|
|
}
|
|
if (index < blinkt_led_count()) {
|
|
/* brightness intensity from 0..31, 0=OFF, 1=dimmest, 31=brightest */
|
|
if (isgreaterequal(value, 1.0)) {
|
|
brightness = linear_interpolate(1.0, value, 100.0, 1, 31);
|
|
} else {
|
|
brightness = 0;
|
|
}
|
|
blinkt_set_pixel_brightness(index, brightness);
|
|
printf(
|
|
"LED[%u]=%.1f%% (%u)\n", (unsigned)index, value,
|
|
(unsigned)brightness);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Callback for tracking value
|
|
* @param object_instance - object-instance number of the object
|
|
* @param old_value - Color temperature value prior to write
|
|
* @param value - Color temperature value of the write
|
|
*/
|
|
static void Color_Temperature_Write_Value_Handler(
|
|
uint32_t object_instance, uint32_t old_value, uint32_t value)
|
|
{
|
|
uint8_t red, green, blue;
|
|
uint8_t index = 255;
|
|
|
|
(void)old_value;
|
|
if (object_instance > 0) {
|
|
index = object_instance - 1;
|
|
}
|
|
if (index < blinkt_led_count()) {
|
|
color_rgb_from_temperature(value, &red, &green, &blue);
|
|
blinkt_set_pixel(index, red, green, blue);
|
|
printf(
|
|
"%u Kelvin RGB[%u]=%u,%u,%u\n", (unsigned)value, (unsigned)index,
|
|
(unsigned)red, (unsigned)green, (unsigned)blue);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Callback for tracking value
|
|
* @param object_instance - object-instance number of the object
|
|
* @param old_value - BACnetXYColor value prior to write
|
|
* @param value - BACnetXYColor value of the write
|
|
*/
|
|
static void Color_Write_Value_Handler(
|
|
uint32_t object_instance,
|
|
BACNET_XY_COLOR *old_value,
|
|
BACNET_XY_COLOR *value)
|
|
{
|
|
uint8_t red, green, blue;
|
|
float brightness_percent = 100.0;
|
|
uint8_t index = 255;
|
|
|
|
(void)old_value;
|
|
if (object_instance > 0) {
|
|
index = object_instance - 1;
|
|
}
|
|
if (index < blinkt_led_count()) {
|
|
color_rgb_from_xy(
|
|
&red, &green, &blue, value->x_coordinate, value->y_coordinate,
|
|
brightness_percent);
|
|
blinkt_set_pixel(index, red, green, blue);
|
|
printf(
|
|
"x,y=%0.2f,%0.2f(%.1f%%) RGB[%u]=%u,%u,%u\n", value->x_coordinate,
|
|
value->y_coordinate, brightness_percent, (unsigned)index,
|
|
(unsigned)red, (unsigned)green, (unsigned)blue);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Create the objects and configure the callbacks for BACnet objects
|
|
*/
|
|
static void BACnet_Object_Table_Init(void *context)
|
|
{
|
|
unsigned i = 0;
|
|
uint8_t led_max;
|
|
uint32_t object_instance = 0, member_element = 0;
|
|
BACNET_COLOR_COMMAND command = { 0 };
|
|
BACNET_OBJECT_ID object_id = { 0 };
|
|
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE member = { 0 };
|
|
BACNET_TIMER_STATE_CHANGE_VALUE timer_transition = { 0 };
|
|
|
|
(void)context;
|
|
Device_Set_Object_Instance_Number(Device_ID);
|
|
Device_Object_Name_ANSI_Init(Device_Name);
|
|
/* 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, Vacancy_Timeout_Milliseconds);
|
|
printf(
|
|
"Vacancy timeout: %lu milliseconds\n",
|
|
(unsigned long)Vacancy_Timeout_Milliseconds);
|
|
/* 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);
|
|
/* timer members */
|
|
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_ID;
|
|
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++) {
|
|
object_instance = 1 + i;
|
|
member_element = 1 + i;
|
|
/* color */
|
|
Color_Create(object_instance);
|
|
Color_Write_Enable(object_instance);
|
|
/* fade to black */
|
|
Color_Command(object_instance, &command);
|
|
command.operation = BACNET_COLOR_OPERATION_FADE_TO_COLOR;
|
|
command.target.color.x_coordinate = 0.0;
|
|
command.target.color.y_coordinate = 0.0;
|
|
command.transit.fade_time = 0;
|
|
Color_Command_Set(object_instance, &command);
|
|
|
|
/* configure channel members */
|
|
member.objectIdentifier.type = OBJECT_COLOR;
|
|
member.objectIdentifier.instance = object_instance;
|
|
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
|
member.arrayIndex = BACNET_ARRAY_ALL;
|
|
member.deviceIdentifier.type = OBJECT_DEVICE;
|
|
member.deviceIdentifier.instance = Device_ID;
|
|
Channel_Reference_List_Member_Element_Set(
|
|
Color_Channel_Instance, member_element, &member);
|
|
|
|
/* color temperature */
|
|
Color_Temperature_Create(object_instance);
|
|
Color_Temperature_Write_Enable(object_instance);
|
|
/* stop the color temperature */
|
|
Color_Temperature_Command(object_instance, &command);
|
|
command.operation = BACNET_COLOR_OPERATION_STOP;
|
|
Color_Temperature_Command_Set(object_instance, &command);
|
|
|
|
/* configure channel members */
|
|
member.objectIdentifier.type = OBJECT_COLOR_TEMPERATURE;
|
|
member.objectIdentifier.instance = object_instance;
|
|
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
|
member.arrayIndex = BACNET_ARRAY_ALL;
|
|
member.deviceIdentifier.type = OBJECT_DEVICE;
|
|
member.deviceIdentifier.instance = Device_ID;
|
|
Channel_Reference_List_Member_Element_Set(
|
|
CCT_Channel_Instance, member_element, &member);
|
|
|
|
/* lighting output */
|
|
Lighting_Output_Create(object_instance);
|
|
|
|
/* configure references */
|
|
object_id.type = OBJECT_COLOR;
|
|
object_id.instance = object_instance;
|
|
Lighting_Output_Color_Reference_Set(object_instance, &object_id);
|
|
|
|
/* configure channel members */
|
|
member.objectIdentifier.type = OBJECT_LIGHTING_OUTPUT;
|
|
member.objectIdentifier.instance = object_instance;
|
|
member.propertyIdentifier = PROP_PRESENT_VALUE;
|
|
member.arrayIndex = BACNET_ARRAY_ALL;
|
|
member.deviceIdentifier.type = OBJECT_DEVICE;
|
|
member.deviceIdentifier.instance = Device_ID;
|
|
Channel_Reference_List_Member_Element_Set(
|
|
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);
|
|
Lighting_Output_Write_Present_Value_Callback_Set(
|
|
Lighting_Output_Write_Value_Handler);
|
|
/* set the observer callbacks. log the internal object-to-object writes */
|
|
Channel_Write_Property_Observer.callback = channel_write_property_observer;
|
|
Channel_Write_Property_Notification_Add(&Channel_Write_Property_Observer);
|
|
Timer_Write_Property_Observer.callback = timer_write_property_observer;
|
|
Timer_Write_Property_Notification_Add(&Timer_Write_Property_Observer);
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Print the terse usage info
|
|
* @param filename - this application file name
|
|
*/
|
|
static void print_usage(const char *filename)
|
|
{
|
|
printf("Usage: %s [device-instance]\n", filename);
|
|
printf(" [--device N][--test][--color COLOR][--vacancy MS]\n");
|
|
printf(" [--version][--help]\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Print the verbose usage info
|
|
* @param filename - this application file name
|
|
*/
|
|
static void print_help(const char *filename)
|
|
{
|
|
printf("BACnet Blinkt! server device.\n");
|
|
printf("device-instance:\n"
|
|
"--device N:\n"
|
|
"BACnet Device Object Instance number of this device.\n"
|
|
"This number will be used when other devices\n"
|
|
"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("--vacancy:\n"
|
|
"Vacancy timeout in milliseconds.\n");
|
|
printf("\n");
|
|
printf("--test:\n"
|
|
"Test the Blinkt! RGB LEDs with a cycling pattern.\n");
|
|
printf("\n");
|
|
printf(
|
|
"Example:\n"
|
|
"%s 9009\n",
|
|
filename);
|
|
}
|
|
|
|
/** Main function of server demo.
|
|
* @param argc [in] Arg count.
|
|
* @param argv [in] Argument list.
|
|
* @return 0 on success.
|
|
*/
|
|
int main(int argc, char *argv[])
|
|
{
|
|
unsigned int target_args = 0;
|
|
uint32_t device_id = BACNET_MAX_INSTANCE, vacancy_timeout = 0;
|
|
int argi = 0;
|
|
const char *filename = NULL;
|
|
const char *color_name = "darkred";
|
|
|
|
filename = filename_remove_path(argv[0]);
|
|
for (argi = 1; argi < argc; argi++) {
|
|
if (strcmp(argv[argi], "--help") == 0) {
|
|
print_usage(filename);
|
|
print_help(filename);
|
|
return 0;
|
|
}
|
|
if (strcmp(argv[argi], "--version") == 0) {
|
|
printf("%s %s\n", filename, BACNET_VERSION_TEXT);
|
|
printf("Copyright (C) 2023 by Steve Karg and others.\n"
|
|
"This is free software; see the source for copying "
|
|
"conditions.\n"
|
|
"There is NO warranty; not even for MERCHANTABILITY or\n"
|
|
"FITNESS FOR A PARTICULAR PURPOSE.\n");
|
|
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) {
|
|
/* 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 (strcmp(argv[argi], "--vacancy") == 0) {
|
|
/* allow the device ID to be set */
|
|
if (++argi < argc) {
|
|
if (!bacnet_string_to_uint32(argv[argi], &vacancy_timeout)) {
|
|
fprintf(stderr, "vacancy=%s invalid\n", argv[argi]);
|
|
return 1;
|
|
}
|
|
Vacancy_Timeout_Milliseconds = vacancy_timeout;
|
|
}
|
|
} 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++;
|
|
}
|
|
}
|
|
}
|
|
/* hardware init */
|
|
blinkt_init();
|
|
atexit(blinkt_cleanup);
|
|
debug_printf_stdout("Blinkt! initialized\n");
|
|
/* application init */
|
|
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("BACnet initialized\n");
|
|
/* application info */
|
|
printf(
|
|
"BACnet Raspberry Pi Blinkt! Demo %s\n"
|
|
"BACnet Stack Version %s\n"
|
|
"BACnet Device ID: %u\n"
|
|
"Max APDU: %d\n",
|
|
Device_Application_Software_Version(), Device_Firmware_Revision(),
|
|
Device_Object_Instance_Number(), MAX_APDU);
|
|
/* operation */
|
|
BACnet_Object_Value_Init(color_name);
|
|
for (;;) {
|
|
bacnet_basic_task();
|
|
bacnet_port_task();
|
|
}
|
|
|
|
return 0;
|
|
}
|