-
-
Save bbartling/334b01026dcf74f78ab60f1d914f76d2 to your computer and use it in GitHub Desktop.
#include <stddef.h> | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/* BACnet Stack includes */ | |
#include "bacnet/bacdef.h" | |
#include "bacnet/apdu.h" | |
#include "bacnet/bacdcode.h" | |
#include "bacnet/bactext.h" | |
#include "bacnet/dcc.h" | |
#include "bacnet/getevent.h" | |
#include "bacnet/iam.h" | |
#include "bacnet/npdu.h" | |
#include "bacnet/version.h" | |
#include "bacnet/datalink/datalink.h" | |
#include "bacnet/datalink/dlenv.h" | |
#include "bacnet/basic/binding/address.h" | |
#include "bacnet/basic/object/device.h" | |
#include "bacnet/basic/object/ai.h" | |
#include "bacnet/basic/object/bv.h" | |
#include "bacnet/bacstr.h" | |
#include "bacnet/basic/services.h" | |
#include "bacnet/basic/service/h_whois.h" | |
#include "bacnet/basic/service/h_rp.h" | |
#include "bacnet/basic/service/h_wp.h" | |
#include "bacnet/basic/service/h_apdu.h" | |
#include "bacnet/basic/service/s_iam.h" | |
/* Buffers */ | |
static uint8_t Rx_Buf[MAX_MPDU] = {0}; | |
/** | |
* @brief Initializes the BACnet objects (AI-0 and BV-0). | |
*/ | |
static void Init_Service_Handlers(void) | |
{ | |
BACNET_CHARACTER_STRING ai_name, bv_name; | |
/* Initialize device and objects */ | |
Device_Init(NULL); | |
Analog_Input_Init(); | |
Binary_Value_Init(); | |
/* Create Analog Input 0 */ | |
Analog_Input_Create(0); | |
Analog_Input_Present_Value_Set(0, 25.5); | |
characterstring_init_ansi(&ai_name, "Room Temperature"); | |
Analog_Input_Object_Name(0, &ai_name); | |
printf("Created Analog Input AI-0: Room Temperature\n"); | |
/* Create Binary Value 0 */ | |
Binary_Value_Create(0); | |
Binary_Value_Present_Value_Set(0, 0); | |
characterstring_init_ansi(&bv_name, "Fan Control Relay"); | |
Binary_Value_Object_Name(0, &bv_name); | |
printf("Created Binary Value BV-0: Fan Control Relay\n"); | |
printf("Testing 123 \n"); | |
/* Configure required BACnet service handlers */ | |
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is); | |
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property); | |
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property); | |
} | |
/** | |
* @brief Main entry point for the BACnet server. | |
*/ | |
int main() | |
{ | |
BACNET_ADDRESS src = {0}; /* Source address */ | |
uint16_t pdu_len = 0; | |
unsigned timeout = 1000; /* 1 second */ | |
printf("Starting Minimal BACnet Server...\n"); | |
/* Initialize BACnet stack */ | |
dlenv_init(); | |
Init_Service_Handlers(); | |
atexit(datalink_cleanup); | |
/* Announce device */ | |
Send_I_Am(&Rx_Buf[0]); | |
/* Main loop */ | |
for (;;) | |
{ | |
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); | |
if (pdu_len) | |
{ | |
npdu_handler(&src, &Rx_Buf[0], pdu_len); | |
} | |
} | |
return 0; | |
} | |
oh cool thanks so much @nazaryev-cool . This works below. Would you have any advice how to make commandable BACnet or writeable points? Thanks again!
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* BACnet Stack includes */
#include "bacnet/bacdef.h"
#include "bacnet/apdu.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bactext.h"
#include "bacnet/dcc.h"
#include "bacnet/getevent.h"
#include "bacnet/iam.h"
#include "bacnet/npdu.h"
#include "bacnet/version.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/datalink/dlenv.h"
#include "bacnet/basic/binding/address.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/ai.h"
#include "bacnet/basic/object/bv.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/service/h_whois.h"
#include "bacnet/basic/service/h_rp.h"
#include "bacnet/basic/service/h_wp.h"
#include "bacnet/basic/service/h_apdu.h"
#include "bacnet/basic/service/s_iam.h"
/* Buffers */
static uint8_t Rx_Buf[MAX_MPDU] = {0};
/* Custom Object Table */
static object_functions_t My_Object_Table[] = {
{ OBJECT_DEVICE, NULL /* Init - don't init Device or it will recurse! */,
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number, Device_Object_Name,
Device_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists, DeviceGetRRInfo, NULL /* Iterator */,
NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */,
NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */,
NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */,
NULL /* Timer */ },
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
Analog_Input_Object_Name, Analog_Input_Read_Property,
Analog_Input_Write_Property, Analog_Input_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Analog_Input_Encode_Value_List, Analog_Input_Change_Of_Value,
Analog_Input_Change_Of_Value_Clear, Analog_Input_Intrinsic_Reporting,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Analog_Input_Create, Analog_Input_Delete, NULL /* Timer */ },
{ OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
Binary_Value_Object_Name, Binary_Value_Read_Property,
Binary_Value_Write_Property, Binary_Value_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Binary_Value_Encode_Value_List, Binary_Value_Change_Of_Value,
Binary_Value_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Binary_Value_Create, Binary_Value_Delete, NULL /* Timer */ },
{ MAX_BACNET_OBJECT_TYPE, NULL /* End of list marker */ }
};
/**
* @brief Initializes the BACnet objects (AI-0 and BV-0).
*/
static void Init_Service_Handlers(void)
{
BACNET_CHARACTER_STRING ai_name, bv_name;
/* Initialize device and objects */
Device_Init(My_Object_Table);
/* Create Analog Input 0 */
Analog_Input_Create(0);
Analog_Input_Present_Value_Set(0, 25.5);
characterstring_init_ansi(&ai_name, "Room Temperature");
Analog_Input_Object_Name(0, &ai_name);
printf("Created Analog Input AI-0: Room Temperature\n");
/* Create Binary Value 0 */
Binary_Value_Create(0);
Binary_Value_Present_Value_Set(0, 0);
characterstring_init_ansi(&bv_name, "Fan Control Relay");
Binary_Value_Object_Name(0, &bv_name);
printf("Created Binary Value BV-0: Fan Control Relay\n");
/* Configure required BACnet service handlers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
}
/**
* @brief Main entry point for the BACnet server.
*/
int main()
{
BACNET_ADDRESS src = {0}; /* Source address */
uint16_t pdu_len = 0;
unsigned timeout = 1000; /* 1 second */
printf("Starting Minimal BACnet Server...\n");
/* Initialize BACnet stack */
dlenv_init();
Init_Service_Handlers();
atexit(datalink_cleanup);
/* Announce device */
Send_I_Am(&Rx_Buf[0]);
/* Main loop */
for (;;)
{
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
if (pdu_len)
{
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
}
return 0;
}
Also what ever I am doing in the
static void Init_Service_Handlers(void)
{
BACNET_CHARACTER_STRING ai_name, bv_name;
/* Initialize device and objects */
Device_Init(My_Object_Table);
/* Create Analog Input 0 */
Analog_Input_Create(0);
Analog_Input_Present_Value_Set(0, 25.5);
characterstring_init_ansi(&ai_name, "Room Temperature");
Analog_Input_Object_Name(0, &ai_name);
printf("Created Analog Input AI-0: Room Temperature\n");
/* Create Binary Value 0 */
Binary_Value_Create(0);
Binary_Value_Present_Value_Set(0, 0);
characterstring_init_ansi(&bv_name, "Fan Control Relay");
Binary_Value_Object_Name(0, &bv_name);
printf("Created Binary Value BV-0: Fan Control Relay\n");
/* Configure required BACnet service handlers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
}
doesnt appear to work for manually defining my Room Temperature
AI point and my Fan Control Relay
BV being a SERVICE_CONFIRMED_WRITE_PROPERTY
any tips greatly appreciated @nazaryev-cool
Unfortunately, there is no way to easily make any object commandable: in case if provided object type implementation (e.g. bv.c) doesn't support "commandability" (=no priority_array & relinquish_default properties are exposed and processed properly), you need to dive into the code and implement it by yourself in your version of bv.c or patch the existing code in the library. That's why I called them templates/samples and not real/production-ready object type implementations.
Some of object type implementations support being commandable, and you can "port" this feature to object type implementation that you want to make commandable; just look at src/bacnet/basic/object/*.c and search for object types with Priority_Array in them. The same applies to "writability" feature, even though it's much easier to implement or port from another object type. You can find xxx_Write_Enable
(e.g. Binary_Value_Write_Enable
), port it to another object type if needed and use it to make it writable.
Luckily for you, I've done this before, and you can use these patches for bv.c:
https://github.com/bacnet-stack/bacnet-stack/commit/11acd50badbc272afe32f5c72c3e3b7ba9e37227.patch
https://github.com/bacnet-stack/bacnet-stack/commit/13368f4b31f487c59c57be6ca54ff276c94991af.patch
doesnt appear to work for manually defining my Room Temperature AI point
Try to use this as a sample:
uint32_t room_temp_obj_instance = Analog_Input_Create(0);
Analog_Input_Name_Set(room_temp_obj_instance, "Room temperature");
Analog_Input_Units_Set(room_temp_obj_instance, UNITS_DEGREES_CELSIUS);
Analog_Input_Present_Value_Set(room_temp_obj_instance, 24.2f);
Unfortunately, there is no way to easily make any object commandable: in case if provided object type implementation (e.g. bv.c) doesn't support "commandability" (=no priority_array & relinquish_default properties are exposed and processed properly), you need to dive into the code and implement it by yourself in your version of bv.c or patch the existing code in the library. That's why I called them templates/samples and not real/production-ready object type implementations.
Some of object type implementations support being commandable, and you can "port" this feature to object type implementation that you want to make commandable; just look at src/bacnet/basic/object/*.c and search for object types with Priority_Array in them. The same applies to "writability" feature, even though it's much easier to implement or port from another object type. You can find
xxx_Write_Enable
(e.g.Binary_Value_Write_Enable
), port it to another object type if needed and use it to make it writable.Luckily for you, I've done this before, and you can use these patches for bv.c: https://github.com/bacnet-stack/bacnet-stack/commit/11acd50badbc272afe32f5c72c3e3b7ba9e37227.patch https://github.com/bacnet-stack/bacnet-stack/commit/13368f4b31f487c59c57be6ca54ff276c94991af.patch
Hi @nazaryev-cool can you reiterate that again? Are those patches applied to the Steve's repository? If it is not then I need to modify the stack myself...?
Sorry for being such a newbie but I think this would be the complete file from your patches links which I could just copy paste over the bv.c
my repo clone, right?
https://github.com/bacnet-stack/bacnet-stack/blob/13368f4b31f487c59c57be6ca54ff276c94991af/src/bacnet/basic/object/bv.c
And then in my app just modify like:
static void Init_Service_Handlers(void)
{
BACNET_CHARACTER_STRING ai_name, bv_name;
/* Initialize device and objects */
Device_Init(My_Object_Table);
/* Create Analog Input 0 */
uint32_t room_temp_obj_instance = Analog_Input_Create(0);
Analog_Input_Name_Set(room_temp_obj_instance, "Room Temperature");
Analog_Input_Units_Set(room_temp_obj_instance, UNITS_DEGREES_CELSIUS);
Analog_Input_Present_Value_Set(room_temp_obj_instance, 24.2f);
printf("Created Analog Input AI-0: Room Temperature\n");
/* Create Binary Value 0 (Fan Control Relay) */
uint32_t fan_control_obj_instance = Binary_Value_Create(0);
Binary_Value_Name_Set(fan_control_obj_instance, "Fan Control Relay");
/* Set default behavior */
Binary_Value_Relinquish_Default_Set(fan_control_obj_instance, BINARY_INACTIVE); /* Default to inactive */
Binary_Value_Out_Of_Service_Set(fan_control_obj_instance, true); /* Allow writing */
Binary_Value_Write_Enable(fan_control_obj_instance); /* Ensure writing is allowed */
printf("Created Binary Value BV-0: Fan Control Relay (Commandable)\n");
/* Configure required BACnet service handlers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
}
Thank you for your time in response!
Are those patches applied to the Steve's repository?
No, these patches are not applied, they are from my fork. In my opinion, as there is no way to manage in runtime is this specific binary-value object should be commandable or not, it's not good enough to be accepted to upstream. Not everyone wants to have commandable binary-value objects, so it's up to us, developers, to modify the code and make them fit our needs :)
If it is not then I need to modify the stack myself...?
Yes, you need to apply these patches by yourself by using git am
or patch -p1
in the terminal or some GUI tool that works with git.
I could just copy paste over the bv.c my repo clone
Yes, you can also take final version of bv.c from the link. After that there are at least two options:
- replace original bv.c, recompile bacnet-stack, use the code you sent in your last message and it should work
- copy bv.c to your project instead and make some magic with CMakeLists to use/compile your version of bv.c and not the original one from bacnet-stack
P.S. You don't need to make object out-of-service to make it writable, just Write_Enable should be enough.
I also suggest you to add apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
to quickly answer to other BACnet devices that you don't support anything but ReadProperty & WriteProperty. Otherwise, for example, YABE will try to do ReadPropertyMultiple with your device, won't receive an answer and will try it again several times before finally fallback to ReadProperty mode.
Yes thanks for the tip on the out-of-service. I may start this process over with your fork : )
To me that seems odd why the bacnet stack doesn't have that feature for commandable points out of the box. To me it makes sense not to have for an AI, BI or hardware inputs by why not BV?
From: Steve Karg
Sent: Tuesday, August 22, 2023 12:32 PM
To: Discussion for developers of the BACnet stack
Subject: Re: [Bacnet-developers] relinquish-default, priority-arrayHello Andreas,
The debate about priority-array in Value objects has been around since the inception of the BACnet standard (so I've been told). After lots of discussion in the BACnet committee related to HOA (hand-off-auto) in Input/Output/Value objects, I am convinced that there should not be a priority-array in value objects. If a priority-array (commandability) is needed, there exist output objects for that specific purpose, and therefore, I don't encourage using priority-array in the value objects in the examples in the library. That doesn't preclude someone from doing that - the examples are just that - examples.
In 2017, David Fisher proposed a Prioritization object (DMF-083). "While various object types support the concept of commandability, there is no standard mechanism for synchronizing access to non-commandable object types, or non-Present_Value properties." After working its way through working groups, in 2022 it was voted by SSPC for inclusion in a future addendum (subject to public review); not sure when it will become part of the BACnet standard.
Best Regards,
Steve
Okay so this works... I recompiled with your fork.
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* BACnet Stack includes */
#include "bacnet/bacdef.h"
#include "bacnet/apdu.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bactext.h"
#include "bacnet/dcc.h"
#include "bacnet/getevent.h"
#include "bacnet/iam.h"
#include "bacnet/npdu.h"
#include "bacnet/version.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/datalink/dlenv.h"
#include "bacnet/basic/binding/address.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/ai.h"
#include "bacnet/basic/object/bv.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/service/h_whois.h"
#include "bacnet/basic/service/h_rp.h"
#include "bacnet/basic/service/h_wp.h"
#include "bacnet/basic/service/h_apdu.h"
#include "bacnet/basic/service/s_iam.h"
/* Buffers */
static uint8_t Rx_Buf[MAX_MPDU] = {0};
/* Custom Object Table */
static object_functions_t My_Object_Table[] = {
{ OBJECT_DEVICE, NULL /* Init - don't init Device or it will recurse! */,
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number, Device_Object_Name,
Device_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists, DeviceGetRRInfo, NULL /* Iterator */,
NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */,
NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */,
NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */,
NULL /* Timer */ },
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
Analog_Input_Object_Name, Analog_Input_Read_Property,
Analog_Input_Write_Property, Analog_Input_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Analog_Input_Encode_Value_List, Analog_Input_Change_Of_Value,
Analog_Input_Change_Of_Value_Clear, Analog_Input_Intrinsic_Reporting,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Analog_Input_Create, Analog_Input_Delete, NULL /* Timer */ },
{ OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
Binary_Value_Object_Name, Binary_Value_Read_Property,
Binary_Value_Write_Property, Binary_Value_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Binary_Value_Encode_Value_List, Binary_Value_Change_Of_Value,
Binary_Value_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Binary_Value_Create, Binary_Value_Delete, NULL /* Timer */ },
{ MAX_BACNET_OBJECT_TYPE, NULL /* End of list marker */ }
};
/**
* @brief Initializes the BACnet objects (AI-0 and BV-0).
*/
static void Init_Service_Handlers(void)
{
BACNET_CHARACTER_STRING ai_name, bv_name;
/* Initialize device and objects */
Device_Init(My_Object_Table);
/* Create Analog Input 0 */
uint32_t room_temp_obj_instance = Analog_Input_Create(0);
Analog_Input_Name_Set(room_temp_obj_instance, "Room Temperature");
Analog_Input_Units_Set(room_temp_obj_instance, UNITS_DEGREES_CELSIUS);
Analog_Input_Present_Value_Set(room_temp_obj_instance, 24.2f);
printf("Created Analog Input AI-0: Room Temperature\n");
/* Create Binary Value 0 (Fan Control Relay) */
uint32_t fan_control_obj_instance = Binary_Value_Create(0);
Binary_Value_Name_Set(fan_control_obj_instance, "Fan Control Relay");
printf("Created Binary Value BV-0: Fan Control Relay\n");
/* Configure required BACnet service handlers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
}
/**
* @brief Main entry point for the BACnet server.
*/
int main()
{
BACNET_ADDRESS src = {0}; /* Source address */
uint16_t pdu_len = 0;
unsigned timeout = 1000; /* 1 second */
printf("Starting Minimal BACnet Server...\n");
/* Initialize BACnet stack */
dlenv_init();
Init_Service_Handlers();
atexit(datalink_cleanup);
/* Announce device */
Send_I_Am(&Rx_Buf[0]);
/* Main loop */
for (;;)
{
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
if (pdu_len)
{
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
}
return 0;
}
Is it possible @nazaryev-cool to reiterate once more on commandable points in the bacnet-stack? I know BV being commandable is a custom feature of your fork ... If you had the time could you bullet point out some steps wheater its an AO, AV, BV, BO one creating an additional point and making it writeable/commandable? Thank you so much for just getting me here : )
Priority arr not working but there is a server app with 2 AVs one writeable and one BV.
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* BACnet Stack includes */
#include "bacnet/bacdef.h"
#include "bacnet/apdu.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bactext.h"
#include "bacnet/dcc.h"
#include "bacnet/getevent.h"
#include "bacnet/iam.h"
#include "bacnet/npdu.h"
#include "bacnet/version.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/datalink/dlenv.h"
#include "bacnet/basic/binding/address.h"
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/ai.h"
#include "bacnet/basic/object/av.h"
#include "bacnet/basic/object/bv.h"
#include "bacnet/basic/services.h"
#include "bacnet/basic/service/h_whois.h"
#include "bacnet/basic/service/h_rp.h"
#include "bacnet/basic/service/h_wp.h"
#include "bacnet/basic/service/h_apdu.h"
#include "bacnet/basic/service/s_iam.h"
/* Buffers */
static uint8_t Rx_Buf[MAX_MPDU] = {0};
/* Custom Object Table */
static object_functions_t My_Object_Table[] = {
{ OBJECT_DEVICE, NULL /* Init - don't init Device or it will recurse! */,
Device_Count, Device_Index_To_Instance,
Device_Valid_Object_Instance_Number, Device_Object_Name,
Device_Read_Property_Local, Device_Write_Property_Local,
Device_Property_Lists, DeviceGetRRInfo, NULL /* Iterator */,
NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */,
NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */,
NULL /* Remove_List_Element */, NULL /* Create */, NULL /* Delete */,
NULL /* Timer */ },
{ OBJECT_ANALOG_INPUT, Analog_Input_Init, Analog_Input_Count,
Analog_Input_Index_To_Instance, Analog_Input_Valid_Instance,
Analog_Input_Object_Name, Analog_Input_Read_Property,
Analog_Input_Write_Property, Analog_Input_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Analog_Input_Encode_Value_List, Analog_Input_Change_Of_Value,
Analog_Input_Change_Of_Value_Clear, Analog_Input_Intrinsic_Reporting,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Analog_Input_Create, Analog_Input_Delete, NULL /* Timer */ },
{ OBJECT_ANALOG_VALUE, Analog_Value_Init, Analog_Value_Count,
Analog_Value_Index_To_Instance, Analog_Value_Valid_Instance,
Analog_Value_Object_Name, Analog_Value_Read_Property,
Analog_Value_Write_Property, Analog_Value_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Analog_Value_Encode_Value_List, NULL /* COV */, NULL /* COV Clear */,
NULL /* Intrinsic Reporting */, NULL /* Add_List_Element */,
NULL /* Remove_List_Element */, Analog_Value_Create, Analog_Value_Delete, NULL /* Timer */ },
{ OBJECT_BINARY_VALUE, Binary_Value_Init, Binary_Value_Count,
Binary_Value_Index_To_Instance, Binary_Value_Valid_Instance,
Binary_Value_Object_Name, Binary_Value_Read_Property,
Binary_Value_Write_Property, Binary_Value_Property_Lists,
NULL /* ReadRangeInfo */, NULL /* Iterator */,
Binary_Value_Encode_Value_List, Binary_Value_Change_Of_Value,
Binary_Value_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */,
NULL /* Add_List_Element */, NULL /* Remove_List_Element */,
Binary_Value_Create, Binary_Value_Delete, NULL /* Timer */ },
{ MAX_BACNET_OBJECT_TYPE, NULL /* End of list marker */ }
};
/**
* @brief Initializes the BACnet objects (AI-0, AV-0, and BV-0).
*/
static void Init_Service_Handlers(void)
{
BACNET_CHARACTER_STRING ai_name, av_name, bv_name;
/* Initialize device and objects */
Device_Init(My_Object_Table);
/* Create Analog Input 0 (Read-Only) */
uint32_t room_temp_obj_instance = Analog_Input_Create(0);
Analog_Input_Name_Set(room_temp_obj_instance, "Room Temperature");
Analog_Input_Units_Set(room_temp_obj_instance, UNITS_DEGREES_CELSIUS);
Analog_Input_Present_Value_Set(room_temp_obj_instance, 24.2f);
printf("Created Analog Input AI-0: Room Temperature\n");
/* Create Analog Value 0 (Commandable Setpoint) */
uint32_t setpoint_obj_instance = Analog_Value_Create(0);
Analog_Value_Name_Set(setpoint_obj_instance, "Commandable Setpoint");
Analog_Value_Units_Set(setpoint_obj_instance, UNITS_DEGREES_CELSIUS);
Analog_Value_Present_Value_Set(setpoint_obj_instance, 22.5, 8); // Priority 8
printf("Created Analog Value AV-0: Commandable Setpoint\n");
/* Create Binary Value 0 (Fan Control Relay) */
uint32_t fan_control_obj_instance = Binary_Value_Create(0);
Binary_Value_Name_Set(fan_control_obj_instance, "Fan Control Relay");
printf("Created Binary Value BV-0: Fan Control Relay\n");
/* Configure required BACnet service handlers */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY, handler_write_property);
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
}
/**
* @brief Main entry point for the BACnet server.
*/
int main()
{
BACNET_ADDRESS src = {0}; /* Source address */
uint16_t pdu_len = 0;
unsigned timeout = 1000; /* 1 second */
printf("Starting Minimal BACnet Server...\n");
/* Initialize BACnet stack */
dlenv_init();
Init_Service_Handlers();
atexit(datalink_cleanup);
/* Announce device */
Send_I_Am(&Rx_Buf[0]);
/* Main loop */
for (;;)
{
pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout);
if (pdu_len)
{
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
}
return 0;
}
Hi! I saw your message on the mailing list.
You have this issue because you're using default object table defined in
bacnet-stack/src/bacnet/basic/object/device.c
. In this table there are "init" functions for all supported object types by the stack. Some object type implementations provide you with functions to dynamically allocate objects (e.g. Binary_Value_Create or Analog_Value_Create), but some of implementations statically allocate some amount of objects of their type. For example, Schedule Object Type statically allocates 4 (MAX_SCHEDULES) objects duringSchedule_Init
, and you'll see them in the object list.So, if you want to get rid of them, you should copy an object table from
bacnet-stack/src/bacnet/basic/object/device.c
to your code, remove all object types that you don't want to work with as a "server", pass your object table pointer to Device_Init() (and remove your Analog_Input_Init and Binary_Value_Init function calls), and in such case no init functions from unused object type implementations would be executed -> no redundant/unwanted objects would be created in the object list.Moreover, you should treat these object type implementations (ai.c or bv.c) as examples or templates and not as production-ready functions. That's why you likely need to copy them to your code, get rid of redundant properties or add missing ones and glue them with your application, and fill your object table with your own handlers for each object type.