Split dlenv_init in order to use bsc node registration from outside (#1230)
This commit is contained in:
+251
-145
@@ -823,22 +823,62 @@ void dlenv_network_port_bsc_init(uint32_t instance)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bsc_register_as_node(uint32_t instance)
|
/**
|
||||||
|
* Check if BACnet/SC hub connection is established.
|
||||||
|
*
|
||||||
|
* If no hub URIs (primary or failover) are configured, connection/registration
|
||||||
|
* is not required and this function returns true, consistent with
|
||||||
|
* bsc_register_as_node().
|
||||||
|
*/
|
||||||
|
bool dlenv_is_bsc_hub_connected(void)
|
||||||
{
|
{
|
||||||
#if defined(BACDL_BSC)
|
#if defined(BACDL_BSC)
|
||||||
/* if a user has configured BACnet/SC port with primary hub URI, */
|
const char *primary_uri =
|
||||||
/* wait for a establishing of a connection to BACnet/SC hub at first */
|
Network_Port_SC_Primary_Hub_URI_char(Network_Port_Instance);
|
||||||
/* to reduce possibility of packet losses. */
|
const char *failover_uri =
|
||||||
if (Network_Port_SC_Primary_Hub_URI_char(instance)) {
|
Network_Port_SC_Failover_Hub_URI_char(Network_Port_Instance);
|
||||||
debug_printf_stderr("Waiting for a BACnet/SC connection to hub...\n");
|
if (!primary_uri && !failover_uri) {
|
||||||
while (!dlenv_hub_connection_status_check(instance)) {
|
/* No hub URIs configured: registration/connection not required. */
|
||||||
bsc_wait(1);
|
return true;
|
||||||
bsc_maintenance_timer(1);
|
|
||||||
}
|
|
||||||
debug_printf_stderr("Connected to a BACnet/SC hub!\n");
|
|
||||||
}
|
}
|
||||||
|
return dlenv_hub_connection_status_check(Network_Port_Instance);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool bsc_register_as_node(uint32_t instance, bool wait_until_connected)
|
||||||
|
{
|
||||||
|
#if defined(BACDL_BSC)
|
||||||
|
bool is_connected = false;
|
||||||
|
const char *primary_uri =
|
||||||
|
Network_Port_SC_Primary_Hub_URI_char(Network_Port_Instance);
|
||||||
|
const char *failover_uri =
|
||||||
|
Network_Port_SC_Failover_Hub_URI_char(Network_Port_Instance);
|
||||||
|
if (primary_uri || failover_uri) {
|
||||||
|
debug_printf_stderr("Waiting for a BACnet/SC connection to hub...\n");
|
||||||
|
is_connected = dlenv_hub_connection_status_check(instance);
|
||||||
|
if (!is_connected) {
|
||||||
|
do {
|
||||||
|
bsc_wait(1);
|
||||||
|
bsc_maintenance_timer(1);
|
||||||
|
is_connected = dlenv_hub_connection_status_check(instance);
|
||||||
|
} while (wait_until_connected && !is_connected);
|
||||||
|
}
|
||||||
|
if (is_connected) {
|
||||||
|
debug_printf_stderr("Connected to a BACnet/SC hub!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No primary/failover hub URI configured: registration/connection
|
||||||
|
* not required.
|
||||||
|
*/
|
||||||
|
is_connected = true;
|
||||||
|
}
|
||||||
|
return is_connected;
|
||||||
#else
|
#else
|
||||||
(void)instance;
|
(void)instance;
|
||||||
|
(void)wait_until_connected;
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,6 +940,200 @@ void dlenv_maintenance_timer(uint16_t elapsed_seconds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Determine the DataLink port type from Environment variables,
|
||||||
|
* or else to defaults. In BACDL_MULTIPLE builds, this selection
|
||||||
|
* is also used to choose the active Datalink_Transport.
|
||||||
|
*
|
||||||
|
* @return Detected port type based on environment variables and
|
||||||
|
* compile-time configuration, which can be PORT_TYPE_BIP,
|
||||||
|
* PORT_TYPE_BIP6, PORT_TYPE_MSTP, PORT_TYPE_BSC, PORT_TYPE_ETHERNET,
|
||||||
|
* PORT_TYPE_ARCNET, PORT_TYPE_ZIGBEE, or PORT_TYPE_NON_BACNET.
|
||||||
|
*/
|
||||||
|
uint8_t dlenv_get_port_type(void)
|
||||||
|
{
|
||||||
|
uint8_t port_type = PORT_TYPE_BIP;
|
||||||
|
|
||||||
|
if (getenv("BACNET_DATALINK_DEBUG")) {
|
||||||
|
dlenv_debug_enable();
|
||||||
|
}
|
||||||
|
#if defined(BACDL_MULTIPLE)
|
||||||
|
char *pEnv = getenv("BACNET_DATALINK");
|
||||||
|
if (pEnv) {
|
||||||
|
datalink_set(pEnv);
|
||||||
|
if (bacnet_stricmp("none", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_NON_BACNET;
|
||||||
|
} else if (bacnet_stricmp("bip", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_BIP;
|
||||||
|
} else if (bacnet_stricmp("bip6", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_BIP6;
|
||||||
|
} else if (bacnet_stricmp("ethernet", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_ETHERNET;
|
||||||
|
} else if (bacnet_stricmp("arcnet", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_ARCNET;
|
||||||
|
} else if (bacnet_stricmp("mstp", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_MSTP;
|
||||||
|
} else if (bacnet_stricmp("bsc", pEnv) == 0) {
|
||||||
|
port_type = PORT_TYPE_BSC;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if defined(BACDL_BIP)
|
||||||
|
datalink_set("bip");
|
||||||
|
port_type = PORT_TYPE_BIP;
|
||||||
|
#elif defined(BACDL_BIP6)
|
||||||
|
datalink_set("bip6");
|
||||||
|
port_type = PORT_TYPE_BIP6;
|
||||||
|
#elif defined(BACDL_MSTP)
|
||||||
|
datalink_set("mstp");
|
||||||
|
port_type = PORT_TYPE_MSTP;
|
||||||
|
#elif defined(BACDL_ETHERNET)
|
||||||
|
datalink_set("ethernet");
|
||||||
|
port_type = PORT_TYPE_ETHERNET;
|
||||||
|
#elif defined(BACDL_ARCNET)
|
||||||
|
datalink_set("arcnet");
|
||||||
|
port_type = PORT_TYPE_ARCNET;
|
||||||
|
#elif defined(BACDL_ZIGBEE)
|
||||||
|
datalink_set("zigbee");
|
||||||
|
port_type = PORT_TYPE_ZIGBEE;
|
||||||
|
#elif defined(BACDL_BSC)
|
||||||
|
datalink_set("bsc");
|
||||||
|
port_type = PORT_TYPE_BSC;
|
||||||
|
#else
|
||||||
|
datalink_set("none");
|
||||||
|
port_type = PORT_TYPE_NON_BACNET;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* if we are not compiling with multiple datalinks,
|
||||||
|
then we are using the only one available */
|
||||||
|
#if defined(BACDL_BIP)
|
||||||
|
port_type = PORT_TYPE_BIP;
|
||||||
|
#elif defined(BACDL_BIP6)
|
||||||
|
port_type = PORT_TYPE_BIP6;
|
||||||
|
#elif defined(BACDL_MSTP)
|
||||||
|
port_type = PORT_TYPE_MSTP;
|
||||||
|
#elif defined(BACDL_ETHERNET)
|
||||||
|
port_type = PORT_TYPE_ETHERNET;
|
||||||
|
#elif defined(BACDL_ARCNET)
|
||||||
|
port_type = PORT_TYPE_ARCNET;
|
||||||
|
#elif defined(BACDL_ZIGBEE)
|
||||||
|
port_type = PORT_TYPE_ZIGBEE;
|
||||||
|
#elif defined(BACDL_BSC)
|
||||||
|
port_type = PORT_TYPE_BSC;
|
||||||
|
#else
|
||||||
|
port_type = PORT_TYPE_NON_BACNET;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return port_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Datalink configuration according to the given port type
|
||||||
|
* without registering the devices to the network. This is useful when the
|
||||||
|
* device registration needs to be delayed or shall be done separately, e.g. in
|
||||||
|
* a different thread.
|
||||||
|
*
|
||||||
|
* @param port_type Port type to initialize, such as PORT_TYPE_BIP,
|
||||||
|
* PORT_TYPE_BIP6, PORT_TYPE_MSTP, PORT_TYPE_BSC, or other supported PORT_TYPE_*
|
||||||
|
* values. It should be determined before by calling dlenv_get_port_type()
|
||||||
|
*/
|
||||||
|
void dlenv_init_no_device_registration(uint8_t port_type)
|
||||||
|
{
|
||||||
|
char *pEnv = NULL;
|
||||||
|
|
||||||
|
#if defined(BACFILE)
|
||||||
|
/* initialize the POSIX file objects */
|
||||||
|
bacfile_posix_init();
|
||||||
|
if (Datalink_Debug) {
|
||||||
|
debug_printf_stderr("POSIX file services initialized.\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
/* === Initialize the Network Port Object Here === */
|
||||||
|
Network_Port_Type_Set(Network_Port_Instance, port_type);
|
||||||
|
switch (port_type) {
|
||||||
|
case PORT_TYPE_BIP:
|
||||||
|
dlenv_network_port_bip_init(Network_Port_Instance);
|
||||||
|
break;
|
||||||
|
case PORT_TYPE_MSTP:
|
||||||
|
dlenv_network_port_mstp_init(Network_Port_Instance);
|
||||||
|
break;
|
||||||
|
case PORT_TYPE_BIP6:
|
||||||
|
dlenv_network_port_bip6_init(Network_Port_Instance);
|
||||||
|
break;
|
||||||
|
case PORT_TYPE_ZIGBEE:
|
||||||
|
dlenv_network_port_zigbee_init(Network_Port_Instance);
|
||||||
|
break;
|
||||||
|
case PORT_TYPE_BSC:
|
||||||
|
dlenv_network_port_bsc_init(Network_Port_Instance);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pEnv = getenv("BACNET_APDU_TIMEOUT");
|
||||||
|
if (pEnv) {
|
||||||
|
apdu_timeout_set((uint16_t)strtol(pEnv, NULL, 0));
|
||||||
|
} else {
|
||||||
|
if (port_type == PORT_TYPE_MSTP) {
|
||||||
|
apdu_timeout_set(60000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pEnv = getenv("BACNET_APDU_RETRIES");
|
||||||
|
if (pEnv) {
|
||||||
|
apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0));
|
||||||
|
}
|
||||||
|
/* === INIT - Initialize the Datalink Here === */
|
||||||
|
pEnv = getenv("BACNET_IFACE");
|
||||||
|
if (Datalink_Debug) {
|
||||||
|
debug_fprintf(stderr, "BACNET_IFACE=%s\n", pEnv ? pEnv : "none");
|
||||||
|
}
|
||||||
|
if (!datalink_init(pEnv)) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
/* === POST INIT - After the Datalink is Initialized === */
|
||||||
|
#if (MAX_TSM_TRANSACTIONS)
|
||||||
|
pEnv = getenv("BACNET_INVOKE_ID");
|
||||||
|
if (pEnv) {
|
||||||
|
tsm_invokeID_set((uint8_t)strtol(pEnv, NULL, 0));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a device to the network according to the given port type.
|
||||||
|
* As prerequisite, the Datalink configuration should have been initialized by
|
||||||
|
* calling dlenv_init_no_device_registration() with the same port type.
|
||||||
|
*
|
||||||
|
* This function is not thread safe. It must be called only after
|
||||||
|
* dlenv_init_no_device_registration() has completed for the same port type,
|
||||||
|
* and while no other thread is concurrently using or modifying the datalink
|
||||||
|
* or Network Port Object state. The call may be made immediately after init
|
||||||
|
* returns or at a later time (including from a different thread), provided
|
||||||
|
* these conditions are satisfied.
|
||||||
|
*
|
||||||
|
* @param port_type
|
||||||
|
* The network port type that determines which registration mechanism
|
||||||
|
* (e.g., BIP, BIP6, BSC) is used. For other port types, no registration
|
||||||
|
* is performed.
|
||||||
|
* @param wait_until_connected
|
||||||
|
* Only used for PORT_TYPE_BSC. If true, block until the
|
||||||
|
* device is connected/registered; otherwise return immediately.
|
||||||
|
* @return
|
||||||
|
* true if the device was successfully registered or registration is not
|
||||||
|
* required for the given port type; false if registration was attempted
|
||||||
|
* but failed.
|
||||||
|
*/
|
||||||
|
bool dlenv_register_device(uint8_t port_type, bool wait_until_connected)
|
||||||
|
{
|
||||||
|
if (port_type == PORT_TYPE_BIP) {
|
||||||
|
return (bbmd_register_as_foreign_device() >= 0);
|
||||||
|
} else if (port_type == PORT_TYPE_BIP6) {
|
||||||
|
return (bbmd6_register_as_foreign_device() >= 0);
|
||||||
|
} else if (port_type == PORT_TYPE_BSC) {
|
||||||
|
return bsc_register_as_node(
|
||||||
|
Network_Port_Instance, wait_until_connected);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/** Initialize the DataLink configuration from Environment variables,
|
/** Initialize the DataLink configuration from Environment variables,
|
||||||
* or else to defaults.
|
* or else to defaults.
|
||||||
* @ingroup DataLink
|
* @ingroup DataLink
|
||||||
@@ -975,139 +1209,11 @@ void dlenv_maintenance_timer(uint16_t elapsed_seconds)
|
|||||||
*/
|
*/
|
||||||
void dlenv_init(void)
|
void dlenv_init(void)
|
||||||
{
|
{
|
||||||
char *pEnv = NULL;
|
uint8_t port_type = dlenv_get_port_type();
|
||||||
uint8_t port_type = PORT_TYPE_BIP;
|
dlenv_init_no_device_registration(port_type);
|
||||||
|
if (!dlenv_register_device(port_type, true)) {
|
||||||
if (getenv("BACNET_DATALINK_DEBUG")) {
|
debug_fprintf(
|
||||||
dlenv_debug_enable();
|
stderr, "dlenv_init: failed to register device for port type %u\n",
|
||||||
}
|
(unsigned)port_type);
|
||||||
#if defined(BACDL_MULTIPLE)
|
|
||||||
pEnv = getenv("BACNET_DATALINK");
|
|
||||||
if (pEnv) {
|
|
||||||
datalink_set(pEnv);
|
|
||||||
if (bacnet_stricmp("none", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_NON_BACNET;
|
|
||||||
} else if (bacnet_stricmp("bip", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_BIP;
|
|
||||||
} else if (bacnet_stricmp("bip6", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_BIP6;
|
|
||||||
} else if (bacnet_stricmp("ethernet", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_ETHERNET;
|
|
||||||
} else if (bacnet_stricmp("arcnet", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_ARCNET;
|
|
||||||
} else if (bacnet_stricmp("mstp", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_MSTP;
|
|
||||||
} else if (bacnet_stricmp("bsc", pEnv) == 0) {
|
|
||||||
port_type = PORT_TYPE_BSC;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if defined(BACDL_BIP)
|
|
||||||
datalink_set("bip");
|
|
||||||
port_type = PORT_TYPE_BIP;
|
|
||||||
#elif defined(BACDL_BIP6)
|
|
||||||
datalink_set("bip6");
|
|
||||||
port_type = PORT_TYPE_BIP6;
|
|
||||||
#elif defined(BACDL_MSTP)
|
|
||||||
datalink_set("mstp");
|
|
||||||
port_type = PORT_TYPE_MSTP;
|
|
||||||
#elif defined(BACDL_ETHERNET)
|
|
||||||
datalink_set("ethernet");
|
|
||||||
port_type = PORT_TYPE_ETHERNET;
|
|
||||||
#elif defined(BACDL_ARCNET)
|
|
||||||
datalink_set("arcnet");
|
|
||||||
port_type = PORT_TYPE_ARCNET;
|
|
||||||
#elif defined(BACDL_ZIGBEE)
|
|
||||||
datalink_set("zigbee");
|
|
||||||
port_type = PORT_TYPE_ZIGBEE;
|
|
||||||
#elif defined(BACDL_BSC)
|
|
||||||
datalink_set("bsc");
|
|
||||||
port_type = PORT_TYPE_BSC;
|
|
||||||
#else
|
|
||||||
datalink_set("none");
|
|
||||||
port_type = PORT_TYPE_NON_BACNET;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* if we are not compiling with multiple datalinks,
|
|
||||||
then we are using the only one available */
|
|
||||||
#if defined(BACDL_BIP)
|
|
||||||
port_type = PORT_TYPE_BIP;
|
|
||||||
#elif defined(BACDL_BIP6)
|
|
||||||
port_type = PORT_TYPE_BIP6;
|
|
||||||
#elif defined(BACDL_MSTP)
|
|
||||||
port_type = PORT_TYPE_MSTP;
|
|
||||||
#elif defined(BACDL_ETHERNET)
|
|
||||||
port_type = PORT_TYPE_ETHERNET;
|
|
||||||
#elif defined(BACDL_ARCNET)
|
|
||||||
port_type = PORT_TYPE_ARCNET;
|
|
||||||
#elif defined(BACDL_ZIGBEE)
|
|
||||||
port_type = PORT_TYPE_ZIGBEE;
|
|
||||||
#elif defined(BACDL_BSC)
|
|
||||||
port_type = PORT_TYPE_BSC;
|
|
||||||
#else
|
|
||||||
port_type = PORT_TYPE_NON_BACNET;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if defined(BACFILE)
|
|
||||||
/* initialize the POSIX file objects */
|
|
||||||
bacfile_posix_init();
|
|
||||||
if (Datalink_Debug) {
|
|
||||||
debug_printf_stderr("POSIX file services initialized.\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* === Initialize the Network Port Object Here === */
|
|
||||||
Network_Port_Type_Set(Network_Port_Instance, port_type);
|
|
||||||
switch (port_type) {
|
|
||||||
case PORT_TYPE_BIP:
|
|
||||||
dlenv_network_port_bip_init(Network_Port_Instance);
|
|
||||||
break;
|
|
||||||
case PORT_TYPE_MSTP:
|
|
||||||
dlenv_network_port_mstp_init(Network_Port_Instance);
|
|
||||||
break;
|
|
||||||
case PORT_TYPE_BIP6:
|
|
||||||
dlenv_network_port_bip6_init(Network_Port_Instance);
|
|
||||||
break;
|
|
||||||
case PORT_TYPE_ZIGBEE:
|
|
||||||
dlenv_network_port_zigbee_init(Network_Port_Instance);
|
|
||||||
break;
|
|
||||||
case PORT_TYPE_BSC:
|
|
||||||
dlenv_network_port_bsc_init(Network_Port_Instance);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pEnv = getenv("BACNET_APDU_TIMEOUT");
|
|
||||||
if (pEnv) {
|
|
||||||
apdu_timeout_set((uint16_t)strtol(pEnv, NULL, 0));
|
|
||||||
} else {
|
|
||||||
if (port_type == PORT_TYPE_MSTP) {
|
|
||||||
apdu_timeout_set(60000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pEnv = getenv("BACNET_APDU_RETRIES");
|
|
||||||
if (pEnv) {
|
|
||||||
apdu_retries_set((uint8_t)strtol(pEnv, NULL, 0));
|
|
||||||
}
|
|
||||||
/* === INIT - Initialize the Datalink Here === */
|
|
||||||
pEnv = getenv("BACNET_IFACE");
|
|
||||||
if (Datalink_Debug) {
|
|
||||||
debug_fprintf(stderr, "BACNET_IFACE=%s\n", pEnv ? pEnv : "none");
|
|
||||||
}
|
|
||||||
if (!datalink_init(pEnv)) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
/* === POST INIT - After the Datalink is Initialized === */
|
|
||||||
#if (MAX_TSM_TRANSACTIONS)
|
|
||||||
pEnv = getenv("BACNET_INVOKE_ID");
|
|
||||||
if (pEnv) {
|
|
||||||
tsm_invokeID_set((uint8_t)strtol(pEnv, NULL, 0));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (port_type == PORT_TYPE_BIP) {
|
|
||||||
bbmd_register_as_foreign_device();
|
|
||||||
} else if (port_type == PORT_TYPE_BIP6) {
|
|
||||||
bbmd6_register_as_foreign_device();
|
|
||||||
} else if (port_type == PORT_TYPE_BSC) {
|
|
||||||
bsc_register_as_node(Network_Port_Instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,15 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
uint8_t dlenv_get_port_type(void);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void dlenv_init_no_device_registration(uint8_t port_type);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool dlenv_register_device(uint8_t port_type, bool wait_until_connected);
|
||||||
|
|
||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
void dlenv_init(void);
|
void dlenv_init(void);
|
||||||
|
|
||||||
@@ -47,6 +56,9 @@ void dlenv_bbmd_ttl_set(uint16_t ttl_secs);
|
|||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
int dlenv_bbmd_result(void);
|
int dlenv_bbmd_result(void);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool dlenv_is_bsc_hub_connected(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
Reference in New Issue
Block a user