Modified the MS/TP Master Node state machine to handle Data Expecting Reply in a more appropriate manner. Updated the MS/TP monitor rx_fsm, and updated the linux and windows dlsmtp for new functionality.
This commit is contained in:
+27
-45
@@ -727,28 +727,25 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
|
||||
break;
|
||||
}
|
||||
}
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
/* For DATA_EXPECTING_REPLY, we will keep the Rx Frame for
|
||||
reference, and the flag will be cleared in the next state */
|
||||
if (mstp_port->master_state !=
|
||||
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST) {
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* In the USE_TOKEN state, the node is allowed to send one or */
|
||||
/* more data frames. These may be BACnet Data frames or */
|
||||
/* proprietary frames. */
|
||||
case MSTP_MASTER_STATE_USE_TOKEN:
|
||||
length = MSTP_Get_Send(
|
||||
mstp_port->This_Station,
|
||||
(uint8_t *)&mstp_port->OutputBuffer[0],
|
||||
mstp_port->OutputBufferSize,
|
||||
0); /* milliseconds to wait for a packet */
|
||||
/* FIXME: We could wait for up to Tusage_delay */
|
||||
length = MSTP_Get_Send(mstp_port, 0);
|
||||
if (length < 1) {
|
||||
/* NothingToSend */
|
||||
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
|
||||
transition_now = true;
|
||||
} else if (mstp_port->SilenceTimer() > Tusage_delay) {
|
||||
/* Don't send it if we are too late in getting out. */
|
||||
/* Don't worry. If we missed our timing deadline,
|
||||
another token will be sent */
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||
} else {
|
||||
uint8_t frame_type = mstp_port->OutputBuffer[2];
|
||||
uint8_t destination = mstp_port->OutputBuffer[3];
|
||||
@@ -1078,14 +1075,9 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
|
||||
/* BACnet Data Expecting Reply, a Test_Request, or */
|
||||
/* a proprietary frame that expects a reply is received. */
|
||||
case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST:
|
||||
#if 0
|
||||
/* FIXME: we always defer the reply to be legal */
|
||||
/* FIXME: if we knew the APDU type received, we could
|
||||
see if the next message was that same APDU type
|
||||
along with the matching src/dest and invoke ID */
|
||||
/* FIXME: we could use 2 queues: one for DER and one for non-DER */
|
||||
if ((mstp_port->SilenceTimer() <= Treply_delay) &&
|
||||
mstp_port->TxReady) {
|
||||
/* FIXME: we could wait for up to Treply_delay */
|
||||
length = MSTP_Get_Reply(mstp_port, 0);
|
||||
if (length > 0) {
|
||||
/* Reply */
|
||||
/* If a reply is available from the higher layers */
|
||||
/* within Treply_delay after the reception of the */
|
||||
@@ -1093,38 +1085,28 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
|
||||
/* (the mechanism used to determine this is a local matter), */
|
||||
/* then call MSTP_Create_And_Send_Frame to transmit the reply frame */
|
||||
/* and enter the IDLE state to wait for the next frame. */
|
||||
length = MSTP_Get_Send(
|
||||
mstp_port->This_Station,
|
||||
(uint8_t *)&mstp_port->OutputBuffer[0],
|
||||
mstp_port->OutputBufferSize,
|
||||
0); /* milliseconds to wait for a packet */
|
||||
if ((mstp_port->FrameType ==
|
||||
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY)
|
||||
&& (length > 0)) {
|
||||
RS485_Send_Frame(mstp_port,
|
||||
(uint8_t *) & mstp_port->TxBuffer[0],
|
||||
length);
|
||||
mstp_port->TxReady = false;
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
/* DeferredReply */
|
||||
/* If no reply will be available from the higher layers */
|
||||
/* within Treply_delay after the reception of the */
|
||||
/* final octet of the requesting frame (the mechanism */
|
||||
/* used to determine this is a local matter), */
|
||||
/* then an immediate reply is not possible. */
|
||||
/* Any reply shall wait until this node receives the token. */
|
||||
/* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */
|
||||
/* and enter the IDLE state. */
|
||||
{
|
||||
RS485_Send_Frame(mstp_port,
|
||||
(uint8_t *) & mstp_port->OutputBuffer[0],
|
||||
length);
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||
} else {
|
||||
/* DeferredReply */
|
||||
/* If no reply will be available from the higher layers */
|
||||
/* within Treply_delay after the reception of the */
|
||||
/* final octet of the requesting frame (the mechanism */
|
||||
/* used to determine this is a local matter), */
|
||||
/* then an immediate reply is not possible. */
|
||||
/* Any reply shall wait until this node receives the token. */
|
||||
/* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */
|
||||
/* and enter the IDLE state. */
|
||||
MSTP_Create_And_Send_Frame(mstp_port,
|
||||
FRAME_TYPE_REPLY_POSTPONED,
|
||||
mstp_port->SourceAddress,
|
||||
mstp_port->This_Station, NULL, 0);
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||
}
|
||||
/* clear our flag we were holding for comparison */
|
||||
mstp_port->ReceivedValidFrame = false;
|
||||
break;
|
||||
default:
|
||||
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
|
||||
|
||||
+7
-3
@@ -292,9 +292,13 @@ extern "C" {
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
/* for the MS/TP state machine to use for getting the reply for
|
||||
Data-Expecting-Reply Frame */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout); /* milliseconds to wait for a packet */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -190,6 +190,37 @@ int npdu_encode_pdu(uint8_t * npdu,
|
||||
|
||||
/* Configure the NPDU portion of the packet for an APDU */
|
||||
/* This function does not handle the network messages, just APDUs. */
|
||||
/* From BACnet 5.1:
|
||||
Applicability of ICI parameters for abstract service primitives
|
||||
Service Primitive DA SA NP DER
|
||||
----------------- --- --- --- ---
|
||||
CONF_SERV.request Yes No Yes Yes
|
||||
CONF_SERV.indication Yes Yes Yes Yes
|
||||
CONF_SERV.response Yes No Yes Yes
|
||||
CONF_SERV.confirm Yes Yes Yes No
|
||||
UNCONF_SERV.request Yes No Yes No
|
||||
UNCONF_SERV.indication Yes Yes Yes No
|
||||
REJECT.request Yes No Yes No
|
||||
REJECT.indication Yes Yes Yes No
|
||||
SEGMENT_ACK.request Yes No Yes No
|
||||
SEGMENT_ACK.indication Yes Yes Yes No
|
||||
ABORT.request Yes No Yes No
|
||||
ABORT.indication Yes Yes Yes No
|
||||
|
||||
Where:
|
||||
'destination_address' (DA): the address of the device(s) intended
|
||||
to receive the service primitive. Its format (device name,
|
||||
network address, etc.) is a local matter. This address may
|
||||
also be a multicast, local broadcast or global broadcast type.
|
||||
'source_address' (SA): the address of the device from which
|
||||
the service primitive was received. Its format (device name,
|
||||
network address, etc.) is a local matter.
|
||||
'network_priority' (NP): a four-level network priority parameter
|
||||
described in 6.2.2.
|
||||
'data_expecting_reply' (DER): a Boolean parameter that indicates
|
||||
whether (TRUE) or not (FALSE) a reply service primitive
|
||||
is expected for the service being issued.
|
||||
*/
|
||||
void npdu_encode_npdu_data(BACNET_NPDU_DATA * npdu_data,
|
||||
bool data_expecting_reply, BACNET_MESSAGE_PRIORITY priority)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "dlmstp.h"
|
||||
#include "rs485.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "bits.h"
|
||||
/* This file has been customized for use with the AT91SAM7S-EK */
|
||||
#include "board.h"
|
||||
#include "timer.h"
|
||||
@@ -196,7 +198,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address)
|
||||
|
||||
/* for the MS/TP state machine to use for putting received data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
DLMSTP_PACKET packet;
|
||||
uint16_t pdu_len = mstp_port->DataLength;
|
||||
@@ -222,34 +224,216 @@ uint16_t MSTP_Put_Receive(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
if (Transmit_Packet.ready) {
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((8 /* header len */ + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
pdu, /* <-- loading this */
|
||||
max_pdu,
|
||||
Transmit_Packet.frame_type,
|
||||
destination, src,
|
||||
&Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
Transmit_Packet.ready = false;
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* 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);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
bool dlmstp_same_bacnet_address(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!dest || !src)
|
||||
return false;
|
||||
if (dest->mac_len != src->mac_len)
|
||||
return false;
|
||||
for (i = 0; i < dest->mac_len; i++) {
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
return false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
return false;
|
||||
if (dest->len != src->len)
|
||||
return false;
|
||||
for (i = 0; i < dest->len; i++) {
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dlmstp_compare_data_expecting_reply(
|
||||
uint8_t *request_pdu,
|
||||
uint16_t request_pdu_len,
|
||||
uint8_t src_address,
|
||||
uint8_t *reply_pdu,
|
||||
uint16_t reply_pdu_len,
|
||||
BACNET_ADDRESS *dest_address)
|
||||
{
|
||||
uint16_t offset;
|
||||
/* One way to check the message is to compare NPDU
|
||||
src, dest, along with the APDU type, invoke id.
|
||||
Seems a bit overkill */
|
||||
struct DER_compare_t {
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS address;
|
||||
uint8_t pdu_type;
|
||||
uint8_t invoke_id;
|
||||
uint8_t service_choice;
|
||||
};
|
||||
struct DER_compare_t request;
|
||||
struct DER_compare_t reply;
|
||||
|
||||
/* decode the request data */
|
||||
request.address.mac[0] = src_address;
|
||||
request.address.mac_len = 1;
|
||||
offset = npdu_decode(&request_pdu[0],
|
||||
NULL, &request.address, &request.npdu_data);
|
||||
if (request.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
request.pdu_type = request_pdu[offset] & 0xF0;
|
||||
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
|
||||
return false;
|
||||
}
|
||||
request.invoke_id = request_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (request_pdu[offset] & BIT3)
|
||||
request.service_choice = request_pdu[offset+5];
|
||||
else
|
||||
request.service_choice = request_pdu[offset+3];
|
||||
/* decode the reply data */
|
||||
dlmstp_copy_bacnet_address(&reply.address, dest_address);
|
||||
offset = npdu_decode(&reply_pdu[0],
|
||||
&reply.address, NULL, &reply.npdu_data);
|
||||
if (reply.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
/* reply could be a lot of things:
|
||||
confirmed, simple ack, abort, reject, error */
|
||||
reply.pdu_type = reply_pdu[offset] & 0xF0;
|
||||
switch (reply.pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
reply.invoke_id = reply_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+5];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+3];
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+4];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/* these don't have service choice included */
|
||||
if ((reply.pdu_type == PDU_TYPE_REJECT) ||
|
||||
(reply.pdu_type == PDU_TYPE_ABORT)) {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
if (request.service_choice != reply.service_choice) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) {
|
||||
return false;
|
||||
}
|
||||
if (request.npdu_data.priority != reply.npdu_data.priority) {
|
||||
return false;
|
||||
}
|
||||
if (!dlmstp_same_bacnet_address(&request.address, &reply.address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
bool matched = false;
|
||||
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* does destination match source? */
|
||||
if (mstp_port->SourceAddress != destination) {
|
||||
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);
|
||||
if (!matched)
|
||||
return 0;
|
||||
/* 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);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ SIZE = arm-elf-size
|
||||
LDSCRIPT=at91sam7s256.ld
|
||||
|
||||
BACNET_FLAGS = -DBACDL_MSTP
|
||||
BACNET_FLAGS += -DMAX_TSM_TRANSACTIONS=0
|
||||
BACNET_FLAGS += -DPRINT_ENABLED=0
|
||||
BACNET_FLAGS += -DBIG_ENDIAN=0
|
||||
BACNET_FLAGS += -DMAX_APDU=480
|
||||
#BACNET_FLAGS += -DDLMSTP_TEST
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ static void Timer_Silence_Reset(void)
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
void dlmstp_millisecond_timer(void)
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
@@ -290,15 +290,11 @@ uint16_t MSTP_Put_Receive(
|
||||
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
int dlmstp_get_transmit_packet(
|
||||
DLMSTP_PACKET *packet,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET packet;
|
||||
int received_bytes = 0; /* return value */
|
||||
struct timeval select_timeout;
|
||||
fd_set read_fds;
|
||||
int max = 0;
|
||||
@@ -323,8 +319,8 @@ uint16_t MSTP_Get_Send(
|
||||
if (select(max + 1, &read_fds, NULL, NULL, &select_timeout) > 0) {
|
||||
received_bytes = read(
|
||||
Transmit_Client_SockFD,
|
||||
&packet,
|
||||
sizeof(packet));
|
||||
packet,
|
||||
sizeof(DLMSTP_PACKET));
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@@ -344,30 +340,227 @@ uint16_t MSTP_Get_Send(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (received_bytes == 0)
|
||||
return 0;
|
||||
return (received_bytes);
|
||||
}
|
||||
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
int received_bytes = 0;
|
||||
DLMSTP_PACKET packet;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
received_bytes = dlmstp_get_transmit_packet(&packet, timeout);
|
||||
if (received_bytes <= 0)
|
||||
return 0;
|
||||
/* load destination MAC address */
|
||||
if (packet.address.mac_len == 1) {
|
||||
destination = packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((8 /* header len */ + packet.pdu_len) > MAX_MPDU) {
|
||||
if ((MAX_HEADER + packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* convert the PDU into the MSTP Frame */
|
||||
pdu_len = MSTP_Create_Frame(
|
||||
pdu, /* <-- loading this */
|
||||
max_pdu,
|
||||
&mstp_port->OutputBuffer[0], /* <-- loading this */
|
||||
mstp_port->OutputBufferSize,
|
||||
packet.frame_type,
|
||||
destination, src,
|
||||
destination,
|
||||
mstp_port->This_Station,
|
||||
&packet.pdu[0],
|
||||
packet.pdu_len);
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
bool dlmstp_same_bacnet_address(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!dest || !src)
|
||||
return false;
|
||||
if (dest->mac_len != src->mac_len)
|
||||
return false;
|
||||
for (i = 0; i < dest->mac_len; i++) {
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
return false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
return false;
|
||||
if (dest->len != src->len)
|
||||
return false;
|
||||
for (i = 0; i < dest->len; i++) {
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dlmstp_compare_data_expecting_reply(
|
||||
uint8_t *request_pdu,
|
||||
uint16_t request_pdu_len,
|
||||
uint8_t src_address,
|
||||
uint8_t *reply_pdu,
|
||||
uint16_t reply_pdu_len,
|
||||
BACNET_ADDRESS *dest_address)
|
||||
{
|
||||
uint16_t offset;
|
||||
/* One way to check the message is to compare NPDU
|
||||
src, dest, along with the APDU type, invoke id.
|
||||
Seems a bit overkill */
|
||||
struct DER_compare_t {
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS address;
|
||||
uint8_t pdu_type;
|
||||
uint8_t invoke_id;
|
||||
uint8_t service_choice;
|
||||
};
|
||||
struct DER_compare_t request;
|
||||
struct DER_compare_t reply;
|
||||
|
||||
/* decode the request data */
|
||||
request.address.mac[0] = src_address;
|
||||
request.address.mac_len = 1;
|
||||
offset = npdu_decode(&request_pdu[0],
|
||||
NULL, &request.address, &request.npdu_data);
|
||||
if (request.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
request.pdu_type = request_pdu[offset] & 0xF0;
|
||||
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
|
||||
return false;
|
||||
}
|
||||
request.invoke_id = request_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (request_pdu[offset] & BIT3)
|
||||
request.service_choice = request_pdu[offset+5];
|
||||
else
|
||||
request.service_choice = request_pdu[offset+3];
|
||||
/* decode the reply data */
|
||||
dlmstp_copy_bacnet_address(&reply.address, dest_address);
|
||||
offset = npdu_decode(&reply_pdu[0],
|
||||
&reply.address, NULL, &reply.npdu_data);
|
||||
if (reply.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
/* reply could be a lot of things:
|
||||
confirmed, simple ack, abort, reject, error */
|
||||
reply.pdu_type = reply_pdu[offset] & 0xF0;
|
||||
switch (reply.pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
reply.invoke_id = reply_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+5];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+3];
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+4];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/* these don't have service choice included */
|
||||
if ((reply.pdu_type == PDU_TYPE_REJECT) ||
|
||||
(reply.pdu_type == PDU_TYPE_ABORT)) {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
if (request.service_choice != reply.service_choice) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) {
|
||||
return false;
|
||||
}
|
||||
if (request.npdu_data.priority != reply.npdu_data.priority) {
|
||||
return false;
|
||||
}
|
||||
if (!dlmstp_same_bacnet_address(&request.address, &reply.address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
int received_bytes = 0;
|
||||
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(&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];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_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);
|
||||
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);
|
||||
/* not used here, but setting it anyway */
|
||||
Transmit_Packet.ready = false;
|
||||
} else {
|
||||
/* put it back into the queue */
|
||||
(void)write(Transmit_Server_SockFD, &packet, sizeof(packet));
|
||||
}
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
void dlmstp_set_mac_address(uint8_t mac_address)
|
||||
{
|
||||
/* Master Nodes can only have address 0-127 */
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <sys/time.h>
|
||||
@@ -50,13 +51,26 @@
|
||||
#include "mstp.h"
|
||||
#include "mstptext.h"
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
/* local port data - shared with RS-485 */
|
||||
static volatile struct mstp_port_struct_t MSTP_Port;
|
||||
/* buffers needed by mstp port struct */
|
||||
static uint8_t RxBuffer[MAX_MPDU];
|
||||
static uint8_t TxBuffer[MAX_MPDU];
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
void *milliseconds_task(void *pArg)
|
||||
{
|
||||
@@ -67,17 +81,12 @@ void *milliseconds_task(void *pArg)
|
||||
|
||||
for (;;) {
|
||||
nanosleep(&timeOut, &remains);
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
dlmstp_millisecond_timer();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
volatile uint16_t *dlmstp_millisecond_timer_address(void)
|
||||
{
|
||||
return (&(MSTP_Port.SilenceTimer));
|
||||
}
|
||||
|
||||
/* functions used by the MS/TP state machine to put or get data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
@@ -90,14 +99,19 @@ uint16_t MSTP_Put_Receive(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)src;
|
||||
(void)pdu;
|
||||
(void)max_pdu;
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
@@ -192,6 +206,8 @@ int main(int argc, char *argv[])
|
||||
MSTP_Port.This_Station = my_mac;
|
||||
MSTP_Port.Nmax_info_frames = 1;
|
||||
MSTP_Port.Nmax_master = 127;
|
||||
MSTP_Port.SilenceTimer = Timer_Silence;
|
||||
MSTP_Port.SilenceTimerReset = Timer_Silence_Reset;
|
||||
MSTP_Init(mstp_port);
|
||||
mstp_port->Lurking = true;
|
||||
/* start our MilliSec task */
|
||||
|
||||
@@ -89,6 +89,23 @@ void dlmstp_cleanup(void)
|
||||
}
|
||||
}
|
||||
|
||||
void dlmstp_copy_bacnet_address(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (dest && src) {
|
||||
dest->mac_len = src->mac_len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->mac[i] = src->mac[i];
|
||||
}
|
||||
dest->net = src->net;
|
||||
dest->len = src->len;
|
||||
for (i = 0; i < MAX_MAC_LEN; i++) {
|
||||
dest->adr[i] = src->adr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* returns number of bytes sent on success, zero on failure */
|
||||
int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
BACNET_NPDU_DATA * npdu_data, /* network information */
|
||||
@@ -97,32 +114,23 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
|
||||
{ /* number of bytes of data */
|
||||
int bytes_sent = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
unsigned i = 0;
|
||||
|
||||
if (!Transmit_Packet.ready) {
|
||||
if (npdu_data->data_expecting_reply)
|
||||
Transmit_Packet.frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
else
|
||||
if (npdu_data->data_expecting_reply) {
|
||||
Transmit_Packet.frame_type =
|
||||
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
|
||||
} else {
|
||||
Transmit_Packet.frame_type =
|
||||
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
|
||||
|
||||
/* load destination MAC address */
|
||||
if (dest && dest->mac_len == 1) {
|
||||
destination = dest->mac[0];
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
if ((8 /* header len */ + pdu_len) > MAX_MPDU) {
|
||||
return -4;
|
||||
Transmit_Packet.pdu_len = pdu_len;
|
||||
for (i = 0; i < pdu_len; i++) {
|
||||
Transmit_Packet.pdu[i] = pdu[i];
|
||||
}
|
||||
Transmit_Packet.pdu_len = MSTP_Create_Frame(
|
||||
(uint8_t *) & Transmit_Packet.pdu[0],
|
||||
sizeof(Transmit_Packet.pdu),
|
||||
Transmit_Packet.frame_type,
|
||||
destination,
|
||||
MSTP_Port.This_Station,
|
||||
pdu, pdu_len);
|
||||
dlmstp_copy_bacnet_address(&Transmit_Packet.address, dest);
|
||||
bytes_sent = pdu_len + MAX_HEADER;
|
||||
Transmit_Packet.ready = true;
|
||||
MSTP_Packets++;
|
||||
}
|
||||
|
||||
return bytes_sent;
|
||||
@@ -276,24 +284,213 @@ uint16_t MSTP_Put_Receive(
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
uint8_t destination = 0; /* destination address */
|
||||
|
||||
(void)src;
|
||||
(void)timeout;
|
||||
if (Transmit_Packet.ready) {
|
||||
if (Transmit_Packet.pdu_len <= max_pdu) {
|
||||
memmove(&pdu[0],
|
||||
(void *) & Transmit_Packet.pdu[0],
|
||||
Transmit_Packet.pdu_len);
|
||||
pdu_len = Transmit_Packet.pdu_len;
|
||||
}
|
||||
Transmit_Packet.ready = false;
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) {
|
||||
return 0;
|
||||
}
|
||||
/* 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);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
bool dlmstp_same_bacnet_address(BACNET_ADDRESS * dest, BACNET_ADDRESS * src)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!dest || !src)
|
||||
return false;
|
||||
if (dest->mac_len != src->mac_len)
|
||||
return false;
|
||||
for (i = 0; i < dest->mac_len; i++) {
|
||||
if (dest->mac[i] != src->mac[i])
|
||||
return false;
|
||||
}
|
||||
if (dest->net != src->net)
|
||||
return false;
|
||||
if (dest->len != src->len)
|
||||
return false;
|
||||
for (i = 0; i < dest->len; i++) {
|
||||
if (dest->adr[i] != src->adr[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dlmstp_compare_data_expecting_reply(
|
||||
uint8_t *request_pdu,
|
||||
uint16_t request_pdu_len,
|
||||
uint8_t src_address,
|
||||
uint8_t *reply_pdu,
|
||||
uint16_t reply_pdu_len,
|
||||
BACNET_ADDRESS *dest_address)
|
||||
{
|
||||
uint16_t offset;
|
||||
/* One way to check the message is to compare NPDU
|
||||
src, dest, along with the APDU type, invoke id.
|
||||
Seems a bit overkill */
|
||||
struct DER_compare_t {
|
||||
BACNET_NPDU_DATA npdu_data;
|
||||
BACNET_ADDRESS address;
|
||||
uint8_t pdu_type;
|
||||
uint8_t invoke_id;
|
||||
uint8_t service_choice;
|
||||
};
|
||||
struct DER_compare_t request;
|
||||
struct DER_compare_t reply;
|
||||
|
||||
/* decode the request data */
|
||||
request.address.mac[0] = src_address;
|
||||
request.address.mac_len = 1;
|
||||
offset = npdu_decode(&request_pdu[0],
|
||||
NULL, &request.address, &request.npdu_data);
|
||||
if (request.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
request.pdu_type = request_pdu[offset] & 0xF0;
|
||||
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
|
||||
return false;
|
||||
}
|
||||
request.invoke_id = request_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (request_pdu[offset] & BIT3)
|
||||
request.service_choice = request_pdu[offset+5];
|
||||
else
|
||||
request.service_choice = request_pdu[offset+3];
|
||||
/* decode the reply data */
|
||||
dlmstp_copy_bacnet_address(&reply.address, dest_address);
|
||||
offset = npdu_decode(&reply_pdu[0],
|
||||
&reply.address, NULL, &reply.npdu_data);
|
||||
if (reply.npdu_data.network_layer_message) {
|
||||
return false;
|
||||
}
|
||||
/* reply could be a lot of things:
|
||||
confirmed, simple ack, abort, reject, error */
|
||||
reply.pdu_type = reply_pdu[offset] & 0xF0;
|
||||
switch (reply.pdu_type) {
|
||||
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
|
||||
reply.invoke_id = reply_pdu[offset+2];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+5];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+3];
|
||||
break;
|
||||
case PDU_TYPE_SIMPLE_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_COMPLEX_ACK:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
/* segmented message? */
|
||||
if (reply_pdu[offset] & BIT3)
|
||||
reply.service_choice = reply_pdu[offset+4];
|
||||
else
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_ERROR:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
reply.service_choice = reply_pdu[offset+2];
|
||||
break;
|
||||
case PDU_TYPE_REJECT:
|
||||
case PDU_TYPE_ABORT:
|
||||
reply.invoke_id = reply_pdu[offset+1];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/* these don't have service choice included */
|
||||
if ((reply.pdu_type == PDU_TYPE_REJECT) ||
|
||||
(reply.pdu_type == PDU_TYPE_ABORT)) {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (request.invoke_id != reply.invoke_id) {
|
||||
return false;
|
||||
}
|
||||
if (request.service_choice != reply.service_choice) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (request.npdu_data.protocol_version != reply.npdu_data.protocol_version) {
|
||||
return false;
|
||||
}
|
||||
if (request.npdu_data.priority != reply.npdu_data.priority) {
|
||||
return false;
|
||||
}
|
||||
if (!dlmstp_same_bacnet_address(&request.address, &reply.address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
uint16_t pdu_len = 0; /* return value */
|
||||
uint8_t destination = 0; /* destination address */
|
||||
bool matched = false;
|
||||
|
||||
(void)timeout;
|
||||
if (!Transmit_Packet.ready) {
|
||||
return 0;
|
||||
}
|
||||
/* load destination MAC address */
|
||||
if (Transmit_Packet.address.mac_len == 1) {
|
||||
destination = Transmit_Packet.address.mac[0];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if ((MAX_HEADER + Transmit_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);
|
||||
if (!matched)
|
||||
return 0;
|
||||
/* 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);
|
||||
Transmit_Packet.ready = false;
|
||||
|
||||
return pdu_len;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Windows includes */
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -49,46 +50,63 @@
|
||||
#include "mstptext.h"
|
||||
#include "crc.h"
|
||||
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
|
||||
/* local port data - shared with RS-485 */
|
||||
volatile struct mstp_port_struct_t MSTP_Port;
|
||||
static uint8_t RxBuffer[MAX_MPDU];
|
||||
static uint8_t TxBuffer[MAX_MPDU];
|
||||
static uint16_t SilenceTime;
|
||||
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
|
||||
static uint16_t Timer_Silence(void)
|
||||
{
|
||||
return SilenceTime;
|
||||
}
|
||||
static void Timer_Silence_Reset(void)
|
||||
{
|
||||
SilenceTime = 0;
|
||||
}
|
||||
|
||||
static void dlmstp_millisecond_timer(void)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(SilenceTime);
|
||||
}
|
||||
|
||||
void *milliseconds_task(void *pArg)
|
||||
{
|
||||
(void)pArg;
|
||||
for (;;) {
|
||||
Sleep(1);
|
||||
dlmstp_millisecond_timer();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
//return NULL;
|
||||
}
|
||||
|
||||
void dlmstp_millisecond_timer(void)
|
||||
/* functions used by the MS/TP state machine to put or get data */
|
||||
uint16_t MSTP_Put_Receive(
|
||||
volatile struct mstp_port_struct_t *mstp_port)
|
||||
{
|
||||
INCREMENT_AND_LIMIT_UINT16(MSTP_Port.SilenceTimer);
|
||||
}
|
||||
|
||||
uint16_t dlmstp_put_receive(
|
||||
uint8_t src, /* source MS/TP address */
|
||||
uint8_t * pdu, /* PDU data */
|
||||
uint16_t pdu_len)
|
||||
{
|
||||
(void)src;
|
||||
(void)pdu;
|
||||
(void)pdu_len;
|
||||
|
||||
(void)mstp_port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dlmstp_get_send(
|
||||
uint8_t src, /* source MS/TP address for creating packet */
|
||||
uint8_t * pdu, /* data to send */
|
||||
uint16_t max_pdu, /* amount of space available */
|
||||
/* for the MS/TP state machine to use for getting data to send */
|
||||
/* Return: amount of PDU data */
|
||||
uint16_t MSTP_Get_Send(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t MSTP_Get_Reply(
|
||||
volatile struct mstp_port_struct_t *mstp_port,
|
||||
unsigned timeout) /* milliseconds to wait for a packet */
|
||||
{
|
||||
(void)mstp_port;
|
||||
(void)timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -163,6 +181,8 @@ int main(int argc, char *argv[])
|
||||
MSTP_Port.This_Station = my_mac;
|
||||
MSTP_Port.Nmax_info_frames = 1;
|
||||
MSTP_Port.Nmax_master = 127;
|
||||
MSTP_Port.SilenceTimer = Timer_Silence;
|
||||
MSTP_Port.SilenceTimerReset = Timer_Silence_Reset;
|
||||
MSTP_Init(&MSTP_Port);
|
||||
mstp_port->Lurking = true;
|
||||
/* start our MilliSec task */
|
||||
@@ -185,6 +205,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
//return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#if !defined(__cplusplus)
|
||||
|
||||
/*typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool;*/
|
||||
typedef enum { _Bool_must_promote_to_int = -1, false = 0, true = 1 } _Bool;
|
||||
#define bool _Bool
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
Reference in New Issue
Block a user