Skip to content

Instantly share code, notes, and snippets.

@bbartling
Created February 18, 2025 20:18
Show Gist options
  • Save bbartling/334b01026dcf74f78ab60f1d914f76d2 to your computer and use it in GitHub Desktop.
Save bbartling/334b01026dcf74f78ab60f1d914f76d2 to your computer and use it in GitHub Desktop.
Minimal BACnet Server Attempt
#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;
}
@bbartling
Copy link
Author

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;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment