Files
bacnet_stack/bacnet-stack/mstp.c
T

1760 lines
75 KiB
C

/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2003 Steve Karg
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
The Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307
USA.
As a special exception, if other files instantiate templates or
use macros or inline functions from this file, or you compile
this file and link it with other works to produce a work based
on this file, this file does not by itself cause the resulting
work to be covered by the GNU General Public License. However
the source code for this file must still be made available in
accordance with section (3) of the GNU General Public License.
This exception does not invalidate any other reasons why a work
based on this file might be covered by the GNU General Public
License.
-------------------------------------------
####COPYRIGHTEND####*/
/* This clause describes a Master-Slave/Token-Passing (MS/TP) data link */
/* protocol, which provides the same services to the network layer as */
/* ISO 8802-2 Logical Link Control. It uses services provided by the */
/* EIA-485 physical layer. Relevant clauses of EIA-485 are deemed to be */
/* included in this standard by reference. The following hardware is assumed: */
/* (a) A UART (Universal Asynchronous Receiver/Transmitter) capable of */
/* transmitting and receiving eight data bits with one stop bit */
/* and no parity. */
/* (b) An EIA-485 transceiver whose driver may be disabled. */
/* (c) A timer with a resolution of five milliseconds or less */
#include <stddef.h>
#include <stdint.h>
#if PRINT_ENABLED
#include <stdio.h>
#endif
#include "mstp.h"
#include "bytes.h"
#include "crc.h"
#include "rs485.h"
/* debug print statements */
#define PRINT_ENABLED_RECEIVE 0
#define PRINT_ENABLED_MASTER 0
/* MS/TP Frame Format */
/* All frames are of the following format: */
/* */
/* Preamble: two octet preamble: X`55', X`FF' */
/* Frame Type: one octet */
/* Destination Address: one octet address */
/* Source Address: one octet address */
/* Length: two octets, most significant octet first, of the Data field */
/* Header CRC: one octet */
/* Data: (present only if Length is non-zero) */
/* Data CRC: (present only if Length is non-zero) two octets, */
/* least significant octet first */
/* (pad): (optional) at most one octet of padding: X'FF' */
/* The number of tokens received or used before a Poll For Master cycle */
/* is executed: 50. */
const unsigned Npoll = 50;
/* The number of retries on sending Token: 1. */
const unsigned Nretry_token = 1;
/* The minimum number of DataAvailable or ReceiveError events that must be */
/* seen by a receiving node in order to declare the line "active": 4. */
const uint8_t Nmin_octets = 4;
/* The minimum time without a DataAvailable or ReceiveError event within */
/* a frame before a receiving node may discard the frame: 60 bit times. */
/* (Implementations may use larger values for this timeout, */
/* 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);
/* The maximum idle time a sending node may allow to elapse between octets */
/* of a frame the node is transmitting: 20 bit times. */
const unsigned Tframe_gap = 20;
/* The time without a DataAvailable or ReceiveError event before declaration */
/* of loss of token: 500 milliseconds. */
const uint16_t Tno_token = 500;
/* The maximum time after the end of the stop bit of the final */
/* octet of a transmitted frame before a node must disable its */
/* EIA-485 driver: 15 bit times. */
const unsigned Tpostdrive = 15;
/* The maximum time a node may wait after reception of a frame that expects */
/* a reply before sending the first octet of a reply or Reply Postponed */
/* frame: 250 milliseconds. */
const uint16_t Treply_delay = 225;
/* The minimum time without a DataAvailable or ReceiveError event */
/* that a node must wait for a station to begin replying to a */
/* confirmed request: 255 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 300 milliseconds.) */
const uint16_t Treply_timeout = 255;
/* Repeater turnoff delay. The duration of a continuous logical one state */
/* at the active input port of an MS/TP repeater after which the repeater */
/* will enter the IDLE state: 29 bit times < Troff < 40 bit times. */
const unsigned Troff = 30;
/* The width of the time slot within which a node may generate a token: */
/* 10 milliseconds. */
const uint16_t Tslot = 10;
/* The maximum time a node may wait after reception of the token or */
/* a Poll For Master frame before sending the first octet of a frame: */
/* 15 milliseconds. */
const uint16_t Tusage_delay = 15;
/* The minimum time without a DataAvailable or ReceiveError event that a */
/* node must wait for a remote node to begin using a token or replying to */
/* a Poll For Master frame: 20 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 100 milliseconds.) */
const uint16_t Tusage_timeout = 20;
/* we need to be able to increment without rolling over */
#define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;}
#define INCREMENT_AND_LIMIT_UINT16(x) {if (x < 0xFFFF) x++;}
unsigned MSTP_Create_Frame(uint8_t * buffer, /* where frame is loaded */
unsigned 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) */
uint8_t crc8 = 0xFF; /* used to calculate the crc value */
uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */
unsigned index = 0; /* used to load the data portion of the frame */
/* not enough to do a header */
if (buffer_len < 8)
return 0;
buffer[0] = 0x55;
buffer[1] = 0xFF;
buffer[2] = frame_type;
crc8 = CRC_Calc_Header(buffer[2], crc8);
buffer[3] = destination;
crc8 = CRC_Calc_Header(buffer[3], crc8);
buffer[4] = source;
crc8 = CRC_Calc_Header(buffer[4], crc8);
buffer[5] = data_len / 256;
crc8 = CRC_Calc_Header(buffer[5], crc8);
buffer[6] = data_len % 256;
crc8 = CRC_Calc_Header(buffer[6], crc8);
buffer[7] = ~crc8;
index = 8;
while (data_len && data && (index < buffer_len)) {
buffer[index] = *data;
crc16 = CRC_Calc_Data(buffer[index], crc16);
data++;
index++;
data_len--;
}
/* append the data CRC if necessary */
if (index > 8) {
if ((index + 2) <= buffer_len) {
crc16 = ~crc16;
buffer[index] = LO_BYTE(crc16);
index++;
buffer[index] = HI_BYTE(crc16);
index++;
} else
return 0;
}
return index; /* returns the frame length */
}
void MSTP_Create_And_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port to send from */
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) */
uint8_t buffer[MAX_MPDU] = {0}; /* buffer for sending */
uint16_t len = 0; /* number of bytes to send */
len = (uint16_t) MSTP_Create_Frame(&buffer[0], /* where frame is loaded */
sizeof(buffer), /* 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, &buffer[0], len);
}
/* Millisecond Timer - called every millisecond */
void MSTP_Millisecond_Timer(volatile struct mstp_port_struct_t *mstp_port)
{
INCREMENT_AND_LIMIT_UINT16(mstp_port->SilenceTimer);
INCREMENT_AND_LIMIT_UINT16(mstp_port->ReplyPostponedTimer);
return;
}
#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;
case MSTP_RECEIVE_STATE_DATA_CRC:
text = "CRC";
break;
default:
break;
}
return text;
}
#endif
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\r\n",
mstp_receive_state_text(mstp_port->receive_state),
mstp_port->DataRegister,
mstp_port->HeaderCRC,
mstp_port->Index,
mstp_port->EventCount,
mstp_port->DataLength,
mstp_port->SilenceTimer);
#endif
switch (mstp_port->receive_state) {
/* In the IDLE state, the node waits for the beginning of a frame. */
case MSTP_RECEIVE_STATE_IDLE:
/* EatAnError */
if (mstp_port->ReceiveError == true) {
mstp_port->ReceiveError = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else {
if (mstp_port->DataAvailable == true) {
/* Preamble1 */
if (mstp_port->DataRegister == 0x55) {
mstp_port->DataAvailable = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* receive the remainder of the frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE;
}
/* EatAnOctet */
else {
mstp_port->DataAvailable = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
}
}
break;
/* In the PREAMBLE state, the node waits for the second octet of the preamble. */
case MSTP_RECEIVE_STATE_PREAMBLE:
/* Timeout */
if (mstp_port->SilenceTimer > Tframe_abort) {
/* a correct preamble has not been received */
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
/* Error */
else if (mstp_port->ReceiveError == true) {
mstp_port->ReceiveError = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else {
if (mstp_port->DataAvailable == true) {
/* Preamble2 */
if (mstp_port->DataRegister == 0xFF) {
mstp_port->DataAvailable = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->Index = 0;
mstp_port->HeaderCRC = 0xFF;
/* receive the remainder of the frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* ignore RepeatedPreamble1 */
else if (mstp_port->DataRegister == 0x55) {
mstp_port->DataAvailable = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* wait for the second preamble octet. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE;
}
/* NotPreamble */
else {
mstp_port->DataAvailable = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
}
}
break;
/* In the HEADER state, the node waits for the fixed message header. */
case MSTP_RECEIVE_STATE_HEADER:
/* Timeout */
if (mstp_port->SilenceTimer > Tframe_abort) {
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
/* Error */
else if (mstp_port->ReceiveError == true) {
mstp_port->ReceiveError = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else if (mstp_port->DataAvailable == true) {
/* FrameType */
if (mstp_port->Index == 0) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->FrameType = mstp_port->DataRegister;
mstp_port->DataAvailable = false;
mstp_port->Index = 1;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* Destination */
else if (mstp_port->Index == 1) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->DestinationAddress = mstp_port->DataRegister;
mstp_port->DataAvailable = false;
mstp_port->Index = 2;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* Source */
else if (mstp_port->Index == 2) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->SourceAddress = mstp_port->DataRegister;
mstp_port->DataAvailable = false;
mstp_port->Index = 3;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* Length1 */
else if (mstp_port->Index == 3) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->DataLength = mstp_port->DataRegister * 256;
mstp_port->DataAvailable = false;
mstp_port->Index = 4;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* Length2 */
else if (mstp_port->Index == 4) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->DataLength += mstp_port->DataRegister;
mstp_port->DataAvailable = false;
mstp_port->Index = 5;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER;
}
/* HeaderCRC */
else if (mstp_port->Index == 5) {
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
mstp_port->HeaderCRC =
CRC_Calc_Header(mstp_port->DataRegister,
mstp_port->HeaderCRC);
mstp_port->DataAvailable = false;
mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER_CRC;
}
/* not per MS/TP standard, but it is a case not covered */
else {
mstp_port->ReceiveError = false;
mstp_port->SilenceTimer = 0;
INCREMENT_AND_LIMIT_UINT8(mstp_port->EventCount);
/* indicate that an error has occurred during */
/* the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of a frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
}
break;
/* In the HEADER_CRC state, the node validates the CRC on the fixed */
/* message header. */
case MSTP_RECEIVE_STATE_HEADER_CRC:
/* BadCRC */
if (mstp_port->HeaderCRC != 0x55) {
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* 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)) {
/* 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;
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
/* 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;
}
/* 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;
}
}
break;
/* In the DATA state, the node waits for the data portion of a frame. */
case MSTP_RECEIVE_STATE_DATA:
/* Timeout */
if (mstp_port->SilenceTimer > Tframe_abort) {
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
/* Error */
else if (mstp_port->ReceiveError == true) {
mstp_port->ReceiveError = false;
mstp_port->SilenceTimer = 0;
/* indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
} else if (mstp_port->DataAvailable == true) {
/* DataOctet */
if (mstp_port->Index < mstp_port->DataLength) {
mstp_port->SilenceTimer = 0;
mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister,
mstp_port->DataCRC);
mstp_port->InputBuffer[mstp_port->Index] =
mstp_port->DataRegister;
mstp_port->DataAvailable = false;
mstp_port->Index++;
mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA;
}
/* CRC1 */
else if (mstp_port->Index == mstp_port->DataLength) {
mstp_port->SilenceTimer = 0;
mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister,
mstp_port->DataCRC);
mstp_port->DataAvailable = false;
mstp_port->Index++; /* Index now becomes the number of data octets */
mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA;
}
/* CRC2 */
else if (mstp_port->Index == (mstp_port->DataLength + 1)) {
mstp_port->SilenceTimer = 0;
mstp_port->DataCRC = CRC_Calc_Data(mstp_port->DataRegister,
mstp_port->DataCRC);
mstp_port->DataAvailable = false;
mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA_CRC;
}
}
break;
/* In the DATA_CRC state, the node validates the CRC of the message data. */
case MSTP_RECEIVE_STATE_DATA_CRC:
/* GoodCRC */
if (mstp_port->DataCRC == 0xF0B8) {
/* indicate the complete reception of a valid frame */
mstp_port->ReceivedValidFrame = true;
/* now might be a good time to process the message or */
/* copy the data to a buffer so that we can process the message */
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
/* BadCRC */
else {
/* to indicate that an error has occurred during the reception of a frame */
mstp_port->ReceivedInvalidFrame = true;
/* wait for the start of the next frame. */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
}
break;
default:
/* shouldn't get here - but if we do... */
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
break;
}
return;
}
void mstp_put_receive(volatile struct mstp_port_struct_t
*mstp_port)
{
if (mstp_port)
{
dlmstp_put_receive(
mstp_port->SourceAddress, /* source MS/TP address */
(uint8_t *) & mstp_port->InputBuffer[0],
mstp_port->Index);
}
}
#if PRINT_ENABLED_MASTER
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
void MSTP_Master_Node_FSM(volatile struct mstp_port_struct_t *mstp_port)
{
int mtu_len = 0;
int frame_type = 0;
uint8_t next_poll_station = 0;
uint8_t next_poll_neighbor = 0;
uint8_t next_station = 0;
/* some calculations that several states need */
next_poll_station = (mstp_port->Poll_Station + 1) %
(mstp_port->Nmax_master + 1);
next_poll_neighbor = (mstp_port->This_Station + 1) %
(mstp_port->Nmax_master + 1);
next_station = (mstp_port->Next_Station + 1) %
(mstp_port->Nmax_master + 1);
#if PRINT_ENABLED_MASTER
fprintf(stderr,"MSTP: State=%s TS=%u NS=%u PS=%u EC=%u TC=%u Silence=%u\r\n",
mstp_master_state_text(mstp_port->master_state),
mstp_port->This_Station,
mstp_port->Next_Station,
mstp_port->Poll_Station,
mstp_port->EventCount,
mstp_port->TokenCount,
mstp_port->SilenceTimer);
fprintf(stderr,"MSTP: NextPollStation=%u NextPollNeighbor=%u NextStation=%u\r\n",
next_poll_station,
next_poll_neighbor,
next_station);
#endif
switch (mstp_port->master_state) {
case MSTP_MASTER_STATE_INITIALIZE:
/* DoneInitializing */
/* indicate that the next station is unknown */
mstp_port->Next_Station = mstp_port->This_Station;
mstp_port->Poll_Station = mstp_port->This_Station;
/* cause a Poll For Master to be sent when this node first */
/* receives the token */
mstp_port->TokenCount = Npoll;
mstp_port->SoleMaster = false;
mstp_port->ReceivedValidFrame = false;
mstp_port->ReceivedInvalidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
break;
/* In the IDLE state, the node waits for a frame. */
case MSTP_MASTER_STATE_IDLE:
/* LostToken */
if (mstp_port->SilenceTimer >= Tno_token) {
/* assume that the token has been lost */
mstp_port->EventCount = 0; /* Addendum 135-2004d-8 */
mstp_port->master_state = MSTP_MASTER_STATE_NO_TOKEN;
}
/* ReceivedInvalidFrame */
else if (mstp_port->ReceivedInvalidFrame == true) {
/* invalid frame was received */
mstp_port->ReceivedInvalidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
else if (mstp_port->ReceivedValidFrame == true) {
#if PRINT_ENABLED
fprintf(stderr,"MSTP: ReceivedValidFrame Type=%s Dest=%02X\r\n",
mstp_frame_type_text(mstp_port->FrameType),
mstp_port->DestinationAddress);
#endif
/* ReceivedUnwantedFrame - not for me */
if (!((mstp_port->DestinationAddress == mstp_port->This_Station)
|| (mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS))) {
/* an unexpected or unwanted frame was received. */
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedUnwantedFrame - broadcast TOKEN or TEST_REQUEST */
/* DestinationAddress is equal to 255 (broadcast) and */
/* FrameType has a value of Token, BACnet Data Expecting Reply, Test_Request, */
/* or a proprietary type known to this node that expects a reply */
/* (such frames may not be broadcast), or */
else if ((mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS)
&& ((mstp_port->FrameType == FRAME_TYPE_TOKEN)
/* removed in Add-2004-135b-PR1 - see BroadcastDataNeedingReply
|| (mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) */
|| (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) {
/* an unexpected or unwanted frame was received. */
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedUnwantedFrame - PROPRIETARY unknown to me */
/* FrameType has a value that indicates a standard or proprietary type */
/* that is not known to this node. */
/* FIXME: change this if you add a proprietary type */
else if /*( */ (mstp_port->FrameType >=
FRAME_TYPE_PROPRIETARY_MIN) { /*&& */
/*(FrameType <= FRAME_TYPE_PROPRIETARY_MAX)) */
/* unnecessary if FrameType is uint8_t with max of 255 */
/* an unexpected or unwanted frame was received. */
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedToken */
else if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
&& (mstp_port->FrameType == FRAME_TYPE_TOKEN)) {
mstp_port->ReceivedValidFrame = false;
mstp_port->FrameCount = 0;
mstp_port->SoleMaster = false;
mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN;
}
/* ReceivedPFM */
else if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
&& (mstp_port->FrameType == FRAME_TYPE_POLL_FOR_MASTER)) {
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER,
mstp_port->SourceAddress, mstp_port->This_Station,
NULL, 0);
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedDataNoReply */
/* or a proprietary type known to this node that does not expect a reply */
else if (((mstp_port->DestinationAddress ==
mstp_port->This_Station)
|| (mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS))
&& ((mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY) ||
/* (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || */
(mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE))) {
/* indicate successful reception to the higher layers */
mstp_put_receive(mstp_port);
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedDataNeedingReply */
/* or a proprietary type known to this node that expects a reply */
else if ((mstp_port->DestinationAddress ==
mstp_port->This_Station)
&& ((mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) ||
/* (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY) || */
(mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) {
mstp_port->ReplyPostponedTimer = 0;
/* indicate successful reception to the higher layers */
/* (management entity in the case of Test_Request); */
mstp_put_receive(mstp_port);
mstp_port->ReceivedValidFrame = false;
mstp_port->master_state =
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST;
}
/* BroadcastDataNeedingReply */
else if ((mstp_port->DestinationAddress ==
MSTP_BROADCAST_ADDRESS)
&& (mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY))
{
/* indicate successful reception to the higher layers */
mstp_put_receive(mstp_port);
mstp_port->ReceivedValidFrame = false;
/* wait for the next frame */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
}
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:
/* NothingToSend */
if (!mstp_port->TxReady)
{
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
}
else
{
uint8_t destination = mstp_port->TxBuffer[3];
RS485_Send_Frame(
mstp_port,
(uint8_t *) &mstp_port->TxBuffer[0],
mstp_port->TxLength);
mstp_port->TxReady = false;
mstp_port->FrameCount++;
/* SendNoWait */
/* There is a frame awaiting transmission that */
/* is of type Test_Response, BACnet Data Not Expecting Reply, */
/* or a proprietary type that does not expect a reply, */
if ((mstp_port->TxFrameType == FRAME_TYPE_TEST_RESPONSE) ||
(mstp_port->TxFrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY) ||
((mstp_port->TxFrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) &&
(destination == MSTP_BROADCAST_ADDRESS)))
{
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
}
/* SendAndWait */
/* If there is a frame awaiting transmission that is of */
/* type Test_Request, BACnet Data Expecting Reply, or */
/* a proprietary type that expects a reply, */
else if ((mstp_port->TxFrameType == FRAME_TYPE_TEST_REQUEST) ||
(mstp_port->TxFrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY))
{
mstp_port->master_state = MSTP_MASTER_STATE_WAIT_FOR_REPLY;
}
}
/* In the WAIT_FOR_REPLY state, the node waits for */
/* a reply from another node. */
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
/* ReplyTimeout */
if (mstp_port->SilenceTimer >= Treply_timeout) {
/* assume that the request has failed */
mstp_port->FrameCount = mstp_port->Nmax_info_frames;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
/* Any retry of the data frame shall await the next entry */
/* to the USE_TOKEN state. (Because of the length of the timeout, */
/* this transition will cause the token to be passed regardless */
/* of the initial value of FrameCount.) */
}
/* InvalidFrame */
else if ((mstp_port->SilenceTimer < Treply_timeout) &&
(mstp_port->ReceivedInvalidFrame == true)) {
/* error in frame reception */
mstp_port->ReceivedInvalidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
}
/* ReceivedReply */
/* or a proprietary type that indicates a reply */
else if ((mstp_port->SilenceTimer < Treply_timeout) &&
(mstp_port->ReceivedValidFrame == true) &&
(mstp_port->DestinationAddress == mstp_port->This_Station) &&
((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) ||
/*(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || */
(mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) {
/* indicate successful reception to the higher layers */
mstp_put_receive(mstp_port);
mstp_port->ReceivedValidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
}
/* ReceivedPostpone */
else if ((mstp_port->SilenceTimer < Treply_timeout) &&
(mstp_port->ReceivedValidFrame == true) &&
(mstp_port->DestinationAddress == mstp_port->This_Station) &&
(mstp_port->FrameType == FRAME_TYPE_REPLY_POSTPONED)) {
/* FIXME: then the reply to the message has been postponed until a later time. */
/* So, what does this really mean? */
mstp_port->ReceivedValidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN;
}
/* ReceivedUnexpectedFrame */
else if ((mstp_port->SilenceTimer < Treply_timeout) &&
(mstp_port->ReceivedValidFrame == true) &&
(mstp_port->DestinationAddress != mstp_port->This_Station))
/*the expected reply should not be broadcast) */
{
/* an unexpected frame was received */
/* This may indicate the presence of multiple tokens. */
mstp_port->ReceivedValidFrame = false;
/* Synchronize with the network. */
/* This action drops the token. */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* ReceivedUnexpectedFrame */
else if ((mstp_port->SilenceTimer < Treply_timeout) &&
(mstp_port->ReceivedValidFrame == true) &&
((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) ||
/*(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || */
(mstp_port->FrameType ==
FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) {
/* An unexpected frame was received. */
/* This may indicate the presence of multiple tokens. */
mstp_port->ReceivedValidFrame = false;
/* Synchronize with the network. */
/* This action drops the token. */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
break;
/* The DONE_WITH_TOKEN state either sends another data frame, */
/* passes the token, or initiates a Poll For Master cycle. */
case MSTP_MASTER_STATE_DONE_WITH_TOKEN:
/* SendAnotherFrame */
if (mstp_port->FrameCount < mstp_port->Nmax_info_frames) {
/* then this node may send another information frame */
/* before passing the token. */
mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN;
}
/* SoleMaster */
else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) &&
/* Npoll changed in Errata SSPC-135-2004 */
(mstp_port->TokenCount < (Npoll-1)) &&
(mstp_port->SoleMaster == true)) {
/* there are no other known master nodes to */
/* which the token may be sent (true master-slave operation). */
mstp_port->FrameCount = 0;
mstp_port->TokenCount++;
mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN;
}
/* SendToken */
else if (((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) &&
/* Npoll changed in Errata SSPC-135-2004 */
(mstp_port->TokenCount < (Npoll-1)) &&
(mstp_port->SoleMaster == false)) ||
/* The comparison of NS and TS+1 eliminates the Poll For Master */
/* if there are no addresses between TS and NS, since there is no */
/* address at which a new master node may be found in that case. */
(mstp_port->Next_Station == next_poll_neighbor)) {
mstp_port->TokenCount++;
/* transmit a Token frame to NS */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TOKEN,
mstp_port->Next_Station, mstp_port->This_Station, NULL, 0);
mstp_port->RetryCount = 0;
mstp_port->EventCount = 0;
mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
}
/* SendMaintenancePFM */
else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) &&
/* Npoll changed in Errata SSPC-135-2004 */
(mstp_port->TokenCount >= (Npoll-1)) &&
(next_poll_station != mstp_port->Next_Station)) {
mstp_port->Poll_Station = next_poll_station;
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_POLL_FOR_MASTER, mstp_port->Poll_Station,
mstp_port->This_Station, NULL, 0);
mstp_port->RetryCount = 0;
mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER;
}
/* ResetMaintenancePFM */
else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) &&
/* Npoll changed in Errata SSPC-135-2004 */
(mstp_port->TokenCount >= (Npoll-1)) &&
(next_poll_station == mstp_port->Next_Station)
&& (mstp_port->SoleMaster == false)) {
mstp_port->Poll_Station = mstp_port->This_Station;
/* transmit a Token frame to NS */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TOKEN,
mstp_port->Next_Station, mstp_port->This_Station, NULL, 0);
mstp_port->RetryCount = 0;
mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */
mstp_port->EventCount = 0;
mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
}
/* SoleMasterRestartMaintenancePFM */
else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) &&
/* Npoll changed in Errata SSPC-135-2004 */
(mstp_port->TokenCount >= (Npoll-1)) &&
(next_poll_station == mstp_port->Next_Station)
&& (mstp_port->SoleMaster == true)) {
mstp_port->Poll_Station = next_poll_station;
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_POLL_FOR_MASTER, mstp_port->Poll_Station,
mstp_port->This_Station, NULL, 0);
/* no known successor node */
mstp_port->Next_Station = mstp_port->This_Station;
mstp_port->RetryCount = 0;
mstp_port->TokenCount = 1; /* changed in Errata SSPC-135-2004 */
/* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */
/* find a new successor to TS */
mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER;
}
/* The PASS_TOKEN state listens for a successor to begin using */
/* the token that this node has just attempted to pass. */
case MSTP_MASTER_STATE_PASS_TOKEN:
/* SawTokenUser */
if ((mstp_port->SilenceTimer < Tusage_timeout) &&
(mstp_port->EventCount > Nmin_octets)) {
/* Assume that a frame has been sent by the new token user. */
/* Enter the IDLE state to process the frame. */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* RetrySendToken */
else if ((mstp_port->SilenceTimer >= Tusage_timeout) &&
(mstp_port->RetryCount < Nretry_token)) {
mstp_port->RetryCount++;
/* Transmit a Token frame to NS */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TOKEN,
mstp_port->Next_Station, mstp_port->This_Station, NULL, 0);
mstp_port->EventCount = 0;
/* re-enter the current state to listen for NS */
/* to begin using the token. */
}
/* FindNewSuccessor */
else if ((mstp_port->SilenceTimer >= Tusage_timeout) &&
(mstp_port->RetryCount >= Nretry_token)) {
/* Assume that NS has failed. */
mstp_port->Poll_Station = next_station;
/* Transmit a Poll For Master frame to PS. */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_POLL_FOR_MASTER,
mstp_port->Poll_Station, mstp_port->This_Station, NULL, 0);
/* no known successor node */
mstp_port->Next_Station = mstp_port->This_Station;
mstp_port->RetryCount = 0;
mstp_port->TokenCount = 0;
/* mstp_port->EventCount = 0; removed in Addendum 135-2004d-8 */
/* find a new successor to TS */
mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER;
}
break;
/* The NO_TOKEN state is entered if mstp_port->SilenceTimer becomes greater */
/* than Tno_token, indicating that there has been no network activity */
/* for that period of time. The timeout is continued to determine */
/* whether or not this node may create a token. */
case MSTP_MASTER_STATE_NO_TOKEN:
/* SawFrame */
if ((mstp_port->SilenceTimer <
(Tno_token + (Tslot * mstp_port->This_Station)))
&& (mstp_port->EventCount > Nmin_octets)) {
/* Some other node exists at a lower address. */
/* Enter the IDLE state to receive and process the incoming frame. */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* GenerateToken */
else if ((mstp_port->SilenceTimer >=
(Tno_token + (Tslot * mstp_port->This_Station)))
&& (mstp_port->SilenceTimer <
(Tno_token + (Tslot * (mstp_port->This_Station + 1))))) {
/* Assume that this node is the lowest numerical address */
/* on the network and is empowered to create a token. */
mstp_port->Poll_Station = next_poll_neighbor;
/* Transmit a Poll For Master frame to PS. */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_POLL_FOR_MASTER,
mstp_port->Poll_Station, mstp_port->This_Station, NULL, 0);
/* indicate that the next station is unknown */
mstp_port->Next_Station = mstp_port->This_Station;
mstp_port->RetryCount = 0;
mstp_port->TokenCount = 0;
/* mstp_port->EventCount = 0; removed Addendum 135-2004d-8 */
/* enter the POLL_FOR_MASTER state to find a new successor to TS. */
mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER;
}
break;
/* In the POLL_FOR_MASTER state, the node listens for a reply to */
/* a previously sent Poll For Master frame in order to find */
/* a successor node. */
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
/* ReceivedReplyToPFM */
if ((mstp_port->ReceivedValidFrame == true) &&
(mstp_port->DestinationAddress == mstp_port->This_Station) &&
(mstp_port->FrameType == FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER))
{
mstp_port->SoleMaster = false;
mstp_port->Next_Station = mstp_port->SourceAddress;
mstp_port->EventCount = 0;
/* Transmit a Token frame to NS */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TOKEN,
mstp_port->Next_Station, mstp_port->This_Station, NULL, 0);
mstp_port->Poll_Station = mstp_port->This_Station;
mstp_port->TokenCount = 0;
mstp_port->RetryCount = 0;
mstp_port->ReceivedValidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
}
/* ReceivedUnexpectedFrame */
else if ((mstp_port->ReceivedValidFrame == true) &&
((mstp_port->DestinationAddress != mstp_port->This_Station) ||
(mstp_port->FrameType !=
FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER))) {
/* An unexpected frame was received. */
/* This may indicate the presence of multiple tokens. */
mstp_port->ReceivedValidFrame = false;
/* enter the IDLE state to synchronize with the network. */
/* This action drops the token. */
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* SoleMaster */
else if ((mstp_port->SoleMaster == true) &&
((mstp_port->SilenceTimer >= Tusage_timeout) ||
(mstp_port->ReceivedInvalidFrame == true))) {
/* There was no valid reply to the periodic poll */
/* by the sole known master for other masters. */
mstp_port->FrameCount = 0;
/* mstp_port->TokenCount++; removed in 2004 */
mstp_port->ReceivedInvalidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN;
}
/* DoneWithPFM */
else if ((mstp_port->SoleMaster == false) &&
(mstp_port->Next_Station != mstp_port->This_Station) &&
((mstp_port->SilenceTimer >= Tusage_timeout) ||
(mstp_port->ReceivedInvalidFrame == true))) {
/* There was no valid reply to the maintenance */
/* poll for a master at address PS. */
mstp_port->EventCount = 0;
/* transmit a Token frame to NS */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_TOKEN,
mstp_port->Next_Station, mstp_port->This_Station, NULL, 0);
mstp_port->RetryCount = 0;
mstp_port->ReceivedInvalidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
}
/* SendNextPFM */
else if ((mstp_port->SoleMaster == false) &&
(mstp_port->Next_Station == mstp_port->This_Station) && /* no known successor node */
(next_poll_station != mstp_port->This_Station) &&
((mstp_port->SilenceTimer >= Tusage_timeout)
|| (mstp_port->ReceivedInvalidFrame == true))) {
mstp_port->Poll_Station = next_poll_station;
/* Transmit a Poll For Master frame to PS. */
MSTP_Create_And_Send_Frame(mstp_port,
FRAME_TYPE_POLL_FOR_MASTER,
mstp_port->Poll_Station, mstp_port->This_Station, NULL, 0);
mstp_port->RetryCount = 0;
mstp_port->ReceivedInvalidFrame = false;
/* Re-enter the current state. */
}
/* DeclareSoleMaster */
else if ((mstp_port->SoleMaster == false) && (mstp_port->Next_Station == mstp_port->This_Station) && /* no known successor node */
(next_poll_station == mstp_port->This_Station)
&& ((mstp_port->SilenceTimer >= Tusage_timeout)
|| (mstp_port->ReceivedInvalidFrame == true))) {
/* to indicate that this station is the only master */
mstp_port->SoleMaster = true;
mstp_port->FrameCount = 0;
mstp_port->ReceivedInvalidFrame = false;
mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN;
}
break;
/* The ANSWER_DATA_REQUEST state is entered when a */
/* 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 (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. */
/* 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. */
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->Index);
}
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
}
/* */
/* 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. */
else {
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;
}
break;
default:
mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
break;
}
return;
}
void MSTP_Init(volatile struct mstp_port_struct_t *mstp_port,
uint8_t this_station_mac)
{
int i; /*loop counter */
if (mstp_port) {
mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE;
mstp_port->ReceiveError = false;
mstp_port->DataAvailable = false;
mstp_port->DataRegister = 0;
mstp_port->DataCRC = 0;
mstp_port->DataCRC = 0;
mstp_port->DataLength = 0;
mstp_port->DestinationAddress = 0;
mstp_port->EventCount = 0;
mstp_port->FrameType = FRAME_TYPE_TOKEN;
mstp_port->FrameCount = 0;
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 = this_station_mac;
mstp_port->Poll_Station = this_station_mac;
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->This_Station = this_station_mac;
mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES;
mstp_port->Nmax_master = DEFAULT_MAX_MASTER;
}
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
/* test stub functions */
void RS485_Send_Frame(volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes)
{ /* number of bytes of data (up to 501) */
(void) mstp_port;
(void) buffer;
(void) nbytes;
}
#define RING_BUFFER_DATA_SIZE 1
#define RING_BUFFER_SIZE MAX_MPDU
static RING_BUFFER Test_Buffer;
static uint8_t Test_Buffer_Data[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
static void Load_Input_Buffer(uint8_t * buffer, size_t len)
{
static bool initialized = false; /* tracks our init */
if (!initialized) {
initialized = true;
Ringbuf_Init(&Test_Buffer,
(char *) Test_Buffer_Data,
RING_BUFFER_DATA_SIZE, RING_BUFFER_SIZE);
}
/* empty any the existing data */
while (!Ringbuf_Empty(&Test_Buffer)) {
(void) Ringbuf_Pop_Front(&Test_Buffer);
}
if (buffer) {
while (len) {
(void) Ringbuf_Put(&Test_Buffer, (char *) buffer);
len--;
buffer++;
}
}
}
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
{ /* port specific data */
char *data;
if (!Ringbuf_Empty(&Test_Buffer) && mstp_port &&
(mstp_port->DataAvailable == false)) {
data = Ringbuf_Pop_Front(&Test_Buffer);
if (data) {
mstp_port->DataRegister = *data;
mstp_port->DataAvailable = true;
}
}
}
void testReceiveNodeFSM(Test * pTest)
{
volatile struct mstp_port_struct_t mstp_port; /* port data */
unsigned EventCount = 0; /* local counter */
uint8_t my_mac = 0x05; /* local MAC address */
uint8_t HeaderCRC = 0; /* for local CRC calculation */
uint8_t FrameType = 0; /* type of packet that was sent */
unsigned len; /* used for the size of the message packet */
size_t i; /* used to loop through the message bytes */
uint8_t buffer[MAX_MPDU] = { 0 };
uint8_t data[MAX_MPDU - 8 /*header */ - 2 /*CRC*/] = { 0 };
MSTP_Init(&mstp_port, my_mac);
/* check the receive error during idle */
mstp_port.receive_state = MSTP_RECEIVE_STATE_IDLE;
mstp_port.ReceiveError = true;
mstp_port.SilenceTimer = 255;
mstp_port.EventCount = 0;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.ReceiveError == false);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for bad packet header */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x11;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for good packet header, but timeout */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
/* force the timeout */
mstp_port.SilenceTimer = Tframe_abort + 1;
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for good packet header preamble, but receive error */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
/* force the error */
mstp_port.ReceiveError = true;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceiveError == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for good packet header preamble1, but bad preamble2 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
MSTP_Receive_Frame_FSM(&mstp_port);
/* no change of state if no data yet */
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
/* repeated preamble1 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
/* repeated preamble1 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
/* bad data */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x11;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceiveError == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for good packet header preamble, but timeout in packet */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
MSTP_Receive_Frame_FSM(&mstp_port);
/* preamble2 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0xFF;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 0);
ct_test(pTest, mstp_port.HeaderCRC == 0xFF);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
/* force the timeout */
mstp_port.SilenceTimer = Tframe_abort + 1;
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
ct_test(pTest, mstp_port.ReceivedInvalidFrame == true);
/* check for good packet header preamble, but error in packet */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
MSTP_Receive_Frame_FSM(&mstp_port);
/* preamble2 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0xFF;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 0);
ct_test(pTest, mstp_port.HeaderCRC == 0xFF);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
/* force the error */
mstp_port.ReceiveError = true;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceiveError == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* check for good packet header preamble */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x55;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE);
MSTP_Receive_Frame_FSM(&mstp_port);
/* preamble2 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0xFF;
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 0);
ct_test(pTest, mstp_port.HeaderCRC == 0xFF);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
/* no change of state if no data yet */
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
/* Data is received - index is incremented */
/* FrameType */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = FRAME_TYPE_TOKEN;
HeaderCRC = 0xFF;
HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 1);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
ct_test(pTest, FrameType == FRAME_TYPE_TOKEN);
/* Destination */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0x10;
HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 2);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
ct_test(pTest, mstp_port.DestinationAddress == 0x10);
/* Source */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = my_mac;
HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 3);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
ct_test(pTest, mstp_port.SourceAddress == my_mac);
/* Length1 = length*256 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0;
HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 4);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
ct_test(pTest, mstp_port.DataLength == 0);
/* Length2 */
mstp_port.DataAvailable = true;
mstp_port.DataRegister = 0;
HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister, HeaderCRC);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 5);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER);
ct_test(pTest, mstp_port.DataLength == 0);
/* HeaderCRC */
mstp_port.DataAvailable = true;
ct_test(pTest, HeaderCRC == 0x73); /* per Annex G example */
mstp_port.DataRegister = ~HeaderCRC; /* one's compliment of CRC is sent */
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
ct_test(pTest, mstp_port.Index == 5);
ct_test(pTest,
mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC);
ct_test(pTest, mstp_port.HeaderCRC == 0x55);
/* NotForUs */
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* BadCRC in header check */
mstp_port.ReceivedInvalidFrame = false;
mstp_port.ReceivedValidFrame = false;
len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, 0x10, /* destination */
my_mac, /* source */
NULL, /* data */
0); /* data size */
ct_test(pTest, len > 0);
/* make the header CRC bad */
buffer[7] = 0x00;
Load_Input_Buffer(buffer, len);
for (i = 0; i < len; i++) {
RS485_Check_UART_Data(&mstp_port);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
}
ct_test(pTest,
mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceivedInvalidFrame == true);
ct_test(pTest, mstp_port.ReceivedValidFrame == false);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* NoData for us */
mstp_port.ReceivedInvalidFrame = false;
mstp_port.ReceivedValidFrame = false;
len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */
my_mac, /* source */
NULL, /* data */
0); /* data size */
ct_test(pTest, len > 0);
Load_Input_Buffer(buffer, len);
for (i = 0; i < len; i++) {
RS485_Check_UART_Data(&mstp_port);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
}
ct_test(pTest,
mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceivedInvalidFrame == false);
ct_test(pTest, mstp_port.ReceivedValidFrame == true);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* FrameTooLong */
mstp_port.ReceivedInvalidFrame = false;
mstp_port.ReceivedValidFrame = false;
len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_TOKEN, my_mac, /* destination */
my_mac, /* source */
NULL, /* data */
0); /* data size */
ct_test(pTest, len > 0);
/* make the header data length bad */
buffer[5] = 0x02;
Load_Input_Buffer(buffer, len);
for (i = 0; i < len; i++) {
RS485_Check_UART_Data(&mstp_port);
INCREMENT_AND_LIMIT_UINT8(EventCount);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.DataAvailable == false);
ct_test(pTest, mstp_port.SilenceTimer == 0);
ct_test(pTest, mstp_port.EventCount == EventCount);
}
ct_test(pTest,
mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC);
MSTP_Receive_Frame_FSM(&mstp_port);
ct_test(pTest, mstp_port.ReceivedInvalidFrame == true);
ct_test(pTest, mstp_port.ReceivedValidFrame == false);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
/* Data */
mstp_port.ReceivedInvalidFrame = false;
mstp_port.ReceivedValidFrame = false;
memset(data, 0, sizeof(data));
len = MSTP_Create_Frame(buffer, sizeof(buffer), FRAME_TYPE_PROPRIETARY_MIN, my_mac, /* destination */
my_mac, /* source */
data, /* data */
sizeof(data)); /* data size */
ct_test(pTest, len > 0);
Load_Input_Buffer(buffer, len);
RS485_Check_UART_Data(&mstp_port);
MSTP_Receive_Frame_FSM(&mstp_port);
while (mstp_port.receive_state != MSTP_RECEIVE_STATE_IDLE) {
RS485_Check_UART_Data(&mstp_port);
MSTP_Receive_Frame_FSM(&mstp_port);
}
ct_test(pTest, mstp_port.DataLength == sizeof(data));
ct_test(pTest, mstp_port.ReceivedInvalidFrame == false);
ct_test(pTest, mstp_port.ReceivedValidFrame == true);
ct_test(pTest, mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE);
return;
}
void testMasterNodeFSM(Test * pTest)
{
volatile struct mstp_port_struct_t mstp_port; /* port data */
uint8_t my_mac = 0x05; /* local MAC address */
MSTP_Init(&mstp_port, my_mac);
ct_test(pTest, mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE);
}
#endif
#ifdef TEST_MSTP
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("mstp", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testReceiveNodeFSM);
assert(rc);
rc = ct_addTestFunction(pTest, testMasterNodeFSM);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void) ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif