Add BACnet Zigbee VMAC table and unit test. (#1054)
This commit is contained in:
@@ -74,6 +74,11 @@ option(
|
|||||||
"compile with ipv6 datalink support"
|
"compile with ipv6 datalink support"
|
||||||
ON)
|
ON)
|
||||||
|
|
||||||
|
option(
|
||||||
|
BACDL_ZIGBEE
|
||||||
|
"compile with zigbee datalink support"
|
||||||
|
ON)
|
||||||
|
|
||||||
option(
|
option(
|
||||||
BACDL_BSC
|
BACDL_BSC
|
||||||
"compile with secure-connect support"
|
"compile with secure-connect support"
|
||||||
@@ -84,6 +89,7 @@ if(NOT (BACDL_ETHERNET OR
|
|||||||
BACDL_ARCNET OR
|
BACDL_ARCNET OR
|
||||||
BACDL_BIP OR
|
BACDL_BIP OR
|
||||||
BACDL_BIP6 OR
|
BACDL_BIP6 OR
|
||||||
|
BACDL_ZIGBEE OR
|
||||||
BACDL_BSC OR
|
BACDL_BSC OR
|
||||||
BACDL_CUSTOM))
|
BACDL_CUSTOM))
|
||||||
add_definitions(-DBACDL_NONE)
|
add_definitions(-DBACDL_NONE)
|
||||||
@@ -295,6 +301,8 @@ add_library(${PROJECT_NAME}
|
|||||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/h_bbmd6.h>
|
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/h_bbmd6.h>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/vmac.c>
|
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/vmac.c>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/vmac.h>
|
$<$<BOOL:${BACDL_BIP6}>:src/bacnet/basic/bbmd6/vmac.h>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:src/bacnet/basic/bzll/bzllvmac.c>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:src/bacnet/basic/bzll/bzllvmac.h>
|
||||||
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bvlc-sc.c>
|
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bvlc-sc.c>
|
||||||
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bvlc-sc.h>
|
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bvlc-sc.h>
|
||||||
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bsc-socket.c>
|
$<$<BOOL:${BACDL_BSC}>:src/bacnet/datalink/bsc/bsc-socket.c>
|
||||||
@@ -693,6 +701,7 @@ target_compile_definitions(
|
|||||||
$<$<BOOL:${BACDL_BIP}>:BACDL_BIP>
|
$<$<BOOL:${BACDL_BIP}>:BACDL_BIP>
|
||||||
$<$<BOOL:${BACDL_BSC}>:BACDL_BSC>
|
$<$<BOOL:${BACDL_BSC}>:BACDL_BSC>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:BACDL_BIP6>
|
$<$<BOOL:${BACDL_BIP6}>:BACDL_BIP6>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:BACDL_ZIGBEE>
|
||||||
$<$<BOOL:${BACDL_ARCNET}>:BACDL_ARCNET>
|
$<$<BOOL:${BACDL_ARCNET}>:BACDL_ARCNET>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:BACDL_MSTP>
|
$<$<BOOL:${BACDL_MSTP}>:BACDL_MSTP>
|
||||||
$<$<BOOL:${BACDL_ETHERNET}>:BACDL_ETHERNET>
|
$<$<BOOL:${BACDL_ETHERNET}>:BACDL_ETHERNET>
|
||||||
@@ -733,6 +742,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
|||||||
ports/linux/datetime-init.c
|
ports/linux/datetime-init.c
|
||||||
$<$<BOOL:${BACDL_BIP}>:ports/linux/bip-init.c>
|
$<$<BOOL:${BACDL_BIP}>:ports/linux/bip-init.c>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:ports/linux/bip6.c>
|
$<$<BOOL:${BACDL_BIP6}>:ports/linux/bip6.c>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:ports/linux/bzll-init.c>
|
||||||
$<$<BOOL:${BACDL_ARCNET}>:ports/linux/arcnet.c>
|
$<$<BOOL:${BACDL_ARCNET}>:ports/linux/arcnet.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/linux/rs485.c>
|
$<$<BOOL:${BACDL_MSTP}>:ports/linux/rs485.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/linux/rs485.h>
|
$<$<BOOL:${BACDL_MSTP}>:ports/linux/rs485.h>
|
||||||
@@ -761,6 +771,7 @@ elseif(WIN32)
|
|||||||
ports/win32/bacport.h
|
ports/win32/bacport.h
|
||||||
$<$<BOOL:${BACDL_BIP6}>:ports/win32/bip6.c>
|
$<$<BOOL:${BACDL_BIP6}>:ports/win32/bip6.c>
|
||||||
$<$<BOOL:${BACDL_BIP}>:ports/win32/bip-init.c>
|
$<$<BOOL:${BACDL_BIP}>:ports/win32/bip-init.c>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:ports/win32/bzll-init.c>
|
||||||
ports/win32/datetime-init.c
|
ports/win32/datetime-init.c
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/win32/dlmstp.c>
|
$<$<BOOL:${BACDL_MSTP}>:ports/win32/dlmstp.c>
|
||||||
# ports/win32/dlmstp-mm.c
|
# ports/win32/dlmstp-mm.c
|
||||||
@@ -808,6 +819,7 @@ elseif(APPLE)
|
|||||||
target_sources(${PROJECT_NAME} PRIVATE
|
target_sources(${PROJECT_NAME} PRIVATE
|
||||||
ports/bsd/bacport.h
|
ports/bsd/bacport.h
|
||||||
$<$<BOOL:${BACDL_BIP}>:ports/bsd/bip-init.c>
|
$<$<BOOL:${BACDL_BIP}>:ports/bsd/bip-init.c>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:ports/bsd/bzll-init.c>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:ports/bsd/bip6.c>
|
$<$<BOOL:${BACDL_BIP6}>:ports/bsd/bip6.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.c>
|
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.h>
|
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.h>
|
||||||
@@ -848,6 +860,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
|
|||||||
target_sources(${PROJECT_NAME} PRIVATE
|
target_sources(${PROJECT_NAME} PRIVATE
|
||||||
ports/bsd/bacport.h
|
ports/bsd/bacport.h
|
||||||
$<$<BOOL:${BACDL_BIP}>:ports/bsd/bip-init.c>
|
$<$<BOOL:${BACDL_BIP}>:ports/bsd/bip-init.c>
|
||||||
|
$<$<BOOL:${BACDL_ZIGBEE}>:ports/bsd/bzll-init.c>
|
||||||
$<$<BOOL:${BACDL_BIP6}>:ports/bsd/bip6.c>
|
$<$<BOOL:${BACDL_BIP6}>:ports/bsd/bip6.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.c>
|
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.c>
|
||||||
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.h>
|
$<$<BOOL:${BACDL_MSTP}>:ports/bsd/rs485.h>
|
||||||
@@ -1231,4 +1244,5 @@ message(STATUS "BACNET: BACDL_BIP:......................\"${BACDL_BIP}\"")
|
|||||||
message(STATUS "BACNET: BACDL_BSC:......................\"${BACDL_BSC}\"")
|
message(STATUS "BACNET: BACDL_BSC:......................\"${BACDL_BSC}\"")
|
||||||
message(STATUS "BACNET: BACDL_ARCNET:...................\"${BACDL_ARCNET}\"")
|
message(STATUS "BACNET: BACDL_ARCNET:...................\"${BACDL_ARCNET}\"")
|
||||||
message(STATUS "BACNET: BACDL_MSTP:.....................\"${BACDL_MSTP}\"")
|
message(STATUS "BACNET: BACDL_MSTP:.....................\"${BACDL_MSTP}\"")
|
||||||
|
message(STATUS "BACNET: BACDL_ZIGBEE:...................\"${BACDL_ZIGBEE}\"")
|
||||||
message(STATUS "BACNET: BACDL_ETHERNET:.................\"${BACDL_ETHERNET}\"")
|
message(STATUS "BACNET: BACDL_ETHERNET:.................\"${BACDL_ETHERNET}\"")
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ PORT_MSTP_SRC = \
|
|||||||
PORT_ETHERNET_SRC = \
|
PORT_ETHERNET_SRC = \
|
||||||
$(BACNET_PORT_DIR)/ethernet.c
|
$(BACNET_PORT_DIR)/ethernet.c
|
||||||
|
|
||||||
|
PORT_ZIGBEE_SRC = \
|
||||||
|
$(BACNET_PORT_DIR)/bzll-init.c \
|
||||||
|
$(BACNET_SRC_DIR)/bacnet/basic/bzll/bzllvmac.c
|
||||||
|
|
||||||
PORT_BIP_SRC = \
|
PORT_BIP_SRC = \
|
||||||
$(BACNET_PORT_DIR)/bip-init.c \
|
$(BACNET_PORT_DIR)/bip-init.c \
|
||||||
$(BACNET_SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c
|
$(BACNET_SRC_DIR)/bacnet/basic/bbmd/h_bbmd.c
|
||||||
@@ -81,6 +85,7 @@ PORT_ALL_SRC = \
|
|||||||
$(PORT_ARCNET_SRC) \
|
$(PORT_ARCNET_SRC) \
|
||||||
$(PORT_MSTP_SRC) \
|
$(PORT_MSTP_SRC) \
|
||||||
$(PORT_ETHERNET_SRC) \
|
$(PORT_ETHERNET_SRC) \
|
||||||
|
$(PORT_ZIGBEE_SRC) \
|
||||||
$(PORT_BIP_SRC) \
|
$(PORT_BIP_SRC) \
|
||||||
$(PORT_BIP6_SRC) \
|
$(PORT_BIP6_SRC) \
|
||||||
$(PORT_BSC_SRC)
|
$(PORT_BSC_SRC)
|
||||||
@@ -103,6 +108,9 @@ endif
|
|||||||
ifeq (${BACDL_DEFINE},-DBACDL_ETHERNET=1)
|
ifeq (${BACDL_DEFINE},-DBACDL_ETHERNET=1)
|
||||||
BACNET_PORT_SRC = ${PORT_ETHERNET_SRC} ${APPS_ENVIRONMENT_SRC}
|
BACNET_PORT_SRC = ${PORT_ETHERNET_SRC} ${APPS_ENVIRONMENT_SRC}
|
||||||
endif
|
endif
|
||||||
|
ifeq (${BACDL_DEFINE},-DBACDL_ZIGBEE=1)
|
||||||
|
BACNET_PORT_SRC = ${PORT_ZIGBEE_SRC} ${APPS_ENVIRONMENT_SRC}
|
||||||
|
endif
|
||||||
ifeq (${BACDL_DEFINE},-DBACDL_NONE=1)
|
ifeq (${BACDL_DEFINE},-DBACDL_NONE=1)
|
||||||
BACNET_PORT_SRC = ${PORT_NONE_SRC}
|
BACNET_PORT_SRC = ${PORT_NONE_SRC}
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Initializes BACnet Zigbee Link Layer interface (BSD).
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
/* BACnet specific */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
#include "bacnet/bacaddr.h"
|
||||||
|
#include "bacnet/bacint.h"
|
||||||
|
#include "bacnet/datalink/bzll.h"
|
||||||
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
|
/**
|
||||||
|
* @brief Initialize the datalink
|
||||||
|
* @param ifname - the name of the datalink
|
||||||
|
*/
|
||||||
|
bool bzll_init(char *ifname)
|
||||||
|
{
|
||||||
|
(void)ifname;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a protocol data unit (PDU) to the network
|
||||||
|
* @param dest - destination address
|
||||||
|
* @param npdu_data - network routing data
|
||||||
|
* @param pdu - protocol data unit (PDU) to send
|
||||||
|
* @param pdu_len - size of the protocol data unit (PDU)
|
||||||
|
*/
|
||||||
|
int bzll_send_pdu(
|
||||||
|
BACNET_ADDRESS *dest,
|
||||||
|
BACNET_NPDU_DATA *npdu_data,
|
||||||
|
uint8_t *pdu,
|
||||||
|
unsigned pdu_len)
|
||||||
|
{
|
||||||
|
(void)dest;
|
||||||
|
(void)npdu_data;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll the datalink queue to see if a packet has arrived
|
||||||
|
* @param src - origin address of the packet
|
||||||
|
* @param pdu - protocol data unit (PDU) buffer to store received packet
|
||||||
|
* @param pdu_size - size of the protocol data unit (PDU) buffer
|
||||||
|
* @param timeout - number of milliseconds to wait for a packet
|
||||||
|
*/
|
||||||
|
uint16_t bzll_receive(
|
||||||
|
BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_size, unsigned timeout)
|
||||||
|
{
|
||||||
|
(void)src;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_size;
|
||||||
|
(void)timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cleanup the datalink data or connections
|
||||||
|
*/
|
||||||
|
void bzll_cleanup(void)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the a data link broadcast address
|
||||||
|
* @param dest - address to be filled with broadcast designator
|
||||||
|
*/
|
||||||
|
void bzll_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->mac_len = 3;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->mac[i] = 0xFF;
|
||||||
|
}
|
||||||
|
dest->net = BACNET_BROADCAST_NETWORK;
|
||||||
|
/* always zero when DNET is broadcast */
|
||||||
|
dest->len = 0;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->adr[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BACnet address for my interface
|
||||||
|
* @param my_address - address to be filled with my interface address
|
||||||
|
*/
|
||||||
|
void bzll_get_my_address(BACNET_ADDRESS *my_address)
|
||||||
|
{
|
||||||
|
uint32_t instance;
|
||||||
|
|
||||||
|
instance = Device_Object_Instance_Number();
|
||||||
|
bacnet_vmac_address_set(my_address, instance);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the maintenance timer for the datalink
|
||||||
|
* @param seconds - number of seconds to set the timer
|
||||||
|
*/
|
||||||
|
void bzll_maintenance_timer(uint16_t seconds)
|
||||||
|
{
|
||||||
|
(void)seconds;
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Initializes BACnet Zigbee Link Layer interface (Linux).
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
/* BACnet specific */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
#include "bacnet/bacaddr.h"
|
||||||
|
#include "bacnet/bacint.h"
|
||||||
|
#include "bacnet/datalink/bzll.h"
|
||||||
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the datalink
|
||||||
|
* @param ifname - the name of the datalink
|
||||||
|
*/
|
||||||
|
bool bzll_init(char *ifname)
|
||||||
|
{
|
||||||
|
(void)ifname;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a protocol data unit (PDU) to the network
|
||||||
|
* @param dest - destination address
|
||||||
|
* @param npdu_data - network routing data
|
||||||
|
* @param pdu - protocol data unit (PDU) to send
|
||||||
|
* @param pdu_len - size of the protocol data unit (PDU)
|
||||||
|
*/
|
||||||
|
int bzll_send_pdu(
|
||||||
|
BACNET_ADDRESS *dest,
|
||||||
|
BACNET_NPDU_DATA *npdu_data,
|
||||||
|
uint8_t *pdu,
|
||||||
|
unsigned pdu_len)
|
||||||
|
{
|
||||||
|
(void)dest;
|
||||||
|
(void)npdu_data;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll the datalink queue to see if a packet has arrived
|
||||||
|
* @param src - origin address of the packet
|
||||||
|
* @param pdu - protocol data unit (PDU) buffer to store received packet
|
||||||
|
* @param pdu_size - size of the protocol data unit (PDU) buffer
|
||||||
|
* @param timeout - number of milliseconds to wait for a packet
|
||||||
|
*/
|
||||||
|
uint16_t bzll_receive(
|
||||||
|
BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_size, unsigned timeout)
|
||||||
|
{
|
||||||
|
(void)src;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_size;
|
||||||
|
(void)timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cleanup the datalink data or connections
|
||||||
|
*/
|
||||||
|
void bzll_cleanup(void)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the a data link broadcast address
|
||||||
|
* @param dest - address to be filled with broadcast designator
|
||||||
|
*/
|
||||||
|
void bzll_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->mac_len = 3;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->mac[i] = 0xFF;
|
||||||
|
}
|
||||||
|
dest->net = BACNET_BROADCAST_NETWORK;
|
||||||
|
/* always zero when DNET is broadcast */
|
||||||
|
dest->len = 0;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->adr[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BACnet address for my interface
|
||||||
|
* @param my_address - address to be filled with my interface address
|
||||||
|
*/
|
||||||
|
void bzll_get_my_address(BACNET_ADDRESS *my_address)
|
||||||
|
{
|
||||||
|
uint32_t instance;
|
||||||
|
|
||||||
|
instance = Device_Object_Instance_Number();
|
||||||
|
bacnet_vmac_address_set(my_address, instance);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the maintenance timer for the datalink
|
||||||
|
* @param seconds - number of seconds to set the timer
|
||||||
|
*/
|
||||||
|
void bzll_maintenance_timer(uint16_t seconds)
|
||||||
|
{
|
||||||
|
(void)seconds;
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Initializes BACnet Zigbee Link Layer interface (Windows).
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
/* BACnet specific */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
#include "bacnet/bacaddr.h"
|
||||||
|
#include "bacnet/bacint.h"
|
||||||
|
#include "bacnet/datalink/bzll.h"
|
||||||
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the datalink
|
||||||
|
* @param ifname - the name of the datalink
|
||||||
|
*/
|
||||||
|
bool bzll_init(char *ifname)
|
||||||
|
{
|
||||||
|
(void)ifname;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a protocol data unit (PDU) to the network
|
||||||
|
* @param dest - destination address
|
||||||
|
* @param npdu_data - network routing data
|
||||||
|
* @param pdu - protocol data unit (PDU) to send
|
||||||
|
* @param pdu_len - size of the protocol data unit (PDU)
|
||||||
|
*/
|
||||||
|
int bzll_send_pdu(
|
||||||
|
BACNET_ADDRESS *dest,
|
||||||
|
BACNET_NPDU_DATA *npdu_data,
|
||||||
|
uint8_t *pdu,
|
||||||
|
unsigned pdu_len)
|
||||||
|
{
|
||||||
|
(void)dest;
|
||||||
|
(void)npdu_data;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Poll the datalink queue to see if a packet has arrived
|
||||||
|
* @param src - origin address of the packet
|
||||||
|
* @param pdu - protocol data unit (PDU) buffer to store received packet
|
||||||
|
* @param pdu_size - size of the protocol data unit (PDU) buffer
|
||||||
|
* @param timeout - number of milliseconds to wait for a packet
|
||||||
|
*/
|
||||||
|
uint16_t bzll_receive(
|
||||||
|
BACNET_ADDRESS *src, uint8_t *pdu, uint16_t pdu_size, unsigned timeout)
|
||||||
|
{
|
||||||
|
(void)src;
|
||||||
|
(void)pdu;
|
||||||
|
(void)pdu_size;
|
||||||
|
(void)timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cleanup the datalink data or connections
|
||||||
|
*/
|
||||||
|
void bzll_cleanup(void)
|
||||||
|
{
|
||||||
|
/* nothing to do */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the a data link broadcast address
|
||||||
|
* @param dest - address to be filled with broadcast designator
|
||||||
|
*/
|
||||||
|
void bzll_get_broadcast_address(BACNET_ADDRESS *dest)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->mac_len = 3;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->mac[i] = 0xFF;
|
||||||
|
}
|
||||||
|
dest->net = BACNET_BROADCAST_NETWORK;
|
||||||
|
/* always zero when DNET is broadcast */
|
||||||
|
dest->len = 0;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
dest->adr[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the BACnet address for my interface
|
||||||
|
* @param my_address - address to be filled with my interface address
|
||||||
|
*/
|
||||||
|
void bzll_get_my_address(BACNET_ADDRESS *my_address)
|
||||||
|
{
|
||||||
|
uint32_t instance;
|
||||||
|
|
||||||
|
instance = Device_Object_Instance_Number();
|
||||||
|
bacnet_vmac_address_set(my_address, instance);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the maintenance timer for the datalink
|
||||||
|
* @param seconds - number of seconds to set the timer
|
||||||
|
*/
|
||||||
|
void bzll_maintenance_timer(uint16_t seconds)
|
||||||
|
{
|
||||||
|
(void)seconds;
|
||||||
|
}
|
||||||
@@ -539,3 +539,29 @@ int bacnet_vmac_entry_decode(
|
|||||||
|
|
||||||
return apdu_len;
|
return apdu_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Set a BACnet VMAC Address from a Device ID
|
||||||
|
*
|
||||||
|
* @param addr - BACnet address that be set
|
||||||
|
* @param device_id - 22-bit device ID
|
||||||
|
*
|
||||||
|
* @return true if the address is set
|
||||||
|
*/
|
||||||
|
bool bacnet_vmac_address_set(BACNET_ADDRESS *addr, uint32_t device_id)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (addr) {
|
||||||
|
encode_unsigned24(&addr->mac[0], device_id);
|
||||||
|
addr->mac_len = 3;
|
||||||
|
addr->net = 0;
|
||||||
|
addr->len = 0;
|
||||||
|
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||||
|
addr->adr[i] = 0;
|
||||||
|
}
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ int bacnet_vmac_entry_encode(
|
|||||||
BACNET_STACK_EXPORT
|
BACNET_STACK_EXPORT
|
||||||
int bacnet_vmac_entry_decode(
|
int bacnet_vmac_entry_decode(
|
||||||
const uint8_t *apdu, uint32_t apdu_size, BACNET_VMAC_ENTRY *value);
|
const uint8_t *apdu, uint32_t apdu_size, BACNET_VMAC_ENTRY *value);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool bacnet_vmac_address_set(BACNET_ADDRESS *addr, uint32_t device_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Virtual MAC (VMAC) for BACnet ZigBee Link Layer
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/sys/keylist.h"
|
||||||
|
/* me! */
|
||||||
|
#include "bacnet/basic/bzll/bzllvmac.h"
|
||||||
|
|
||||||
|
/* enable debugging */
|
||||||
|
static bool VMAC_Debug = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable debugging if print is enabled
|
||||||
|
*/
|
||||||
|
void BZLL_VMAC_Debug_Enable(void)
|
||||||
|
{
|
||||||
|
VMAC_Debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
Handle VMAC address binding */
|
||||||
|
|
||||||
|
/* This module is used to handle the virtual MAC address binding that */
|
||||||
|
/* occurs in BACnet for ZigBee or IPv6. */
|
||||||
|
|
||||||
|
/* Key List for storing the object data sorted by instance number */
|
||||||
|
static OS_Keylist VMAC_List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of VMAC in the list
|
||||||
|
*/
|
||||||
|
unsigned int BZLL_VMAC_Count(void)
|
||||||
|
{
|
||||||
|
return (unsigned int)Keylist_Count(VMAC_List);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a VMAC to the list
|
||||||
|
*
|
||||||
|
* @param device_id - BACnet device object instance number
|
||||||
|
* @param vmac - BACnet ZigBee Link Layer address
|
||||||
|
*
|
||||||
|
* @return true if the device ID and MAC are added
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Add(uint32_t device_id, const struct bzll_vmac_data *vmac)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
struct bzll_vmac_data *list_vmac = NULL;
|
||||||
|
uint32_t list_device_id = 0;
|
||||||
|
int index = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
if (BZLL_VMAC_Entry_To_Device_ID(vmac, &list_device_id)) {
|
||||||
|
if (list_device_id == device_id) {
|
||||||
|
/* valid VMAC entry exists. */
|
||||||
|
found = true;
|
||||||
|
status = true;
|
||||||
|
} else {
|
||||||
|
/* VMAC exists, but device ID changed */
|
||||||
|
BZLL_VMAC_Delete(list_device_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
list_vmac = Keylist_Data(VMAC_List, device_id);
|
||||||
|
if (list_vmac) {
|
||||||
|
/* device ID already exists. Update MAC. */
|
||||||
|
memmove(list_vmac, vmac, sizeof(struct bzll_vmac_data));
|
||||||
|
found = true;
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
/* new entry - add it! */
|
||||||
|
list_vmac = calloc(1, sizeof(struct bzll_vmac_data));
|
||||||
|
if (list_vmac) {
|
||||||
|
/* copy the MAC into the data store */
|
||||||
|
for (i = 0; i < sizeof(list_vmac->mac); i++) {
|
||||||
|
list_vmac->mac[i] = vmac->mac[i];
|
||||||
|
}
|
||||||
|
list_vmac->endpoint = vmac->endpoint;
|
||||||
|
index = Keylist_Data_Add(VMAC_List, device_id, list_vmac);
|
||||||
|
if (index >= 0) {
|
||||||
|
status = true;
|
||||||
|
if (VMAC_Debug) {
|
||||||
|
debug_fprintf(
|
||||||
|
stderr, "BZLL VMAC %u added.\n",
|
||||||
|
(unsigned int)device_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a VMAC in the list by seeking the Device ID, and deletes it.
|
||||||
|
*
|
||||||
|
* @param device_id - BACnet device object instance number
|
||||||
|
*
|
||||||
|
* @return pointer to the VMAC data from the list - be sure to free() it!
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Delete(uint32_t device_id)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
struct bzll_vmac_data *pVMAC;
|
||||||
|
|
||||||
|
pVMAC = Keylist_Data_Delete(VMAC_List, device_id);
|
||||||
|
if (pVMAC) {
|
||||||
|
free(pVMAC);
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a VMAC in the list by seeking the Device ID.
|
||||||
|
*
|
||||||
|
* @param device_id - BACnet device object instance number
|
||||||
|
*
|
||||||
|
* @return pointer to the VMAC data from the list
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Entry_By_Device_ID(
|
||||||
|
uint32_t device_id, struct bzll_vmac_data *vmac)
|
||||||
|
{
|
||||||
|
struct bzll_vmac_data *data = Keylist_Data(VMAC_List, device_id);
|
||||||
|
if (data && vmac) {
|
||||||
|
memcpy(vmac, data, sizeof(struct bzll_vmac_data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a VMAC in the list by seeking the list index
|
||||||
|
*
|
||||||
|
* @param index - Index that shall be returned
|
||||||
|
* @param device_id - BACnet device object instance number
|
||||||
|
*
|
||||||
|
* @return true if the device_id and vmac are found
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Entry_By_Index(
|
||||||
|
int index, uint32_t *device_id, struct bzll_vmac_data *vmac)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
struct bzll_vmac_data *data;
|
||||||
|
KEY key = 0;
|
||||||
|
|
||||||
|
data = Keylist_Data_Index(VMAC_List, index);
|
||||||
|
if (data) {
|
||||||
|
/* virtual MAC is the Device ID */
|
||||||
|
status = Keylist_Index_Key(VMAC_List, index, &key);
|
||||||
|
if (status) {
|
||||||
|
if (device_id) {
|
||||||
|
*device_id = key;
|
||||||
|
}
|
||||||
|
if (vmac) {
|
||||||
|
memcpy(vmac, data, sizeof(struct bzll_vmac_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compare the VMAC address
|
||||||
|
*
|
||||||
|
* @param vmac1 - VMAC address that will be compared to vmac2
|
||||||
|
* @param vmac2 - VMAC address that will be compared to vmac1
|
||||||
|
*
|
||||||
|
* @return true if the addresses are the same
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Same(
|
||||||
|
const struct bzll_vmac_data *vmac1, const struct bzll_vmac_data *vmac2)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (vmac1 && vmac2) {
|
||||||
|
if (memcmp(vmac1->mac, vmac2->mac, BZLL_VMAC_EUI64) == 0 &&
|
||||||
|
vmac1->endpoint == vmac2->endpoint) {
|
||||||
|
status = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a VMAC in the list by seeking a matching VMAC address
|
||||||
|
*
|
||||||
|
* @param vmac - VMAC address that will be sought
|
||||||
|
* @param device_id - BACnet device object instance number
|
||||||
|
*
|
||||||
|
* @return true if the VMAC address was found
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Entry_To_Device_ID(
|
||||||
|
const struct bzll_vmac_data *vmac, uint32_t *device_id)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
struct bzll_vmac_data *list_vmac;
|
||||||
|
int count = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if (!vmac) {
|
||||||
|
return false; /* invalid parameter */
|
||||||
|
}
|
||||||
|
count = Keylist_Count(VMAC_List);
|
||||||
|
while (count) {
|
||||||
|
index = count - 1;
|
||||||
|
list_vmac = Keylist_Data_Index(VMAC_List, index);
|
||||||
|
if (list_vmac) {
|
||||||
|
if (BZLL_VMAC_Same(vmac, list_vmac)) {
|
||||||
|
status = Keylist_Index_Key(VMAC_List, index, device_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the VMAC address into the provided MAC and endpoint
|
||||||
|
*
|
||||||
|
* @param vmac - VMAC address that will be copied
|
||||||
|
* @param mac - pointer to the MAC array to copy into
|
||||||
|
* @param endpoint - pointer to the endpoint to copy into
|
||||||
|
*
|
||||||
|
* @return true if the VMAC address was copied
|
||||||
|
*/
|
||||||
|
bool BZLL_VMAC_Entry_Set(
|
||||||
|
struct bzll_vmac_data *vmac, const uint8_t *mac, uint8_t endpoint)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (vmac && mac) {
|
||||||
|
for (i = 0; i < BZLL_VMAC_EUI64; i++) {
|
||||||
|
vmac->mac[i] = mac[i]; /* copy the MAC */
|
||||||
|
}
|
||||||
|
vmac->endpoint = endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up the memory used by the VMAC list data
|
||||||
|
*/
|
||||||
|
void BZLL_VMAC_Cleanup(void)
|
||||||
|
{
|
||||||
|
struct bzll_vmac_data *pVMAC;
|
||||||
|
const int index = 0;
|
||||||
|
unsigned i = 0;
|
||||||
|
|
||||||
|
if (VMAC_List) {
|
||||||
|
do {
|
||||||
|
uint32_t device_id;
|
||||||
|
if (VMAC_Debug) {
|
||||||
|
Keylist_Index_Key(VMAC_List, index, &device_id);
|
||||||
|
}
|
||||||
|
pVMAC = Keylist_Data_Delete_By_Index(VMAC_List, index);
|
||||||
|
if (pVMAC) {
|
||||||
|
if (VMAC_Debug) {
|
||||||
|
debug_fprintf(
|
||||||
|
stderr, "BZLL VMAC List: %lu [",
|
||||||
|
(unsigned long)device_id);
|
||||||
|
/* print the MAC */
|
||||||
|
for (i = 0; i < BZLL_VMAC_EUI64; i++) {
|
||||||
|
debug_fprintf(stderr, "%02X", pVMAC->mac[i]);
|
||||||
|
}
|
||||||
|
debug_fprintf(stderr, "]\n");
|
||||||
|
}
|
||||||
|
free(pVMAC);
|
||||||
|
}
|
||||||
|
} while (pVMAC);
|
||||||
|
Keylist_Delete(VMAC_List);
|
||||||
|
VMAC_List = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the VMAC list data
|
||||||
|
*/
|
||||||
|
void BZLL_VMAC_Init(void)
|
||||||
|
{
|
||||||
|
VMAC_List = Keylist_Create();
|
||||||
|
if (VMAC_List) {
|
||||||
|
atexit(BZLL_VMAC_Cleanup);
|
||||||
|
debug_fprintf(stderr, "BZLL VMAC List initialized.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief API for Virtual MAC (VMAC) of BACnet Zigbee Link Layer (BZLL)
|
||||||
|
* @author Steve Karg <skarg@users.sourceforge.net>
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#ifndef BACNET_BASIC_BZLL_VMAC_H
|
||||||
|
#define BACNET_BASIC_BZLL_VMAC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
/* BACnet Stack defines - first */
|
||||||
|
#include "bacnet/bacdef.h"
|
||||||
|
|
||||||
|
/* define the max MAC as big as EUI64 */
|
||||||
|
#define BZLL_VMAC_EUI64 8
|
||||||
|
/**
|
||||||
|
* VMAC data structure
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
struct bzll_vmac_data {
|
||||||
|
uint8_t mac[BZLL_VMAC_EUI64];
|
||||||
|
uint8_t endpoint;
|
||||||
|
};
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Entry_By_Device_ID(
|
||||||
|
uint32_t device_id, struct bzll_vmac_data *vmac);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Entry_By_Index(
|
||||||
|
int index, uint32_t *device_id, struct bzll_vmac_data *vmac);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Entry_To_Device_ID(
|
||||||
|
const struct bzll_vmac_data *vmac, uint32_t *device_id);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Entry_Set(
|
||||||
|
struct bzll_vmac_data *vmac, const uint8_t *mac, uint8_t endpoint);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Add(uint32_t device_id, const struct bzll_vmac_data *vmac);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Delete(uint32_t device_id);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
bool BZLL_VMAC_Same(
|
||||||
|
const struct bzll_vmac_data *vmac1, const struct bzll_vmac_data *vmac2);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
unsigned int BZLL_VMAC_Count(void);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void BZLL_VMAC_Cleanup(void);
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void BZLL_VMAC_Init(void);
|
||||||
|
|
||||||
|
BACNET_STACK_EXPORT
|
||||||
|
void BZLL_VMAC_Debug_Enable(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif
|
||||||
@@ -276,7 +276,7 @@ void datalink_cleanup(void)
|
|||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_ZIGBEE)
|
#if defined(BACDL_ZIGBEE)
|
||||||
case DATALINK_ZIGBEE:
|
case DATALINK_ZIGBEE:
|
||||||
bytes = bzll_cleanup();
|
bzll_cleanup();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_BSC)
|
#if defined(BACDL_BSC)
|
||||||
@@ -321,7 +321,7 @@ void datalink_get_broadcast_address(BACNET_ADDRESS *dest)
|
|||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_ZIGBEE)
|
#if defined(BACDL_ZIGBEE)
|
||||||
case DATALINK_ZIGBEE:
|
case DATALINK_ZIGBEE:
|
||||||
bytes = bzll_get_broadcast_address(dest);
|
bzll_get_broadcast_address(dest);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_BSC)
|
#if defined(BACDL_BSC)
|
||||||
@@ -366,7 +366,7 @@ void datalink_get_my_address(BACNET_ADDRESS *my_address)
|
|||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_ZIGBEE)
|
#if defined(BACDL_ZIGBEE)
|
||||||
case DATALINK_ZIGBEE:
|
case DATALINK_ZIGBEE:
|
||||||
bytes = bzll_get_my_address(my_address);
|
bzll_get_my_address(my_address);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(BACDL_BSC)
|
#if defined(BACDL_BSC)
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ list(APPEND testdirs
|
|||||||
bacnet/basic/binding/address
|
bacnet/basic/binding/address
|
||||||
bacnet/basic/bbmd
|
bacnet/basic/bbmd
|
||||||
bacnet/basic/bbmd6
|
bacnet/basic/bbmd6
|
||||||
|
bacnet/basic/bzll
|
||||||
# basic/object
|
# basic/object
|
||||||
bacnet/basic/object/acc
|
bacnet/basic/object/acc
|
||||||
bacnet/basic/object/access_credential
|
bacnet/basic/object/access_credential
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||||
|
|
||||||
|
get_filename_component(basename ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||||
|
project(test_${basename}
|
||||||
|
VERSION 1.0.0
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z0-9_/-]*$"
|
||||||
|
"/src"
|
||||||
|
SRC_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
string(REGEX REPLACE
|
||||||
|
"/test/bacnet/[a-zA-Z0-9_/-]*$"
|
||||||
|
"/test"
|
||||||
|
TST_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
add_compile_definitions(
|
||||||
|
BIG_ENDIAN=0
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${SRC_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(${PROJECT_NAME}
|
||||||
|
# File(s) under test
|
||||||
|
${SRC_DIR}/bacnet/basic/bzll/bzllvmac.c
|
||||||
|
# Support files and stubs (pathname alphabetical)
|
||||||
|
${SRC_DIR}/bacnet/bacaddr.c
|
||||||
|
${SRC_DIR}/bacnet/bacdcode.c
|
||||||
|
${SRC_DIR}/bacnet/bacint.c
|
||||||
|
${SRC_DIR}/bacnet/bacstr.c
|
||||||
|
${SRC_DIR}/bacnet/bacreal.c
|
||||||
|
${SRC_DIR}/bacnet/iam.c
|
||||||
|
${SRC_DIR}/bacnet/npdu.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/bigend.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/debug.c
|
||||||
|
${SRC_DIR}/bacnet/basic/sys/keylist.c
|
||||||
|
${SRC_DIR}/bacnet/hostnport.c
|
||||||
|
# Test and test library files
|
||||||
|
./src/main.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Test file for a basic BACnet Zigbee Link Layer (BZLL)
|
||||||
|
* @author Steve Karg
|
||||||
|
* @date July 2025
|
||||||
|
* @copyright SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
#include <stdio.h> /* for standard i/o, like printing */
|
||||||
|
#include <stdint.h> /* for standard integer types uint8_t etc. */
|
||||||
|
#include <stdbool.h> /* for the standard bool type. */
|
||||||
|
#include <string.h> /* for memcpy */
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "bacnet/bacaddr.h"
|
||||||
|
#include "bacnet/bacdcode.h"
|
||||||
|
#include "bacnet/iam.h"
|
||||||
|
#include "bacnet/npdu.h"
|
||||||
|
#include "bacnet/datalink/bzll.h"
|
||||||
|
#include "bacnet/basic/sys/debug.h"
|
||||||
|
#include "bacnet/basic/object/device.h"
|
||||||
|
#include "bacnet/basic/bzll/bzllvmac.h"
|
||||||
|
|
||||||
|
struct device_info_t {
|
||||||
|
uint32_t Device_ID;
|
||||||
|
/* MAC Address shall be a ZigBee EUI64 and BACnet endpoint */
|
||||||
|
struct bzll_vmac_data VMAC_Data;
|
||||||
|
BACNET_ADDRESS BACnet_Address;
|
||||||
|
};
|
||||||
|
static struct device_info_t TD;
|
||||||
|
static struct device_info_t IUT;
|
||||||
|
|
||||||
|
/* network stub functions */
|
||||||
|
/**
|
||||||
|
* BACnet/IP Datalink Receive handler.
|
||||||
|
*
|
||||||
|
* @param src - returns the source address
|
||||||
|
* @param npdu - returns the NPDU buffer
|
||||||
|
* @param max_npdu -maximum size of the NPDU buffer
|
||||||
|
* @param timeout - number of milliseconds to wait for a packet
|
||||||
|
*
|
||||||
|
* @return Number of bytes received, or 0 if none or timeout.
|
||||||
|
*/
|
||||||
|
uint16_t bzll_receive(
|
||||||
|
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
|
||||||
|
{
|
||||||
|
(void)src;
|
||||||
|
(void)npdu;
|
||||||
|
(void)max_npdu;
|
||||||
|
(void)timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The send function for BACnet/IPv6 driver layer
|
||||||
|
*
|
||||||
|
* @param dest - Points to a BACNET_IP6_ADDRESS structure containing the
|
||||||
|
* destination address.
|
||||||
|
* @param mtu - the bytes of data to send
|
||||||
|
* @param mtu_len - the number of bytes of data to send
|
||||||
|
*
|
||||||
|
* @return Upon successful completion, returns the number of bytes sent.
|
||||||
|
* Otherwise, -1 shall be returned to indicate the error.
|
||||||
|
*/
|
||||||
|
int bzll_send_mpdu(
|
||||||
|
const BACNET_IP6_ADDRESS *dest, const uint8_t *mtu, uint16_t mtu_len)
|
||||||
|
{
|
||||||
|
(void)dest;
|
||||||
|
(void)mtu;
|
||||||
|
(void)mtu_len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return the Object Instance number for our (single) Device Object.
|
||||||
|
* This is a key function, widely invoked by the handler code, since
|
||||||
|
* it provides "our" (ie, local) address.
|
||||||
|
*
|
||||||
|
* @return The Instance number used in the BACNET_OBJECT_ID for the Device.
|
||||||
|
*/
|
||||||
|
uint32_t Device_Object_Instance_Number(void)
|
||||||
|
{
|
||||||
|
return IUT.Device_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test setup function
|
||||||
|
*/
|
||||||
|
static void test_setup(void)
|
||||||
|
{
|
||||||
|
uint8_t td_mac[BZLL_VMAC_EUI64] = { 0x00, 0x12, 0x34, 0x56,
|
||||||
|
0x78, 0x9A, 0xBC, 0xDE };
|
||||||
|
uint8_t td_endpoint = 0x01;
|
||||||
|
uint8_t iut_mac[BZLL_VMAC_EUI64] = { 0x00, 0x12, 0x34, 0x56,
|
||||||
|
0x78, 0x9A, 0xBC, 0xDF };
|
||||||
|
uint8_t iut_endpoint = 0x02;
|
||||||
|
|
||||||
|
BZLL_VMAC_Init();
|
||||||
|
TD.Device_ID = 12345;
|
||||||
|
bacnet_vmac_address_set(&TD.BACnet_Address, TD.Device_ID);
|
||||||
|
BZLL_VMAC_Entry_Set(&TD.VMAC_Data, td_mac, td_endpoint);
|
||||||
|
IUT.Device_ID = 67890;
|
||||||
|
bacnet_vmac_address_set(&IUT.BACnet_Address, IUT.Device_ID);
|
||||||
|
BZLL_VMAC_Entry_Set(&IUT.VMAC_Data, iut_mac, iut_endpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup function to free resources
|
||||||
|
*/
|
||||||
|
static void test_cleanup(void)
|
||||||
|
{
|
||||||
|
BZLL_VMAC_Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test function to execute the virtual address resolution
|
||||||
|
* and verify the functionality of the BZLL VMAC handling.
|
||||||
|
*
|
||||||
|
* This function will test adding, retrieving, and comparing VMAC entries.
|
||||||
|
* It will also check the behavior when changing device IDs.
|
||||||
|
*/
|
||||||
|
static void test_Execute_Virtual_Address_Resolution(void)
|
||||||
|
{
|
||||||
|
uint32_t test_vmac_src = 0;
|
||||||
|
uint32_t test_device_id = 0;
|
||||||
|
uint32_t old_device_id = 0;
|
||||||
|
struct bzll_vmac_data test_vmac_data = { 0 };
|
||||||
|
unsigned int count = 0;
|
||||||
|
int index = 0;
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
test_setup();
|
||||||
|
status = BZLL_VMAC_Add(TD.Device_ID, &TD.VMAC_Data);
|
||||||
|
assert(status == true);
|
||||||
|
status = BZLL_VMAC_Entry_By_Device_ID(TD.Device_ID, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
status = BZLL_VMAC_Same(&TD.VMAC_Data, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
/* change Device ID */
|
||||||
|
old_device_id = TD.Device_ID;
|
||||||
|
TD.Device_ID += 42;
|
||||||
|
status = BZLL_VMAC_Add(TD.Device_ID, &TD.VMAC_Data);
|
||||||
|
assert(status == true);
|
||||||
|
count = BZLL_VMAC_Count();
|
||||||
|
assert(count == 1);
|
||||||
|
status = BZLL_VMAC_Entry_By_Device_ID(TD.Device_ID, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
status = BZLL_VMAC_Entry_By_Device_ID(old_device_id, &test_vmac_data);
|
||||||
|
assert(status == false);
|
||||||
|
status = BZLL_VMAC_Entry_By_Index(0, &test_device_id, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
assert(test_device_id == TD.Device_ID);
|
||||||
|
status = BZLL_VMAC_Same(&TD.VMAC_Data, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
status = BZLL_VMAC_Add(IUT.Device_ID, &IUT.VMAC_Data);
|
||||||
|
assert(status == true);
|
||||||
|
count = BZLL_VMAC_Count();
|
||||||
|
for (index = 0; index < count; index++) {
|
||||||
|
status = BZLL_VMAC_Entry_By_Index(index, &test_vmac_src, NULL);
|
||||||
|
assert(status == true);
|
||||||
|
status = BZLL_VMAC_Entry_By_Device_ID(test_vmac_src, &test_vmac_data);
|
||||||
|
assert(status == true);
|
||||||
|
}
|
||||||
|
test_cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Main function to execute the test
|
||||||
|
*
|
||||||
|
* @return 0 on success, non-zero on failure
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
test_Execute_Virtual_Address_Resolution();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user