Moved west manifest, zephyr folder, and ports/zephyr folders to another repository bacnet-stack-zephyr (#757)
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Port specific configuration for BACnet Stack for Zephyr OS
|
||||
* @author Steve Karg
|
||||
* @date 2024
|
||||
* @section LICENSE
|
||||
*
|
||||
* Copyright (C) 2024 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef BACNET_PORTS_ZEPHYR_BACNET_CONFIG_H
|
||||
#define BACNET_PORTS_ZEPHYR_BACNET_CONFIG_H
|
||||
|
||||
#if ! defined BACNET_CONFIG_H || ! BACNET_CONFIG_H
|
||||
#error bacnet-config.h included outside of BACNET_CONFIG_H control
|
||||
#endif
|
||||
|
||||
/* provides platform specific define for ARRAY_SIZE */
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#endif
|
||||
@@ -1,65 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef BITS_H
|
||||
#define BITS_H
|
||||
|
||||
#include <zephyr/sys/util.h> /* defines BIT(n) */
|
||||
|
||||
/********************************************************************
|
||||
* Bit Masks
|
||||
*********************************************************************/
|
||||
#define BIT0 BIT( 0)
|
||||
#define BIT1 BIT( 1)
|
||||
#define BIT2 BIT( 2)
|
||||
#define BIT3 BIT( 3)
|
||||
#define BIT4 BIT( 4)
|
||||
#define BIT5 BIT( 5)
|
||||
#define BIT6 BIT( 6)
|
||||
#define BIT7 BIT( 7)
|
||||
#define BIT8 BIT( 8)
|
||||
#define BIT9 BIT( 9)
|
||||
#define BIT10 BIT(10)
|
||||
#define BIT11 BIT(11)
|
||||
#define BIT12 BIT(12)
|
||||
#define BIT13 BIT(13)
|
||||
#define BIT14 BIT(14)
|
||||
#define BIT15 BIT(15)
|
||||
#define BIT16 BIT(16)
|
||||
#define BIT17 BIT(17)
|
||||
#define BIT18 BIT(18)
|
||||
#define BIT19 BIT(19)
|
||||
#define BIT20 BIT(20)
|
||||
#define BIT21 BIT(21)
|
||||
#define BIT22 BIT(22)
|
||||
#define BIT23 BIT(23)
|
||||
#define BIT24 BIT(24)
|
||||
#define BIT25 BIT(25)
|
||||
#define BIT26 BIT(26)
|
||||
#define BIT27 BIT(27)
|
||||
#define BIT28 BIT(28)
|
||||
#define BIT29 BIT(29)
|
||||
#define BIT30 BIT(30)
|
||||
#define BIT31 BIT(31)
|
||||
|
||||
/* a=register, b=bit number to act upon 0-n */
|
||||
#define BIT_SET(a,b) ((a) |= (1<<(b)))
|
||||
#define BIT_CLEAR(a,b) ((a) &= ~(1<<(b)))
|
||||
#define BIT_FLIP(a,b) ((a) ^= (1<<(b)))
|
||||
#define BIT_CHECK(a,b) ((a) & (1<<(b)))
|
||||
|
||||
/* x=target variable, y=mask */
|
||||
#define BITMASK_SET(x,y) ((x) |= (y))
|
||||
#define BITMASK_CLEAR(x,y) ((x) &= (~(y)))
|
||||
#define BITMASK_FLIP(x,y) ((x) ^= (y))
|
||||
#define BITMASK_CHECK(x,y) (((x) & (y)) == (y))
|
||||
|
||||
#ifndef _BV
|
||||
#define _BV(x) (1<<(x))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef ETHERNET_H
|
||||
#define ETHERNET_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/npdu.h"
|
||||
|
||||
/* specific defines for Ethernet */
|
||||
#define ETHERNET_HEADER_MAX (6+6+2+1+1+1)
|
||||
#define ETHERNET_MPDU_MAX (ETHERNET_HEADER_MAX+MAX_PDU)
|
||||
|
||||
/* Unless we explicitly need these remaps to be NOT exposed
|
||||
* (e.g. implementation where we need both bacnet and Zephyr symbols),
|
||||
* replace the BACnet Ethernet API symbols with non-conflicting ones.
|
||||
*/
|
||||
#if !defined(BACNET_ETHERNET_NO_REMAP_DEFINES)
|
||||
#define ethernet_valid bacnet_ethernet_valid
|
||||
#define ethernet_cleanup bacnet_ethernet_cleanup
|
||||
#define ethernet_init bacnet_ethernet_init
|
||||
#define ethernet_send_pdu bacnet_ethernet_send_pdu
|
||||
#define ethernet_receive bacnet_ethernet_receive
|
||||
#define ethernet_set_my_address bacnet_ethernet_set_my_address
|
||||
#define ethernet_get_my_address bacnet_ethernet_get_my_address
|
||||
#define ethernet_get_broadcast_address bacnet_ethernet_get_broadcast_address
|
||||
#define ethernet_debug_address bacnet_ethernet_debug_address
|
||||
#define ethernet_send bacnet_ethernet_send
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
bool bacnet_ethernet_valid(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_ethernet_cleanup(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
bool bacnet_ethernet_init(
|
||||
char *interface_name);
|
||||
|
||||
/* function to send a packet out the 802.2 socket */
|
||||
/* returns number of bytes sent on success, negative on failure */
|
||||
BACNET_STACK_EXPORT
|
||||
int bacnet_ethernet_send_pdu(
|
||||
BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
uint8_t * pdu, /* any data to be sent - may be null */
|
||||
unsigned pdu_len); /* number of bytes of data */
|
||||
|
||||
/* receives an 802.2 framed packet */
|
||||
/* returns the number of octets in the PDU, or zero on failure */
|
||||
BACNET_STACK_EXPORT
|
||||
uint16_t bacnet_ethernet_receive(
|
||||
BACNET_ADDRESS * src, /* source address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t max_pdu, /* amount of space available in the PDU */
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_ethernet_set_my_address(
|
||||
const BACNET_ADDRESS * my_address);
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_ethernet_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_ethernet_get_broadcast_address(
|
||||
BACNET_ADDRESS * dest); /* destination address */
|
||||
|
||||
/* some functions from Linux driver */
|
||||
BACNET_STACK_EXPORT
|
||||
void bacnet_ethernet_debug_address(
|
||||
const char *info,
|
||||
BACNET_ADDRESS * dest);
|
||||
BACNET_STACK_EXPORT
|
||||
int bacnet_ethernet_send(
|
||||
uint8_t * mtu,
|
||||
int mtu_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (c) 2020 Legrand North America, LLC.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef NET_H
|
||||
#define NET_H
|
||||
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/kernel.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/basic/object/device.h"
|
||||
|
||||
static inline char *inet_ntoa(struct in_addr in) {
|
||||
return "(inet_ntoa() to be implemented)";
|
||||
}
|
||||
|
||||
/* Local helper functions for this port */
|
||||
extern int bip_get_local_netmask(
|
||||
struct in_addr *netmask);
|
||||
|
||||
#ifdef CONFIG_BACNET_USE_SECTION_ITERABLE_OBJECT_TABLE
|
||||
|
||||
#define BACNET_OBJECT_TABLE(table_name, _type, _init, _count, \
|
||||
_index_to_instance, _valid_instance, _object_name, \
|
||||
_read_property, _write_property, _RPM_list, \
|
||||
_RR_info, _iterator, _value_list, _COV, \
|
||||
_COV_clear, _intrinsic_reporting) \
|
||||
STRUCT_SECTION_ITERABLE(object_functions, table_name) = { \
|
||||
.Object_Type = _type, \
|
||||
.Object_Init = _init, \
|
||||
.Object_Count = _count, \
|
||||
.Object_Index_To_Instance = _index_to_instance, \
|
||||
.Object_Valid_Instance = _valid_instance, \
|
||||
.Object_Name = _object_name, \
|
||||
.Object_Read_Property = _read_property, \
|
||||
.Object_Write_Property = _write_property, \
|
||||
.Object_RPM_List = _RPM_list, \
|
||||
.Object_RR_Info = _RR_info, \
|
||||
.Object_Iterator = _iterator, \
|
||||
.Object_Value_List = _value_list, \
|
||||
.Object_COV = _COV, \
|
||||
.Object_COV_Clear = _COV_clear, \
|
||||
.Object_Intrinsic_Reporting = _intrinsic_reporting \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BACNET_OBJECT_TABLE(table_name, _type, _init, _count, \
|
||||
_index_to_instance, _valid_instance, _object_name, \
|
||||
_read_property, _write_property, _RPM_list, \
|
||||
_RR_info, _iterator, _value_list, _COV, \
|
||||
_COV_clear, _intrinsic_reporting) \
|
||||
while{}(0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,613 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/net/socket_select.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#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 <zephyr/logging/log.h>
|
||||
#include <zephyr/logging/log_ctrl.h>
|
||||
|
||||
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
|
||||
|
||||
#define THIS_FILE "bip-init.c"
|
||||
|
||||
/* zephyr sockets */
|
||||
static int BIP_Socket = -1;
|
||||
static int BIP_Broadcast_Socket = -1;
|
||||
|
||||
/* NOTE: we store address and port in network byte order
|
||||
since BACnet/IP uses network byte order for all address byte arrays
|
||||
*/
|
||||
/* 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 (IS_ENABLED(CONFIG_BACNETSTACK_LOG_LEVEL)) {
|
||||
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]);
|
||||
}
|
||||
|
||||
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)", str, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the BACnet/IP address
|
||||
* @param addr - network IPv4 address
|
||||
* @return true if the address was set
|
||||
*/
|
||||
bool bip_set_addr(const BACNET_IP_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
memcpy(&BIP_Address.s_addr, &addr->address[0], IP_ADDRESS_MAX);
|
||||
BIP_Port = htons(addr->port);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the BACnet/IP address
|
||||
* @param addr - network IPv4 address (in network byte order)
|
||||
* @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);
|
||||
addr->port = ntohs(BIP_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(const 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 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++) {
|
||||
if ((address | mask) == 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(
|
||||
const BACNET_IP_ADDRESS *dest, const 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, (const 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;
|
||||
int socket;
|
||||
|
||||
/* 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);
|
||||
ZSOCK_FD_SET(BIP_Broadcast_Socket, &read_fds);
|
||||
|
||||
max = BIP_Socket > BIP_Broadcast_Socket ? BIP_Socket : BIP_Broadcast_Socket;
|
||||
|
||||
/* see if there is a packet for us */
|
||||
if (zsock_select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
socket =
|
||||
FD_ISSET(BIP_Socket, &read_fds) ? BIP_Socket : BIP_Broadcast_Socket;
|
||||
received_bytes = zsock_recvfrom(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 = socket == BIP_Socket
|
||||
? bvlc_handler(&addr, src, npdu, received_bytes)
|
||||
: bvlc_broadcast_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(const char *ifname)
|
||||
{
|
||||
struct net_if *iface = 0;
|
||||
int index = -1;
|
||||
uint8_t x = 0;
|
||||
BACNET_IP_ADDRESS unicast = { 0 };
|
||||
BACNET_IP_ADDRESS broadcast = { 0 };
|
||||
|
||||
/* Network byte order */
|
||||
unicast.port = ntohs(BIP_Port);
|
||||
broadcast.port = ntohs(BIP_Port);
|
||||
LOG_INF("bip_set_interface()");
|
||||
LOG_INF("UDP port: %d", unicast.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 {
|
||||
iface = net_if_get_by_index(index);
|
||||
if (iface) {
|
||||
LOG_INF("Using iface %d", index);
|
||||
} else {
|
||||
LOG_ERR(
|
||||
"%s:%d - No iface at index %d", THIS_FILE, __LINE__, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
LOG_WRN("%s:%d - No valid interface specified - using default ",
|
||||
THIS_FILE, __LINE__);
|
||||
iface = net_if_get_default();
|
||||
}
|
||||
if (iface) {
|
||||
LOG_INF("Interface set.");
|
||||
#if defined(CONFIG_BACDL_BIP_ADDRESS_INDEX)
|
||||
LOG_INF("Config unicast address %d/%d",
|
||||
CONFIG_BACDL_BIP_ADDRESS_INDEX, NET_IF_MAX_IPV4_ADDR);
|
||||
index = CONFIG_BACDL_BIP_ADDRESS_INDEX;
|
||||
#else
|
||||
int i;
|
||||
char hr_addr[NET_IPV4_ADDR_LEN];
|
||||
index = 0;
|
||||
for (i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) {
|
||||
struct net_if_addr *if_addr = &iface->config.ip.ipv4->unicast[i];
|
||||
|
||||
if (!if_addr->is_used) {
|
||||
continue;
|
||||
}
|
||||
index = i;
|
||||
LOG_INF("IPv4 address: %s",
|
||||
net_addr_ntop(AF_INET, &if_addr->address.in_addr, hr_addr,
|
||||
NET_IPV4_ADDR_LEN));
|
||||
LOG_INF("Subnet: %s",
|
||||
net_addr_ntop(AF_INET, &iface->config.ip.ipv4->netmask, hr_addr,
|
||||
NET_IPV4_ADDR_LEN));
|
||||
LOG_INF("Router: %s",
|
||||
net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, hr_addr,
|
||||
NET_IPV4_ADDR_LEN));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (index >= NET_IF_MAX_IPV4_ADDR) {
|
||||
LOG_ERR("%s:%d - IPv4 address index of %d is out of range (0-%d)",
|
||||
THIS_FILE, __LINE__, index, NET_IF_MAX_IPV4_ADDR - 1);
|
||||
return;
|
||||
}
|
||||
LOG_INF("Using IPv4 address at index %d", index);
|
||||
/* Build the broadcast address from the unicast and netmask */
|
||||
struct net_if_addr *if_addr = &iface->config.ip.ipv4->unicast[index];
|
||||
for (x = 0; x < IP_ADDRESS_MAX; x++) {
|
||||
unicast.address[x] = if_addr->address.in_addr.s4_addr[x];
|
||||
broadcast.address[x] = if_addr->address.in_addr.s4_addr[x] |
|
||||
~iface->config.ip.ipv4->netmask.s4_addr[x];
|
||||
}
|
||||
bip_set_addr(&unicast);
|
||||
bip_set_broadcast_addr(&broadcast);
|
||||
LOG_INF("BACnet/IP Unicast: %u.%u.%u.%u:%d", unicast.address[0],
|
||||
unicast.address[1], unicast.address[2], unicast.address[3],
|
||||
unicast.port);
|
||||
LOG_INF("BACnet/IP Broadcast: %u.%u.%u.%u", broadcast.address[0],
|
||||
broadcast.address[1], broadcast.address[2], broadcast.address[3]);
|
||||
} else {
|
||||
LOG_ERR("%s:%d - Failed to set iface", THIS_FILE, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
static int createSocket(const struct sockaddr_in *sin)
|
||||
{
|
||||
int sock_fd = -1;
|
||||
const int sockopt = 1;
|
||||
int status = -1;
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
sock_fd = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock_fd < 0) {
|
||||
LOG_ERR("%s:%d - Failed to create socket", THIS_FILE, __LINE__);
|
||||
return sock_fd;
|
||||
} 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);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* bind the socket to the local port number and IP address */
|
||||
status = zsock_bind(
|
||||
sock_fd, (const struct sockaddr *)sin, sizeof(struct sockaddr));
|
||||
if (status < 0) {
|
||||
zsock_close(sock_fd);
|
||||
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
|
||||
return status;
|
||||
} else {
|
||||
LOG_DBG("Socket bound");
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
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__, ifname ? ifname : "[default]");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* bind the socket to the local port number and IP address */
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = BIP_Port;
|
||||
|
||||
sin.sin_addr.s_addr = BIP_Address.s_addr;
|
||||
sock_fd = createSocket(&sin);
|
||||
BIP_Socket = sock_fd;
|
||||
if (sock_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
sock_fd = createSocket(&sin);
|
||||
BIP_Broadcast_Socket = sock_fd;
|
||||
if (sock_fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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()");
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,578 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005-2020 Steve Karg
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/socket.h>
|
||||
#include <zephyr/net/socket_select.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/bacdcode.h"
|
||||
#include "bacnet/bacint.h"
|
||||
#include "bacnet/datalink/bip6.h"
|
||||
#include "bacnet/basic/object/device.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 <zephyr/logging/log.h>
|
||||
#include <zephyr/logging/log_ctrl.h>
|
||||
|
||||
LOG_MODULE_DECLARE(bacnet, CONFIG_BACNETSTACK_LOG_LEVEL);
|
||||
|
||||
#define THIS_FILE "bip6-init.c"
|
||||
|
||||
/* zephyr socket */
|
||||
static int BIP6_Socket = -1;
|
||||
static int BIP6_Socket_Scope_Id;
|
||||
/* local address - filled by init functions */
|
||||
static BACNET_IP6_ADDRESS BIP6_Addr;
|
||||
static BACNET_IP6_ADDRESS BIP6_Broadcast_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(const 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 += snprintf(
|
||||
&ipv6_addr_str[d], sizeof(ipv6_addr_str), "%02X%02X",
|
||||
a->s6_addr[x], a->s6_addr[x + 1]);
|
||||
}
|
||||
|
||||
if (x < 14) {
|
||||
d += snprintf(&ipv6_addr_str[d], sizeof(ipv6_addr_str), ":");
|
||||
}
|
||||
}
|
||||
|
||||
if (!non_zero_count) {
|
||||
snprintf(&ipv6_addr_str[0], sizeof(ipv6_addr_str), "undefined");
|
||||
}
|
||||
#endif
|
||||
return &ipv6_addr_str[0];
|
||||
}
|
||||
|
||||
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_get_port();
|
||||
multicast.port = unicast.port;
|
||||
|
||||
LOG_DBG("bip6_set_interface()");
|
||||
LOG_INF("BIP6: UDP port: 0x%04X", (unsigned)unicast.port);
|
||||
LOG_INF("BIP6: seeking interface: %s", ifname?ifname:"NULL");
|
||||
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("BIP6: Using interface %d", index);
|
||||
} else {
|
||||
LOG_ERR(
|
||||
"%s:%d - No interface at index %d", THIS_FILE, __LINE__,
|
||||
index);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
LOG_INF("BIP6: No valid interface specified. Using default ");
|
||||
interface = net_if_get_default();
|
||||
}
|
||||
|
||||
if (interface) {
|
||||
BIP6_Socket_Scope_Id = net_if_get_by_iface(interface);
|
||||
LOG_INF("BIP6: Socket Scope ID = %d", BIP6_Socket_Scope_Id);
|
||||
LOG_INF("BIP6: 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, 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, 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("BIP6: Using configured 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", inet6_ntoa((struct in6_addr *)&unicast.address));
|
||||
LOG_INF(
|
||||
" Multicast: %s",
|
||||
inet6_ntoa((struct in6_addr *)&multicast.address));
|
||||
} else {
|
||||
LOG_ERR("%s:%d - Failed to set interface", THIS_FILE, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet IPv6 UDP port number
|
||||
*
|
||||
* @param port - IPv6 UDP port number
|
||||
*/
|
||||
void bip6_set_port(uint16_t port)
|
||||
{
|
||||
BIP6_Addr.port = port;
|
||||
BIP6_Broadcast_Addr.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet IPv6 UDP port number
|
||||
*
|
||||
* @return IPv6 UDP port number
|
||||
*/
|
||||
uint16_t bip6_get_port(void)
|
||||
{
|
||||
return BIP6_Addr.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet broadcast address for my interface.
|
||||
* Used as dest address in messages sent as BROADCAST
|
||||
*
|
||||
* @param addr - IPv6 source address
|
||||
*/
|
||||
void bip6_get_broadcast_address(BACNET_ADDRESS *addr)
|
||||
{
|
||||
if (addr) {
|
||||
addr->net = BACNET_BROADCAST_NETWORK;
|
||||
addr->mac_len = 0;
|
||||
addr->len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IPv6 address for my interface. Used as src address in messages sent.
|
||||
*
|
||||
* @param addr - IPv6 source address
|
||||
*/
|
||||
void bip6_get_my_address(BACNET_ADDRESS *addr)
|
||||
{
|
||||
uint32_t device_id = 0;
|
||||
|
||||
if (addr) {
|
||||
device_id = Device_Object_Instance_Number();
|
||||
bvlc6_vmac_address_set(addr, device_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet/IP address
|
||||
*
|
||||
* @param addr - network IPv6 address
|
||||
*/
|
||||
bool bip6_set_addr(const BACNET_IP6_ADDRESS *addr)
|
||||
{
|
||||
return bvlc6_address_copy(&BIP6_Addr, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet/IP address
|
||||
*
|
||||
* @return BACnet/IP address
|
||||
*/
|
||||
bool bip6_get_addr(BACNET_IP6_ADDRESS *addr)
|
||||
{
|
||||
return bvlc6_address_copy(addr, &BIP6_Addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the BACnet/IP address
|
||||
*
|
||||
* @param addr - network IPv6 address
|
||||
*/
|
||||
bool bip6_set_broadcast_addr(const BACNET_IP6_ADDRESS *addr)
|
||||
{
|
||||
return bvlc6_address_copy(&BIP6_Broadcast_Addr, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BACnet/IP address
|
||||
*
|
||||
* @return BACnet/IP address
|
||||
*/
|
||||
bool bip6_get_broadcast_addr(BACNET_IP6_ADDRESS *addr)
|
||||
{
|
||||
return bvlc6_address_copy(addr, &BIP6_Broadcast_Addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* The send function for BACnet/IPv6 driver layer
|
||||
*
|
||||
* @param dest - Points to a BACNET_IP6_ADDRESS structure containing the
|
||||
* destination address.
|
||||
* @param mtu - the bytes of data to send
|
||||
* @param mtu_len - the number of bytes of data to send
|
||||
*
|
||||
* @return Upon successful completion, returns the number of bytes sent.
|
||||
* Otherwise, -1 shall be returned and errno set to indicate the error.
|
||||
*/
|
||||
int bip6_send_mpdu(
|
||||
const BACNET_IP6_ADDRESS *dest, const uint8_t *mtu, uint16_t mtu_len)
|
||||
{
|
||||
struct sockaddr_in6 bvlc_dest = { 0 };
|
||||
uint16_t addr16[8];
|
||||
|
||||
/* 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 */
|
||||
bvlc_dest.sin6_family = AF_INET6;
|
||||
bvlc6_address_get(
|
||||
dest, &addr16[0], &addr16[1], &addr16[2], &addr16[3], &addr16[4],
|
||||
&addr16[5], &addr16[6], &addr16[7]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[0] = htons(addr16[0]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[1] = htons(addr16[1]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[2] = htons(addr16[2]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[3] = htons(addr16[3]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[4] = htons(addr16[4]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[5] = htons(addr16[5]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[6] = htons(addr16[6]);
|
||||
bvlc_dest.sin6_addr.s6_addr16[7] = htons(addr16[7]);
|
||||
bvlc_dest.sin6_port = htons(dest->port);
|
||||
bvlc_dest.sin6_scope_id = BIP6_Socket_Scope_Id;
|
||||
inet6_ntoa(&bvlc_dest.sin6_addr);
|
||||
LOG_DBG("BIP6: Sending MPDU to %s", ipv6_addr_str);
|
||||
/* Send the packet */
|
||||
return zsock_sendto(
|
||||
BIP6_Socket, (const char *)mtu, mtu_len, 0,
|
||||
(struct sockaddr *)&bvlc_dest, sizeof(bvlc_dest));
|
||||
}
|
||||
|
||||
/**
|
||||
* The common send function for BACnet/IPv6 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 pdu - the bytes of data to send
|
||||
* @param pdu_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_pdu(
|
||||
BACNET_ADDRESS *dest,
|
||||
BACNET_NPDU_DATA *npdu_data,
|
||||
uint8_t *pdu,
|
||||
unsigned pdu_len)
|
||||
{
|
||||
return bvlc6_send_pdu(dest, npdu_data, pdu, pdu_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate ASCII address string from BACnet/IPv6 address
|
||||
* @param s - buffer to store the string
|
||||
* @param n - size of the buffer
|
||||
* @param addr - BACnet/IPv6 address
|
||||
*/
|
||||
static int bvlc6_snprintf_addr(
|
||||
char *s, size_t n, const BACNET_IP6_ADDRESS *addr)
|
||||
{
|
||||
uint16_t addr16[8];
|
||||
|
||||
bvlc6_address_get(
|
||||
addr, &addr16[0], &addr16[1], &addr16[2], &addr16[3], &addr16[4],
|
||||
&addr16[5], &addr16[6], &addr16[7]);
|
||||
|
||||
return snprintf(s, n, "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
|
||||
addr16[0], addr16[1], addr16[2], addr16[3], addr16[4], addr16[5],
|
||||
addr16[6], addr16[7]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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_DBG("BIP6: not a BACnet packet. Dropped.");
|
||||
return 0;
|
||||
}
|
||||
/* pass the packet into the BBMD handler */
|
||||
inet6_ntoa(&sin.sin6_addr);
|
||||
LOG_DBG("BIP6: Received MPDU from %s", ipv6_addr_str);
|
||||
bvlc6_address_set(
|
||||
&addr, ntohs(sin.sin6_addr.s6_addr16[0]),
|
||||
ntohs(sin.sin6_addr.s6_addr16[1]), ntohs(sin.sin6_addr.s6_addr16[2]),
|
||||
ntohs(sin.sin6_addr.s6_addr16[3]), ntohs(sin.sin6_addr.s6_addr16[4]),
|
||||
ntohs(sin.sin6_addr.s6_addr16[5]), ntohs(sin.sin6_addr.s6_addr16[6]),
|
||||
ntohs(sin.sin6_addr.s6_addr16[7]));
|
||||
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 (too long)!", THIS_FILE, __LINE__);
|
||||
npdu_len = 0;
|
||||
}
|
||||
}
|
||||
return npdu_len;
|
||||
}
|
||||
|
||||
/** Cleanup and close out the BACnet/IP services by closing the socket.
|
||||
* @ingroup DLBIP6
|
||||
*/
|
||||
void bip6_cleanup(void)
|
||||
{
|
||||
LOG_DBG("bip6_cleanup();");
|
||||
bvlc6_cleanup();
|
||||
if (BIP6_Socket != -1) {
|
||||
zsock_close(BIP6_Socket);
|
||||
}
|
||||
BIP6_Socket = -1;
|
||||
}
|
||||
|
||||
/** Initialize the BACnet/IP services at the given interface.
|
||||
* @ingroup DLBIP6
|
||||
* -# Gets the local IP address and local broadcast address from the system,
|
||||
* and saves it into the BACnet/IPv6 data structures.
|
||||
* -# Opens a UDP socket
|
||||
* -# Configures the socket for sending and receiving
|
||||
* -# Configures the socket so it can send multicasts
|
||||
* -# Binds the socket to the local IP address at the specified port for
|
||||
* BACnet/IPv6 (by default, 0xBAC0 = 47808).
|
||||
*
|
||||
* @param ifname [in] The named interface to use for the network layer.
|
||||
* If NULL, the "eth0" interface is assigned.
|
||||
* @return True if the socket is successfully opened for BACnet/IP,
|
||||
* else False if the socket functions fail.
|
||||
*/
|
||||
bool bip6_init(char *ifname)
|
||||
{
|
||||
int status = -1;
|
||||
struct sockaddr_in6 server = { 0 };
|
||||
struct in6_addr broadcast_address;
|
||||
struct ipv6_mreq join_request;
|
||||
const int sockopt = 1;
|
||||
char addr6_str[40] = "";
|
||||
|
||||
LOG_DBG("bip6_init()");
|
||||
if (BIP6_Addr.port == 0) {
|
||||
bip6_set_port(0xBAC0U);
|
||||
}
|
||||
bip6_set_interface(ifname);
|
||||
LOG_INF("BIP6: IPv6 UDP port: 0x%04X", (unsigned)BIP6_Addr.port);
|
||||
bvlc6_snprintf_addr(addr6_str, sizeof(addr6_str), &BIP6_Addr);
|
||||
LOG_INF("BIP6: IPv6 unicast addr: %s", addr6_str);
|
||||
if (BIP6_Broadcast_Addr.address[0] == 0) {
|
||||
bvlc6_address_set(
|
||||
&BIP6_Broadcast_Addr, BIP6_MULTICAST_SITE_LOCAL, 0, 0, 0, 0, 0, 0,
|
||||
BIP6_MULTICAST_GROUP_ID);
|
||||
LOG_INF("BIP6: IPv6 MULTICAST_SITE_LOCAL");
|
||||
}
|
||||
bvlc6_snprintf_addr(addr6_str, sizeof(addr6_str), &BIP6_Broadcast_Addr);
|
||||
LOG_INF("BIP6: IPv6 multicast addr: %s", addr6_str);
|
||||
|
||||
/* assumes that the driver has already been initialized */
|
||||
BIP6_Socket = zsock_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (BIP6_Socket < 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(
|
||||
BIP6_Socket, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
LOG_ERR("BIP6: setsockopt(SO_REUSEADDR)");
|
||||
}
|
||||
/* allow us to send a broadcast */
|
||||
status = zsock_setsockopt(
|
||||
BIP6_Socket, SOL_SOCKET, SO_BROADCAST, &sockopt, sizeof(sockopt));
|
||||
if (status < 0) {
|
||||
/* ignored? For compatibility? Really? */
|
||||
LOG_ERR("BIP6: setsockopt(SO_BROADCAST)");
|
||||
}
|
||||
/* subscribe to a multicast address */
|
||||
memcpy(
|
||||
&broadcast_address.s6_addr[0], &BIP6_Broadcast_Addr.address[0],
|
||||
IP6_ADDRESS_MAX);
|
||||
memcpy(
|
||||
&join_request.ipv6mr_multiaddr, &broadcast_address,
|
||||
sizeof(struct in6_addr));
|
||||
/* Let system not choose the interface */
|
||||
join_request.ipv6mr_ifindex = BIP6_Socket_Scope_Id;
|
||||
status = setsockopt(
|
||||
BIP6_Socket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &join_request,
|
||||
sizeof(join_request));
|
||||
if (status < 0) {
|
||||
LOG_ERR("BIP6: setsockopt(IPV6_ADD_MEMBERSHIP)");
|
||||
return false;
|
||||
}
|
||||
/* bind the socket to the local port number and IP address */
|
||||
server.sin6_family = AF_INET6;
|
||||
#if 0
|
||||
uint16_t addr16[8];
|
||||
bvlc6_address_get(&BIP6_Addr, &addr16[0], &addr16[1], &addr16[2],
|
||||
&addr16[3], &addr16[4], &addr16[5], &addr16[6], &addr16[7]);
|
||||
server.sin6_addr.s6_addr16[0] = htons(addr16[0]);
|
||||
server.sin6_addr.s6_addr16[1] = htons(addr16[1]);
|
||||
server.sin6_addr.s6_addr16[2] = htons(addr16[2]);
|
||||
server.sin6_addr.s6_addr16[3] = htons(addr16[3]);
|
||||
server.sin6_addr.s6_addr16[4] = htons(addr16[4]);
|
||||
server.sin6_addr.s6_addr16[5] = htons(addr16[5]);
|
||||
server.sin6_addr.s6_addr16[6] = htons(addr16[6]);
|
||||
server.sin6_addr.s6_addr16[7] = htons(addr16[7]);
|
||||
#else
|
||||
server.sin6_addr = in6addr_any;
|
||||
#endif
|
||||
server.sin6_port = htons(BIP6_Addr.port);
|
||||
LOG_INF("BIP6: Binding to port %d", BIP6_Addr.port);
|
||||
status =
|
||||
zsock_bind(BIP6_Socket, (const struct sockaddr *)&server, sizeof(server));
|
||||
if (status < 0) {
|
||||
zsock_close(BIP6_Socket);
|
||||
BIP6_Socket = -1;
|
||||
LOG_ERR("%s:%d - zsock_bind() failure", THIS_FILE, __LINE__);
|
||||
return false;
|
||||
} else {
|
||||
LOG_INF("BIP6: Socket bound. Success!");
|
||||
}
|
||||
bvlc6_init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the BACnet/IPv6 socket is valid
|
||||
* @return True if the socket is valid, else False
|
||||
*/
|
||||
bool bip6_valid(void)
|
||||
{
|
||||
return (BIP6_Socket != -1);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2020 Steve Karg
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*
|
||||
*********************************************************************/
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#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;
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/**
|
||||
* @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 <time.h>
|
||||
#include <sys/time.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#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 */
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Legrand North America, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/* Standard includes */
|
||||
#include <stdint.h>
|
||||
|
||||
/* Zephyr includes */
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_BACNETSTACK_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bacnet);
|
||||
|
||||
/* To do: init()
|
||||
|
||||
static int init(struct device *unused)
|
||||
{
|
||||
ARG_UNUSED(unused);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||
|
||||
*/
|
||||
@@ -1,30 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
* Multimedia Timer contribution by Cameron Crothers, 2008
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*********************************************************************/
|
||||
#include <zephyr/kernel.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#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_32();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialization for timer
|
||||
*/
|
||||
void mstimer_init(void)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2004 Steve Karg
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0
|
||||
*
|
||||
*********************************************************************/
|
||||
#ifndef RS485_H
|
||||
#define RS485_H
|
||||
|
||||
#include <stdint.h>
|
||||
/* BACnet Stack defines - first */
|
||||
#include "bacnet/bacdef.h"
|
||||
/* BACnet Stack API */
|
||||
#include "bacnet/datalink/mstp.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Set_Interface(
|
||||
char *ifname);
|
||||
BACNET_STACK_EXPORT
|
||||
const char *RS485_Interface(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Initialize(
|
||||
void);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Send_Frame(
|
||||
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
|
||||
const uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
|
||||
uint16_t nbytes); /* number of bytes of data (up to 501) */
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Check_UART_Data(
|
||||
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t RS485_Get_Port_Baud_Rate(
|
||||
volatile struct mstp_port_struct_t *mstp_port);
|
||||
BACNET_STACK_EXPORT
|
||||
uint32_t RS485_Get_Baud_Rate(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
bool RS485_Set_Baud_Rate(
|
||||
uint32_t baud);
|
||||
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Cleanup(
|
||||
void);
|
||||
BACNET_STACK_EXPORT
|
||||
void RS485_Print_Ports(
|
||||
void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
||||
Reference in New Issue
Block a user