BACnet …

BACNET Task erstellen…

Du bekommst den offiziellen BACnet/IP Stack von Steve Karg hier:

🔗 https://github.com/bacnet-stack/bacnet-stack

Hier ablegen:
/Middlewares/BACnet/bacnet-stack/
├── bacnet/ ← kompletter Inhalt aus GitHub
├── ports/embedded/ ← für embedded config (optional)
├── demo/ ← nicht notwendig, kann gelöscht werden

In deinem Build-Setup (STM32CubeIDE → Properties → C/C++ General → Includes):

Füge diese Include-Pfade hinzu:

Middlewares/BACnet/bacnet
Middlewares/BACnet/bacnet/basic
Middlewares/BACnet/bacnet/basic/sys
Middlewares/BACnet/bacnet/datalink
Middlewares/BACnet/bacnet/object
Middlewares/BACnet/bacnet/services


------------------------------------------------------------------
bacnet_task.c:
------------------------------------------------------------------
#include "bacnet_task.h"
#include "socket.h"
#include "wizchip_conf.h"
#include "w5500.h"
#include "bacnet/bacnet.h"
#include "bacnet/datalink/bip.h"
#include "bacnet/basic/sys/mstimer.h"
#include "bacnet/basic/sys/debug.h"
#include "cmsis_os.h"
#include <string.h>
#include "bacnet_config.h"

bacnet_config_init();

#define BACNET_PORT 47808
#define BACNET_BUFFER_SIZE 1476

static uint8_t bacnet_socket = 0;
static uint8_t bacnet_buf[BACNET_BUFFER_SIZE];
static BACNET_ADDRESS src;

void bacnet_task_init(void)
{
    // UDP-Socket für BACnet/IP öffnen (Port 47808)
    bacnet_socket = socket(1, Sn_MR_UDP, BACNET_PORT, 0);

    if (bacnet_socket != 1) {
        debug_printf("[BACnet] Fehler beim Öffnen des UDP-Sockets\n");
    } else {
        debug_printf("[BACnet] Socket geöffnet auf Port %u\n", BACNET_PORT);
    }

    // BACnet Stack initialisieren
    Device_Init(NULL);
    bip_init(NULL);
    mstimer_init();
    dlenv_init();
}

void StartBACnetTask(void *argument)
{
    bacnet_task_init();

    for(;;)
    {
        uint16_t len = getSn_RX_RSR(bacnet_socket);
        if (len > 0 && len < BACNET_BUFFER_SIZE) {
            int received = recvfrom(bacnet_socket, bacnet_buf, len, (uint8_t*)&src.mac, &src.port);
            if (received > 0) {
                npdu_handler(&src, bacnet_buf, received);
            }
        }

        // BACnet interne Timer verarbeiten
        mstimer_tick(10);
        osDelay(10);  // 10ms Taktung
    }
}
------------------------------------------------------------------
bacnet_task.h:
------------------------------------------------------------------
#ifndef __BACNET_TASK_H
#define __BACNET_TASK_H

#ifdef __cplusplus
extern "C" {
#endif

void StartBACnetTask(void *argument);

#ifdef __cplusplus
}
#endif

#endif // __BACNET_TASK_H
------------------------------------------------------------------
bacnet_config.h:
------------------------------------------------------------------
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/analogValue.h"
#include "bacnet/basic/object/analogInput.h"
#include "bacnet/basic/object/analogOutput.h"
#include "bacnet/basic/object/binaryOutput.h"
#include "bacnet/basic/object/binaryInput.h"
#include "bacnet/basic/object/multistateInput.h"
#include "bacnet/basic/services/handlers/h_rpm.h"
#include "bacnet/basic/sys/debug.h"
#include "stm32h7xx_hal.h"
#include "data_points.h"
#include <stdint.h>

