Zephyr core bacnet server port; bacnet/device test (#123)
Co-authored-by: Gregory Shue <gregory.shue@legrand.us>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# Copyright (c) 2020 Legrand North America, LLC.
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_BACNETSTACK_BACNET_SERVER server)
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
)
|
||||
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
tests:
|
||||
bacnet.device:
|
||||
tags: bacnet
|
||||
Reference in New Issue
Block a user