mirror of
				https://github.com/stargieg/bacnet-stack
				synced 2025-10-26 23:35:52 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			1279 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1279 lines
		
	
	
		
			58 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 */
 | |
| #if PRINT_ENABLED
 | |
| #define PRINT_ENABLED_RECEIVE 0
 | |
| #define PRINT_ENABLED_RECEIVE_DATA 1
 | |
| #define PRINT_ENABLED_MASTER 0
 | |
| #else
 | |
| #define PRINT_ENABLED_RECEIVE 0
 | |
| #define PRINT_ENABLED_RECEIVE_DATA 0
 | |
| #define PRINT_ENABLED_MASTER 0
 | |
| #endif
 | |
| 
 | |
| /* 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); */
 | |
| const uint16_t 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. */
 | |
| 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 = 250;
 | |
| 
 | |
| /* 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 = 30;
 | |
| 
 | |
| /* 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++;}
 | |
| 
 | |
| 
 | |
| 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 */
 | |
|     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] = HI_BYTE(data_len);
 | |
|     crc8 = CRC_Calc_Header(buffer[5], crc8);
 | |
|     buffer[6] = LO_BYTE(data_len);
 | |
|     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);
 | |
|     /* FIXME: be sure to reset SilenceTimer after each octet is sent! */
 | |
| }
 | |
| 
 | |
| /* 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_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
 | |
|     static MSTP_RECEIVE_STATE receive_state = MSTP_RECEIVE_STATE_IDLE;
 | |
| #endif
 | |
| #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),
 | |
|         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) {
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|                 fprintf(stderr, "MSTP Rx: %02X ", mstp_port->DataRegister);
 | |
| #endif
 | |
|                 /* 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 {
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|                     fprintf(stderr, "\n");
 | |
| #endif
 | |
|                     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) {
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|                 fprintf(stderr, "%02X ", mstp_port->DataRegister);
 | |
| #endif
 | |
|                 /* 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) {
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|                 fprintf(stderr, "%02X ", mstp_port->DataRegister);
 | |
| #endif
 | |
|                 /* 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;
 | |
|                     /* don't wait for next state - do it here */
 | |