// Beispielwerte (können per WriteProperty geändert werden)
static float analog_input_value[4] = {21.5, 22.0, 23.1, 24.3};
static float analog_output_value[1] = {0.0};
static float analog_value_value[1] = {50.0};
static BACNET_BINARY_PV binary_output_state[1] = {BINARY_INACTIVE};
static BACNET_BINARY_PV binary_input_state[1] = {BINARY_INACTIVE};
static uint32_t multistate_input_value[1] = {2};

// GPIO Mapping: z. B. PE15 als Ausgang für Binary Output 0
#define BO0_GPIO_PORT GPIOE
#define BO0_GPIO_PIN  GPIO_PIN_15
#define BI0_GPIO_PORT GPIOE
#define BI0_GPIO_PIN  GPIO_PIN_4

void bacnet_config_init(void)
{
    // Device-Objekt
    Device_Set_Object_Instance_Number(1234);
    Device_Object_Name_Set("STM32H7 BACnet Device", 24);
    Device_Vendor_Identifier_Set(123);

    // Analoge Eingänge
    Analog_Input_Init();
    Analog_Input_Instances_Set(4);
    Analog_Input_Name_Set(0, "Temp Sensor 1", 14);
    Analog_Input_Name_Set(1, "Temp Sensor 2", 14);
    Analog_Input_Name_Set(2, "Temp Sensor 3", 14);
    Analog_Input_Name_Set(3, "Temp Sensor 4", 14);
    for (unsigned i = 0; i < 4; i++) {
        Analog_Input_Present_Value_Set(i, analog_input_value[i]);
    }

    // Analoge Ausgänge
    Analog_Output_Init();
    Analog_Output_Instances_Set(1);
    Analog_Output_Present_Value_Set(0, analog_output_value[0]);
    Analog_Output_Name_Set(0, "Lüfterregelung", 16);

    // Analoge Werte
    Analog_Value_Init();
    Analog_Value_Instances_Set(1);
    Analog_Value_Present_Value_Set(0, analog_value_value[0]);
    Analog_Value_Name_Set(0, "Sollwert", 8);

    // Binary Output
    Binary_Output_Init();
    Binary_Output_Instances_Set(1);
    Binary_Output_Name_Set(0, "Ventil", 6);
    Binary_Output_Present_Value_Set(0, binary_output_state[0]);
    HAL_GPIO_WritePin(BO0_GPIO_PORT, BO0_GPIO_PIN, binary_output_state[0] == BINARY_ACTIVE ? GPIO_PIN_SET : GPIO_PIN_RESET);

    // Binary Input
    Binary_Input_Init();
    Binary_Input_Instances_Set(1);
    Binary_Input_Name_Set(0, "Schalter", 8);
    binary_input_state[0] = (HAL_GPIO_ReadPin(BI0_GPIO_PORT, BI0_GPIO_PIN) == GPIO_PIN_SET) ? BINARY_ACTIVE : BINARY_INACTIVE;
    Binary_Input_Present_Value_Set(0, binary_input_state[0]);

    // Multistate Input
    Multistate_Input_Init();
    Multistate_Input_Instances_Set(1);
    Multistate_Input_Name_Set(0, "Moduswahl", 10);
    Multistate_Input_Present_Value_Set(0, multistate_input_value[0]);
    Multistate_Input_Number_Of_States_Set(0, 3);

    // ReadPropertyMultiple aktivieren
    handler_read_property_multiple_init();

    // Abbildung für data_points
    datapoint_add_float("AI1", &analog_input_value[0], DP_READONLY);
    datapoint_add_float("AI2", &analog_input_value[1], DP_READONLY);
    datapoint_add_float("AO1", &analog_output_value[0], DP_RW);
    datapoint_add_float("AV1", &analog_value_value[0], DP_RW);
    datapoint_add_uint32("MSI1", &multistate_input_value[0], DP_RW);
    datapoint_add_bool("BO1", (bool*)&binary_output_state[0], DP_RW);
    datapoint_add_bool("BI1", (bool*)&binary_input_state[0], DP_READONLY);

    debug_printf("[BACnet] Device/Objekte konfiguriert\n");
}
------------------------------------------------------------------
data_points.c:
------------------------------------------------------------------
#include "data_points.h"
#include <string.h>
#include <stdbool.h>
#include <stdio.h>

