From bedd7469d46cc12ed8a1e042ef33caea41813ea6 Mon Sep 17 00:00:00 2001 From: Sho Date: Sun, 14 Dec 2025 17:31:56 +0000 Subject: [PATCH] Support for Issue-137, Issue-138 with new initialization, Issue-139 --- .github/workflows/docker-build-release.yml | 2 +- CHANGELOG.md | 11 + VERSION | 2 +- bacnet-stack/apps/server/main.c | 5 +- bacnet-stack/apps/server/mqtt_client.c | 18 +- bacnet-stack/apps/server/yaml_config.c | 192 +++++++++++++++++- bacnet-stack/apps/server/yaml_config.h | 20 ++ bacnet-stack/ports/linux/bip-init.c | 133 +++++++++++- bacnet-stack/src/bacnet/basic/object/ai.c | 48 +++-- bacnet-stack/src/bacnet/basic/object/ao.c | 51 +++-- bacnet-stack/src/bacnet/basic/object/av.c | 51 +++-- bacnet-stack/src/bacnet/basic/object/bi.c | 47 +++-- bacnet-stack/src/bacnet/basic/object/bo.c | 47 +++-- bacnet-stack/src/bacnet/basic/object/bv.c | 47 +++-- bacnet-stack/src/bacnet/basic/object/device.c | 2 + bacnet-stack/src/bacnet/basic/service/s_rp.c | 3 + 16 files changed, 554 insertions(+), 125 deletions(-) diff --git a/.github/workflows/docker-build-release.yml b/.github/workflows/docker-build-release.yml index d9caa7a..5fa9295 100644 --- a/.github/workflows/docker-build-release.yml +++ b/.github/workflows/docker-build-release.yml @@ -101,7 +101,7 @@ jobs: - uses: actions/checkout@v3 - name: Cache Docker layers - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: /home/runner/docker key: ${{ runner.os }}-docker-${{ github.sha }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9485b4d..4e538e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # CHANGELOG +## [v1.0.3-rc.2](https://github.com/NubeIO/driver-bacnet/tree/v1.0.3-rc.2) (2025-12-15) +- Issue-138: Initial object instances based on the points from the config file +- Prerequisites: + - ROS >= 1.0.0 + +## [v1.0.3-rc.1](https://github.com/NubeIO/driver-bacnet/tree/v1.0.3-rc.1) (2025-08-28) +- Issue-137: Remove Multi-state points; Add an error message when the request resulted an error +- Issue-138: Support for points list in the config file +- Issue-139: Support for binding to specific IP address/interface +- Prerequisites: + - ROS >= 1.0.0 ## [v1.0.2](https://github.com/NubeIO/driver-bacnet/tree/v1.0.2) (2024-11-08) - Fixed device ID returned from reading property list. diff --git a/VERSION b/VERSION index 53ebb0f..11c7fbd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.2-rc.4 +1.0.3-rc.2 diff --git a/bacnet-stack/apps/server/main.c b/bacnet-stack/apps/server/main.c index 32eeb3e..3ca4c01 100644 --- a/bacnet-stack/apps/server/main.c +++ b/bacnet-stack/apps/server/main.c @@ -291,7 +291,10 @@ int main(int argc, char *argv[]) #endif /* defined(BAC_UCI) */ #if defined(YAML_CONFIG) - yaml_config_init(); + if (yaml_config_init()) { + return 1; + } + val_uint32 = strtoul(yaml_config_service_id(), NULL, 10); if (val_uint32 > 0) { Device_Set_Object_Instance_Number(val_uint32); diff --git a/bacnet-stack/apps/server/mqtt_client.c b/bacnet-stack/apps/server/mqtt_client.c index f9cd817..da8dc70 100644 --- a/bacnet-stack/apps/server/mqtt_client.c +++ b/bacnet-stack/apps/server/mqtt_client.c @@ -1436,6 +1436,10 @@ int process_bacnet_client_whois_command(bacnet_client_cmd_opts *opts) } } + if (mqtt_debug) { + printf("global_broadcast: %d\n", global_broadcast); + } + if (global_broadcast) { datalink_get_broadcast_address(&dest); } else { @@ -1493,6 +1497,13 @@ int process_bacnet_client_whois_command(bacnet_client_cmd_opts *opts) add_bacnet_client_whois(&dest, opts); + if (mqtt_debug) { + printf("Sending WHOIS to: %u.%u.%u.%u %02X%02X\n", (unsigned)dest.mac[0], + (unsigned)dest.mac[1], (unsigned)dest.mac[2], + (unsigned)dest.mac[3], (unsigned)dest.mac[4], + (unsigned)dest.mac[5]); + } + Send_WhoIs_To_Network( &dest, opts->device_instance_min, opts->device_instance_max); @@ -3990,6 +4001,11 @@ static void bacnet_client_error_handler(BACNET_ADDRESS *src, if (!tmp->data.obj_data.dont_publish_on_success) { init_cmd_opts_from_list_cb(&opts, &tmp->data.obj_data); sprintf(err_msg, "%s", bactext_error_code_name((int)error_code)); + if ((!strcasecmp(err_msg, "unknown-object")) && + tmp->data.obj_data.topic_id == MQTT_WRITE_VALUE_CMD_RESULT_TOPIC) { + sprintf(err_msg, "failed to write"); + } + mqtt_publish_command_error(err_msg, &opts, tmp->data.obj_data.topic_id); } @@ -4691,7 +4707,7 @@ int mqtt_publish_command_error(char *err_msg, bacnet_client_cmd_opts *opts, int mqtt_opts.onFailure = mqtt_on_send_failure; mqtt_opts.context = mqtt_client; - snprintf(topic_value, sizeof(topic_value), "{ \"error\" : \"%s\" ", err_msg); + snprintf(topic_value, sizeof(topic_value), "{ \"fault\" : \"true\", \"error\" : \"%s\" ", err_msg); snprintf(&topic_value[strlen(topic_value)], sizeof(topic_value) - strlen(topic_value), ", \"objectType\" : \"%d\" ", opts->object_type); snprintf(&topic_value[strlen(topic_value)], sizeof(topic_value) - strlen(topic_value), ", \"objectInstance\" : \"%d\" ", diff --git a/bacnet-stack/apps/server/yaml_config.c b/bacnet-stack/apps/server/yaml_config.c index d8c5267..e9fc2ee 100644 --- a/bacnet-stack/apps/server/yaml_config.c +++ b/bacnet-stack/apps/server/yaml_config.c @@ -10,9 +10,9 @@ #include "yaml_config.h" #include "bacnet/basic/object/device.h" +#include "bacnet/bactext.h" #define DEFAULT_YAML_CONFIG "/data/bacnet-server-driver/config/config.yml" -#define MAX_YAML_STR_VALUE_LENGTH 51 /* mqtt struct */ struct _mqtt { @@ -65,6 +65,9 @@ struct _bacnet_config { char **properties; unsigned n_properties; struct _bacnet_client *bacnet_client; + char *use_points_list; + unsigned int n_points; + struct _point *points; }; /* forward decls */ @@ -151,6 +154,27 @@ static const cyaml_schema_field_t bacnet_client_fields_schema[] = { CYAML_FIELD_END }; +static const cyaml_schema_field_t point_fields_schema[] = { + CYAML_FIELD_STRING_PTR( + "point", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, + struct _point, label, 0, CYAML_UNLIMITED), + + CYAML_FIELD_STRING_PTR( + "name", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, + struct _point, name, 0, CYAML_UNLIMITED), + + CYAML_FIELD_STRING_PTR( + "units", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, + struct _point, units, 0, CYAML_UNLIMITED), + + CYAML_FIELD_END +}; + +static const cyaml_schema_value_t point_schema = { + CYAML_VALUE_MAPPING(CYAML_FLAG_DEFAULT, + struct _point, point_fields_schema), +}; + static const cyaml_schema_field_t config_fields_schema[] = { CYAML_FIELD_STRING_PTR( "server_name", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, @@ -230,6 +254,15 @@ static const cyaml_schema_field_t config_fields_schema[] = { "bacnet_client", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, struct _bacnet_config, bacnet_client, bacnet_client_fields_schema), + CYAML_FIELD_STRING_PTR( + "use_points_list", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, + struct _bacnet_config, use_points_list, 0, CYAML_UNLIMITED), + + CYAML_FIELD_SEQUENCE_COUNT( + "points", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL, + struct _bacnet_config, points, n_points, + &point_schema, 0, CYAML_UNLIMITED), + CYAML_FIELD_END }; @@ -414,7 +447,77 @@ void load_default_settings(void) bacnet_config->bacnet_client->filter_objects = malloc(sizeof(char) * MAX_YAML_STR_VALUE_LENGTH); strcpy(bacnet_config->bacnet_client->filter_objects, "true"); } + + if (!bacnet_config->use_points_list) { + bacnet_config->use_points_list = malloc(sizeof(char) * MAX_YAML_STR_VALUE_LENGTH); + strcpy(bacnet_config->use_points_list, "false"); + } + } +} + + +/* + * Check if recognized object name. + */ +static bool is_valid_object_name(const char *name) +{ + int i; + bool found = false; + char *object_names[] = { + "ai", + "ao", + "av", + "bi", + "bo", + "bv", + NULL + }; + + for (i = 0; object_names[i] != NULL; i++) { + if (!strcasecmp(object_names[i], name)) { + found = true; + break; + } } + + return(found); +} + + +/* + * Normalize config. + */ +static int normalize_config(void) +{ + char buf[1024] = {0}; + char *ptr; + unsigned int i, idx; + + if (bacnet_config->n_points > 0) { + for(i = 0; i < bacnet_config->n_points; i++) { + strncpy(buf, bacnet_config->points[i].label, sizeof(buf) - 1); + ptr = &buf[0]; + if (!strsep(&ptr, "-")) { + printf("- Invalid Point name: [%s]\n", buf); + return(1); + } + + if (!is_valid_object_name(buf)) { + printf("- Invalid Object name: [%s]\n", buf); + return(1); + } + + strcpy(bacnet_config->points[i].object_name, buf); + bacnet_config->points[i].object_instance = atoi(ptr); + + if (!bactext_engineering_unit_index(bacnet_config->points[i].units, &idx)) { + printf("- Invalid Units: [%s]\n", bacnet_config->points[i].units); + return(1); + } + } + } + + return(0); } @@ -448,7 +551,7 @@ int yaml_config_init(void) sprintf(config_file, "%s/config/", pEnv); } else { printf("Global configuration directory not specified. Exiting!\n"); - exit(0); + return(1); } pEnv = getenv("s"); @@ -456,7 +559,7 @@ int yaml_config_init(void) sprintf(&config_file[strlen(config_file)], "%s", pEnv); } else { printf("Configuration file not specified. Exiting!\n"); - exit(0); + return(1); } if (yaml_config_debug) { @@ -465,18 +568,22 @@ int yaml_config_init(void) if (stat(config_file, &statbuf) < 0) { printf("Configuration file (%s) not found. Exiting!\n", config_file); - exit(0); + return(1); } err = cyaml_load_file(config_file, &yaml_config, &config_schema, (void **)&bacnet_config, NULL); if (err != CYAML_OK) { fprintf(stderr, "ERROR: %s\n", cyaml_strerror(err)); - exit(1); + return(1); } load_default_settings(); + if (normalize_config()) { + return(1); + } + if (yaml_config_debug) { yaml_config_dump(); } @@ -571,6 +678,21 @@ void yaml_config_dump(void) printf("YAML Config: bacnet_client->filter_objects: %s\n", (bacnet_config->bacnet_client->filter_objects) ? bacnet_config->bacnet_client->filter_objects: "null"); } + + printf("YAML Config: use_points_list: %s\n", (bacnet_config->use_points_list) ? + bacnet_config->use_points_list : "null"); + + if (bacnet_config->n_points > 0) { + printf("YAML Config: Points\n"); + + for(i = 0; i < bacnet_config->n_points; i++) { + printf("[%d]: label => [%s]\n", i, bacnet_config->points[i].label); + printf("[%d]: name => [%s]\n", i, bacnet_config->points[i].name); + printf("[%d]: units => [%s]\n", i, bacnet_config->points[i].units); + printf("[%d]: object_name => [%s]\n", i, bacnet_config->points[i].object_name); + printf("[%d]: object_instance => %d\n", i, bacnet_config->points[i].object_instance); + } + } } @@ -958,3 +1080,63 @@ int yaml_config_cleanup(void) return(0); } + + +/* + * Get use point list enable flag. + */ +int yaml_use_point_list_enable(void) +{ + return (!strcmp(bacnet_config->use_points_list, "true") ? true : false); +} + + +/* + * Get points length. + */ +point_cb *yaml_get_points_by_name(char *name, int *length) +{ + point_cb *points = NULL; + int i, ii, len; + + for (i = 0, len = 0; i < bacnet_config->n_points; i++) { + if (!strcasecmp(bacnet_config->points[i].object_name, name)) { + len++; + } + } + + if (len > 0) { + points = (point_cb*)malloc(sizeof(point_cb) * len); + if (!points) { + return(NULL); + } + + *length = len; + for (i = 0, ii = 0; i < bacnet_config->n_points; i++) { + if (!strcasecmp(bacnet_config->points[i].object_name, name)) { + memcpy(&points[ii], &bacnet_config->points[i], sizeof(point_cb)); + ii++; + } + } + } + + return(points); +} + + +/* + * Get points max object_instance_id. + */ +int yaml_get_points_max_object_instance_id(point_cb *points, int n_points) +{ + int i, max = 0; + + for (i = 0; i < n_points; i++) { + if (max < points[i].object_instance) { + max = points[i].object_instance; + } + } + + return(max); +} + diff --git a/bacnet-stack/apps/server/yaml_config.h b/bacnet-stack/apps/server/yaml_config.h index 16bc7c8..04e5b9b 100644 --- a/bacnet-stack/apps/server/yaml_config.h +++ b/bacnet-stack/apps/server/yaml_config.h @@ -1,6 +1,20 @@ #ifndef YAML_CONFIG_H #define YAML_CONFIG_H +#define MAX_YAML_STR_VALUE_LENGTH 51 + + +/* point */ +typedef struct _point { + char *label; + char *name; + char *units; + char object_name[MAX_YAML_STR_VALUE_LENGTH]; + unsigned int object_type; + unsigned int object_instance; +} point_cb; + + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -83,6 +97,12 @@ extern "C" { int yaml_config_cleanup(void); + int yaml_use_point_list_enable(void); + + point_cb *yaml_get_points_by_name(char *name, int *length); + + int yaml_get_points_max_object_instance_id(point_cb *points, int n_points); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/bacnet-stack/ports/linux/bip-init.c b/bacnet-stack/ports/linux/bip-init.c index 5c03b54..ad52b1c 100644 --- a/bacnet-stack/ports/linux/bip-init.c +++ b/bacnet-stack/ports/linux/bip-init.c @@ -61,6 +61,7 @@ /* unix socket */ static int BIP_Socket = -1; +static int BIP_Broadcast_Socket = -1; /* NOTE: we store address and port in network byte order since BACnet/IP uses network byte order for all address byte arrays @@ -101,6 +102,8 @@ static void debug_print_ipv4(const char *str, */ int bip_get_socket(void) { +printf("-- bip_get_socket()\n"); +exit(0); return BIP_Socket; } @@ -341,11 +344,27 @@ uint16_t bip_receive( } FD_ZERO(&read_fds); FD_SET(BIP_Socket, &read_fds); + + if (BIP_Broadcast_Socket >= 0) { + FD_SET(BIP_Broadcast_Socket, &read_fds); + } + max = BIP_Socket; + if (BIP_Broadcast_Socket > max) { + max = BIP_Broadcast_Socket; + } + /* see if there is a packet for us */ if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) { - received_bytes = recvfrom(max, (char *)&npdu[0], max_npdu, 0, - (struct sockaddr *)&sin, &sin_len); + if (FD_ISSET(BIP_Socket, &read_fds)) { + fprintf(stderr, "BIP: Reading from BIP_Socket\n"); + received_bytes = recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu, 0, + (struct sockaddr *)&sin, &sin_len); + } else if (FD_ISSET(BIP_Broadcast_Socket, &read_fds)) { + fprintf(stderr, "BIP: Reading from BIP_Broadcast_Socket\n"); + received_bytes = recvfrom(BIP_Broadcast_Socket, (char *)&npdu[0], max_npdu, 0, + (struct sockaddr *)&sin, &sin_len); + } } else { return 0; } @@ -781,13 +800,45 @@ bool bip_init(char *ifname) struct sockaddr_in sin; int sockopt = 0; int sock_fd = -1; - - if (ifname) { - strncpy(BIP_Interface_Name, ifname, sizeof(BIP_Interface_Name)); - bip_set_interface(ifname); - } else { - bip_set_interface(ifname_default()); + struct in_addr addr; + struct in_addr netmask = {0}; + char ip_str[INET_ADDRSTRLEN]; + char ip_ifname[INET_ADDRSTRLEN]; + int prefix_len; + int is_address = false; + + if (sscanf(ifname, "%[^/]/%d/%[^/]", ip_str, &prefix_len, ip_ifname) == 3) { + fprintf(stderr, "BIP: ifname (%s) is a valid IP/Prefix address\n", ifname); + inet_aton(ip_str, &addr); + BIP_Address.s_addr = addr.s_addr; + netmask.s_addr = htonl((0xFFFFFFFF << (32 - prefix_len)) & 0xFFFFFFFF); + BIP_Broadcast_Addr.s_addr = (addr.s_addr & netmask.s_addr) | ~netmask.s_addr; + strncpy(BIP_Interface_Name, ip_ifname, sizeof(BIP_Interface_Name)); + is_address = true; + fprintf(stderr, "BIP: Interface: %s\n", ip_ifname); + fprintf(stderr, "BIP: Address: %s\n", inet_ntoa(addr)); + fprintf(stderr, "BIP: Netmask: %s\n", + inet_ntoa(netmask)); + fprintf(stderr, "BIP: Broadcast Address: %s\n", + inet_ntoa(BIP_Broadcast_Addr)); + fprintf(stderr, "BIP: UDP Port: 0x%04X [%hu]\n", ntohs(BIP_Port), + ntohs(BIP_Port)); + } else if (inet_aton(ifname, &addr)) { + fprintf(stderr, "BIP: ifname (%s) is a valid IP address\n", ifname); + BIP_Address.s_addr = addr.s_addr; + BIP_Broadcast_Addr.s_addr = ~0; + is_address = true; + } else { + fprintf(stderr, "BIP: ifname (%s) is not a valid IP address\n", ifname); + + if (ifname) { + strncpy(BIP_Interface_Name, ifname, sizeof(BIP_Interface_Name)); + bip_set_interface(ifname); + } else { + bip_set_interface(ifname_default()); + } } + if (BIP_Address.s_addr == 0) { fprintf(stderr, "BIP: Failed to get an IP address from %s!\n", BIP_Interface_Name); @@ -797,7 +848,9 @@ bool bip_init(char *ifname) /* assumes that the driver has already been initialized */ sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); BIP_Socket = sock_fd; + fprintf(stderr, "BIP: BIP_Socket: %d\n", BIP_Socket); if (sock_fd < 0) { + fprintf(stderr, "BIP: Failed to open UDP socket!\n"); return false; } /* Allow us to use the same socket for sending and receiving */ @@ -806,6 +859,7 @@ bool bip_init(char *ifname) status = setsockopt( sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)); if (status < 0) { + fprintf(stderr, "BIP: Unable to reuse socket for sending/receiving!\n"); close(sock_fd); BIP_Socket = -1; return status; @@ -814,17 +868,26 @@ bool bip_init(char *ifname) status = setsockopt( sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt)); if (status < 0) { + fprintf(stderr, "BIP: Unable to set socket to send broadcase messages!\n"); close(sock_fd); BIP_Socket = -1; return false; } /* Bind to the proper interface to send without default gateway */ - setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name, - sizeof(BIP_Interface_Name)); + if (strlen(BIP_Interface_Name) > 0) { + fprintf(stderr, "BIP: Binding to (%s) for sending without default gateway\n", BIP_Interface_Name); + setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name, + sizeof(BIP_Interface_Name)); + } /* bind the socket to the local port number and IP address */ sin.sin_family = AF_INET; - sin.sin_addr.s_addr = htonl(INADDR_ANY); + if (is_address) { + // sin.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; + sin.sin_addr.s_addr = BIP_Address.s_addr; + } else { + sin.sin_addr.s_addr = htonl(INADDR_ANY); + } sin.sin_port = BIP_Port; memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); status = @@ -834,6 +897,54 @@ bool bip_init(char *ifname) BIP_Socket = -1; return false; } + + if (is_address) { + fprintf(stderr, "BIP: Binding to broadcast address (%s)\n", inet_ntoa(BIP_Broadcast_Addr)); + + sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + BIP_Broadcast_Socket = sock_fd; + fprintf(stderr, "BIP: BIP_Broadcast_Socket: %d\n", BIP_Broadcast_Socket); + if (sock_fd < 0) { + fprintf(stderr, "BIP: Failed to open UDP socket!\n"); + return false; + } + + status = setsockopt( + sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)); + if (status < 0) { + fprintf(stderr, "BIP: Unable to reuse socket for sending/receiving!\n"); + close(sock_fd); + BIP_Broadcast_Socket = -1; + return status; + } + /* allow us to send a broadcast */ + status = setsockopt( + sock_fd, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt)); + if (status < 0) { + fprintf(stderr, "BIP: Unable to set socket to send broadcase messages!\n"); + close(sock_fd); + BIP_Broadcast_Socket = -1; + return false; + } + /* Bind to the proper interface to send without default gateway */ + fprintf(stderr, "BIP: Binding to (%s) for sending without default gateway\n", BIP_Interface_Name); + setsockopt(sock_fd, SOL_SOCKET, SO_BINDTODEVICE, BIP_Interface_Name, + sizeof(BIP_Interface_Name)); + + /* bind the socket to the local port number and IP address */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = BIP_Broadcast_Addr.s_addr; + sin.sin_port = BIP_Port; + memset(&(sin.sin_zero), '\0', sizeof(sin.sin_zero)); + status = + bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr)); + if (status < 0) { + close(sock_fd); + BIP_Broadcast_Socket = -1; + return false; + } + } + bvlc_init(); return true; diff --git a/bacnet-stack/src/bacnet/basic/object/ai.c b/bacnet-stack/src/bacnet/basic/object/ai.c index a1846b0..83a8c4c 100644 --- a/bacnet-stack/src/bacnet/basic/object/ai.c +++ b/bacnet-stack/src/bacnet/basic/object/ai.c @@ -40,13 +40,9 @@ #include "bacnet/proplist.h" #include "bacnet/timestamp.h" #include "bacnet/basic/object/ai.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #if PRINT_ENABLED #include @@ -106,28 +102,39 @@ void Analog_Input_Init(void) #if defined(INTRINSIC_REPORTING) unsigned j; #endif + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; + + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("ai", &n_points); + printf("- Analog Input Points Found: %d\n", n_points); + Analog_Input_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Analog_Input_Instances = yaml_config_ai_max(); + } -#if defined(YAML_CONFIG) - Analog_Input_Instances = yaml_config_ai_max(); if (Analog_Input_Instances == 0) { -#endif - pEnv = getenv("AI"); - if (pEnv) { + pEnv = getenv("AI"); + if (pEnv) { Analog_Input_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Analog_Input_Instances: %d\n", Analog_Input_Instances); if (Analog_Input_Instances> 0) { - AI_Descr = malloc(Analog_Input_Instances * sizeof(ANALOG_INPUT_DESCR)); - Analog_Input_Instance_Names = malloc(Analog_Input_Instances * sizeof(BACNET_CHARACTER_STRING)); + AI_Descr = calloc(Analog_Input_Instances, sizeof(ANALOG_INPUT_DESCR)); + Analog_Input_Instance_Names = calloc(Analog_Input_Instances, sizeof(BACNET_CHARACTER_STRING)); } for (i = 0; i < Analog_Input_Instances; i++) { + sprintf(buf, "AI_%d_SPARE", i + 1); + characterstring_init_ansi(&Analog_Input_Instance_Names[i], buf); + AI_Descr[i].Units = UNITS_NO_UNITS; + AI_Descr[i].Present_Value = 0.0f; AI_Descr[i].Out_Of_Service = false; - AI_Descr[i].Units = UNITS_NO_UNITS; AI_Descr[i].Reliability = RELIABILITY_NO_FAULT_DETECTED; AI_Descr[i].Prior_Value = 0.0f; AI_Descr[i].COV_Increment = 1.0f; @@ -152,9 +159,16 @@ void Analog_Input_Init(void) handler_get_alarm_summary_set( OBJECT_ANALOG_INPUT, Analog_Input_Alarm_Summary); #endif + } + + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Analog_Input_Instance_Names[obj_instance_id], points[i].name); + bactext_engineering_unit_index(points[i].units, (unsigned int*)&AI_Descr[obj_instance_id].Units); + } - sprintf(buf, "AI_%d_SPARE", i + 1); - characterstring_init_ansi(&Analog_Input_Instance_Names[i], buf); + free(points); } } diff --git a/bacnet-stack/src/bacnet/basic/object/ao.c b/bacnet-stack/src/bacnet/basic/object/ao.c index fdf9934..1a91532 100644 --- a/bacnet-stack/src/bacnet/basic/object/ao.c +++ b/bacnet-stack/src/bacnet/basic/object/ao.c @@ -38,13 +38,9 @@ #include "bacnet/wp.h" #include "bacnet/basic/object/ao.h" #include "bacnet/basic/services.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #ifndef MAX_ANALOG_OUTPUTS #define MAX_ANALOG_OUTPUTS 4 @@ -105,47 +101,64 @@ void Analog_Output_Init(void) char buf[51]; char *pEnv; unsigned i, j; + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; if (!Analog_Output_Initialized) { Analog_Output_Initialized = true; -#if defined(YAML_CONFIG) - Analog_Output_Instances = yaml_config_ao_max(); + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("ao", &n_points); + printf("- Analog Output Points Found: %d\n", n_points); + Analog_Output_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Analog_Output_Instances = yaml_config_ao_max(); + } + if (Analog_Output_Instances == 0) { -#endif - pEnv = getenv("AO"); - if (pEnv) { + pEnv = getenv("AO"); + if (pEnv) { Analog_Output_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Analog_Output_Instances: %d\n", Analog_Output_Instances); /* initialize all the analog output priority arrays to NULL */ if (Analog_Output_Instances > 0) { - Analog_Output_Level = malloc(Analog_Output_Instances * sizeof(float *)); + Analog_Output_Level = calloc(Analog_Output_Instances, sizeof(float *)); for (i = 0; i < Analog_Output_Instances; i++) { - Analog_Output_Level[i] = malloc(BACNET_MAX_PRIORITY * sizeof(float)); + Analog_Output_Level[i] = calloc(BACNET_MAX_PRIORITY, sizeof(float)); for (j = 0; j < BACNET_MAX_PRIORITY; j++) { Analog_Output_Level[i][j] = AO_LEVEL_NULL; } } - Out_Of_Service = malloc(Analog_Output_Instances * sizeof(bool)); - Analog_Output_Instance_Names = malloc(Analog_Output_Instances * sizeof(BACNET_CHARACTER_STRING)); + Out_Of_Service = calloc(Analog_Output_Instances, sizeof(bool)); + Analog_Output_Instance_Names = calloc(Analog_Output_Instances, sizeof(BACNET_CHARACTER_STRING)); for (i = 0; i < Analog_Output_Instances; i++) { - sprintf(buf, "AO_%d_SPARE", i + 1); - characterstring_init_ansi(&Analog_Output_Instance_Names[i], buf); + sprintf(buf, "AO_%d_SPARE", i + 1); + characterstring_init_ansi(&Analog_Output_Instance_Names[i], buf); } - Analog_Output_Relinquish_Defaults = malloc(Analog_Output_Instances * sizeof(float)); + Analog_Output_Relinquish_Defaults = calloc(Analog_Output_Instances, sizeof(float)); for (i = 0; i < Analog_Output_Instances; i++) { Analog_Output_Relinquish_Defaults[i] = AO_RELINQUISH_DEFAULT; } } } + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Analog_Output_Instance_Names[obj_instance_id], points[i].name); + } + + free(points); + } + return; } diff --git a/bacnet-stack/src/bacnet/basic/object/av.c b/bacnet-stack/src/bacnet/basic/object/av.c index bf4b504..536786b 100644 --- a/bacnet-stack/src/bacnet/basic/object/av.c +++ b/bacnet-stack/src/bacnet/basic/object/av.c @@ -40,13 +40,9 @@ #include "bacnet/basic/object/device.h" #include "bacnet/basic/services.h" #include "bacnet/basic/object/av.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #ifndef MAX_ANALOG_VALUES #define MAX_ANALOG_VALUES 4 @@ -115,28 +111,40 @@ void Analog_Value_Init(void) #if defined(INTRINSIC_REPORTING) unsigned j; #endif + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; + + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("av", &n_points); + printf("- Analog Value Points Found: %d\n", n_points); + Analog_Value_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Analog_Value_Instances = yaml_config_av_max(); + } -#if defined(YAML_CONFIG) - Analog_Value_Instances = yaml_config_av_max(); if (Analog_Value_Instances == 0) { -#endif - pEnv = getenv("AV"); - if (pEnv) { + pEnv = getenv("AV"); + if (pEnv) { Analog_Value_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Analog_Value_Instances: %d\n", Analog_Value_Instances); if (Analog_Value_Instances > 0) { - AV_Descr = malloc(Analog_Value_Instances * sizeof(ANALOG_VALUE_DESCR)); - Analog_Value_Instance_Names = malloc(Analog_Value_Instances * sizeof(BACNET_CHARACTER_STRING)); + AV_Descr = calloc(Analog_Value_Instances, sizeof(ANALOG_VALUE_DESCR)); + Analog_Value_Instance_Names = calloc(Analog_Value_Instances, sizeof(BACNET_CHARACTER_STRING)); } for (i = 0; i < Analog_Value_Instances; i++) { memset(&AV_Descr[i], 0x00, sizeof(ANALOG_VALUE_DESCR)); - AV_Descr[i].Present_Value = 0.0; + + sprintf(buf, "AV_%d_SPARE", i + 1); + characterstring_init_ansi(&Analog_Value_Instance_Names[i], buf); AV_Descr[i].Units = UNITS_NO_UNITS; + + AV_Descr[i].Present_Value = 0.0; AV_Descr[i].Prior_Value = 0.0f; AV_Descr[i].COV_Increment = 1.0f; AV_Descr[i].Changed = false; @@ -161,15 +169,22 @@ void Analog_Value_Init(void) OBJECT_ANALOG_VALUE, Analog_Value_Alarm_Summary); #endif - sprintf(buf, "AV_%d_SPARE", i + 1); - characterstring_init_ansi(&Analog_Value_Instance_Names[i], buf); - for (j = 0; j < BACNET_MAX_PRIORITY; j++) { AV_Descr[i].Present_Value_Level[j] = AV_LEVEL_NULL; } AV_Descr[i].Relinquish_Default = AV_RELINQUISH_DEFAULT; } + + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Analog_Value_Instance_Names[obj_instance_id], points[i].name); + bactext_engineering_unit_index(points[i].units, (unsigned int*)&AV_Descr[obj_instance_id].Units); + } + + free(points); + } } /** diff --git a/bacnet-stack/src/bacnet/basic/object/bi.c b/bacnet-stack/src/bacnet/basic/object/bi.c index b7c4f7a..c7b8973 100644 --- a/bacnet-stack/src/bacnet/basic/object/bi.c +++ b/bacnet-stack/src/bacnet/basic/object/bi.c @@ -39,13 +39,9 @@ #include "bacnet/config.h" /* the custom stuff */ #include "bacnet/basic/object/bi.h" #include "bacnet/basic/services.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #ifndef MAX_BINARY_INPUTS #define MAX_BINARY_INPUTS 5 @@ -125,30 +121,38 @@ void Binary_Input_Init(void) char *pEnv; static bool initialized = false; unsigned i; + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; if (!initialized) { initialized = true; -#if defined(YAML_CONFIG) - Binary_Input_Instances = yaml_config_bi_max(); + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("bi", &n_points); + printf("- Binary Input Points Found: %d\n", n_points); + Binary_Input_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Binary_Input_Instances = yaml_config_bi_max(); + } + if (Binary_Input_Instances == 0) { -#endif - pEnv = getenv("BI"); - if (pEnv) { + pEnv = getenv("BI"); + if (pEnv) { Binary_Input_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Binary_Input_Instances: %d\n", Binary_Input_Instances); /* initialize all the values */ if (Binary_Input_Instances > 0) { - Present_Value = malloc(Binary_Input_Instances * sizeof(BACNET_BINARY_PV)); - Out_Of_Service = malloc(Binary_Input_Instances * sizeof(bool)); - Change_Of_Value = malloc(Binary_Input_Instances * sizeof(bool)); - Polarity = malloc(Binary_Input_Instances * sizeof(BACNET_POLARITY)); + Present_Value = calloc(Binary_Input_Instances, sizeof(BACNET_BINARY_PV)); + Out_Of_Service = calloc(Binary_Input_Instances, sizeof(bool)); + Change_Of_Value = calloc(Binary_Input_Instances, sizeof(bool)); + Polarity = calloc(Binary_Input_Instances, sizeof(BACNET_POLARITY)); - Binary_Input_Instance_Names = malloc(Binary_Input_Instances * sizeof(BACNET_CHARACTER_STRING)); + Binary_Input_Instance_Names = calloc(Binary_Input_Instances, sizeof(BACNET_CHARACTER_STRING)); for (i = 0; i < Binary_Input_Instances; i++) { sprintf(buf, "BI_%d_SPARE", i + 1); characterstring_init_ansi(&Binary_Input_Instance_Names[i], buf); @@ -161,6 +165,15 @@ void Binary_Input_Init(void) } } + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Binary_Input_Instance_Names[obj_instance_id], points[i].name); + } + + free(points); + } + return; } diff --git a/bacnet-stack/src/bacnet/basic/object/bo.c b/bacnet-stack/src/bacnet/basic/object/bo.c index c6a1460..13dca09 100644 --- a/bacnet-stack/src/bacnet/basic/object/bo.c +++ b/bacnet-stack/src/bacnet/basic/object/bo.c @@ -39,13 +39,9 @@ #include "bacnet/wp.h" #include "bacnet/basic/object/bo.h" #include "bacnet/basic/services.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #ifndef MAX_BINARY_OUTPUTS #define MAX_BINARY_OUTPUTS 4 @@ -99,27 +95,35 @@ void Binary_Output_Init(void) char *pEnv; unsigned i, j; static bool initialized = false; + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; if (!initialized) { initialized = true; -#if defined(YAML_CONFIG) - Binary_Output_Instances = yaml_config_bo_max(); + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("bo", &n_points); + printf("- Binary Output Points Found: %d\n", n_points); + Binary_Output_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Binary_Output_Instances = yaml_config_bo_max(); + } + if (Binary_Output_Instances == 0) { -#endif - pEnv = getenv("BO"); - if (pEnv) { + pEnv = getenv("BO"); + if (pEnv) { Binary_Output_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Binary_Output_Instances: %d\n", Binary_Output_Instances); /* initialize all the analog output priority arrays to NULL */ if (Binary_Output_Instances > 0) { - Binary_Output_Level = malloc(Binary_Output_Instances * sizeof(BACNET_BINARY_PV*)); + Binary_Output_Level = calloc(Binary_Output_Instances, sizeof(BACNET_BINARY_PV*)); for (i = 0; i < Binary_Output_Instances; i++) { - Binary_Output_Level[i] = malloc(BACNET_MAX_PRIORITY * sizeof(BACNET_BINARY_PV)); + Binary_Output_Level[i] = calloc(BACNET_MAX_PRIORITY, sizeof(BACNET_BINARY_PV)); } for (i = 0; i < Binary_Output_Instances; i++) { @@ -128,20 +132,29 @@ void Binary_Output_Init(void) } } - Out_Of_Service = malloc(Binary_Output_Instances * sizeof(bool)); - Binary_Output_Instance_Names = malloc(Binary_Output_Instances * sizeof(BACNET_CHARACTER_STRING)); + Out_Of_Service = calloc(Binary_Output_Instances, sizeof(bool)); + Binary_Output_Instance_Names = calloc(Binary_Output_Instances, sizeof(BACNET_CHARACTER_STRING)); for (i = 0; i < Binary_Output_Instances; i++) { sprintf(buf, "BO_%d_SPARE", i + 1); characterstring_init_ansi(&Binary_Output_Instance_Names[i], buf); } - Binary_Output_Relinquish_Defaults = malloc(Binary_Output_Instances * sizeof(BACNET_BINARY_PV)); + Binary_Output_Relinquish_Defaults = calloc(Binary_Output_Instances, sizeof(BACNET_BINARY_PV)); for (i = 0; i < Binary_Output_Instances; i++) { Binary_Output_Relinquish_Defaults[i] = RELINQUISH_DEFAULT; } } } + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Binary_Output_Instance_Names[obj_instance_id], points[i].name); + } + + free(points); + } + return; } diff --git a/bacnet-stack/src/bacnet/basic/object/bv.c b/bacnet-stack/src/bacnet/basic/object/bv.c index 410d46a..efb4ea3 100644 --- a/bacnet-stack/src/bacnet/basic/object/bv.c +++ b/bacnet-stack/src/bacnet/basic/object/bv.c @@ -39,13 +39,9 @@ #include "bacnet/rp.h" #include "bacnet/basic/object/bv.h" #include "bacnet/basic/services.h" -#if defined(MQTT) #include "MQTTClient.h" #include "mqtt_client.h" -#endif /* defined(MQTT) */ -#if defined(YAML_CONFIG) #include "yaml_config.h" -#endif /* defined(YAML_CONFIG) */ #ifndef MAX_BINARY_VALUES #define MAX_BINARY_VALUES 10 @@ -109,47 +105,64 @@ void Binary_Value_Init(void) char *pEnv; unsigned i, j; static bool initialized = false; + point_cb *points = NULL; + unsigned int obj_instance_id; + int n_points= 0; if (!initialized) { initialized = true; -#if defined(YAML_CONFIG) - Binary_Value_Instances = yaml_config_bv_max(); + if (yaml_use_point_list_enable()) { + points = yaml_get_points_by_name("bv", &n_points); + printf("- Binary Value Points Found: %d\n", n_points); + Binary_Value_Instances = yaml_get_points_max_object_instance_id(points, n_points); + } else { + Binary_Value_Instances = yaml_config_bv_max(); + } + if (Binary_Value_Instances == 0) { -#endif - pEnv = getenv("BV"); - if (pEnv) { + pEnv = getenv("BV"); + if (pEnv) { Binary_Value_Instances = atoi(pEnv); + } } -#if defined(YAML_CONFIG) - } -#endif + + printf("- Binary_Value_Instances: %d\n", Binary_Value_Instances); /* initialize all the analog output priority arrays to NULL */ if (Binary_Value_Instances > 0) { - Binary_Value_Level = malloc(Binary_Value_Instances * sizeof(BACNET_BINARY_PV*)); + Binary_Value_Level = calloc(Binary_Value_Instances, sizeof(BACNET_BINARY_PV*)); for (i = 0; i < Binary_Value_Instances; i++) { - Binary_Value_Level [i] = malloc(BACNET_MAX_PRIORITY * sizeof(BACNET_BINARY_PV)); + Binary_Value_Level [i] = calloc(BACNET_MAX_PRIORITY, sizeof(BACNET_BINARY_PV)); for (j = 0; j < BACNET_MAX_PRIORITY; j++) { Binary_Value_Level[i][j] = BINARY_NULL; } } - Out_Of_Service = malloc(Binary_Value_Instances * sizeof(bool)); - Binary_Value_Instance_Names = malloc(Binary_Value_Instances * sizeof(BACNET_CHARACTER_STRING)); + Out_Of_Service = calloc(Binary_Value_Instances, sizeof(bool)); + Binary_Value_Instance_Names = calloc(Binary_Value_Instances, sizeof(BACNET_CHARACTER_STRING)); for (i = 0; i < Binary_Value_Instances; i++) { sprintf(buf, "BV_%d_SPARE", i + 1); characterstring_init_ansi(&Binary_Value_Instance_Names[i], buf); } - Binary_Value_Relinquish_Defaults = malloc(Binary_Value_Instances * sizeof(BACNET_BINARY_PV)); + Binary_Value_Relinquish_Defaults = calloc(Binary_Value_Instances, sizeof(BACNET_BINARY_PV)); for (i = 0; i < Binary_Value_Instances; i++) { Binary_Value_Relinquish_Defaults[i] = RELINQUISH_DEFAULT; } } } + if (points) { + for (i = 0; i < n_points; i++) { + obj_instance_id = points[i].object_instance - 1; + characterstring_init_ansi(&Binary_Value_Instance_Names[obj_instance_id], points[i].name); + } + + free(points); + } + return; } diff --git a/bacnet-stack/src/bacnet/basic/object/device.c b/bacnet-stack/src/bacnet/basic/object/device.c index b227138..270d1f5 100644 --- a/bacnet-stack/src/bacnet/basic/object/device.c +++ b/bacnet-stack/src/bacnet/basic/object/device.c @@ -204,6 +204,7 @@ static object_functions_t My_Object_Table[] = { NULL /* ReadRangeInfo */, NULL /* Iterator */, NULL /* Value_Lists */, NULL /* COV */, NULL /* COV Clear */, NULL /* Intrinsic Reporting */ }, #endif +#if 0 { OBJECT_MULTI_STATE_INPUT, Multistate_Input_Init, Multistate_Input_Count, Multistate_Input_Index_To_Instance, Multistate_Input_Valid_Instance, Multistate_Input_Object_Name, Multistate_Input_Read_Property, @@ -225,6 +226,7 @@ static object_functions_t My_Object_Table[] = { Multistate_Value_Encode_Value_List, Multistate_Value_Change_Of_Value, Multistate_Value_Change_Of_Value_Clear, NULL /* Intrinsic Reporting */ }, +#endif #if 0 { OBJECT_TRENDLOG, Trend_Log_Init, Trend_Log_Count, Trend_Log_Index_To_Instance, Trend_Log_Valid_Instance, diff --git a/bacnet-stack/src/bacnet/basic/service/s_rp.c b/bacnet-stack/src/bacnet/basic/service/s_rp.c index d969e1c..11f768a 100644 --- a/bacnet-stack/src/bacnet/basic/service/s_rp.c +++ b/bacnet-stack/src/bacnet/basic/service/s_rp.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include "bacnet/config.h" #include "bacnet/bacdef.h" #include "bacnet/bacdcode.h"