|                     if (mstp_port->HeaderCRC != 0x55) {
 | |
|                         /* BadCRC */
 | |
|                         /* 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) {
 | |
|                                 /* CHEAT: it is very difficult to respond to
 | |
|                                    poll for master in the Master Node state machine
 | |
|                                    before Tusage_timeout, so we will do it here. */
 | |
|                                 if ((mstp_port->FrameType ==
 | |
|                                         FRAME_TYPE_POLL_FOR_MASTER)
 | |
|                                     && (mstp_port->DestinationAddress ==
 | |
|                                         mstp_port->This_Station)
 | |
|                                     && (mstp_port->master_state ==
 | |
|                                         MSTP_MASTER_STATE_IDLE)) {
 | |
|                                     MSTP_Create_And_Send_Frame(mstp_port,
 | |
|                                         FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER,
 | |
|                                         mstp_port->SourceAddress,
 | |
|                                         mstp_port->This_Station, NULL, 0);
 | |
|                                     /* don't indicate that a frame has been received */
 | |
|                                     mstp_port->ReceivedInvalidFrame = false;
 | |
|                                     mstp_port->ReceivedValidFrame = false;
 | |
|                                 } else {
 | |
|                                     /* 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;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
| 
 | |
|                 }
 | |
|                 /* 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 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) {
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|                 fprintf(stderr, "%02X ", mstp_port->DataRegister);
 | |
| #endif
 | |
|                 /* DataOctet */
 | |
|                 if (mstp_port->Index < mstp_port->DataLength) {
 | |
|                     mstp_port->DataCRC =
 | |
|                         CRC_Calc_Data(mstp_port->DataRegister,
 | |
|                         mstp_port->DataCRC);
 | |
|                     mstp_port->InputBuffer[mstp_port->Index] =
 | |
|                         mstp_port->DataRegister;
 | |
|                     mstp_port->Index++;
 | |
|                     mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA;
 | |
|                 }
 | |
|                 /* CRC1 */
 | |
|                 else if (mstp_port->Index == mstp_port->DataLength) {
 | |
|                     mstp_port->DataCRC =
 | |
|                         CRC_Calc_Data(mstp_port->DataRegister,
 | |
|                         mstp_port->DataCRC);
 | |
|                     mstp_port->Index++;
 | |
|                     mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA;
 | |
|                 }
 | |
|                 /* CRC2 */
 | |
|                 else if (mstp_port->Index == (mstp_port->DataLength + 1)) {
 | |
|                     mstp_port->DataCRC =
 | |
|                         CRC_Calc_Data(mstp_port->DataRegister,
 | |
|                         mstp_port->DataCRC);
 | |
|                     /* 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;
 | |
|                     else
 | |
|                         mstp_port->ReceivedInvalidFrame = true;
 | |
|                     mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
 | |
|                 }
 | |
|                 mstp_port->DataAvailable = false;
 | |
|                 mstp_port->SilenceTimer = 0;
 | |
|             }
 | |
|             break;
 | |
|         default:
 | |
|             /* shouldn't get here - but if we do... */
 | |
|             mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE;
 | |
|             break;
 | |
|     }
 | |
| #if PRINT_ENABLED_RECEIVE_DATA
 | |
|     if ((receive_state != MSTP_RECEIVE_STATE_IDLE) &&
 | |
|         (mstp_port->receive_state == MSTP_RECEIVE_STATE_IDLE)) {
 | |
|         fprintf(stderr, "\n");
 | |
|         fflush(stderr);
 | |
|     }
 | |
|     receive_state = mstp_port->receive_state;
 | |
| #endif
 | |
| 
 | |
|     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)
 | |
| {
 | |
|     int mtu_len = 0;
 | |
|     int frame_type = 0;
 | |
|     uint8_t next_poll_station = 0;
 | |
|     uint8_t next_this_station = 0;
 | |
|     uint8_t next_next_station = 0;
 | |
|     uint16_t my_timeout = 10, ns_timeout = 0;
 | |
|     /* transition immediately to the next state */
 | |
|     bool transition_now = false;
 | |
| #if PRINT_ENABLED_MASTER
 | |
|     static MSTP_MASTER_STATE master_state = MSTP_MASTER_STATE_INITIALIZE;
 | |
| #endif
 | |
| 
 | |
|     /* some calculations that several states need */
 | |
|     next_poll_station =
 | |
|         (mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1);
 | |
|     next_this_station =
 | |
|         (mstp_port->This_Station + 1) % (mstp_port->Nmax_master + 1);
 | |
|     next_next_station =
 | |
|         (mstp_port->Next_Station + 1) % (mstp_port->Nmax_master + 1);
 | |
| #if PRINT_ENABLED_MASTER
 | |
|     if (mstp_port->master_state != master_state) {
 | |
|         master_state = mstp_port->master_state;
 | |
|         fprintf(stderr,
 | |
|             "MSTP: TS=%02X[%02X] NS=%02X[%02X] PS=%02X[%02X] EC=%u TC=%u ST=%u %s\n",
 | |
|             mstp_port->This_Station, next_this_station,
 | |
|             mstp_port->Next_Station, next_next_station,
 | |
|             mstp_port->Poll_Station, next_poll_station, mstp_port->EventCount,
 | |
|             mstp_port->TokenCount, mstp_port->SilenceTimer,
 | |
|             mstp_master_state_text(mstp_port->master_state));
 | |
|     }
 | |
| #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->master_state = MSTP_MASTER_STATE_IDLE;
 | |
|             transition_now = true;
 | |
|             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;
 | |
|                 /* set the receive frame flags to false in case we received
 | |
|                    some bytes and had a timeout for some reason */
 | |
|                 mstp_port->ReceivedInvalidFrame = false;
 | |
|                 mstp_port->ReceivedValidFrame = false;
 | |
|                 transition_now = true;
 | |
|             }
 | |
|             /* ReceivedInvalidFrame */
 | |
|             else if (mstp_port->ReceivedInvalidFrame == true) {
 | |
|                 /* invalid frame was received */
 | |
|                 mstp_port->ReceivedInvalidFrame = false;
 | |
|                 /* wait for the next frame - remain in IDLE */
 | |
|             } else if (mstp_port->ReceivedValidFrame == true) {
 | |
| #if PRINT_ENABLED_MASTER
 | |
|                 fprintf(stderr,
 | |
|                     "MSTP: ReceivedValidFrame Src=%02X Dest=%02X DataLen=%u FC=%u ST=%u Type=%s\n",
 | |
|                     mstp_port->SourceAddress, mstp_port->DestinationAddress,
 | |
|                     mstp_port->DataLength, mstp_port->FrameCount,
 | |
|                     mstp_port->SilenceTimer,
 | |
|                     mstp_frame_type_text(mstp_port->FrameType));
 | |
| #endif
 | |
|                 /* destined for me! */
 | |
|                 if ((mstp_port->DestinationAddress == mstp_port->This_Station)
 | |
|                     || (mstp_port->DestinationAddress ==
 | |
|                         MSTP_BROADCAST_ADDRESS)) {
 | |
|                     switch (mstp_port->FrameType) {
 | |
|                             /* ReceivedToken */
 | |
|                         case FRAME_TYPE_TOKEN:
 | |
|                             /* tokens can't be broadcast */
 | |
|                             if (mstp_port->DestinationAddress ==
 | |
|                                 MSTP_BROADCAST_ADDRESS)
 | |
|                                 break;
 | |
|                             mstp_port->ReceivedValidFrame = false;
 | |
|                             mstp_port->FrameCount = 0;
 | |
|                             mstp_port->SoleMaster = false;
 | |
|                             mstp_port->master_state =
 | |
|                                 MSTP_MASTER_STATE_USE_TOKEN;
 | |
|                             transition_now = true;
 | |
|                             break;
 | |
|                             /* ReceivedPFM */
 | |
|                         case FRAME_TYPE_POLL_FOR_MASTER:
 | |
|                             /* CHEAT: we cheat a little and this is really handled in the
 | |
|                                receive state machine since it is difficult to respond
 | |
|                                quick enough (i.e. faster than Tusage_timeout of the
 | |
|                                other node which could be 20ms). */
 | |
|                             MSTP_Create_And_Send_Frame(mstp_port,
 | |
|                                 FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER,
 | |
|                                 mstp_port->SourceAddress,
 | |
|                                 mstp_port->This_Station, NULL, 0);
 | |
|                             break;
 | |
|                         case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
 | |
|                             /* indicate successful reception to the higher layers */
 | |
|                             dlmstp_put_receive(mstp_port->SourceAddress,
 | |
|                                 (uint8_t *) & mstp_port->InputBuffer[0],
 | |
|                                 mstp_port->DataLength);
 | |
|                             break;
 | |
|                         case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
 | |
|                             mstp_port->ReplyPostponedTimer = 0;
 | |
|                             /* indicate successful reception to the higher layers  */
 | |
|                             dlmstp_put_receive(mstp_port->SourceAddress,        /* source MS/TP address */
 | |
|                                 (uint8_t *) & mstp_port->InputBuffer[0],
 | |
|                                 mstp_port->DataLength);
 | |
|                             /* broadcast DER just remains IDLE */
 | |
|                             if (mstp_port->DestinationAddress !=
 | |
|                                 MSTP_BROADCAST_ADDRESS) {
 | |
|                                 mstp_port->master_state =
 | |
|                                     MSTP_MASTER_STATE_ANSWER_DATA_REQUEST;
 | |
|                                 transition_now = true;
 | |
|                             }
 | |
|                             break;
 | |
|                         case 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);
 | |
|                             break;
 | |
|                         case FRAME_TYPE_TEST_RESPONSE:
 | |
|                         default:
 | |
|                             break;
 | |
|                     }
 | |
|                 }
 | |
|                 mstp_port->ReceivedValidFrame = false;
 | |
|             }
 | |