#define MAX_DATAPOINTS 32

typedef struct {
    char name[16];
    void *ptr;
    datapoint_type_t type;
    datapoint_access_t access;
} datapoint_entry_t;

static datapoint_entry_t dp_list[MAX_DATAPOINTS];
static uint8_t dp_count = 0;

bool datapoint_add_float(const char *name, float *ptr, datapoint_access_t access)
{
    if (dp_count >= MAX_DATAPOINTS) return false;
    strncpy(dp_list[dp_count].name, name, sizeof(dp_list[dp_count].name)-1);
    dp_list[dp_count].ptr = ptr;
    dp_list[dp_count].type = DP_FLOAT;
    dp_list[dp_count].access = access;
    dp_count++;
    return true;
}

bool datapoint_add_bool(const char *name, bool *ptr, datapoint_access_t access)
{
    if (dp_count >= MAX_DATAPOINTS) return false;
    strncpy(dp_list[dp_count].name, name, sizeof(dp_list[dp_count].name)-1);
    dp_list[dp_count].ptr = ptr;
    dp_list[dp_count].type = DP_BOOL;
    dp_list[dp_count].access = access;
    dp_count++;
    return true;
}

bool datapoint_add_uint32(const char *name, uint32_t *ptr, datapoint_access_t access)
{
    if (dp_count >= MAX_DATAPOINTS) return false;
    strncpy(dp_list[dp_count].name, name, sizeof(dp_list[dp_count].name)-1);
    dp_list[dp_count].ptr = ptr;
    dp_list[dp_count].type = DP_UINT32;
    dp_list[dp_count].access = access;
    dp_count++;
    return true;
}

void datapoint_list_all(void)
{
    for (uint8_t i = 0; i < dp_count; i++) {
        printf("%s = ", dp_list[i].name);
        switch (dp_list[i].type) {
            case DP_FLOAT:
                printf("%.2f", *((float*)dp_list[i].ptr));
                break;
            case DP_BOOL:
                printf("%s", *((bool*)dp_list[i].ptr) ? "true" : "false");
                break;
            case DP_UINT32:
                printf("%lu", *((uint32_t*)dp_list[i].ptr));
                break;
        }
        printf(" (%s)\n", dp_list[i].access == DP_RW ? "rw" : "ro");
    }
}

bool datapoint_set_value(const char *name, const char *value)
{
    for (uint8_t i = 0; i < dp_count; i++) {
        if (strcmp(dp_list[i].name, name) == 0 && dp_list[i].access == DP_RW) {
            switch (dp_list[i].type) {
                case DP_FLOAT:
                    *((float*)dp_list[i].ptr) = atof(value);
                    return true;
                case DP_BOOL:
                    *((bool*)dp_list[i].ptr) = (strcmp(value, "1") == 0 || strcmp(value, "true") == 0);
                    return true;
                case DP_UINT32:
                    *((uint32_t*)dp_list[i].ptr) = strtoul(value, NULL, 10);
                    return true;
            }
        }
    }
    return false;
}
------------------------------------------------------------------
data_points.h:
------------------------------------------------------------------
#ifndef __DATA_POINTS_H
#define __DATA_POINTS_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
    DP_FLOAT,
    DP_BOOL,
    DP_UINT32
} datapoint_type_t;

typedef enum {
    DP_READONLY,
    DP_RW
} datapoint_access_t;

// Registrierung
bool datapoint_add_float(const char *name, float *ptr, datapoint_access_t access);
bool datapoint_add_bool(const char *name, bool *ptr, datapoint_access_t access);
bool datapoint_add_uint32(const char *name, uint32_t *ptr, datapoint_access_t access);

// Zugriff
void datapoint_list_all(void);
bool datapoint_set_value(const char *name, const char *value);

#ifdef __cplusplus
}
#endif

#endif // __DATA_POINTS_H

Tags:

Comments

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Search


Categories


Recent Posts


Tags