diff --git a/bacnet-stack/dlmstp.h b/bacnet-stack/dlmstp.h index a5d3918d..3c9ee66a 100644 --- a/bacnet-stack/dlmstp.h +++ b/bacnet-stack/dlmstp.h @@ -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 */ diff --git a/bacnet-stack/ports/linux/mstp.c b/bacnet-stack/ports/linux/mstp.c index f5da3012..154e4388 100644 --- a/bacnet-stack/ports/linux/mstp.c +++ b/bacnet-stack/ports/linux/mstp.c @@ -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, diff --git a/bacnet-stack/ports/pic18f6720/mstp.c b/bacnet-stack/ports/pic18f6720/mstp.c index 47a3d6bd..faae1286 100644 --- a/bacnet-stack/ports/pic18f6720/mstp.c +++ b/bacnet-stack/ports/pic18f6720/mstp.c @@ -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, diff --git a/bacnet-stack/ports/rtos32/mstp.c b/bacnet-stack/ports/rtos32/mstp.c index 5303eabf..77971849 100644 --- a/bacnet-stack/ports/rtos32/mstp.c +++ b/bacnet-stack/ports/rtos32/mstp.c @@ -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 diff --git a/bacnet-stack/ports/win32/dlmstp.c b/bacnet-stack/ports/win32/dlmstp.c index 38a62318..cf60c8a5 100644 --- a/bacnet-stack/ports/win32/dlmstp.c +++ b/bacnet-stack/ports/win32/dlmstp.c @@ -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; diff --git a/bacnet-stack/ports/win32/dlmstp.cbp b/bacnet-stack/ports/win32/dlmstp.cbp index 1383ac20..5ac59a48 100644 --- a/bacnet-stack/ports/win32/dlmstp.cbp +++ b/bacnet-stack/ports/win32/dlmstp.cbp @@ -49,6 +49,14 @@ + + + + + +