Zephyr core bacnet server port; bacnet/device test (#123)

Co-authored-by: Gregory Shue <gregory.shue@legrand.us>
This commit is contained in:
Greg Shue
2020-09-22 07:24:38 -07:00
committed by GitHub
parent cbaa106c59
commit a95b7d597e
26 changed files with 4166 additions and 86 deletions
+615
View File
@@ -0,0 +1,615 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2005 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h>
#include <stdbool.h>
#include <device.h>
#include <init.h>
#include <kernel.h>
#include <sys/printk.h>
#include <net/net_ip.h>
#include <net/socket.h>
#include <net/socket_select.h>
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/datalink/bip.h"
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/bbmd/h_bbmd.h"
/* Logging module registration is already done in ports/zephyr/main.c */
#include <logging/log.h>
#include <logging/log_ctrl.h>
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
#define THIS_FILE "bip-init.c"
/* zephyr socket */
static int BIP_Socket = -1;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
*/
/* port to use - stored here in network byte order */
static uint16_t BIP_Port = htons(CONFIG_BACDL_BIP_PORT);
/* IP address - stored here in network byte order */
static struct in_addr BIP_Address;
/* IP broadcast address - stored here in network byte order */
static struct in_addr BIP_Broadcast_Addr;
/* Used by inet_ntoa */
#if CONFIG_BACNETSTACK_LOG_LEVEL
static char ipv4_addr_str[16]={0};
#else
static char ipv4_addr_str[]="";
#endif
/**
* @brief Return a string representation of an IPv4 address
* @param a - IPv4 address
* @return Pointer to global string
*/
char* inet_ntoa(struct in_addr *a)
{
#if CONFIG_BACNETSTACK_LOG_LEVEL
/* Avoid overwhelming the logging system */
while(log_buffered_cnt())
{
k_sleep(K_MSEC(1));
}
snprintf(ipv4_addr_str, sizeof(ipv4_addr_str), "%d.%d.%d.%d",
a->s4_addr[0],a->s4_addr[1],a->s4_addr[2],a->s4_addr[3]);
#endif
return &ipv4_addr_str[0];
}
/**
* @brief Print the IPv4 address with debug info
* @param str - debug info string
* @param addr - IPv4 address
*/
static void debug_print_ipv4(const char *str, const struct in_addr *addr,
const unsigned int port, const unsigned int count)
{
LOG_DBG("%s %s:%hu (%u bytes)", log_strdup(str), log_strdup(inet_ntoa((struct in_addr*) &addr)),
ntohs(port), count);
}
/**
* @brief Set the BACnet IPv4 UDP port number
* @param port - IPv4 UDP port number - in host byte order
*/
void bip_set_port(uint16_t port)
{
BIP_Port = htons(port);
}
/**
* @brief Get the BACnet IPv4 UDP port number
* @return IPv4 UDP port number - in host byte order
*/
uint16_t bip_get_port(void)
{
return ntohs(BIP_Port);
}
/**
* @brief Get the IPv4 address for my interface. Used for sending src address.
* @param addr - BACnet datalink address
*/
void bip_get_my_address(BACNET_ADDRESS *addr)
{
unsigned int i = 0;
if (addr) {
addr->mac_len = BIP_ADDRESS_MAX; /* 6 */
memcpy(&addr->mac[0], &BIP_Address.s_addr, IP_ADDRESS_MAX); /* 4 */
memcpy(&addr->mac[IP_ADDRESS_MAX], &BIP_Port, sizeof(BIP_Port));
/* local only, no routing */
addr->net = 0;
/* no SLEN */
addr->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++) {
/* no SADR */
addr->adr[i] = 0;
}
}
}
/**
* Get the IPv4 broadcast address for my interface.
*
* @param addr - BACnet datalink address
*/
void bip_get_broadcast_address(BACNET_ADDRESS *dest)
{
int i = 0;
if (dest) {
dest->mac_len = BIP_ADDRESS_MAX;
memcpy(&dest->mac[0], &BIP_Broadcast_Addr.s_addr, IP_ADDRESS_MAX);
memcpy(&dest->mac[IP_ADDRESS_MAX], &BIP_Port, sizeof(BIP_Port));
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++) {
dest->adr[i] = 0;
}
}
return;
}
/**
* Set the BACnet/IP address
*
* @param addr - network IPv4 address
*/
bool bip_set_addr(BACNET_IP_ADDRESS *addr)
{
if (addr) {
memcpy(&BIP_Address.s_addr, &addr->address[0], IP_ADDRESS_MAX);
memcpy(&BIP_Port, &addr->port, sizeof(addr->port));
return true;
}
return false;
}
/**
* @brief Get the BACnet/IP address
* @param addr - network IPv4 address
* @return true if the address was retrieved
*/
bool bip_get_addr(BACNET_IP_ADDRESS *addr)
{
if (addr) {
memcpy(&addr->address[0], &BIP_Address.s_addr, IP_ADDRESS_MAX);
memcpy(&addr->port, &BIP_Port, sizeof(addr->port));
return true;
}
return false;
}
/**
* @brief Set the BACnet/IP address
* @param addr - network IPv4 address
* @return true if the address was set
*/
bool bip_set_broadcast_addr(BACNET_IP_ADDRESS *addr)
{
if (addr) {
memcpy(&BIP_Broadcast_Addr.s_addr, &addr->address[0], IP_ADDRESS_MAX);
return true;
}
return false;
}
/**
* Get the BACnet/IP address
*
* @return BACnet/IP address
*/
bool bip_get_broadcast_addr(BACNET_IP_ADDRESS *addr)
{
if (addr) {
memcpy(&addr->address[0], &BIP_Broadcast_Addr.s_addr, IP_ADDRESS_MAX);
addr->port = ntohs(BIP_Port);
return true;
}
return false;
}
/**
* @brief Set the BACnet/IP subnet mask CIDR prefix
* @return true if the subnet mask CIDR prefix is set
*/
bool bip_set_subnet_prefix(uint8_t prefix)
{
/* not something we do within this driver */
return false;
}
/**
* @brief Get the BACnet/IP subnet mask CIDR prefix
* @return subnet mask CIDR prefix 1..32
*/
uint8_t bip_get_subnet_prefix(void)
{
uint32_t address = 0;
uint32_t broadcast = 0;
uint32_t test_broadcast = 0;
uint32_t mask = 0xFFFFFFFE;
uint8_t prefix = 0;
address = BIP_Address.s_addr;
broadcast = BIP_Broadcast_Addr.s_addr;
/* calculate the subnet prefix from the broadcast address */
for (prefix = 1; prefix <= 32; prefix++) {
test_broadcast = (address & mask) | (~mask);
if (test_broadcast == broadcast) {
break;
}
mask = mask<<1;
}
return prefix;
}
/**
* The send function for BACnet/IP driver layer
*
* @param dest - Points to a BACNET_IP_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 and errno set to indicate the error.
*/
int bip_send_mpdu(BACNET_IP_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
{
struct sockaddr_in bip_dest = { 0 };
/* assumes that the driver has already been initialized */
if (BIP_Socket < 0) {
LOG_ERR("%s:%d - Socket not initialized!", THIS_FILE, __LINE__);
return BIP_Socket;
}
/* load destination IP address */
bip_dest.sin_family = AF_INET;
memcpy(&bip_dest.sin_addr.s_addr, &dest->address[0], IP_ADDRESS_MAX);
bip_dest.sin_port = htons(dest->port);
/* Send the packet */
debug_print_ipv4("Sending MPDU->", &bip_dest.sin_addr, bip_dest.sin_port,
mtu_len);
return zsock_sendto(BIP_Socket, (char *)mtu, mtu_len, 0,
(struct sockaddr *)&bip_dest, sizeof(struct sockaddr));
}
/**
* 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 bip_receive(
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
{
uint16_t npdu_len = 0; /* return value */
zsock_fd_set read_fds;
int max = 0;
struct zsock_timeval select_timeout;
struct sockaddr_in sin = { 0 };
BACNET_IP_ADDRESS addr = { { 0 } };
socklen_t sin_len = sizeof(sin);
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
/* Make sure the socket is open */
if (BIP_Socket < 0) {
return 0;
}
/* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as
a select. */
if (timeout >= 1000) {
select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000);
} else {
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout;
}
ZSOCK_FD_ZERO(&read_fds);
ZSOCK_FD_SET(BIP_Socket, &read_fds);
max = BIP_Socket;
/* see if there is a packet for us */
if (zsock_select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = zsock_recvfrom(BIP_Socket, (char *)&npdu[0], max_npdu,
0, (struct sockaddr *)&sin, &sin_len);
}
else
{
return 0;
}
/* See if there is a problem */
if (received_bytes < 0) {
LOG_WRN("%s:%d - RX zsock_recvfrom() error: %d", THIS_FILE, __LINE__, received_bytes);
return 0;
}
/* no problem, just no bytes */
if (received_bytes == 0) {
return 0;
}
/* the signature of a BACnet/IP packet */
if (npdu[0] != BVLL_TYPE_BACNET_IP) {
LOG_WRN("%s:%d - RX bad packet", THIS_FILE, __LINE__);
return 0;
}
/* Data link layer addressing between B/IPv4 nodes consists of a 32-bit
IPv4 address followed by a two-octet UDP port number (both of which
shall be transmitted with the most significant octet first). This
address shall be referred to as a B/IPv4 address.
*/
memcpy(&addr.address[0], &sin.sin_addr.s_addr, IP_ADDRESS_MAX);
addr.port = ntohs(sin.sin_port);
debug_print_ipv4("Received MPDU->", &sin.sin_addr, sin.sin_port,
received_bytes);
/* pass the packet into the BBMD handler */
offset = bvlc_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
debug_print_ipv4("Received NPDU->", &sin.sin_addr, sin.sin_port,
npdu_len);
if (npdu_len <= max_npdu) {
/* shift the buffer to return a valid NPDU */
for (i = 0; i < npdu_len; i++) {
npdu[i] = npdu[offset + i];
}
} else {
LOG_WRN("%s:%d - NPDU dropped!", THIS_FILE, __LINE__);
npdu_len = 0;
}
}
return npdu_len;
}
/**
* The common send function for BACnet/IP application layer
*
* @param dest - Points to a #BACNET_ADDRESS structure containing the
* destination address.
* @param npdu_data - Points to a BACNET_NPDU_DATA structure containing the
* destination network layer control flags and data.
* @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 and errno set to indicate the error.
*/
int bip_send_pdu(BACNET_ADDRESS *dest,
BACNET_NPDU_DATA *npdu_data,
uint8_t *pdu,
unsigned pdu_len)
{
dest->net = BACNET_BROADCAST_NETWORK;
return bvlc_send_pdu(dest, npdu_data, pdu, pdu_len);
}
/** Gets the local IP address and local broadcast address from the system,
* and saves it into the BACnet/IP data structures.
*
* @param ifname [in] The named interface to use for the network layer.
* Eg, for Linux, ifname is eth0, ath0, arc0, and others.
*/
void bip_set_interface(char *ifname)
{
struct net_if *interface = 0;
int index = -1;
uint8_t x=0;
BACNET_IP_ADDRESS unicast = {0};
BACNET_IP_ADDRESS broadcast = {0};
/* Network byte order */
unicast.port = BIP_Port;
broadcast.port = BIP_Port;
LOG_INF("bip_set_interface()");
LOG_INF("UDP port: %d", ntohs(BIP_Port));
if(ifname)
{
index = atoi(ifname);
/* if index is zero, discern between "0" and a parse error */
if(!index && strcmp(ifname,"0"))
{
LOG_ERR("%s:%d - Argument must parse to an integer", THIS_FILE, __LINE__);
}
else
{
interface = net_if_get_by_index(index);
if(interface)
{
LOG_INF("Using interface %d", index);
}
else
{
LOG_ERR("%s:%d - No interface at index %d", THIS_FILE, __LINE__, index);
}
}
}
if(index == -1)
{
LOG_WRN("%s:%d - No valid interface specified - using default ",THIS_FILE, __LINE__);
interface = net_if_get_default();
}
if(interface)
{
LOG_INF("Interface set");
if(CONFIG_BACDL_BIP_ADDRESS_INDEX >= NET_IF_MAX_IPV4_ADDR)
{
LOG_ERR("%s:%d - IPv4 address index of %d is out of range (0-%d)",THIS_FILE, __LINE__, CONFIG_BACDL_BIP_ADDRESS_INDEX, NET_IF_MAX_IPV4_ADDR-1);
return;
}
LOG_INF("Using IPv4 address at index %d", CONFIG_BACDL_BIP_ADDRESS_INDEX);
/* Build the broadcast address from the unicast and netmask */
for(x=0; x<IP_ADDRESS_MAX; x++)
{
broadcast.address[x] = interface->config.ip.ipv4->unicast[CONFIG_BACDL_BIP_ADDRESS_INDEX].address.in_addr.s4_addr[x] |
~interface->config.ip.ipv4->netmask.s4_addr[x];
unicast.address[x] = interface->config.ip.ipv4->unicast[CONFIG_BACDL_BIP_ADDRESS_INDEX].address.in_addr.s4_addr[x];
}
bip_set_addr(&unicast);
bip_set_broadcast_addr(&broadcast);
/* net_if -> net_if_config . net_if_ip . net_if_ipv4 -> net_if_addr . net_addr . in_addr . s4_addr[4] */
LOG_INF(" Unicast: %s", log_strdup(inet_ntoa(&interface->config.ip.ipv4->unicast->address.in_addr)));
LOG_INF(" Broadcast: %s", log_strdup(inet_ntoa(&BIP_Broadcast_Addr)));
LOG_INF(" Netmask: %s", log_strdup(inet_ntoa(&interface->config.ip.ipv4->netmask)) );
}
else
{
LOG_ERR("%s:%d - Failed to set interface", THIS_FILE, __LINE__);
}
}
/** Initialize the BACnet/IP services at the given interface.
* @ingroup DLBIP
* -# Gets the local IP address and local broadcast address from the system,
* and saves it into the BACnet/IP data structures.
* -# Opens a UDP socket
* -# Configures the socket for sending and receiving
* -# Configures the socket so it can send broadcasts
* -# Binds the socket to the local IP address at the specified port for
* BACnet/IP (by default, 0xBAC0 = 47808).
*
* @note For Zephyr, ifname is the index number of the interface as a string.
*
* @param ifname [in] The named interface to use for the network layer.
* If NULL, the default interface is assigned.
* @return True if the socket is successfully opened for BACnet/IP,
* else False if the socket functions fail.
*/
bool bip_init(char *ifname)
{
int sock_fd = -1;
const int sockopt = 1;
int status = -1;
struct sockaddr_in sin = { 0 };
bip_set_interface(ifname);
if (BIP_Address.s_addr == 0) {
LOG_ERR("%s:%d - Failed to get an IP address on interface: %s\n", THIS_FILE, __LINE__, log_strdup(ifname ? ifname : "[default]"));
return false;
}
/* assumes that the driver has already been initialized */
sock_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
BIP_Socket = sock_fd;
if (sock_fd < 0) {
LOG_ERR("%s:%d - Failed to create socket", THIS_FILE, __LINE__);
return false;
}
else
{
LOG_DBG("Socket created");
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
status = zsock_setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
zsock_close(sock_fd);
BIP_Socket = -1;
return false;
}
/* bind the socket to the local port number and IP address */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = BIP_Port;
status =
zsock_bind(sock_fd, (const struct sockaddr *)&sin, sizeof(struct sockaddr));
if (status < 0) {
zsock_close(sock_fd);
BIP_Socket = -1;
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
return false;
}
else
{
LOG_DBG("Socket bound");
}
bvlc_init();
LOG_DBG("bip_init() success");
return true;
}
/**
* @brief Determine if this BACnet/IP datalink is valid
* @return true if the BACnet/IP datalink is valid
*/
bool bip_valid(void)
{
return (BIP_Socket != -1);
}
/** Cleanup and close out the BACnet/IP services by closing the socket.
* @ingroup DLBIP
*/
void bip_cleanup(void)
{
LOG_DBG("bip_cleanup()");
BIP_Port = 0;
memset(&BIP_Address, 0, sizeof(BIP_Address));
memset(&BIP_Broadcast_Addr, 0, sizeof(BIP_Broadcast_Addr));
if (BIP_Socket != -1) {
zsock_close(BIP_Socket);
}
BIP_Socket = -1;
return;
}
+564
View File
@@ -0,0 +1,564 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2005-2020 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include <stdint.h>
#include <stdbool.h>
#include <device.h>
#include <init.h>
#include <kernel.h>
#include <sys/printk.h>
#include <net/net_ip.h>
#include <net/socket.h>
#include <net/socket_select.h>
#include "bacnet/bacdcode.h"
#include "bacnet/bacint.h"
#include "bacnet/datalink/bip6.h"
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/bbmd6/h_bbmd6.h"
/* Logging module registration is already done in ports/zephyr/main.c */
#include <logging/log.h>
#include <logging/log_ctrl.h>
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
#define THIS_FILE "bip6-init.c"
#if (MAX_MAC_LEN < BIP6_ADDRESS_MAX) /* Make sure an 18 byte address can be stored */
#error "BACNET_ADDRESS.mac (bacdef.h) is not large enough to store an IPv6 address."
#endif
/* zephyr socket */
static int BIP6_Socket = -1;
/* NOTE: we store address and port in network byte order
since BACnet/IP uses network byte order for all address byte arrays
*/
/* port to use - stored here in network byte order */
static uint16_t BIP6_Port = htons(CONFIG_BACDL_BIP6_PORT);
/* IP address - stored here in network byte order */
static struct in6_addr BIP6_Address;
/* IP multicast address - stored here in network byte order */
static struct in6_addr BIP6_Multicast_Addr;
/* Used by inet6_ntoa */
#if CONFIG_BACNETSTACK_LOG_LEVEL
static char ipv6_addr_str[42]={0};
#else
static char ipv6_addr_str[]="";
#endif
/**
* @brief Return a string representation of an IPv6 address
* @param a - IPv6 address
* @return Pointer to global string
*/
static char* inet6_ntoa(struct in6_addr *a)
{
#if CONFIG_BACNETSTACK_LOG_LEVEL
uint8_t x=0;
uint8_t d=0;
uint8_t non_zero_count = 0;
/* Avoid overwhelming the logging system */
while(log_buffered_cnt())
{
k_sleep(K_MSEC(1));
}
for(x=0; x<IP6_ADDRESS_MAX; x+=2)
{
if(a->s6_addr[x] | a->s6_addr[x+1])
{
non_zero_count++;
d+=sprintf(&ipv6_addr_str[d], "%02X%02X", a->s6_addr[x], a->s6_addr[x+1]);
}
if(x<14)
{
d+=sprintf(&ipv6_addr_str[d], ":");
}
}
if(!non_zero_count)
{
sprintf(&ipv6_addr_str[0], "undefined");
}
#endif
return &ipv6_addr_str[0];
}
/**
* @brief Set the BACnet IPv6 UDP port number
* @param port - IPv6 UDP port number - in host byte order
*/
void bip6_set_port(uint16_t port)
{
BIP6_Port = htons(port);
}
/**
* @brief Get the BACnet IPv6 UDP port number
* @return IPv4 UDP port number - in host byte order
*/
uint16_t bip6_get_port(void)
{
return ntohs(BIP6_Port);
}
/**
* @brief Get the IPv6 address for my interface. Used for sending src address.
* @param addr - BACnet datalink address
*/
void bip6_get_my_address(BACNET_ADDRESS *addr)
{
unsigned int i = 0;
if (addr) {
addr->mac_len = BIP6_ADDRESS_MAX; /* 18 */
memcpy(&addr->mac[0], &BIP6_Address.s6_addr, IP6_ADDRESS_MAX); /* 16 */
memcpy(&addr->mac[IP6_ADDRESS_MAX], &BIP6_Port, sizeof(BIP6_Port));
/* local only, no routing */
addr->net = 0;
/* no SLEN */
addr->len = 0;
for (i = 0; i < MAX_MAC_LEN; i++) {
/* no SADR */
addr->adr[i] = 0;
}
}
}
/**
* Get the IPv6 broadcast address for my interface.
*
* @param addr - BACnet datalink address
*/
void bip6_get_broadcast_address(BACNET_ADDRESS *dest)
{
/* BIP6_ADDRESS_MAX = 18 */
/* IP6_ADDRESS_MAX = 16 */
/* Store IPv6 address and port in dest->mac and
clear dest->adr which is used for hardware MAC */
if (dest) {
dest->mac_len = BIP6_ADDRESS_MAX;
memcpy(&dest->mac[0], &BIP6_Multicast_Addr.s6_addr, IP6_ADDRESS_MAX);
memcpy(&dest->mac[IP6_ADDRESS_MAX], &BIP6_Port, sizeof(BIP6_Port) );
memset(&dest->adr, 0, sizeof(dest->adr));
dest->net = BACNET_BROADCAST_NETWORK;
dest->len = 0;
}
return;
}
/**
* Set the BACnet/IP address
*
* @param addr - network IPv6 address
*/
bool bip6_set_addr(BACNET_IP6_ADDRESS *addr)
{
if (addr) {
memcpy(&BIP6_Address.s6_addr, &addr->address[0], IP6_ADDRESS_MAX);
memcpy(&BIP6_Port, &addr->port, sizeof(addr->port));
return true;
}
return false;
}
/**
* @brief Get the BACnet/IP address
* @param addr - network IPv6 address
* @return true if the address was retrieved
*/
bool bip6_get_addr(BACNET_IP6_ADDRESS *addr)
{
if (addr) {
memcpy(&addr->address[0], &BIP6_Address, IP6_ADDRESS_MAX);
memcpy(&addr->port, &BIP6_Port, sizeof(addr->port));
return true;
}
return false;
}
/**
* @brief Set the BACnet/IP address
* @param addr - network IPv6 address
* @return true if the address was set
*/
bool bip6_set_broadcast_addr(BACNET_IP6_ADDRESS *addr)
{
if (addr) {
memcpy(&BIP6_Multicast_Addr.s6_addr, &addr->address[0], IP6_ADDRESS_MAX);
return true;
}
return false;
}
/**
* Get the BACnet/IP address
*
* @return BACnet/IP address
*/
bool bip6_get_broadcast_addr(BACNET_IP6_ADDRESS *addr)
{
if (addr) {
memcpy(&addr->address[0], &BIP6_Multicast_Addr.s6_addr, IP6_ADDRESS_MAX);
addr->port = ntohs(BIP6_Port);
return true;
}
return false;
}
/**
* @brief Set the BACnet/IP subnet mask CIDR prefix
* @return true if the subnet mask CIDR prefix is set
*/
bool bip6_set_subnet_prefix(uint8_t prefix)
{
/* not something we do within this driver */
return false;
}
/**
* @brief Set the BACnet/IP subnet mask CIDR prefix
* @return true if the subnet mask CIDR prefix is set
*/
uint8_t bip6_get_subnet_prefix(void)
{
/* not something we do within this driver */
return 0;
}
/**
* The send function for BACnet/IP driver layer
*
* @param dest - Points to a BACNET_IP_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 and errno set to indicate the error.
*/
int bip6_send_mpdu(BACNET_IP6_ADDRESS *dest, uint8_t *mtu, uint16_t mtu_len)
{
struct sockaddr_in6 bip6_dest = { 0 };
/* assumes that the driver has already been initialized */
if (BIP6_Socket < 0) {
LOG_ERR("%s:%d - Socket not initialized!", THIS_FILE, __LINE__);
return BIP6_Socket;
}
/* load destination IP address */
bip6_dest.sin6_family = AF_INET6;
memcpy(&bip6_dest.sin6_addr.s6_addr, &dest->address[0], IP6_ADDRESS_MAX);
bip6_dest.sin6_port = htons(dest->port);
/* Send the packet */
return zsock_sendto(BIP6_Socket, (char *)mtu, mtu_len, 0,
(struct sockaddr *)&bip6_dest, sizeof(struct sockaddr));
}
uint16_t bip6_receive(
BACNET_ADDRESS *src, uint8_t *npdu, uint16_t max_npdu, unsigned timeout)
{
uint16_t npdu_len = 0; /* return value */
zsock_fd_set read_fds;
int max = 0;
struct zsock_timeval select_timeout;
struct sockaddr_in6 sin = { 0 };
BACNET_IP6_ADDRESS addr = { { 0 } };
socklen_t sin_len = sizeof(sin);
int received_bytes = 0;
int offset = 0;
uint16_t i = 0;
/* Make sure the socket is open */
if (BIP6_Socket < 0) {
return 0;
}
/* we could just use a non-blocking socket, but that consumes all
the CPU time. We can use a timeout; it is only supported as
a select. */
if (timeout >= 1000) {
select_timeout.tv_sec = timeout / 1000;
select_timeout.tv_usec =
1000 * (timeout - select_timeout.tv_sec * 1000);
} else {
select_timeout.tv_sec = 0;
select_timeout.tv_usec = 1000 * timeout;
}
ZSOCK_FD_ZERO(&read_fds);
ZSOCK_FD_SET(BIP6_Socket, &read_fds);
max = BIP6_Socket;
/* see if there is a packet for us */
if (zsock_select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
received_bytes = zsock_recvfrom(BIP6_Socket, (char *)&npdu[0], max_npdu,
0, (struct sockaddr *)&sin, &sin_len);
}
else
{
return 0;
}
/* See if there is a problem */
if (received_bytes < 0) {
LOG_WRN("%s:%d - RX zsock_recvfrom() error: %d", THIS_FILE, __LINE__, received_bytes);
return 0;
}
/* no problem, just no bytes */
if (received_bytes == 0) {
return 0;
}
/* the signature of a BACnet/IPv6 packet */
if (npdu[0] != BVLL_TYPE_BACNET_IP6) {
LOG_WRN("%s:%d - RX bad packet", THIS_FILE, __LINE__);
return 0;
}
/* Data link layer addressing between B/IPv6 nodes consists of a 128-bit
IPv6 address followed by a two-octet UDP port number (both of which
shall be transmitted with the most significant octet first). This
address shall be referred to as a B/IPv6 address.
*/
memcpy(&addr.address[0], &sin.sin6_addr.s6_addr, IP6_ADDRESS_MAX);
addr.port = ntohs(sin.sin6_port);
offset = bvlc6_handler(&addr, src, npdu, received_bytes);
if (offset > 0) {
npdu_len = received_bytes - offset;
if (npdu_len <= max_npdu) {
/* shift the buffer to return a valid NPDU */
for (i = 0; i < npdu_len; i++) {
npdu[i] = npdu[offset + i];
}
} else {
LOG_WRN("%s:%d - NPDU dropped!", THIS_FILE, __LINE__);
npdu_len = 0;
}
}
return npdu_len;
}
int bip6_send_pdu(BACNET_ADDRESS *dest,
BACNET_NPDU_DATA *npdu_data,
uint8_t *pdu,
unsigned pdu_len)
{
dest->net = BACNET_BROADCAST_NETWORK;
return bvlc6_send_pdu(dest, npdu_data, pdu, pdu_len);
}
void bip6_set_interface(char *ifname)
{
struct net_if *interface = 0;
int index = -1;
int x=0;
BACNET_IP6_ADDRESS unicast = {0};
BACNET_IP6_ADDRESS multicast = {0};
unicast.port = BIP6_Port;
multicast.port = BIP6_Port;
LOG_INF("bip6_set_interface()");
LOG_INF("UDP port: %d", ntohs(BIP6_Port));
if(ifname)
{
index = atoi(ifname);
/* if index is zero, discern between "0" and a parse error */
if(!index && strcmp(ifname,"0"))
{
LOG_ERR("%s:%d - Argument must parse to an integer", THIS_FILE, __LINE__);
}
else
{
interface = net_if_get_by_index(index);
if(interface)
{
LOG_INF("Using interface %d", index);
}
else
{
LOG_ERR("%s:%d - No interface at index %d", THIS_FILE, __LINE__, index);
}
}
}
if(index == -1)
{
LOG_WRN("%s:%d - No valid interface specified - using default ",THIS_FILE, __LINE__);
interface = net_if_get_default();
}
if(interface)
{
LOG_INF("Interface set - Configured addresses:");
for(x=0; x<NET_IF_MAX_IPV6_ADDR; x++)
{
inet6_ntoa(&interface->config.ip.ipv6->unicast[x].address.in6_addr );
LOG_INF(" unicast[%d]: %s", x, log_strdup(ipv6_addr_str));
}
for(x=0; x<NET_IF_MAX_IPV6_MADDR; x++)
{
inet6_ntoa(&interface->config.ip.ipv6->mcast[x].address.in6_addr );
LOG_INF(" multicast[%d]: %s", x, log_strdup(ipv6_addr_str));
}
if(CONFIG_BACDL_BIP6_ADDRESS_INDEX >= NET_IF_MAX_IPV6_ADDR)
{
LOG_ERR("%s:%d - IPv6 address index of %d is out of range (0-%d)", THIS_FILE,
__LINE__, CONFIG_BACDL_BIP6_ADDRESS_INDEX, NET_IF_MAX_IPV6_ADDR-1);
return;
}
LOG_INF("Using IPv6 address at index %d", CONFIG_BACDL_BIP6_ADDRESS_INDEX);
memcpy(&unicast.address, &interface->config.ip.ipv6->unicast
[CONFIG_BACDL_BIP6_ADDRESS_INDEX].address.in6_addr, IP6_ADDRESS_MAX);
if(net_addr_pton(AF_INET6, CONFIG_BACDL_BIP6_MCAST_ADDRESS, &multicast.address))
{
LOG_ERR("%s:%d - Failed to parse IPv6 multicast address: %s", THIS_FILE, __LINE__, CONFIG_BACDL_BIP6_MCAST_ADDRESS);
}
bip6_set_addr(&unicast);
bip6_set_broadcast_addr(&multicast);
LOG_INF(" Unicast: %s", log_strdup(inet6_ntoa((struct in6_addr*)&unicast.address)));
LOG_INF(" Multicast: %s", log_strdup(inet6_ntoa((struct in6_addr*)&multicast.address)));
}
else
{
LOG_ERR("%s:%d - Failed to set interface", THIS_FILE, __LINE__);
}
}
bool bip6_init(char *ifname)
{
LOG_INF("bip6_init()");
int sock_fd = -1;
const int sockopt = 1;
int status = -1;
struct sockaddr_in6 sin6 = { 0 };
bip6_set_interface(ifname);
if (BIP6_Address.s6_addr == 0) {
LOG_ERR("%s:%d - Failed to get an IPv6 address on interface: %s\n", THIS_FILE, __LINE__, log_strdup(ifname ? ifname : "[default]"));
return false;
}
/* assumes that the driver has already been initialized */
sock_fd = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
BIP6_Socket = sock_fd;
if (sock_fd < 0) {
LOG_ERR("%s:%d - Failed to create socket", THIS_FILE, __LINE__);
return false;
}
else
{
LOG_INF("Socket created");
}
/* Allow us to use the same socket for sending and receiving */
/* This makes sure that the src port is correct when sending */
status = zsock_setsockopt(
sock_fd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
if (status < 0) {
zsock_close(sock_fd);
BIP6_Socket = -1;
return false;
}
/* bind the socket to the local port number and IP address */
sin6.sin6_family = AF_INET6;
sin6.sin6_addr = in6addr_any;
sin6.sin6_port = BIP6_Port;
LOG_INF("Binding to port %d", ntohs(BIP6_Port));
status =
zsock_bind(sock_fd, (const struct sockaddr*)&sin6, sizeof(struct sockaddr));
if (status < 0) {
zsock_close(sock_fd);
BIP6_Socket = -1;
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
return false;
}
else
{
LOG_INF("Socket bound");
}
bvlc6_init();
LOG_INF("bip6_init() success");
return true;
}
bool bip6_valid(void)
{
return (BIP6_Socket != -1);
}
void bip6_cleanup(void)
{
LOG_INF("bip6_cleanup()");
BIP6_Port = 0;
memset(&BIP6_Address, 0, sizeof(BIP6_Address));
memset(&BIP6_Multicast_Addr, 0, sizeof(BIP6_Multicast_Addr));
if (BIP6_Socket != -1) {
zsock_close(BIP6_Socket);
}
BIP6_Socket = -1;
return;
}
+64
View File
@@ -0,0 +1,64 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2020 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
#include "bacnet/datalink/bvlc.h"
/**
* @brief Encode the BVLC header
*
* @param pdu - buffer to store the encoding
* @param pdu_size - size of the buffer to store encoding
* @param message_type - BVLL Messages
* @param length - number of bytes for this message type
*
* @return number of bytes encoded
*/
void bvlc_file_bdt_write(
void *data,
size_t len)
{
/* TODO: Write BDT data blob into persistent storage */
}
size_t bvlc_file_bdt_read(
void *data,
size_t len)
{
size_t sz = -1;
/* TODO: Read BD data blob from persistent storage */
return sz;
}
+108
View File
@@ -0,0 +1,108 @@
/**
* @file
* @author Steve Karg
* @date 2009
* @brief System time library header file.
*
* @section DESCRIPTION
*
* This library provides functions for getting and setting the system time.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include "bacnet/datetime.h"
/* HACK:
* - Zephyr does not declare timezone in any header file.
* - The gcc-arm-none-eabi-7-2018-q2-update/bin/arm-none-eabi/lib/thumb/v7e-m/
* libc_nano.a 'time' symbol does not resolve '_gettimeofday'
*
* TODO: figure out how to link in the real time() and timezone;
*/
long timezone;
time_t time(time_t *tloc)
{
time_t time = { 0 };
return time;
}
/**
* @brief Get the date, time, timezone, and UTC offset from system
* @param utc_time - the BACnet Date and Time structure to hold UTC time
* @param local_time - the BACnet Date and Time structure to hold local time
* @param utc_offset_minutes - number of minutes offset from UTC
* For example, -6*60 represents 6.00 hours behind UTC/GMT
* @param true if DST is enabled and active
* @return true if local time was retrieved
*/
bool datetime_local(
BACNET_DATE * bdate,
BACNET_TIME * btime,
int16_t * utc_offset_minutes,
bool * dst_active)
{
bool status = false;
struct tm tblock_st = { 0 };
struct tm *tblock = &tblock_st;
struct timeval tv;
if (gettimeofday(&tv, NULL) == 0)
{
tblock = (struct tm *)localtime((const time_t *)&tv.tv_sec);
}
if (tblock) {
status = true;
/** struct tm
* int tm_sec Seconds [0,60].
* int tm_min Minutes [0,59].
* int tm_hour Hour [0,23].
* int tm_mday Day of month [1,31].
* int tm_mon Month of year [0,11].
* int tm_year Years since 1900.
* int tm_wday Day of week [0,6] (Sunday =0).
* int tm_yday Day of year [0,365].
* int tm_isdst Daylight Savings flag.
*/
datetime_set_date(bdate, (uint16_t)tblock->tm_year + 1900,
(uint8_t)tblock->tm_mon + 1,
(uint8_t)tblock->tm_mday);
datetime_set_time(btime, (uint8_t)tblock->tm_hour,
(uint8_t)tblock->tm_min, (uint8_t)tblock->tm_sec,
(uint8_t)(tv.tv_usec / 10000));
if (dst_active) {
/* The value of tm_isdst is:
- positive if Daylight Saving Time is in effect,
- 0 if Daylight Saving Time is not in effect, and
- negative if the information is not available. */
if (tblock->tm_isdst > 0) {
*dst_active = true;
} else {
*dst_active = false;
}
}
/* note: timezone is declared in <time.h> stdlib. */
if (utc_offset_minutes) {
/* timezone is set to the difference, in seconds,
between Coordinated Universal Time (UTC) and
local standard time */
*utc_offset_minutes = timezone / 60;
}
}
return status;
}
/**
* initialize the date time
*/
void datetime_init(void)
{
/* nothing to do */
}
File diff suppressed because it is too large Load Diff
+1
View File
@@ -14,6 +14,7 @@
#include <sys/util.h>
#include <zephyr.h>
#define LOG_LEVEL CONFIG_BACNETSTACK_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(bacnet);
+45
View File
@@ -0,0 +1,45 @@
/**************************************************************************
*
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
* Multimedia Timer contribution by Cameron Crothers, 2008
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*********************************************************************/
#include <kernel.h>
#include "bacnet/basic/sys/mstimer.h"
/**
* @brief returns the current millisecond count
* @return millisecond counter
*/
unsigned long mstimer_now(void)
{
return (unsigned long) k_uptime_get();
}
/**
* @brief Initialization for timer
*/
void mstimer_init(void)
{
}
+7 -1
View File
@@ -138,7 +138,13 @@ typedef uint32_t BACNET_ARRAY_INDEX;
equal to 7 bytes. The IPv6 addresses are planned to be handled
outside this area. */
/* FIXME: mac[] only needs to be as big as our local datalink MAC */
#define MAX_MAC_LEN 7
#if BACDL_BIP6
#define MAX_MAC_LEN 19
#else
#define MAX_MAC_LEN 7
#endif
struct BACnet_Device_Address {
/* mac_len = 0 is a broadcast address */
uint8_t mac_len;
+2 -1
View File
@@ -167,7 +167,8 @@ static void debug_print_string(const char *str)
* BBMD_BACKUP_FILE should be set to the file name
* in which to store the BDT.
*/
#ifndef BBMD_BACKUP_FILE
#if defined(BBMD_BACKUP_FILE) && (BBMD_BACKUP_FILE == 1)
#undef BBMD_BACKUP_FILE
#define BBMD_BACKUP_FILE BACnet_BDT_table
#endif
#if defined(BBMD_BACKUP_FILE)
+30
View File
@@ -0,0 +1,30 @@
# 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)
set(TST_DIR "../..")
set(ZTST_DIR "${TST_DIR}/ztest/src")
set(SRC_DIR "${TST_DIR}/../src")
add_compile_definitions(
BIG_ENDIAN=0
CONFIG_ZTEST=1
)
include_directories(
${SRC_DIR}
${TST_DIR}/ztest/include
)
add_executable(${PROJECT_NAME}
${SRC_DIR}/device.c
./src/main.c
${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c
)
+93
View File
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2020 Legrand North America, LLC.
*
* SPDX-License-Identifier: MIT
*/
#include <ztest.h>
#include <bacnet/bacstr.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h> /* for memmove */
#include "bacnet/bacdef.h"
#include "bacnet/bacdcode.h"
#include "bacnet/bacenum.h"
#include "bacnet/bacapp.h"
#include "bacnet/config.h" /* the custom stuff */
#include "bacnet/datetime.h"
#include "bacnet/apdu.h"
#include "bacnet/wp.h" /* WriteProperty handling */
#include "bacnet/rp.h" /* ReadProperty handling */
#include "bacnet/dcc.h" /* DeviceCommunicationControl handling */
#include "bacnet/version.h"
#include "bacnet/basic/object/device.h" /* me */
#include "bacnet/basic/services.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/basic/binding/address.h"
/* include the device object */
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/acc.h"
#include "bacnet/basic/object/ai.h"
#include "bacnet/basic/object/ao.h"
#include "bacnet/basic/object/av.h"
#include "bacnet/basic/object/bi.h"
#include "bacnet/basic/object/bo.h"
#include "bacnet/basic/object/bv.h"
#include "bacnet/basic/object/channel.h"
#include "bacnet/basic/object/command.h"
#include "bacnet/basic/object/csv.h"
#include "bacnet/basic/object/iv.h"
#include "bacnet/basic/object/lc.h"
#include "bacnet/basic/object/lsp.h"
#include "bacnet/basic/object/ms-input.h"
#include "bacnet/basic/object/mso.h"
#include "bacnet/basic/object/msv.h"
static void testDevice(void)
{
const char *dev_name = "Patricia";
zassert_true(Device_Set_Object_Instance_Number(0),
"Device_Set_Object_Instance_Number(0) failed");
zassert_true(Device_Object_Instance_Number()==0,
"Failed to set device object instance number to 0.");
zassert_true(Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE),
"Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE) failed");
zassert_true(Device_Object_Instance_Number()==BACNET_MAX_INSTANCE,
"Failed to set device object instance number to BACNET_MAX_INSTANCE");
zassert_true(Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE / 2),
"Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE / 2) failed");
zassert_true(Device_Object_Instance_Number()==(BACNET_MAX_INSTANCE / 2),
"Failed to set device object instance number to BACNET_MAX_INSTANCE / 2");
zassert_false(Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE + 1),
"Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE + 1) uncaught");
zassert_false(Device_Object_Instance_Number()==(BACNET_MAX_INSTANCE + 1),
"Set device object instance number to illegal value BACNET_MAX_INSTANCE + 1");
zassert_false(Device_Set_System_Status(STATUS_NON_OPERATIONAL, true),
"Device_Set_System_Status() failed");
zassert_true(Device_System_Status() == STATUS_NON_OPERATIONAL,
"Failed to set device status to STATUS_NON_OPERATIONAL");
zassert_true(Device_Vendor_Identifier() == BACNET_VENDOR_ID,
"Incorrect BACNET_VENDOR_ID");
zassert_true(Device_Set_Model_Name(dev_name, strlen(dev_name)),
"Device_Set_Model_Name() failed");
zassert_false( strcmp(Device_Model_Name(), dev_name) ,
"Failed to set device model name");
}
void test_main(void)
{
ztest_test_suite(device_tests,
ztest_unit_test(testDevice)
);
ztest_run_test_suite(device_tests);
}
+95 -82
View File
@@ -83,8 +83,8 @@ set(BACNETSTACK_SRCS
${BACNETSTACK_SRC}/bacnet/bactext.h
${BACNETSTACK_SRC}/bacnet/bactimevalue.c
${BACNETSTACK_SRC}/bacnet/bactimevalue.h
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/h_bbmd.c>
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/h_bbmd.h>
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd/h_bbmd.c>
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd/h_bbmd.h>
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/h_bbmd6.c>
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/h_bbmd6.h>
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/vmac.c>
@@ -95,105 +95,58 @@ set(BACNETSTACK_SRCS
${BACNETSTACK_SRC}/bacnet/basic/npdu/h_npdu.h
${BACNETSTACK_SRC}/bacnet/basic/npdu/h_routed_npdu.c
${BACNETSTACK_SRC}/bacnet/basic/npdu/h_routed_npdu.h
${BACNETSTACK_SRC}/bacnet/basic/npdu/s_router.c
${BACNETSTACK_SRC}/bacnet/basic/npdu/s_router.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_credential.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_credential.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_door.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_door.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_point.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_point.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_rights.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_rights.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_user.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_user.h
${BACNETSTACK_SRC}/bacnet/basic/object/access_zone.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_zone.h
${BACNETSTACK_SRC}/bacnet/basic/object/acc.c
${BACNETSTACK_SRC}/bacnet/basic/object/ai.c
${BACNETSTACK_SRC}/bacnet/basic/object/ai.h
${BACNETSTACK_SRC}/bacnet/basic/object/ao.c
${BACNETSTACK_SRC}/bacnet/basic/object/ao.h
${BACNETSTACK_SRC}/bacnet/basic/object/av.c
${BACNETSTACK_SRC}/bacnet/basic/object/av.h
#${BACNETSTACK_SRC}/bacnet/basic/object/bacfile.c # Build error: fseek not supported in Zephyr
${BACNETSTACK_SRC}/bacnet/basic/object/bacfile.h
${BACNETSTACK_SRC}/bacnet/basic/object/bi.c
${BACNETSTACK_SRC}/bacnet/basic/object/bi.h
${BACNETSTACK_SRC}/bacnet/basic/object/bo.c
${BACNETSTACK_SRC}/bacnet/basic/object/bo.h
${BACNETSTACK_SRC}/bacnet/basic/object/bv.c
${BACNETSTACK_SRC}/bacnet/basic/object/bv.h
${BACNETSTACK_SRC}/bacnet/basic/object/channel.c
${BACNETSTACK_SRC}/bacnet/basic/object/channel.h
#${BACNETSTACK_SRC}/bacnet/basic/object/client/device-client.c
${BACNETSTACK_SRC}/bacnet/basic/object/command.c
${BACNETSTACK_SRC}/bacnet/basic/object/command.h
${BACNETSTACK_SRC}/bacnet/basic/object/credential_data_input.c
${BACNETSTACK_SRC}/bacnet/basic/object/credential_data_input.h
${BACNETSTACK_SRC}/bacnet/basic/object/csv.c
${BACNETSTACK_SRC}/bacnet/basic/object/csv.h
${BACNETSTACK_SRC}/bacnet/basic/object/device.c
${BACNETSTACK_SRC}/bacnet/basic/object/device.h
$<$<BOOL:${CONFIG_BAC_ROUTING}>:${BACNETSTACK_SRC}/bacnet/basic/object/gateway/gw_device.c>
${BACNETSTACK_SRC}/bacnet/basic/object/iv.c
${BACNETSTACK_SRC}/bacnet/basic/object/iv.h
${BACNETSTACK_SRC}/bacnet/basic/object/lc.c
${BACNETSTACK_SRC}/bacnet/basic/object/lc.h
${BACNETSTACK_SRC}/bacnet/basic/object/lo.c
${BACNETSTACK_SRC}/bacnet/basic/object/lo.h
${BACNETSTACK_SRC}/bacnet/basic/object/lsp.c
${BACNETSTACK_SRC}/bacnet/basic/object/lsp.h
${BACNETSTACK_SRC}/bacnet/basic/object/Makefile
${BACNETSTACK_SRC}/bacnet/basic/object/ms-input.c
${BACNETSTACK_SRC}/bacnet/basic/object/ms-input.h
${BACNETSTACK_SRC}/bacnet/basic/object/mso.c
${BACNETSTACK_SRC}/bacnet/basic/object/mso.h
${BACNETSTACK_SRC}/bacnet/basic/object/msv.c
${BACNETSTACK_SRC}/bacnet/basic/object/msv.h
${BACNETSTACK_SRC}/bacnet/basic/object/nc.c
${BACNETSTACK_SRC}/bacnet/basic/object/nc.h
${BACNETSTACK_SRC}/bacnet/basic/object/netport.c
${BACNETSTACK_SRC}/bacnet/basic/object/netport.h
${BACNETSTACK_SRC}/bacnet/basic/object/objects.c
${BACNETSTACK_SRC}/bacnet/basic/object/objects.h
${BACNETSTACK_SRC}/bacnet/basic/object/osv.c
${BACNETSTACK_SRC}/bacnet/basic/object/osv.h
${BACNETSTACK_SRC}/bacnet/basic/object/piv.c
${BACNETSTACK_SRC}/bacnet/basic/object/piv.h
${BACNETSTACK_SRC}/bacnet/basic/object/schedule.c
${BACNETSTACK_SRC}/bacnet/basic/object/schedule.h
${BACNETSTACK_SRC}/bacnet/basic/object/trendlog.c
${BACNETSTACK_SRC}/bacnet/basic/object/trendlog.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_alarm_ack.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_alarm_ack.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_apdu.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_apdu.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf_a.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_awf.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_awf.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_ccov.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ccov.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_cov.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_cov.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_dcc.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_dcc.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_gas_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_gas_a.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_get_alarm_sum.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_get_alarm_sum.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent_a.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_iam.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_iam.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_ihave.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ihave.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_lso.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_lso.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_noserv.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_noserv.h
@@ -207,15 +160,10 @@ set(BACNETSTACK_SRCS
${BACNETSTACK_SRC}/bacnet/basic/service/h_rpm_a.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_rpm.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_rpm.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr_a.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_ts.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ts.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_ucov.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ucov.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_upt.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_upt.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_whohas.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_whohas.h
@@ -225,55 +173,34 @@ set(BACNETSTACK_SRCS
${BACNETSTACK_SRC}/bacnet/basic/service/h_wp.h
${BACNETSTACK_SRC}/bacnet/basic/service/h_wpm.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_wpm.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_abort.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_abort.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_ack_alarm.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_ack_alarm.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_arfs.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_arfs.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_awfs.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_awfs.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_cevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_cevent.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_cov.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_cov.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_dcc.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_dcc.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_error.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_error.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_alarm_sum.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_alarm_sum.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_event.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_getevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_event.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_getevent.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_iam.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_iam.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_ihave.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_ihave.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_lso.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_lso.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_rd.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rd.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_readrange.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_readrange.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_rp.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rp.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_rpm.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rpm.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_ts.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_ts.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_uevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_uevent.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_upt.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_upt.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_whohas.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_whohas.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_whois.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_whois.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_wp.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_wp.h
${BACNETSTACK_SRC}/bacnet/basic/service/s_wpm.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_wpm.h
${BACNETSTACK_SRC}/bacnet/basic/services.h
${BACNETSTACK_SRC}/bacnet/basic/sys/bigend.c
@@ -316,8 +243,6 @@ set(BACNETSTACK_SRCS
$<$<BOOL:${CONFIG_BACDL_MSTP}>:${BACNETSTACK_SRC}/bacnet/datalink/crc.c>
${BACNETSTACK_SRC}/bacnet/datalink/datalink.c
${BACNETSTACK_SRC}/bacnet/datalink/datalink.h
${BACNETSTACK_SRC}/bacnet/datalink/dlenv.c
${BACNETSTACK_SRC}/bacnet/datalink/dlenv.h
${BACNETSTACK_SRC}/bacnet/datalink/dlmstp.h
${BACNETSTACK_SRC}/bacnet/datalink/ethernet.h
$<$<BOOL:${CONFIG_BACDL_MSTP}>:${BACNETSTACK_SRC}/bacnet/datalink/mstp.h>
@@ -377,7 +302,86 @@ set(BACNETSTACK_SRCS
${BACNETSTACK_SRC}/bacnet/wp.c
${BACNETSTACK_SRC}/bacnet/wp.h
${BACNETSTACK_SRC}/bacnet/wpm.c
${BACNETSTACK_SRC}/bacnet/wpm.h)
${BACNETSTACK_SRC}/bacnet/wpm.h
)
set(BACNETSTACK_BASIC_SRCS
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/h_bbmd6.c>
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_SRC}/bacnet/basic/bbmd6/vmac.c>
${BACNETSTACK_SRC}/bacnet/basic/npdu/s_router.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_credential.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_door.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_point.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_rights.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_user.c
${BACNETSTACK_SRC}/bacnet/basic/object/access_zone.c
${BACNETSTACK_SRC}/bacnet/basic/object/acc.c
${BACNETSTACK_SRC}/bacnet/basic/object/ai.c
${BACNETSTACK_SRC}/bacnet/basic/object/ao.c
${BACNETSTACK_SRC}/bacnet/basic/object/av.c
${BACNETSTACK_SRC}/bacnet/basic/object/bacfile.c # Build error: fseek not supported in Zephyr
${BACNETSTACK_SRC}/bacnet/basic/object/bi.c
${BACNETSTACK_SRC}/bacnet/basic/object/bo.c
${BACNETSTACK_SRC}/bacnet/basic/object/bv.c
${BACNETSTACK_SRC}/bacnet/basic/object/channel.c
#${BACNETSTACK_SRC}/bacnet/basic/object/client/device-client.c
${BACNETSTACK_SRC}/bacnet/basic/object/command.c
${BACNETSTACK_SRC}/bacnet/basic/object/credential_data_input.c
${BACNETSTACK_SRC}/bacnet/basic/object/csv.c
${BACNETSTACK_SRC}/bacnet/basic/object/device.c
$<$<BOOL:${CONFIG_BAC_ROUTING}>:${BACNETSTACK_SRC}/bacnet/basic/object/gateway/gw_device.c>
${BACNETSTACK_SRC}/bacnet/basic/object/iv.c
${BACNETSTACK_SRC}/bacnet/basic/object/lc.c
${BACNETSTACK_SRC}/bacnet/basic/object/lo.c
${BACNETSTACK_SRC}/bacnet/basic/object/lsp.c
${BACNETSTACK_SRC}/bacnet/basic/object/Makefile
${BACNETSTACK_SRC}/bacnet/basic/object/ms-input.c
${BACNETSTACK_SRC}/bacnet/basic/object/mso.c
${BACNETSTACK_SRC}/bacnet/basic/object/msv.c
${BACNETSTACK_SRC}/bacnet/basic/object/nc.c
${BACNETSTACK_SRC}/bacnet/basic/object/netport.c
${BACNETSTACK_SRC}/bacnet/basic/object/objects.c
${BACNETSTACK_SRC}/bacnet/basic/object/osv.c
${BACNETSTACK_SRC}/bacnet/basic/object/piv.c
${BACNETSTACK_SRC}/bacnet/basic/object/schedule.c
${BACNETSTACK_SRC}/bacnet/basic/object/trendlog.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_alarm_ack.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_arf.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_awf.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ccov.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_gas_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_get_alarm_sum.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_getevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_lso.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr_a.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_rr.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ts.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_ucov.c
${BACNETSTACK_SRC}/bacnet/basic/service/h_upt.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_abort.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_ack_alarm.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_arfs.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_awfs.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_cevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_cov.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_dcc.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_error.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_alarm_sum.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_get_event.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_getevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_lso.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rd.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_readrange.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rp.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_rpm.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_ts.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_uevent.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_upt.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_wp.c
${BACNETSTACK_SRC}/bacnet/basic/service/s_wpm.c
)
#
# add ports
@@ -390,14 +394,23 @@ set(BACNETSTACK_PORT ${CMAKE_CURRENT_LIST_DIR}/../ports/zephyr)
list(
APPEND BACNETSTACK_SRCS
${BACNETSTACK_PORT}/bacport.h
#${BACNETSTACK_PORT}/datetime-init.c
#$<$<BOOL:${CONFIG_BACDL_ETHERNET}>:${BACNETSTACK_PORT}/ethernet.c>
$<IF:$<BOOL:${CONFIG_NATIVE_APPLICATION}>,
${BACNETSTACK_BASIC_SRCS}
,#else
${BACNETSTACK_PORT}/device.c
>
${BACNETSTACK_PORT}/datetime-init.c
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_PORT}/bip-init.c>
$<$<BOOL:${CONFIG_BACDL_BIP6}>:${BACNETSTACK_PORT}/bip6-init.c>
$<$<BOOL:${CONFIG_BACDL_BIP}>:${BACNETSTACK_PORT}/datalink/bvlc.c>
$<$<BOOL:${CONFIG_BACDL_ETHERNET}>:${BACNETSTACK_PORT}/ethernet.c>
${BACNETSTACK_PORT}/main.c
#${BACNETSTACK_PORT}/mstimer-init.c
${BACNETSTACK_PORT}/mstimer-init.c
)
add_subdirectory(subsys)
#
# library
+2 -2
View File
@@ -10,7 +10,7 @@ menuconfig BACNETSTACK
if BACNETSTACK
module = BACNET
module = BACNETSTACK
module-str = Log level for BACnet
module-help = Enable BACnet library to output debug messages
source "$(ZEPHYR_BASE)/subsys/logging/Kconfig.template.log_config"
@@ -100,6 +100,6 @@ config BACDL_BIP6_PORT
help
UDP port to listen on (default=47808)
#rsource "subsys/Kconfig"
rsource "subsys/Kconfig"
endif # BACNETSTACK
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(b-ss)
target_sources(app PRIVATE src/main.c)
+23
View File
@@ -0,0 +1,23 @@
.. _b-ss_sample:
BACnet Profile B-SS Sample
##########################
Overview
********
This is a simple application demonstrating configuration of a
BACnet B-SS device profile.
Requirements
************
* A board with Ethernet support, for instance: mimxrt1064_evk
Building and Running
********************
This sample can be found under :bacnet_file:`samples/profiles/b-ss` in
the BACnet tree.
The sample can be built for several platforms.
+83
View File
@@ -0,0 +1,83 @@
CONFIG_BACNETSTACK=y
# BIP Options
CONFIG_BACDL_BIP=y
CONFIG_BACDL_BIP_PORT=47808
CONFIG_BACDL_BIP_ADDRESS_INDEX=0
# BIP6 Options
#CONFIG_BACDL_BIP6=y
CONFIG_BACDL_BIP6_PORT=47808
CONFIG_BACDL_BIP6_ADDRESS_INDEX=1
CONFIG_NET_IPV6_MLD=y
CONFIG_NET_IPV4=n
CONFIG_NET_ARP=n
CONFIG_BACDL_BIP6_ADDRESS_INDEX=0
CONFIG_BACDL_BIP6_MCAST_ADDRESS="FE80::0020" # YABE unicast workaround
CONFIG_NEWLIB_LIBC=y
# pthreads
CONFIG_POSIX_API=y
CONFIG_PTHREAD_IPC=y
CONFIG_POSIX_MQUEUE=y
# networking
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_ARP=y
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y
#CONFIG_NET_DHCPV4=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_CONFIG_SETTINGS=y
CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.168.10.80"
CONFIG_NET_CONFIG_MY_IPV4_NETMASK="255.255.255.0"
CONFIG_NET_CONFIG_MY_IPV4_GW="192.168.10.1"
CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.168.10.1"
CONFIG_NET_LLDP=y
CONFIG_NET_IF_UNICAST_IPV6_ADDR_COUNT=4
CONFIG_NET_IF_MCAST_IPV6_ADDR_COUNT=4
CONFIG_NET_CONFIG_MY_IPV6_ADDR="FE80::0010"
# Promiscuous mode on layer 2 is required to receive IPv6 multicasts.
# Ethernet hardware will not respond to MAC 33:33:x:x:x:x without this:
CONFIG_ETH_MCUX_PROMISCUOUS_MODE=y
#CONFIG_LOG_STRDUP_BUF_COUNT=4
#CONFIG_LOG_STRDUP_MAX_STRING=96
CONFIG_DNS_RESOLVER=y
CONFIG_SLIP_STATISTICS=n
CONFIG_NET_SHELL=y
CONFIG_NET_TX_STACK_SIZE=8192
CONFIG_NET_RX_STACK_SIZE=8192
CONFIG_NET_IF_UNICAST_IPV4_ADDR_COUNT=4
# logging
#CONFIG_NET_CONN_LOG_LEVEL_DEFAULT=n
#CONFIG_NET_CONN_LOG_LEVEL_DBG=y
#CONFIG_NET_IF_LOG_LEVEL_DEFAULT=n
CONFIG_NET_IF_LOG_LEVEL_DBG=y
CONFIG_NET_LOG=y
CONFIG_LOG=y
CONFIG_BACNETSTACK_LOG_LEVEL_DBG=y
# system
CONFIG_ISR_STACK_SIZE=8192
CONFIG_MAIN_STACK_SIZE=8192
CONFIG_IDLE_STACK_SIZE=2048
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_INIT_STACKS=y
CONFIG_MINIMAL_LIBC_MALLOC_ARENA_SIZE=131072
+7
View File
@@ -0,0 +1,7 @@
sample:
name: BACnet Profile B-SS Sample
tests:
sample.profile.b-ss:
tags: bacnet
platform_whitelist: qemu_x86 native_posix native_posix_64
+157
View File
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2020 Legrand North America, Inc.
*
* SPDX-License-Identifier: MIT
*/
#include <kernel.h>
#include <stdint.h>
#include "bacnet/config.h"
#include "bacnet/bacdef.h"
#include "bacnet/bacdcode.h"
#include "bacnet/apdu.h"
#include "bacnet/dcc.h"
#include "bacnet/iam.h"
#include "bacnet/npdu.h"
#include "bacnet/getevent.h"
#include "bacnet/version.h"
#include "bacnet/basic/services.h"
#include "bacnet/datalink/dlenv.h"
#include "bacnet/basic/sys/filename.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/datalink/datalink.h"
#include "bacnet/basic/binding/address.h"
/* include the device object */
#include "bacnet/basic/object/device.h"
#include "bacnet/basic/object/lc.h"
#include "bacnet/basic/object/trendlog.h"
#if defined(INTRINSIC_REPORTING)
#include "bacnet/basic/object/nc.h"
#endif /* defined(INTRINSIC_REPORTING) */
/* Logging module registration is already done in ports/zephyr/main.c */
#include <logging/log.h>
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
/** Buffer used for receiving */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/** Initialize the handlers we will utilize.
* @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler
*/
static void service_handlers_init(void)
{
Device_Init(NULL);
/* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
handler_who_is);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS,
handler_who_has);
/* set the handler for all the services we don't implement */
/* It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler(
handler_unrecognized_service);
/* Set the handlers for any confirmed services that we support. */
/* We must implement read property - it's required! */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
handler_read_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_write_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE,
handler_write_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_reinitialize_device);
/* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
}
void main(void)
{
LOG_INF("\n*** BACnet Profile B-SS Sample ***\n");
LOG_INF("BACnet Stack Version " BACNET_VERSION_TEXT);
LOG_INF("BACnet Device ID: %u", Device_Object_Instance_Number());
LOG_INF("BACnet Device Max APDU: %d", MAX_APDU);
service_handlers_init();
datalink_init(NULL);
/* configure the timeout values */
s64_t last_ms = k_uptime_get();
/* broadcast an I-Am on startup */
Send_I_Am(&Handler_Transmit_Buffer[0]);
s64_t address_binding_tmr = 0;
#if defined(INTRINSIC_REPORTING)
s64_t recipient_scan_tmr = 0;
#endif
#if defined(BACNET_TIME_MASTER)
BACNET_DATE_TIME bdatetime = { 0 };
#endif
for (;;) {
k_sleep(K_MSEC(1)); /* Allows debug prints */
BACNET_ADDRESS src = { 0 }; /* address where message came from */
const unsigned timeout_ms = 1;
s64_t current_ms = k_uptime_get();
/* returns 0 bytes on timeout */
uint16_t const pdu_len = datalink_receive(&src, &Rx_Buf[0],
MAX_MPDU, timeout_ms);
/* process */
if (pdu_len > 0) {
npdu_handler(&src, &Rx_Buf[0], pdu_len);
}
if (current_ms - last_ms > 1000) {
const uint32_t elapsed_milliseconds =
(uint32_t)(current_ms - last_ms);
//TODO: const uint32_t elapsed_seconds = elapsed_milliseconds / 1000UL;
last_ms = current_ms;
//TODO: dcc_timer_seconds(elapsed_seconds);
//TODO: datalink_maintenance_timer(elapsed_seconds);
//TODO: dlenv_maintenance_timer(elapsed_seconds);
//TODO: Load_Control_State_Machine_handler():
//TODO: handler_cov_timer_seconds(elapsed_seconds);
//TODO: tsm_timer_milliseconds(elapsed_milliseconds);
//TODO: trend_log_timer(elapsed_seconds);
#if defined(INTRINSIC_REPORTING)
//TODO: Device_local_reporting();
#endif
#if defined(BACNET_TIME_MASTER)
//TODO: Device_getCurrentDateTime(&bdatetime);
//TODO: handler_Timesync_task(&bdatetime);
#endif
address_binding_tmr += elapsed_milliseconds;
#if defined(INTRINSIC_REPORTING)
recipient_scan_tmr += elapsed_milliseconds;
#endif
}
//TODO: handler_cov_task();
/* scan cache address */
if (address_binding_tmr >= 60 * 1000) {
//TODO: address_cache_timer(address_binding_tmr / 1000);
address_binding_tmr = 0;
}
#if defined(INTRINSIC_REPORTING)
/* try to find addresses of recipients */
if (recipient_scan_tmr >= NC_RESCAN_RECIPIENTS_SECS * 1000) {
//TODO: Notification_Class_find_recipient();
recipient_scan_tmr = 0;
}
#endif
/* output */
/* blink LEDs, Turn on or off outputs, etc */
}
}
+4
View File
@@ -0,0 +1,4 @@
# Copyright (c) 2020 Legrand North America, LLC.
# SPDX-License-Identifier: MIT
add_subdirectory_ifdef(CONFIG_BACNETSTACK_BACNET_SERVER server)
+8
View File
@@ -0,0 +1,8 @@
# Copyright (c) 2020 Legrand North America, LLC.
# SPDX-License-Identifier: MIT
# Kconfig - Subsystem configuration options
comment "BACnet Subsystems"
rsource "server/Kconfig"
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2020 Legrand North America, LLC.
# SPDX-License-Identifier: MIT
zephyr_include_directories(include)
zephyr_interface_library_named(bac_server)
zephyr_library()
zephyr_library_sources(server.c)
zephyr_library_link_libraries(bac_server)
+35
View File
@@ -0,0 +1,35 @@
# Copyright (c) 2020 Legrand North America, LLC.
# SPDX-License-Identifier: MIT
# Kconfig -
menuconfig BACNETSTACK_BACNET_SERVER
bool "BACNETSTACK_BACNET_SERVER"
help
This option enables BACnet Server services
if BACNETSTACK_BACNET_SERVER
module = BACNETSTACK_BACNET_SERVER
module-str = bac_server
config BACNETSTACK_BACNET_SERVER_APP_PRIORITY
int "App init priority"
default 0
help
This sets the starting priority of the thread.
config BACNETSTACK_BACNET_SERVER_PRIO
int "BACnet server thread priority"
default 50
help
This sets the execution priority of the thread.
config BACNETSTACK_BACNET_SERVER_STACK_SIZE
int "BACnet server stack size"
default 4096
help
This sets the stack size of the thread.
endif # BACNETSTACK_BACNET_SERVER
+242
View File
@@ -0,0 +1,242 @@
/*
* Copyright (c) 2020 Legrand North America, LLC.
*
* SPDX-License-Identifier: MIT
*/
#include <stdalign.h> /*TODO: Not std until C11! */
#include <device.h>
#include <init.h>
#include <kernel.h>
#include <net/net_if.h>
#include <net/net_core.h>
#include <net/net_context.h>
#include <net/net_mgmt.h>
#include <net/net_ip.h>
#include <sys/printk.h>
/* some BACnet modules we use */
#include "bacnet/bacdef.h"
#include "bacnet/config.h"
#include "bacnet/bactext.h"
#include "bacnet/bacerror.h"
#include "bacnet/iam.h"
#include "bacnet/arf.h"
#include "bacnet/npdu.h"
#include "bacnet/apdu.h"
#include "bacnet/version.h"
/* some demo modules we use */
#include "bacnet/basic/sys/debug.h"
#include "bacnet/basic/tsm/tsm.h"
#include "bacnet/basic/binding/address.h"
#include "bacnet/basic/services.h"
/* our datalink layers */
#include "bacnet/datalink/bip.h"
#include "bacnet/datalink/bvlc.h"
/* include the device object */
#include "bacnet/basic/object/device.h"
/* Logging module registration is already done in ports/zephyr/main.c */
#include <logging/log.h>
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
enum bacnet_server_msg_type {
SERVER_MSG_TYPE_INVALID = 0,
SERVER_MSG_TYPE_IPV4_EVENT,
};
struct bacnet_server_msg {
uint8_t type;
uint8_t dummy[3];
uint32_t parm_u32;
void *parm_ptr;
};
K_MSGQ_DEFINE(bacnet_server_msgq, sizeof(struct bacnet_server_msg), 8,
alignof(struct bacnet_server_msg));
#define SERVER_IPV4_EVENTS_MASK \
(NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL)
static struct k_thread server_thread_data;
static K_THREAD_STACK_DEFINE(server_thread_stack,
CONFIG_BACNETSTACK_BACNET_SERVER_STACK_SIZE);
/* Keep a reference to the Ethernet interface */
static struct net_mgmt_event_callback mgmt_cb;
/* track our directly connected ports network number */
static uint16_t BIP_Net;
/* buffer for receiving packets from the directly connected ports */
static uint8_t BIP_Rx_Buffer[MAX_MPDU];
/** Initialize the handlers we will utilize.
* @see Device_Init, apdu_set_unconfirmed_handler, apdu_set_confirmed_handler
*/
static void service_handlers_init(void)
{
Device_Init(NULL);
/* we need to handle who-is to support dynamic device binding */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS,
handler_who_is);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_HAS,
handler_who_has);
/* set the handler for all the services we don't implement */
/* It is required to send the proper reject message... */
apdu_set_unrecognized_service_handler_handler(
handler_unrecognized_service);
/* Set the handlers for any confirmed services that we support. */
/* We must implement read property - it's required! */
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROP_MULTIPLE,
handler_read_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
handler_write_property);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_WRITE_PROP_MULTIPLE,
handler_write_property_multiple);
apdu_set_confirmed_handler(SERVICE_CONFIRMED_REINITIALIZE_DEVICE,
handler_reinitialize_device);
/* handle communication so we can shutup when asked */
apdu_set_confirmed_handler(
SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL,
handler_device_communication_control);
}
/* TODO: Update copyright as this code pattern copied from
* conn_mgr_ipv4_events_handler()
*/
static void ipv4_events_handler(struct net_mgmt_event_callback *cb,
u32_t mgmt_event, struct net_if *iface)
{
static int counter = 0;
printk("\n*** Handler[%d]: IPv4 event %08x received on iface %p ***\n",
++counter, mgmt_event, iface);
if ((mgmt_event & SERVER_IPV4_EVENTS_MASK) != mgmt_event) {
printk("\n*** Handler[%d]: ignoring event %08x on iface %p ***\n",
counter, mgmt_event, iface);
return;
}
struct bacnet_server_msg msg = {
.type = SERVER_MSG_TYPE_IPV4_EVENT,
.parm_u32 = mgmt_event,
.parm_ptr = iface,
};
int ret = k_msgq_put(&bacnet_server_msgq, &msg, K_NO_WAIT);
if (ret != 0) {
printk("\n*** Handler[%d]: queue full, type %u event 0x%08x on iface %p dropped! ***\n",
counter, msg.type, msg.parm_u32, msg.parm_ptr);
}
}
/**
* @brief BACnet Server Thread
*/
static void server_thread(void)
{
LOG_INF("Server: started");
service_handlers_init();
bip_init("Server: from init");
BIP_Net = 1;
net_mgmt_init_event_callback(&mgmt_cb, ipv4_events_handler,
SERVER_IPV4_EVENTS_MASK);
net_mgmt_add_event_callback(&mgmt_cb);
while (1) {
const s32_t sleep_ms = K_FOREVER;
struct bacnet_server_msg msg = {
.type = SERVER_MSG_TYPE_INVALID,
};
int ret = k_msgq_get(&bacnet_server_msgq, &msg, sleep_ms);
/* Waiting period timed out */
if (-EAGAIN == ret) {
BACNET_ADDRESS src = {
0
}; /* address where message came from */
/* input */
/* returns 0 bytes on timeout */
uint16_t pdu_len = bip_receive(&src, &BIP_Rx_Buffer[0],
MAX_MPDU, 5);
/* process */
if (pdu_len) {
LOG_INF("Server: BIP received %u bytes.",
(unsigned)pdu_len);
}
}
/* Message received */
else if (0 == ret) {
switch (msg.type) {
#if defined(CONFIG_NET_IPV4)
case SERVER_MSG_TYPE_IPV4_EVENT: {
LOG_INF("Server: MSG_TYPE_IPV4_EVENT u32: %08x ptr: %p",
msg.parm_u32, msg.parm_ptr);
const u32_t mgmt_event = msg.parm_u32;
//TODO: const struct net_if *iface = msg.parm_ptr;
/* Handle events */
if ((mgmt_event & SERVER_IPV4_EVENTS_MASK) !=
mgmt_event) {
LOG_INF("Server: thread ignoring event");
break;
}
switch (NET_MGMT_GET_COMMAND(mgmt_event)) {
#if 0
case NET_EVENT_IPV4_CMD_ADDR_ADD:
LOG_INF("Server: IPv4 addr activated");
bip_init("Server: from CMD_ADDR_ADD");
BIP_Net = bip_valid() ? 1 : 0;
break;
case NET_EVENT_IPV4_CMD_ADDR_DEL:
LOG_INF("Server: IPv4 addr deactivated");
bip_cleanup();
BIP_Net = 0;
break;
#endif
default:
LOG_INF("Server: Unsupported event %u",
mgmt_event);
break;
}
} break;
#endif /* defined(CONFIG_NET_IPV4) */
default:
LOG_WRN("Server: Dropping unsupported type %u",
msg.type);
break;
}
}
/* Returned without waiting and without message - why? */
else {
LOG_WRN("Server: Msgq returned w/o timeout or msg! req = %d",
ret);
}
}
}
static int server_init(struct device *dev)
{
ARG_UNUSED(dev);
k_thread_create(&server_thread_data, server_thread_stack,
K_THREAD_STACK_SIZEOF(server_thread_stack),
(k_thread_entry_t)server_thread, NULL, NULL, NULL,
K_PRIO_PREEMPT(CONFIG_BACNETSTACK_BACNET_SERVER_PRIO), 0,
K_NO_WAIT);
k_thread_name_set(&server_thread_data, "BACserver");
return 0;
}
SYS_INIT(server_init, APPLICATION, CONFIG_BACNETSTACK_BACNET_SERVER_APP_PRIORITY);
+25
View File
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.13.1)
# Extract module path and names
string(REGEX REPLACE
"/zephyr/tests/[a-zA-Z_/-]*$" ""
BACNET_BASE
${CMAKE_CURRENT_SOURCE_DIR})
string(REGEX REPLACE
"/zephyr/tests/" "/test/"
BACNET_TEST_PATH
${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(BACNET_NAME ${BACNET_BASE} NAME)
# Update include path for this module
list(APPEND BACNET_INCLUDE ${BACNET_BASE}/src)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(${BACNET_NAME})
target_include_directories(app PRIVATE ${BACNET_INCLUDE})
target_sources(app PRIVATE
${BACNET_TEST_PATH}/src/main.c
)
+11
View File
@@ -0,0 +1,11 @@
CONFIG_ZTEST=y
CONFIG_BACNETSTACK=y
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_ARP=y
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y
CONFIG_NEWLIB_LIBC=y
+3
View File
@@ -0,0 +1,3 @@
tests:
bacnet.device:
tags: bacnet