|             break;
 | |
|             /* In the USE_TOKEN state, the node is allowed to send one or  */
 | |
|             /* more data frames. These may be BACnet Data frames or */
 | |
|             /* proprietary frames. */
 | |
|         case MSTP_MASTER_STATE_USE_TOKEN:
 | |
|             if (!mstp_port->TxReady) {
 | |
|                 /* NothingToSend */
 | |
|                 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->FrameCount++;
 | |
|                 switch (mstp_port->TxFrameType) {
 | |
|                     case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY:
 | |
|                         /* SendAndWait */
 | |
|                         if (destination == MSTP_BROADCAST_ADDRESS)
 | |
|                             mstp_port->master_state =
 | |
|                                 MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                         else
 | |
|                             mstp_port->master_state =
 | |
|                                 MSTP_MASTER_STATE_WAIT_FOR_REPLY;
 | |
|                         break;
 | |
|                     case FRAME_TYPE_TEST_REQUEST:
 | |
|                         mstp_port->master_state =
 | |
|                             MSTP_MASTER_STATE_WAIT_FOR_REPLY;
 | |
|                         break;
 | |
|                     case FRAME_TYPE_TEST_RESPONSE:
 | |
|                     case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
 | |
|                     default:
 | |
|                         /* SendNoWait */
 | |
|                         mstp_port->master_state =
 | |
|                             MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                         break;
 | |
|                 }
 | |
|                 mstp_port->TxReady = false;
 | |
|             }
 | |
