Changed the MSTP_MASTER_STATE_ANSWER_DATA_REQUEST state to always send a REPLY_POSTPONED by

commenting out the section that checks for new packets to send.  It was not the intent of the BACnet standard, but it makes the Master Node FSM compliant.  It's either that or re-parse the message for a matching apdu and invoke id, and then defer if the next message does not match.  The problem happens when an unconfirmed request (i.e. WhoIs) is followed immediated by a confirmed request (i.e. ReadProperty) before the device can respond to the unconfirmed request (i.e. the I-Am is queued in the Transmit buffer).
This commit is contained in:
skarg
2007-07-14 00:09:16 +00:00
parent 3d54a5cd50
commit e53f38dd40
8 changed files with 271 additions and 441 deletions
+49
View File
@@ -45,6 +45,55 @@
#define MAX_HEADER (2+1+1+1+2+1+2+1)
#define MAX_MPDU (MAX_HEADER+MAX_PDU)
/* The value 255 is used to denote broadcast when used as a */
/* destination address but is not allowed as a value for a station. */
/* Station addresses for master nodes can be 0-127. */
/* Station addresses for slave nodes can be 127-254. */
#define MSTP_BROADCAST_ADDRESS 255
/* MS/TP Frame Type */
/* Frame Types 8 through 127 are reserved by ASHRAE. */
#define FRAME_TYPE_TOKEN 0
#define FRAME_TYPE_POLL_FOR_MASTER 1
#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2
#define FRAME_TYPE_TEST_REQUEST 3
#define FRAME_TYPE_TEST_RESPONSE 4
#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5
#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define FRAME_TYPE_REPLY_POSTPONED 7
/* Frame Types 128 through 255: Proprietary Frames */
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
/* The first two octets of the Data field shall specify the unique vendor */
/* identification code, most significant octet first, for the type of */
/* vendor-proprietary frame to be conveyed. The length of the data portion */
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
#define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255
/* The initial CRC16 checksum value */
#define CRC16_INITIAL_VALUE (0xFFFF)
/* receive FSM states */
typedef enum {
MSTP_RECEIVE_STATE_IDLE = 0,
MSTP_RECEIVE_STATE_PREAMBLE = 1,
MSTP_RECEIVE_STATE_HEADER = 2,
MSTP_RECEIVE_STATE_HEADER_CRC = 3,
MSTP_RECEIVE_STATE_DATA = 4
} MSTP_RECEIVE_STATE;
/* master node FSM states */
typedef enum {
MSTP_MASTER_STATE_INITIALIZE = 0,
MSTP_MASTER_STATE_IDLE = 1,
MSTP_MASTER_STATE_USE_TOKEN = 2,
MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3,
MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4,
MSTP_MASTER_STATE_PASS_TOKEN = 5,
MSTP_MASTER_STATE_NO_TOKEN = 6,
MSTP_MASTER_STATE_POLL_FOR_MASTER = 7,
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
} MSTP_MASTER_STATE;
typedef struct dlmstp_packet {
bool ready; /* true if ready to be sent or received */
BACNET_ADDRESS address; /* source address */
+7 -4
View File
@@ -1177,9 +1177,11 @@ 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 safe */
/* FIXME: if we knew the APDU type received, we could
see if the next message was that same APDU type */
/* FIXME: we could always defer the reply to be safe */
see if the next message was that same APDU type
along with the matching src/dest and invoke ID */
if ((mstp_port->SilenceTimer <= Treply_delay) &&
mstp_port->TxReady) {
/* Reply */
@@ -1203,7 +1205,8 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
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 */
@@ -1213,7 +1216,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* 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. */
else {
{
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_POSTPONED,
mstp_port->SourceAddress,
+13 -117
View File
@@ -53,6 +53,9 @@
#include "bytes.h"
#include "crc.h"
#include "rs485.h"
#if PRINT_ENABLED
#include "mstptext.h"
#endif
/* debug print statements */
#if PRINT_ENABLED
@@ -227,35 +230,6 @@ void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port,
/* FIXME: be sure to reset SilenceTimer after each octet is sent! */
}
#if PRINT_ENABLED_RECEIVE
char *mstp_receive_state_text(int state)
{
char *text = "unknown";
switch (state) {
case MSTP_RECEIVE_STATE_IDLE:
text = "IDLE";
break;
case MSTP_RECEIVE_STATE_PREAMBLE:
text = "PREAMBLE";
break;
case MSTP_RECEIVE_STATE_HEADER:
text = "HEADER";
break;
case MSTP_RECEIVE_STATE_HEADER_CRC:
text = "HEADER_CRC";
break;
case MSTP_RECEIVE_STATE_DATA:
text = "DATA";
break;
default:
break;
}
return text;
}
#endif
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
{
#if PRINT_ENABLED_RECEIVE_DATA
@@ -264,7 +238,7 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
#if PRINT_ENABLED_RECEIVE
fprintf(stderr,
"MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u Silence=%u\n",
mstp_receive_state_text(mstp_port->receive_state),
mstptext_receive_state(mstp_port->receive_state),
mstp_port->DataRegister, mstp_port->HeaderCRC, mstp_port->Index,
mstp_port->EventCount, mstp_port->DataLength,
mstp_port->SilenceTimer);
@@ -576,88 +550,6 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
return;
}
#if PRINT_ENABLED
char *mstp_master_state_text(int state)
{
char *text = "unknown";
switch (state) {
case MSTP_MASTER_STATE_INITIALIZE:
text = "INITIALIZE";
break;
case MSTP_MASTER_STATE_IDLE:
text = "IDLE";
break;
case MSTP_MASTER_STATE_USE_TOKEN:
text = "USE_TOKEN";
break;
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
text = "WAIT_FOR_REPLY";
break;
case MSTP_MASTER_STATE_DONE_WITH_TOKEN:
text = "IDLE";
break;
case MSTP_MASTER_STATE_PASS_TOKEN:
text = "DONE_WITH_TOKEN";
break;
case MSTP_MASTER_STATE_NO_TOKEN:
text = "NO_TOKEN";
break;
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
text = "POLL_FOR_MASTER";
break;
case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST:
text = "ANSWER_DATA_REQUEST";
break;
default:
break;
}
return text;
}
#endif
#if PRINT_ENABLED
char *mstp_frame_type_text(int type)
{
char *text = "unknown";
switch (type) {
case FRAME_TYPE_TOKEN:
text = "TOKEN";
break;
case FRAME_TYPE_POLL_FOR_MASTER:
text = "POLL_FOR_MASTER";
break;
case FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER:
text = "REPLY_TO_POLL_FOR_MASTER";
break;
case FRAME_TYPE_TEST_REQUEST:
text = "TEST_REQUEST";
break;
case FRAME_TYPE_TEST_RESPONSE:
text = "TEST_RESPONSE";
break;
case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
text = "BACNET_DATA_EXPECTING_REPLY";
break;
case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
text = "BACNET_DATA_NOT_EXPECTING_REPLY";
break;
case FRAME_TYPE_REPLY_POSTPONED:
text = "REPLY_POSTPONED";
break;
default:
if ((type >= FRAME_TYPE_PROPRIETARY_MIN) &&
(type <= FRAME_TYPE_PROPRIETARY_MAX))
text = "PROPRIETARY";
break;
}
return text;
}
#endif
/* returns true if we need to transition immediately */
bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
{
@@ -694,7 +586,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
mstp_port->EventCount,
mstp_port->TokenCount,
mstp_port->SilenceTimer,
mstp_master_state_text(mstp_port->master_state));
mstptext_master_state(mstp_port->master_state));
}
#endif
@@ -736,7 +628,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
mstp_port->DataLength,
mstp_port->FrameCount,
mstp_port->SilenceTimer,
mstp_frame_type_text(mstp_port->FrameType));
mstptext_frame_type(mstp_port->FrameType));
#endif
/* destined for me! */
if ((mstp_port->DestinationAddress ==
@@ -1139,8 +1031,11 @@ 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 safe */
/* FIXME: if we knew the APDU type received, we could
see if the next message was that same APDU type */
see if the next message was that same APDU type
along with the matching src/dest and invoke ID */
if ((mstp_port->SilenceTimer <= Treply_delay) &&
mstp_port->TxReady) {
/* Reply */
@@ -1159,7 +1054,8 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
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 */
@@ -1169,7 +1065,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* 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. */
else {
{
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_POSTPONED,
mstp_port->SourceAddress,
+17 -31
View File
@@ -1166,46 +1166,33 @@ 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
if (mstp_port->ReplyPostponedTimer <= Treply_delay) {
/* Reply */
/* If a reply is 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 call MSTP_Create_And_Send_Frame to transmit the reply frame */
/* and enter the IDLE state to wait for the next frame. */
/* FIXME: we always defer the reply to be safe */
/* 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 */
if ((mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY)
&& (mstp_port->TxReady)) {
/* Reply */
/* If a reply is 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 call MSTP_Create_And_Send_Frame to transmit the reply frame */
/* and enter the IDLE state to wait for the next frame. */
RS485_Send_Frame(mstp_port,
(uint8_t *) & mstp_port->TxBuffer[0],
mstp_port->TxLength);
mstp_port->TxReady = false;
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
transition_now = true;
} else {
/* Test Request - handled directly in IDLE state */
}
/* Test Request */
/* If a receiving node can successfully receive and return */
/* the information field, it shall do so. If it cannot receive */
/* and return the entire information field but can detect */
/* the reception of a valid Test_Request frame */
/* (for example, by computing the CRC on octets as */
/* they are received), then the receiving node shall discard */
/* the information field and return a Test_Response containing */
/* no information field. If the receiving node cannot detect */
/* the valid reception of frames with overlength information fields, */
/* then no response shall be returned. */
else if (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST) {
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TEST_RESPONSE,
mstp_port->SourceAddress,
mstp_port->This_Station,
(uint8_t *) & mstp_port->InputBuffer[0],
mstp_port->DataLength);
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
transition_now = true;
}
}
} else
#endif
/* DeferredReply */
/* If no reply will be available from the higher layers */
/* within Treply_delay after the reception of the */
@@ -1215,7 +1202,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* 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. */
else {
{
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_POSTPONED,
mstp_port->SourceAddress,
@@ -1719,7 +1706,6 @@ void testMasterNodeFSM(Test * pTest)
MSTP_Init(&mstp_port, my_mac);
ct_test(pTest, mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE);
}
#endif
+45 -35
View File
@@ -42,11 +42,14 @@
/* Number of MS/TP Packets Rx/Tx */
uint16_t MSTP_Packets = 0;
/* receive buffer */
static DLMSTP_PACKET Receive_Buffer;
/* temp buffer for NPDU insertion */
/* packet queues */
static DLMSTP_PACKET Receive_Packet;
static DLMSTP_PACKET Transmit_Packet;
/* local MS/TP port data - shared with RS-485 */
volatile struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */
static uint8_t TxBuffer[MAX_MPDU];
static uint8_t RxBuffer[MAX_MPDU];
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
@@ -76,13 +79,12 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
{ /* number of bytes of data */
int bytes_sent = 0;
uint8_t destination = 0; /* destination address */
BACNET_ADDRESS src;
if (MSTP_Port.TxReady == false) {
if (!Transmit_Packet.ready) {
if (npdu_data->data_expecting_reply)
MSTP_Port.TxFrameType = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
Transmit_Packet.frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY;
else
MSTP_Port.TxFrameType =
Transmit_Packet.frame_type =
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY;
/* load destination MAC address */
@@ -91,17 +93,17 @@ int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */
} else {
return -2;
}
dlmstp_get_my_address(&src);
if ((8 /* header len */ + pdu_len) > MAX_MPDU) {
return -4;
}
bytes_sent = MSTP_Create_Frame(
(uint8_t *) & MSTP_Port.TxBuffer[0],
sizeof(MSTP_Port.TxBuffer),
MSTP_Port.TxFrameType,
destination, MSTP_Port.This_Station, pdu, pdu_len);
MSTP_Port.TxLength = bytes_sent;
MSTP_Port.TxReady = true;
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);
Transmit_Packet.ready = true;
MSTP_Packets++;
}
@@ -118,22 +120,22 @@ uint16_t dlmstp_receive(
/* see if there is a packet available, and a place
to put the reply (if necessary) and process it */
if (Receive_Buffer.ready) {
if (Receive_Buffer.pdu_len) {
if (Receive_Packet.ready) {
if (Receive_Packet.pdu_len) {
MSTP_Packets++;
if (src) {
memmove(src,
&Receive_Buffer.address,
sizeof(Receive_Buffer.address));
&Receive_Packet.address,
sizeof(Receive_Packet.address));
}
if (pdu) {
memmove(pdu,
&Receive_Buffer.pdu,
sizeof(Receive_Buffer.pdu));
&Receive_Packet.pdu,
sizeof(Receive_Packet.pdu));
}
pdu_len = Receive_Buffer.pdu_len;
pdu_len = Receive_Packet.pdu_len;
}
Receive_Buffer.ready = false;
Receive_Packet.ready = false;
}
return pdu_len;
@@ -210,10 +212,10 @@ uint16_t dlmstp_put_receive(uint8_t src, /* source MS/TP address */
uint8_t * pdu, /* PDU data */
uint16_t pdu_len)
{ /* amount of PDU data */
/* PDU is already in the Receive_Buffer */
dlmstp_fill_bacnet_address(&Receive_Buffer.address, src);
Receive_Buffer.pdu_len = pdu_len;
Receive_Buffer.ready = true;
/* PDU is already in the Receive_Packet */
dlmstp_fill_bacnet_address(&Receive_Packet.address, src);
Receive_Packet.pdu_len = pdu_len;
Receive_Packet.ready = true;
return pdu_len;
}
@@ -229,11 +231,15 @@ uint16_t dlmstp_get_send(
uint16_t pdu_len = 0;
(void)src;
(void)max_pdu;
if (MSTP_Port.TxReady) {
memmove(&pdu[0],(void *)&MSTP_Port.TxBuffer[0],sizeof(MSTP_Port.TxBuffer));
pdu_len = MSTP_Port.TxLength;
MSTP_Port.TxReady = false;
(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;
}
return pdu_len;
@@ -361,9 +367,9 @@ bool dlmstp_init(char *ifname)
unsigned long hThread = 0;
uint32_t arg_value = 0;
/* initialize buffer */
Receive_Buffer.ready = false;
Receive_Buffer.pdu_len = 0;
/* initialize packet queue */
Receive_Packet.ready = false;
Receive_Packet.pdu_len = 0;
/* initialize hardware */
/* initialize hardware */
if (ifname) {
@@ -373,6 +379,10 @@ bool dlmstp_init(char *ifname)
#endif
}
RS485_Initialize();
MSTP_Port.InputBuffer = &RxBuffer[0];
MSTP_Port.InputBufferSize = sizeof(RxBuffer);
MSTP_Port.OutputBuffer = &TxBuffer[0];
MSTP_Port.OutputBufferSize = sizeof(TxBuffer);
MSTP_Init(&MSTP_Port);
#if 0
uint8_t data;
+9
View File
@@ -49,6 +49,14 @@
<Unit filename="..\..\crc.h" />
<Unit filename="..\..\datalink.h" />
<Unit filename="..\..\dlmstp.h" />
<Unit filename="..\..\indtext.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\indtext.h" />
<Unit filename="..\..\mstptext.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="..\..\mstptext.h" />
<Unit filename="..\..\npdu.h" />
<Unit filename="dlmstp.c">
<Option compilerVar="CC" />
@@ -63,6 +71,7 @@
<Unit filename="rs485.h" />
<Extensions>
<code_completion />
<envvars />
</Extensions>
</Project>
</CodeBlocks_project_file>
+111 -193
View File
@@ -1,6 +1,6 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2003 Steve Karg
Copyright (C) 2003-2007 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -46,15 +46,20 @@
#include <stddef.h>
#include <stdint.h>
#if PRINT_ENABLED
#include <stdio.h>
#endif
#include "mstp.h"
#include "crc.h"
#include "rs485.h"
#if PRINT_ENABLED
#include "mstptext.h"
#endif
/* debug print statements */
#if PRINT_ENABLED
#define PRINT_ENABLED_RECEIVE 0
#define PRINT_ENABLED_RECEIVE_DATA 0
#define PRINT_ENABLED_RECEIVE_DATA 1
#define PRINT_ENABLED_RECEIVE_ERRORS 1
#define PRINT_ENABLED_MASTER 0
#else
@@ -94,7 +99,7 @@
/* not to exceed 100 milliseconds.) */
/* At 9600 baud, 60 bit times would be about 6.25 milliseconds */
/* const uint16_t Tframe_abort = 1 + ((1000 * 60) / 9600); */
#define Tframe_abort 100
#define Tframe_abort 30
/* The maximum idle time a sending node may allow to elapse between octets */
/* of a frame the node is transmitting: 20 bit times. */
@@ -150,13 +155,13 @@ bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port)
return (mstp_port->EventCount > Nmin_octets);
}
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
unsigned buffer_len, /* amount of space available */
uint16_t MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
uint16_t buffer_len, /* amount of space available */
uint8_t frame_type, /* type of frame to send - see defines */
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
unsigned data_len)
uint16_t data_len)
{ /* number of bytes of data (up to 501) */
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
@@ -208,53 +213,25 @@ void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port,
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
unsigned data_len)
uint16_t data_len)
{ /* number of bytes of data (up to 501) */
mstp_port->TxLength = (uint16_t) MSTP_Create_Frame(
(uint8_t *)&mstp_port->TxBuffer[0], /* where frame is loaded */
sizeof(mstp_port->TxBuffer), /* amount of space available */
uint16_t len = 0; /* number of bytes to send */
len = MSTP_Create_Frame(
(uint8_t *)&mstp_port->OutputBuffer[0], /* where frame is loaded */
mstp_port->OutputBufferSize, /* amount of space available */
frame_type, /* type of frame to send - see defines */
destination, /* destination address */
source, /* source address */
data, /* any data to be sent - may be null */
data_len); /* number of bytes of data (up to 501) */
RS485_Send_Frame(
mstp_port,
(uint8_t *)&mstp_port->TxBuffer[0],
mstp_port->TxLength);
RS485_Send_Frame(mstp_port,
(uint8_t *)&mstp_port->OutputBuffer[0],
len);
/* FIXME: be sure to reset SilenceTimer after each octet is sent! */
}
#if PRINT_ENABLED_RECEIVE
char *mstp_receive_state_text(int state)
{
char *text = "unknown";
switch (state) {
case MSTP_RECEIVE_STATE_IDLE:
text = "IDLE";
break;
case MSTP_RECEIVE_STATE_PREAMBLE:
text = "PREAMBLE";
break;
case MSTP_RECEIVE_STATE_HEADER:
text = "HEADER";
break;
case MSTP_RECEIVE_STATE_HEADER_CRC:
text = "HEADER_CRC";
break;
case MSTP_RECEIVE_STATE_DATA:
text = "DATA";
break;
default:
break;
}
return text;
}
#endif
void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
{
#if PRINT_ENABLED_RECEIVE_DATA
@@ -263,7 +240,7 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
#if PRINT_ENABLED_RECEIVE
fprintf(stderr,
"MSTP Rx: State=%s Data=%02X hCRC=%02X Index=%u EC=%u DateLen=%u Silence=%u\n",
mstp_receive_state_text(mstp_port->receive_state),
mstptext_receive_state(mstp_port->receive_state),
mstp_port->DataRegister, mstp_port->HeaderCRC, mstp_port->Index,
mstp_port->EventCount, mstp_port->DataLength,
mstp_port->SilenceTimer);
@@ -365,8 +342,10 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
#if PRINT_ENABLED_RECEIVE_ERRORS
fprintf(stderr,"MSTP: Rx Header: SilenceTimer %d > %d\n",
mstp_port->SilenceTimer, Tframe_abort);
#endif
}
/* Error */
else if (mstp_port->ReceiveError == true) {
@@ -375,7 +354,9 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
#if PRINT_ENABLED_RECEIVE_ERRORS
fprintf(stderr,"MSTP: Rx Header: ReceiveError\n");
#endif
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else if (mstp_port->DataAvailable == true) {
@@ -465,45 +446,50 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else {
if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
|| (mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS)
|| (mstp_port->Lurking)) {
/* FIXME: if we don't decode the data, we could
get confused if the Preamble 55 FF is part
of the data. */
/* Data */
if ((mstp_port->DataLength) &&
(mstp_port->DataLength <= MAX_MPDU)) {
/* Data - decode anyway to keep from false */
mstp_port->Index = 0;
mstp_port->DataCRC = 0xFFFF;
/* receive the data portion of the frame. */
mstp_port->receive_state =
MSTP_RECEIVE_STATE_DATA;
} else {
/* FrameTooLong */
if (mstp_port->DataLength > MAX_MPDU) {
/* indicate that a frame with an illegal or */
/* unacceptable data length has been received */
mstp_port->ReceivedInvalidFrame = true;
#if PRINT_ENABLED_RECEIVE_ERRORS
fprintf(stderr,"MSTP: Rx Header: FrameTooLong %d\n",
mstp_port->DataLength);
#endif
/* wait for the start of the next frame. */
mstp_port->receive_state =
MSTP_RECEIVE_STATE_IDLE;
/* indicate that a frame with an illegal or */
/* unacceptable data length has been received */
mstp_port->ReceivedInvalidFrame = true;
}
/* NoData */
else if (mstp_port->DataLength == 0) {
/* indicate that a frame with no data has been received */
mstp_port->ReceivedValidFrame = true;
/* wait for the start of the next frame. */
mstp_port->receive_state =
MSTP_RECEIVE_STATE_IDLE;
#if PRINT_ENABLED_RECEIVE_DATA
fprintf(stderr, "%s",
mstptext_frame_type(mstp_port->FrameType));
#endif
if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
|| (mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS)
|| (mstp_port->Lurking)) {
/* ForUs */
/* indicate that a frame with no data has been received */
mstp_port->ReceivedValidFrame = true;
} else {
/* NotForUs - drop */
}
}
/* Data */
else {
mstp_port->Index = 0;
mstp_port->DataCRC = 0xFFFF;
/* receive the data portion of the frame. */
mstp_port->receive_state =
MSTP_RECEIVE_STATE_DATA;
}
}
/* NotForUs */
else {
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
mstp_port->receive_state =
MSTP_RECEIVE_STATE_IDLE;
}
}
}
@@ -578,10 +564,25 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister,
mstp_port->DataCRC);
mstp_port->DataCRCActualLSB = mstp_port->DataRegister;
#if PRINT_ENABLED_RECEIVE_DATA
fprintf(stderr, "%s",
mstptext_frame_type(mstp_port->FrameType));
#endif
/* STATE DATA CRC - no need for new state */
/* indicate the complete reception of a valid frame */
if (mstp_port->DataCRC == 0xF0B8)
mstp_port->ReceivedValidFrame = true;
if (mstp_port->DataCRC == 0xF0B8) {
if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
|| (mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS)
|| (mstp_port->Lurking)) {
/* ForUs */
/* indicate that a frame with no data has been received */
mstp_port->ReceivedValidFrame = true;
} else {
/* NotForUs - drop */
}
}
else {
mstp_port->ReceivedInvalidFrame = true;
#if PRINT_ENABLED_RECEIVE_ERRORS
@@ -612,91 +613,10 @@ void MSTP_Receive_Frame_FSM(volatile struct mstp_port_struct_t *mstp_port)
return;
}
#if PRINT_ENABLED
char *mstp_master_state_text(int state)
{
char *text = "unknown";
switch (state) {
case MSTP_MASTER_STATE_INITIALIZE:
text = "INITIALIZE";
break;
case MSTP_MASTER_STATE_IDLE:
text = "IDLE";
break;
case MSTP_MASTER_STATE_USE_TOKEN:
text = "USE_TOKEN";
break;
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
text = "WAIT_FOR_REPLY";
break;
case MSTP_MASTER_STATE_DONE_WITH_TOKEN:
text = "IDLE";
break;
case MSTP_MASTER_STATE_PASS_TOKEN:
text = "DONE_WITH_TOKEN";
break;
case MSTP_MASTER_STATE_NO_TOKEN:
text = "NO_TOKEN";
break;
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
text = "POLL_FOR_MASTER";
break;
case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST:
text = "ANSWER_DATA_REQUEST";
break;
default:
break;
}
return text;
}
#endif
#if PRINT_ENABLED
char *mstp_frame_type_text(int type)
{
char *text = "unknown";
switch (type) {
case FRAME_TYPE_TOKEN:
text = "TOKEN";
break;
case FRAME_TYPE_POLL_FOR_MASTER:
text = "POLL_FOR_MASTER";
break;
case FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER:
text = "REPLY_TO_POLL_FOR_MASTER";
break;
case FRAME_TYPE_TEST_REQUEST:
text = "TEST_REQUEST";
break;
case FRAME_TYPE_TEST_RESPONSE:
text = "TEST_RESPONSE";
break;
case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
text = "BACNET_DATA_EXPECTING_REPLY";
break;
case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
text = "BACNET_DATA_NOT_EXPECTING_REPLY";
break;
case FRAME_TYPE_REPLY_POSTPONED:
text = "REPLY_POSTPONED";
break;
default:
if ((type >= FRAME_TYPE_PROPRIETARY_MIN) &&
(type <= FRAME_TYPE_PROPRIETARY_MAX))
text = "PROPRIETARY";
break;
}
return text;
}
#endif
/* returns true if we need to transition immediately */
bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
{
unsigned length = 0;
uint8_t next_poll_station = 0;
uint8_t next_this_station = 0;
uint8_t next_next_station = 0;
@@ -728,7 +648,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
mstp_port->EventCount,
mstp_port->TokenCount,
mstp_port->SilenceTimer,
mstp_master_state_text(mstp_port->master_state));
mstptext_master_state(mstp_port->master_state));
}
#endif
@@ -770,7 +690,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
mstp_port->DataLength,
mstp_port->FrameCount,
mstp_port->SilenceTimer,
mstp_frame_type_text(mstp_port->FrameType));
mstptext_frame_type(mstp_port->FrameType));
#endif
/* destined for me! */
if ((mstp_port->DestinationAddress ==
@@ -834,12 +754,12 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* more data frames. These may be BACnet Data frames or */
/* proprietary frames. */
case MSTP_MASTER_STATE_USE_TOKEN:
mstp_port->TxLength = dlmstp_get_send(
length = dlmstp_get_send(
mstp_port->This_Station,
(uint8_t *)&mstp_port->TxBuffer[0],
sizeof(mstp_port->TxBuffer),
(uint8_t *)&mstp_port->OutputBuffer[0],
mstp_port->OutputBufferSize,
0); /* milliseconds to wait for a packet */
if (mstp_port->TxLength < 1) {
if (length < 1) {
/* NothingToSend */
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
@@ -848,11 +768,14 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* if we missed our timing deadline, another token will be sent */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
} else {
uint8_t destination = mstp_port->TxBuffer[3];
/* don't send it if we are too late in getting out */
uint8_t frame_type = mstp_port->OutputBuffer[2];
uint8_t destination = mstp_port->OutputBuffer[3];
RS485_Send_Frame(mstp_port,
(uint8_t *) & mstp_port->TxBuffer[0], mstp_port->TxLength);
(uint8_t *) & mstp_port->OutputBuffer[0], length);
mstp_port->FrameCount++;
switch (mstp_port->TxFrameType) {
/* last trasmitted frame type */
switch (frame_type) {
case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
/* SendAndWait */
if (destination == MSTP_BROADCAST_ADDRESS)
@@ -873,7 +796,6 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
MSTP_MASTER_STATE_DONE_WITH_TOKEN;
break;
}
mstp_port->TxReady = false;
}
break;
/* In the WAIT_FOR_REPLY state, the node waits for */
@@ -900,7 +822,8 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
} else if (mstp_port->ReceivedValidFrame == true) {
if (mstp_port->DestinationAddress ==
mstp_port->This_Station) {
switch (mstp_port->TxFrameType) {
/* Last Transmitted Frame Type */
switch (mstp_port->OutputBuffer[2]) {
case FRAME_TYPE_REPLY_POSTPONED:
/* ReceivedReplyPostponed */
mstp_port->master_state =
@@ -1177,9 +1100,11 @@ 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 safe */
/* FIXME: if we knew the APDU type received, we could
see if the next message was that same APDU type */
/* FIXME: we could always defer the reply to be safe */
see if the next message was that same APDU type
along with the matching src/dest and invoke ID */
if ((mstp_port->SilenceTimer <= Treply_delay) &&
mstp_port->TxReady) {
/* Reply */
@@ -1189,21 +1114,22 @@ 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. */
mstp_port->TxLength = dlmstp_get_send(
length = dlmstp_get_send(
mstp_port->This_Station,
(uint8_t *)&mstp_port->TxBuffer[0],
sizeof(mstp_port->TxBuffer),
(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)
&& (mstp_port->TxLength > 0)) {
&& (length > 0)) {
RS485_Send_Frame(mstp_port,
(uint8_t *) & mstp_port->TxBuffer[0],
mstp_port->TxLength);
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 */
@@ -1213,7 +1139,7 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* 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. */
else {
{
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_POSTPONED,
mstp_port->SourceAddress,
@@ -1232,10 +1158,10 @@ bool MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t * mstp_port)
/* note: This_Station assumed to be set with the MAC address */
/* note: Nmax_info_frames assumed to be set (default=1) */
/* note: Nmax_master assumed to be set (default=127) */
/* note: InputBuffer and InputBufferSize assumed to be set */
/* note: OutputBuffer and OutputBufferSize assumed to be set */
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port)
{
int i; /*loop counter */
if (mstp_port) {
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
@@ -1252,35 +1178,27 @@ void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port)
mstp_port->HeaderCRC = 0;
mstp_port->Index = 0;
mstp_port->Index = 0;
for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) {
mstp_port->InputBuffer[i] = 0;
}
mstp_port->Next_Station = mstp_port->This_Station;
mstp_port->Poll_Station = mstp_port->This_Station;
mstp_port->ReceivedInvalidFrame = false;
mstp_port->ReceivedValidFrame = false;
mstp_port->RetryCount = 0;
mstp_port->SilenceTimer = 0;
/* mstp_port->ReplyPostponedTimer = 0; */
mstp_port->SoleMaster = false;
mstp_port->SourceAddress = 0;
mstp_port->TokenCount = 0;
mstp_port->Lurking = false;
#if 0
/* these are adjustable, so should already be set */
/* FIXME: you must point these buffers to actual byte buckets
in the dlmstp function before or after calling this init. */
mstp_port->InputBuffer = &InputBuffer[0];
mstp_port->InputBufferSize = sizeof(InputBuffer);
mstp_port->OutputBuffer = &OutputBuffer[0];
mstp_port->OutputBufferSize = sizeof(OutputBuffer);
/* these are adjustable, so you must set these in dlmstp */
mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES;
mstp_port->Nmax_master = DEFAULT_MAX_MASTER;
#endif
/* An array of octets, used to store PDU octets prior to being transmitted. */
/* This array is only used for APDU messages */
for (i = 0; i < sizeof(mstp_port->TxBuffer); i++) {
mstp_port->TxBuffer[i] = 0;
}
mstp_port->TxLength = 0;
mstp_port->TxReady = false;
mstp_port->TxFrameType = 0;
}
}
+20 -61
View File
@@ -42,55 +42,6 @@
#include "bacdef.h"
#include "dlmstp.h"
/* The value 255 is used to denote broadcast when used as a */
/* destination address but is not allowed as a value for a station. */
/* Station addresses for master nodes can be 0-127. */
/* Station addresses for slave nodes can be 127-254. */
#define MSTP_BROADCAST_ADDRESS 255
/* MS/TP Frame Type */
/* Frame Types 8 through 127 are reserved by ASHRAE. */
#define FRAME_TYPE_TOKEN 0
#define FRAME_TYPE_POLL_FOR_MASTER 1
#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2
#define FRAME_TYPE_TEST_REQUEST 3
#define FRAME_TYPE_TEST_RESPONSE 4
#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5
#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define FRAME_TYPE_REPLY_POSTPONED 7
/* Frame Types 128 through 255: Proprietary Frames */
/* These frames are available to vendors as proprietary (non-BACnet) frames. */
/* The first two octets of the Data field shall specify the unique vendor */
/* identification code, most significant octet first, for the type of */
/* vendor-proprietary frame to be conveyed. The length of the data portion */
/* of a Proprietary frame shall be in the range of 2 to 501 octets. */
#define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255
/* The initial CRC16 checksum value */
#define CRC16_INITIAL_VALUE (0xFFFF)
/* receive FSM states */
typedef enum {
MSTP_RECEIVE_STATE_IDLE = 0,
MSTP_RECEIVE_STATE_PREAMBLE = 1,
MSTP_RECEIVE_STATE_HEADER = 2,
MSTP_RECEIVE_STATE_HEADER_CRC = 3,
MSTP_RECEIVE_STATE_DATA = 4
} MSTP_RECEIVE_STATE;
/* master node FSM states */
typedef enum {
MSTP_MASTER_STATE_INITIALIZE = 0,
MSTP_MASTER_STATE_IDLE = 1,
MSTP_MASTER_STATE_USE_TOKEN = 2,
MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3,
MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4,
MSTP_MASTER_STATE_PASS_TOKEN = 5,
MSTP_MASTER_STATE_NO_TOKEN = 6,
MSTP_MASTER_STATE_POLL_FOR_MASTER = 7,
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8
} MSTP_MASTER_STATE;
struct mstp_port_struct_t {
MSTP_RECEIVE_STATE receive_state;
/* When a master node is powered up or reset, */
@@ -141,7 +92,12 @@ struct mstp_port_struct_t {
/* An array of octets, used to store octets as they are received. */
/* InputBuffer is indexed from 0 to InputBufferSize-1. */
/* The maximum size of a frame is 501 octets. */
uint8_t InputBuffer[MAX_MPDU];
/* FIXME: assign this to an actual array of bytes! */
/* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to
hold contiguous memory. */
uint8_t *InputBuffer;
uint16_t InputBufferSize;
/* "Next Station," the MAC address of the node to which This Station passes */
/* the token. If the Next_Station is unknown, Next_Station shall be equal to */
/* This_Station. */
@@ -202,13 +158,16 @@ struct mstp_port_struct_t {
/* less than or equal to 127. If Max_Master is not writable in a node, */
/* its value shall be 127. */
unsigned Nmax_master;
/* An array of octets, used to store PDU octets prior to being transmitted. */
/* This array is only used for APDU messages */
uint8_t TxBuffer[MAX_MPDU];
unsigned TxLength;
bool TxReady; /* true if ready to be sent or received */
uint8_t TxFrameType; /* type of message - needed by MS/TP */
/* An array of octets, used to store octets for transmitting */
/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */
/* The maximum size of a frame is 501 octets. */
/* FIXME: assign this to an actual array of bytes! */
/* Note: the buffer is designed as a pointer since some compilers
and microcontroller architectures have limits as to places to
hold contiguous memory. */
uint8_t *OutputBuffer;
uint16_t OutputBufferSize;
};
#define DEFAULT_MAX_INFO_FRAMES 1
@@ -239,14 +198,14 @@ extern "C" {
/* returns true if line is active */
bool MSTP_Line_Active(volatile struct mstp_port_struct_t *mstp_port);
unsigned MSTP_Create_Frame(
uint16_t MSTP_Create_Frame(
uint8_t * buffer, /* where frame is loaded */
unsigned buffer_len, /* amount of space available */
uint16_t buffer_len, /* amount of space available */
uint8_t frame_type, /* type of frame to send - see defines */
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
unsigned data_len); /* number of bytes of data (up to 501) */
uint16_t data_len); /* number of bytes of data (up to 501) */
void MSTP_Create_And_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port to send from */
@@ -254,7 +213,7 @@ extern "C" {
uint8_t destination, /* destination address */
uint8_t source, /* source address */
uint8_t * data, /* any data to be sent - may be null */
unsigned data_len);
uint16_t data_len);
#ifdef __cplusplus
}