Testing MS/TP on Linux.
This commit is contained in:
@@ -8,8 +8,8 @@ TARGET = bacserv
|
||||
# Configure the BACnet Datalink Layer
|
||||
#BACDL_DEFINE = -DBACDL_ETHERNET
|
||||
#BACDL_DEFINE = -DBACDL_ARCNET
|
||||
#BACDL_DEFINE = -DBACDL_MSTP
|
||||
BACDL_DEFINE = -DBACDL_BIP -DBIP_DEBUG
|
||||
BACDL_DEFINE = -DBACDL_MSTP
|
||||
#BACDL_DEFINE = -DBACDL_BIP -DBIP_DEBUG
|
||||
BACNET_DEFINES = -DPRINT_ENABLED=1 -DBACAPP_ALL -DBACFILE
|
||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||
|
||||
@@ -27,7 +27,7 @@ INCLUDES = -I$(BACNET_INCLUDE) -I$(BACNET_PORT_DIR)
|
||||
ifeq (${BACNET_PORT},linux)
|
||||
PFLAGS = -pthread
|
||||
TARGET_BIN = ${TARGET}
|
||||
LIBRARIES=-lc,-lgcc,-lm,-L=$(BACNET_LIB_DIR),-l$(BACNET_LIB_NAME)
|
||||
LIBRARIES=-lc,-lgcc,-lrt,-lm,-L=$(BACNET_LIB_DIR),-l$(BACNET_LIB_NAME)
|
||||
endif
|
||||
ifeq (${BACNET_PORT},win32)
|
||||
TARGET_BIN = ${TARGET}.exe
|
||||
|
||||
@@ -12,8 +12,9 @@ LIBRARY = lib$(TARGET).a
|
||||
BACNET_DEFINES=-DPRINT_ENABLED=1 -DBACAPP_ALL -DBACFILE
|
||||
#BACDL_DEFINE=-DBACDL_ETHERNET=1
|
||||
#BACDL_DEFINE=-DBACDL_ARCNET=1
|
||||
#BACDL_DEFINE=-DBACDL_MSTP=1
|
||||
BACDL_DEFINE=-DBACDL_BIP=1
|
||||
BACDL_DEFINE=-DBACDL_MSTP=1
|
||||
#BACDL_DEFINE=-DBACDL_BIP=1
|
||||
|
||||
DEFINES = $(BACNET_DEFINES) $(BACDL_DEFINE)
|
||||
# directories
|
||||
BACNET_PORT = linux
|
||||
@@ -115,6 +116,7 @@ PORT_MSTP_SRC = \
|
||||
$(BACNET_PORT_DIR)/dlmstp.c \
|
||||
$(BACNET_PORT_DIR)/rs485.c \
|
||||
$(BACNET_CORE)/mstp.c \
|
||||
$(BACNET_CORE)/mstptext.c \
|
||||
$(BACNET_CORE)/crc.c \
|
||||
|
||||
PORT_ETHERNET_SRC = \
|
||||
@@ -139,13 +141,13 @@ PORT_ALL_SRC = \
|
||||
ifeq (${BACDL_DEFINE},-DBACDL_BIP=1)
|
||||
PORT_SRC = ${PORT_BIP_SRC}
|
||||
endif
|
||||
ifdef BACDL_MSTP
|
||||
ifeq (${BACDL_DEFINE},-DBACDL_MSTP=1)
|
||||
PORT_SRC = ${PORT_MSTP_SRC}
|
||||
endif
|
||||
ifdef BACDL_ARCNET
|
||||
ifeq (${BACDL_DEFINE},-DBACDL_ARCNET=1)
|
||||
PORT_SRC = ${PORT_ARCNET_SRC}
|
||||
endif
|
||||
ifdef BACDL_ETHERNET
|
||||
ifeq (${BACDL_DEFINE},-DBACDL_ETHERNET=1)
|
||||
PORT_SRC = ${PORT_ETHERNET_SRC}
|
||||
endif
|
||||
ifdef BACDL_ALL
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <mqueue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -50,11 +51,9 @@
|
||||
|
||||
/* Number of MS/TP Packets Rx/Tx */
|
||||
uint16_t MSTP_Packets = 0;
|
||||
/* Sockets are used for NPDU queues */
|
||||
static int Receive_Client_SockFD = -1;
|
||||
static int Transmit_Client_SockFD = -1;
|
||||
static int Receive_Server_SockFD = -1;
|
||||
static int Transmit_Server_SockFD = -1;
|
||||
/* Posix queues are used for NPDU queues */
|
||||
static mqd_t NPDU_Receive_Queue = -1;
|
||||
static mqd_t NPDU_Transmit_Queue = -1;
|
||||
/* local MS/TP port data - shared with RS-485 */
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
/* buffers needed by mstp port struct */
|
||||
@@ -114,7 +113,7 @@ int dlmstp_send_pdu(
|
||||
{ /* number of bytes of data */
|
||||
DLMSTP_PACKET packet;
|
||||
int bytes_sent = 0;
|
||||
ssize_t rc = 0;
|
||||
mqd_t rc = 0;
|
||||
|
||||
if (pdu_len) {
|
||||
if (npdu_data->data_expecting_reply) {
|
||||
@@ -125,7 +124,7 @@ int dlmstp_send_pdu(
|
||||
packet.pdu_len = pdu_len;
|
||||
memmove(&packet.pdu[0], &pdu[0], pdu_len);
|
||||
memmove(&packet.address, dest, sizeof(packet.address));
|
||||
rc = write(Transmit_Server_SockFD, &packet, sizeof(packet));
|
||||
rc = mq_send(NPDU_Transmit_Queue, (const char *)&packet, sizeof(packet), 0);
|
||||
if (rc > 0)
|
||||
bytes_sent = rc;
|
||||
}
|
||||
@@ -142,45 +141,47 @@ uint16_t dlmstp_receive(
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
uint16_t pdu_len = 0;
|
||||
int received_bytes = 0;
|
||||
mqd_t received_bytes = 0;
|
||||
DLMSTP_PACKET packet;
|
||||
struct timeval select_timeout;
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timespec queue_timeout = {0};
|
||||
time_t epoch_time = 0;
|
||||
unsigned msg_prio = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (Receive_Client_SockFD < 0)
|
||||
if (NPDU_Receive_Queue == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* configure queue timeout */
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
queue_timeout.tv_sec = timeout / 1000;
|
||||
queue_timeout.tv_nsec =
|
||||
1000000L * (timeout - queue_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
queue_timeout.tv_sec = 0;
|
||||
queue_timeout.tv_nsec = 1000000L * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(Receive_Client_SockFD, &read_fds);
|
||||
max = Receive_Client_SockFD;
|
||||
/* get current time */
|
||||
epoch_time = time(NULL);
|
||||
queue_timeout.tv_sec += epoch_time;
|
||||
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = read(Receive_Client_SockFD, &packet, sizeof(packet));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
received_bytes = mq_timedreceive(
|
||||
NPDU_Receive_Queue,
|
||||
(char *)&packet,
|
||||
sizeof(packet),
|
||||
&msg_prio,
|
||||
&queue_timeout);
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
if (received_bytes == -1) {
|
||||
/* EAGAIN Non-blocking I/O has been selected */
|
||||
/* using O_NONBLOCK and no data */
|
||||
/* was immediately available for reading. */
|
||||
if (errno != EAGAIN) {
|
||||
#if PRINT_ENABLED
|
||||
fprintf(stderr, "mstp: Read error in Receive_Client packet: %s\n",
|
||||
fprintf(stderr, "mstp: NPDU Receive: %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -285,7 +286,7 @@ uint16_t MSTP_Put_Receive(
|
||||
packet.pdu_len = pdu_len;
|
||||
/* ready is not used in this scheme */
|
||||
packet.ready = true;
|
||||
write(Receive_Server_SockFD, &packet, sizeof(packet));
|
||||
mq_send(NPDU_Receive_Queue, (const char *)&packet, sizeof(packet), 0);
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
@@ -298,35 +299,35 @@ int dlmstp_get_transmit_packet(
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
int received_bytes = 0; /* return value */
|
||||
struct timeval select_timeout;
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
struct timespec queue_timeout = {0};
|
||||
time_t epoch_time = 0;
|
||||
unsigned msg_prio = 0;
|
||||
|
||||
/* Make sure the socket is open */
|
||||
if (Transmit_Client_SockFD < 0)
|
||||
if (NPDU_Transmit_Queue == -1)
|
||||
return 0;
|
||||
|
||||
if (timeout >= 1000) {
|
||||
select_timeout.tv_sec = timeout / 1000;
|
||||
select_timeout.tv_usec =
|
||||
1000 * (timeout - select_timeout.tv_sec * 1000);
|
||||
queue_timeout.tv_sec = timeout / 1000;
|
||||
queue_timeout.tv_nsec =
|
||||
1000000L * (timeout - queue_timeout.tv_sec * 1000);
|
||||
} else {
|
||||
select_timeout.tv_sec = 0;
|
||||
select_timeout.tv_usec = 1000 * timeout;
|
||||
queue_timeout.tv_sec = 0;
|
||||
queue_timeout.tv_nsec = 1000000L * timeout;
|
||||
}
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(Transmit_Client_SockFD, &read_fds);
|
||||
max = Transmit_Client_SockFD;
|
||||
/* get current time */
|
||||
epoch_time = time(NULL);
|
||||
queue_timeout.tv_sec += epoch_time;
|
||||
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes =
|
||||
read(Transmit_Client_SockFD, packet, sizeof(DLMSTP_PACKET));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
received_bytes = mq_timedreceive(
|
||||
NPDU_Transmit_Queue,
|
||||
(char *)&packet,
|
||||
sizeof(packet),
|
||||
&msg_prio,
|
||||
&queue_timeout);
|
||||
|
||||
/* See if there is a problem */
|
||||
if (received_bytes < 0) {
|
||||
if (received_bytes == -1) {
|
||||
/* EAGAIN Non-blocking I/O has been selected */
|
||||
/* using O_NONBLOCK and no data */
|
||||
/* was immediately available for reading. */
|
||||
@@ -488,41 +489,40 @@ uint16_t MSTP_Get_Reply(
|
||||
unsigned timeout)
|
||||
{ /* milliseconds to wait for a packet */
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET Transmit_Packet;
|
||||
DLMSTP_PACKET packet;
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
bool matched = false;
|
||||
|
||||
received_bytes = dlmstp_get_transmit_packet(&Transmit_Packet, timeout);
|
||||
received_bytes = dlmstp_get_transmit_packet(&packet, timeout);
|
||||
if (received_bytes <= 0)
|
||||
return 0;
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
if (packet.address.mac_len == 1) {
|
||||
destination = packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
if ((MAX_HEADER + packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* is this the reply to the DER? */
|
||||
matched =
|
||||
dlmstp_compare_data_expecting_reply(&mstp_port->InputBuffer[0],
|
||||
mstp_port->DataLength, mstp_port->SourceAddress,
|
||||
&Transmit_Packet.pdu[0], Transmit_Packet.pdu_len,
|
||||
&Transmit_Packet.address);
|
||||
&packet.pdu[0], packet.pdu_len,
|
||||
&packet.address);
|
||||
if (matched) {
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize, Transmit_Packet.frame_type,
|
||||
destination, mstp_port->This_Station, &Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
pdu_len = MSTP_Create_Frame(&mstp_port->OutputBuffer[0],
|
||||
mstp_port->OutputBufferSize, packet.frame_type,
|
||||
destination, mstp_port->This_Station, &packet.pdu[0],
|
||||
packet.pdu_len);
|
||||
/* not used here, but setting it anyway */
|
||||
Transmit_Packet.ready = false;
|
||||
packet.ready = false;
|
||||
} else {
|
||||
/* put it back into the queue */
|
||||
(void) write(Transmit_Server_SockFD, &Transmit_Packet,
|
||||
sizeof(Transmit_Packet));
|
||||
(void)mq_send(NPDU_Transmit_Queue, (char *)&packet, sizeof(packet), 1);
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
@@ -655,94 +655,11 @@ uint32_t dlmstp_baud_rate(
|
||||
return RS485_Get_Baud_Rate();
|
||||
}
|
||||
|
||||
static int create_named_server_socket(
|
||||
const char *filename)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
int sock;
|
||||
size_t size;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror("socket");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock));
|
||||
/* Bind a name to the socket. */
|
||||
bzero((char *) &name, sizeof(name));
|
||||
name.sun_family = AF_LOCAL;
|
||||
strncpy(name.sun_path, filename, sizeof(name.sun_path));
|
||||
/* The size of the address is
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof(struct sockaddr_un,
|
||||
sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
if (bind(sock, (struct sockaddr *) &name, size) < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror("bind");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
/* used by the client */
|
||||
static int connect_named_server_socket(
|
||||
const char *filename)
|
||||
{
|
||||
struct sockaddr_un name;
|
||||
int sock;
|
||||
size_t size;
|
||||
|
||||
/* Create the socket. */
|
||||
sock = socket(PF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror("socket");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
bzero((char *) &name, sizeof(name));
|
||||
name.sun_family = AF_LOCAL;
|
||||
strncpy(name.sun_path, filename, sizeof(name.sun_path));
|
||||
/* The size of the address is
|
||||
the offset of the start of the filename,
|
||||
plus its length,
|
||||
plus one for the terminating null byte.
|
||||
Alternatively you can just do:
|
||||
size = SUN_LEN (&name);
|
||||
*/
|
||||
size = (offsetof(struct sockaddr_un,
|
||||
sun_path)
|
||||
+ strlen (name.sun_path) + 1);
|
||||
|
||||
if (connect(sock, (struct sockaddr *) &name, size) < 0) {
|
||||
#if PRINT_ENABLED
|
||||
perror("client: can't connect to socket");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
static char *dlmstp_transmit_socket_name = "/tmp/BACnet_MSTP_Tx";
|
||||
static char *dlmstp_receive_socket_name = "/tmp/BACnet_MSTP_Rx";
|
||||
|
||||
void dlmstp_cleanup(
|
||||
void)
|
||||
{
|
||||
remove(dlmstp_transmit_socket_name);
|
||||
remove(dlmstp_receive_socket_name);
|
||||
mq_close(NPDU_Transmit_Queue);
|
||||
mq_close(NPDU_Receive_Queue);
|
||||
RS485_Cleanup();
|
||||
/* nothing to do for static buffers */
|
||||
}
|
||||
@@ -752,19 +669,19 @@ bool dlmstp_init(
|
||||
{
|
||||
int rc = 0;
|
||||
pthread_t hThread;
|
||||
char mqname[32];
|
||||
struct mq_attr mqattr;
|
||||
|
||||
remove(dlmstp_transmit_socket_name);
|
||||
remove(dlmstp_receive_socket_name);
|
||||
/* create a socket for queuing the NDPU data between MS/TP */
|
||||
Transmit_Server_SockFD =
|
||||
create_named_server_socket(dlmstp_transmit_socket_name);
|
||||
Transmit_Client_SockFD =
|
||||
connect_named_server_socket(dlmstp_transmit_socket_name);
|
||||
/* creates sockets for Receiving data */
|
||||
Receive_Server_SockFD =
|
||||
create_named_server_socket(dlmstp_receive_socket_name);
|
||||
Receive_Client_SockFD =
|
||||
connect_named_server_socket(dlmstp_receive_socket_name);
|
||||
mqattr.mq_flags = 0;
|
||||
mqattr.mq_maxmsg = 100;
|
||||
mqattr.mq_msgsize = sizeof(struct dlmstp_packet);
|
||||
/* create a queue for the NDPU data between MS/TP threads */
|
||||
snprintf(mqname, sizeof(mqname), "/BACnet-MSTP-Rx-%d", getpid());
|
||||
NPDU_Transmit_Queue = mq_open(mqname,
|
||||
O_RDWR | O_CREAT | O_EXCL, 0600, &mqattr);
|
||||
snprintf(mqname, sizeof(mqname), "/BACnet-MSTP-Rx-%d", getpid());
|
||||
NPDU_Receive_Queue = mq_open(mqname,
|
||||
O_RDWR | O_CREAT | O_EXCL, 0600, &mqattr);
|
||||
|
||||
/* initialize hardware */
|
||||
if (ifname) {
|
||||
|
||||
Reference in New Issue
Block a user