|             transition_now = true;
 | |
|             break;
 | |
|             /* In the WAIT_FOR_REPLY state, the node waits for  */
 | |
|             /* a reply from another node. */
 | |
|         case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
 | |
|             if (mstp_port->SilenceTimer >= Treply_timeout) {
 | |
|                 /* ReplyTimeout */
 | |
|                 /* 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.) */
 | |
|                 transition_now = true;
 | |
|             } else {
 | |
|                 if (mstp_port->ReceivedInvalidFrame == true) {
 | |
|                     /* InvalidFrame */
 | |
|                     /* error in frame reception */
 | |
|                     mstp_port->ReceivedInvalidFrame = false;
 | |
|                     mstp_port->master_state =
 | |
|                         MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                     transition_now = true;
 | |
|                 } else if (mstp_port->ReceivedValidFrame == true) {
 | |
|                     if (mstp_port->DestinationAddress ==
 | |
|                         mstp_port->This_Station) {
 | |
|                         switch (mstp_port->TxFrameType) {
 | |
|                             case FRAME_TYPE_REPLY_POSTPONED:
 | |
|                                 /* ReceivedReplyPostponed */
 | |
|                                 mstp_port->master_state =
 | |
|                                     MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                                 break;
 | |
|                             case FRAME_TYPE_TEST_RESPONSE:
 | |
|                                 mstp_port->master_state =
 | |
|                                     MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                                 break;
 | |
|                             case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY:
 | |
|                                 /* ReceivedReply */
 | |
|                                 /* or a proprietary type that indicates a reply */
 | |
|                                 /* indicate successful reception to the higher layers */
 | |
|                                 dlmstp_put_receive(mstp_port->SourceAddress,    /* source MS/TP address */
 | |
|                                     (uint8_t *) & mstp_port->InputBuffer[0],
 | |
|                                     mstp_port->DataLength);
 | |
|                                 mstp_port->master_state =
 | |
|                                     MSTP_MASTER_STATE_DONE_WITH_TOKEN;
 | |
|                                 break;
 | |
|                             default:
 | |
|                                 /* if proprietary frame was expected, you might
 | |
|                                    need to transition to DONE WITH TOKEN */
 | |
|                                 mstp_port->master_state =
 | |
|                                     MSTP_MASTER_STATE_IDLE;
 | |
|                                 break;
 | |
|                         }
 | |
|                     } else {
 | |
|                         /* ReceivedUnexpectedFrame */
 | |
|                         /* an unexpected frame was received */
 | |
|                         /* This may indicate the presence of multiple tokens.  */
 | |
|                         /* Synchronize with the network. */
 | |
|                         /* This action drops the token. */
 | |
|                         mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
 | |
|                     }
 | |
|                     mstp_port->ReceivedValidFrame = false;
 | |
|                     transition_now = true;
 | |
|                 }
 | |
|             }
 | |
|             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;
 | |
|             } else if ((mstp_port->SoleMaster == false) &&
 | |
|                 (mstp_port->Next_Station == mstp_port->This_Station)) {
 | |
|                 /* NextStationUnknown - added in Addendum 135-2008v-1 */
 | |
|                 /*  then the next station to which the token
 | |
|                    should be sent is unknown - so PollForMaster */
 | |
|                 mstp_port->Poll_Station = next_this_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;
 | |
|             }
 | |
|             /* Npoll changed in Errata SSPC-135-2004 */
 | |
|             else if (mstp_port->TokenCount < (Npoll - 1)) {
 | |
|                 if ((mstp_port->SoleMaster == true) &&
 | |
|                     (mstp_port->Next_Station != next_this_station)) {
 | |
|                     /* SoleMaster */
 | |
|                     /* 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;
 | |
|                 } else {
 | |
|                     /* SendToken */
 | |
|                     /* Npoll changed in Errata SSPC-135-2004 */
 | |
|                     /* 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->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;
 | |
|                 }
 | |
|             } else if (next_poll_station == mstp_port->Next_Station) {
 | |
|                 if (mstp_port->SoleMaster == true) {
 | |
|                     /* SoleMasterRestartMaintenancePFM */
 | |
|                     mstp_port->Poll_Station = next_next_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;
 | |
|                 } else {
 | |
|                     /* ResetMaintenancePFM */
 | |
|                     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;
 | |
|                 }
 | |
|             } else {
 | |
|                 /* SendMaintenancePFM */
 | |
|                 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;
 | |
|             }
 | |
|             transition_now = true;
 | |
|             break;
 | |
|             /* 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:
 | |
|             if (mstp_port->SilenceTimer < Tusage_timeout) {
 | |
|                 if (mstp_port->EventCount > Nmin_octets) {
 | |
|                     /* SawTokenUser */
 | |
|                     /* 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;
 | |
|                     transition_now = true;
 | |
|                 }
 | |
|             } else {
 | |
|                 if (mstp_port->RetryCount < Nretry_token) {
 | |
|                     /* RetrySendToken */
 | |
|                     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. */
 | |
|                 } else {
 | |
|                     /* FindNewSuccessor */
 | |
|                     /* Assume that NS has failed.  */
 | |
|                     /* note: if NS=TS-1, this node could send PFM to self! */
 | |
|                     mstp_port->Poll_Station = next_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;
 | |
|                     transition_now = true;
 | |
|                 }
 | |
|             }
 | |
|             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:
 | |
|             my_timeout = Tno_token + (Tslot * mstp_port->This_Station);
 | |
|             if (mstp_port->SilenceTimer < my_timeout) {
 | |
|                 if (mstp_port->EventCount > Nmin_octets) {
 | |
|                     /* SawFrame */
 | |
|                     /* 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;
 | |
|                     transition_now = true;
 | |
|                 }
 | |
|             } else {
 | |
|                 ns_timeout =
 | |
|                     Tno_token + (Tslot * (mstp_port->This_Station + 1));
 | |
|                 if (mstp_port->SilenceTimer < ns_timeout) {
 | |
|                     /* GenerateToken */
 | |
|                     /* Assume that this node is the lowest numerical address  */
 | |
|                     /* on the network and is empowered to create a token.  */
 | |
|                     mstp_port->Poll_Station = next_this_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);
 | |
|                     /* 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;
 | |
|                     transition_now = true;
 | |
|                 }
 | |
|             }
 | |
|             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:
 | |
|             if (mstp_port->ReceivedValidFrame == true) {
 | |
|                 if ((mstp_port->DestinationAddress == mstp_port->This_Station)
 | |
|                     && (mstp_port->FrameType ==
 | |
|                         FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) {
 | |
|                     /* ReceivedReplyToPFM */
 | |
|                     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->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
 | |
|                 } else {
 | |
|                     /* ReceivedUnexpectedFrame */
 | |
|                     /* An unexpected frame was received.  */
 | |
|                     /* This may indicate the presence of multiple tokens. */
 | |
|                     /* enter the IDLE state to synchronize with the network.  */
 | |
|                     /* This action drops the token. */
 | |
|                     mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
 | |
|                 }
 | |
|                 mstp_port->ReceivedValidFrame = false;
 | |
|                 transition_now = true;
 | |
|             } else if ((mstp_port->SilenceTimer >= Tusage_timeout) ||
 | |
|                 (mstp_port->ReceivedInvalidFrame == true)) {
 | |
|                 if (mstp_port->SoleMaster == true) {
 | |
|                     /* SoleMaster */
 | |
|                     /* 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->master_state = MSTP_MASTER_STATE_USE_TOKEN;
 | |
|                 } else {
 | |
|                     if (mstp_port->Next_Station != mstp_port->This_Station) {
 | |
|                         /* DoneWithPFM */
 | |
|                         /* 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->master_state = MSTP_MASTER_STATE_PASS_TOKEN;
 | |
|                     } else {
 | |
|                         if (next_poll_station != mstp_port->This_Station) {
 | |
|                             /* SendNextPFM */
 | |
|                             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;
 | |
|                             /* Re-enter the current state. */
 | |
|                         } else {
 | |
|                             /* DeclareSoleMaster */
 | |
|                             /* to indicate that this station is the only master */
 | |
|                             mstp_port->SoleMaster = true;
 | |
|                             mstp_port->FrameCount = 0;
 | |
|                             mstp_port->master_state =
 | |
|                                 MSTP_MASTER_STATE_USE_TOKEN;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 mstp_port->ReceivedInvalidFrame = false;
 | |
|                 transition_now = true;
 | |
|             }
 | |
|             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 0
 | |
|             if (mstp_port->ReplyPostponedTimer <= Treply_delay) {
 | |
|                 /* 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 */
 | |
|                 }
 | |
|             } else
 | |
| #endif
 | |
|                 /* DeferredReply */
 | |
|                 /* If no reply will be available from the higher layers */
 | |
|                 /* within Treply_delay after the reception of the */
 | |
|                 /* final octet of the requesting frame (the mechanism */
 | |
|                 /* used to determine this is a local matter), */
 | |
|                 /* then an immediate reply is not possible. */
 | |
|                 /* Any reply shall wait until this node receives the token. */
 | |
|                 /* Call MSTP_Create_And_Send_Frame to transmit a Reply Postponed frame, */
 | |
|                 /* and enter the IDLE state. */
 | |
|             {
 | |
|                 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;
 | |
|                 transition_now = true;
 | |
|             }
 | |
|             break;
 | |
|         default:
 | |
|             mstp_port->master_state = MSTP_MASTER_STATE_IDLE;
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     return transition_now;
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 
 | |
|         /* 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;
 | |
| 
 | |
|     }
 | |
| }
 | 
