diff --git a/bacnet-stack/bacdef.h b/bacnet-stack/bacdef.h index dc7efe04..60a0d00f 100644 --- a/bacnet-stack/bacdef.h +++ b/bacnet-stack/bacdef.h @@ -56,21 +56,14 @@ #define BACNET_MIN_PRIORITY 1 #define BACNET_MAX_PRIORITY 16 -/* embedded systems need fixed name sizes */ -#define MAX_OBJECT_NAME 10 -/* common object properties */ -typedef struct BACnet_Object_Data { - uint32_t Object_Identifier; - char Object_Name[MAX_OBJECT_NAME]; - BACNET_OBJECT_TYPE Object_Type; -} BACNET_OBJECT_DATA; - #define BACNET_BROADCAST_NETWORK 0xFFFF /* IPv6 (16 octets) coupled with port number (2 octets) */ +/* note: you could be lame and only support 6 octets */ +/* FIXME: mac[] only needs to be as big as our datalink MAC */ #define MAX_MAC_LEN 18 struct BACnet_Device_Address { /* mac_len = 0 if global address */ - int mac_len; + uint8_t mac_len; /* note: MAC for IP addresses uses 4 bytes for addr, 2 bytes for port */ /* use de/encode_unsigned32/16 for re/storing the IP address */ uint8_t mac[MAX_MAC_LEN]; @@ -80,7 +73,7 @@ struct BACnet_Device_Address { uint16_t net; /* BACnet network number */ /* LEN = 0 denotes broadcast MAC ADR and ADR field is absent */ /* LEN > 0 specifies length of ADR field */ - int len; /* length of MAC address */ + uint8_t len; /* length of MAC address */ uint8_t adr[MAX_MAC_LEN]; /* hwaddr (MAC) address */ }; typedef struct BACnet_Device_Address BACNET_ADDRESS; diff --git a/bacnet-stack/ports/at91sam7s/dlmstp.c b/bacnet-stack/ports/at91sam7s/dlmstp.c index 8d2588d7..954fbfa4 100644 --- a/bacnet-stack/ports/at91sam7s/dlmstp.c +++ b/bacnet-stack/ports/at91sam7s/dlmstp.c @@ -1,72 +1,248 @@ -/************************************************************************** -* -* Copyright (C) 2007 Steve Karg -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -*********************************************************************/ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2007 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + 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####*/ #include #include #include #include #include "bacdef.h" -#include "mstp.h" #include "dlmstp.h" #include "rs485.h" +#include "crc.h" #include "npdu.h" -#include "apdu.h" -#include "bacaddr.h" #include "bits.h" -/* This file has been customized for use with the AT91SAM7S-EK */ +#include "bacaddr.h" + +/* This file has been customized for use with small microprocessors */ +/* Assumptions: + Only one MS/TP datalink layer +*/ #include "board.h" #include "timer.h" -/* Number of MS/TP Packets Rx/Tx */ -uint16_t MSTP_Packets = 0; +/* The value 255 is used to denote broadcast when used as a */ +/* destination address but is not allowed as a value for a station. */ +/* Station addresses for master nodes can be 0-127. */ +/* Station addresses for slave nodes can be 127-254. */ +#define MSTP_BROADCAST_ADDRESS 255 -/* receive buffer */ -static DLMSTP_PACKET Receive_Packet; -static DLMSTP_PACKET Transmit_Packet; -/* local MS/TP port data - shared with RS-485 */ -static volatile struct mstp_port_struct_t MSTP_Port; -/* buffers needed by mstp port struct */ -static uint8_t TxBuffer[MAX_MPDU]; -static uint8_t RxBuffer[MAX_MPDU]; +/* MS/TP Frame Type */ +/* Frame Types 8 through 127 are reserved by ASHRAE. */ +#define FRAME_TYPE_TOKEN 0 +#define FRAME_TYPE_POLL_FOR_MASTER 1 +#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2 +#define FRAME_TYPE_TEST_REQUEST 3 +#define FRAME_TYPE_TEST_RESPONSE 4 +#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5 +#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6 +#define FRAME_TYPE_REPLY_POSTPONED 7 +/* Frame Types 128 through 255: Proprietary Frames */ +/* These frames are available to vendors as proprietary (non-BACnet) frames. */ +/* The first two octets of the Data field shall specify the unique vendor */ +/* identification code, most significant octet first, for the type of */ +/* vendor-proprietary frame to be conveyed. The length of the data portion */ +/* of a Proprietary frame shall be in the range of 2 to 501 octets. */ +#define FRAME_TYPE_PROPRIETARY_MIN 128 +#define FRAME_TYPE_PROPRIETARY_MAX 255 + +/* receive FSM states */ +typedef enum { + MSTP_RECEIVE_STATE_IDLE = 0, + MSTP_RECEIVE_STATE_PREAMBLE = 1, + MSTP_RECEIVE_STATE_HEADER = 2, + MSTP_RECEIVE_STATE_DATA = 3 +} MSTP_RECEIVE_STATE; + +/* master node FSM states */ +typedef enum { + MSTP_MASTER_STATE_INITIALIZE = 0, + MSTP_MASTER_STATE_IDLE = 1, + MSTP_MASTER_STATE_USE_TOKEN = 2, + MSTP_MASTER_STATE_WAIT_FOR_REPLY = 3, + MSTP_MASTER_STATE_DONE_WITH_TOKEN = 4, + MSTP_MASTER_STATE_PASS_TOKEN = 5, + MSTP_MASTER_STATE_NO_TOKEN = 6, + MSTP_MASTER_STATE_POLL_FOR_MASTER = 7, + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST = 8 +} MSTP_MASTER_STATE; + +/* The state of the Receive State Machine */ +static MSTP_RECEIVE_STATE Receive_State; +/* When a master node is powered up or reset, */ +/* it shall unconditionally enter the INITIALIZE state. */ +static MSTP_MASTER_STATE Master_State; +/* bit-sized boolean flags */ +static struct mstp_flag_t { + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if an invalid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedInvalidFrame:1; + /* A Boolean flag set to TRUE by the Receive State Machine */ + /* if a valid frame is received. */ + /* Set to FALSE by the main state machine. */ + unsigned ReceivedValidFrame:1; + /* A Boolean flag set to TRUE by the master machine if this node is the */ + /* only known master node. */ + unsigned SoleMaster:1; + /* A Boolean flag set TRUE by the datalink transmit if a + frame is pending */ + unsigned TransmitPacketPending:1; + /* A Boolean flag set TRUE by the datalink transmit if a + pending packet is DataExpectingReply */ + unsigned TransmitPacketDER:1; + /* A Boolean flag set TRUE by the datalink if a + packet has been received, but not processed. */ + unsigned ReceivePacketPending:1; +} MSTP_Flag; + +/* Used to store the data length of a received frame. */ +static uint16_t DataLength; +/* Used to store the destination address of a received frame. */ +static uint8_t DestinationAddress; +/* Used to count the number of received octets or errors. */ +/* This is used in the detection of link activity. */ +/* Compared to Nmin_octets */ +static uint8_t EventCount; +/* Used to store the frame type of a received frame. */ +static uint8_t FrameType; +/* An array of octets, used to store octets as they are received. */ +/* InputBuffer is indexed from 0 to InputBufferSize-1. */ +/* FIXME: assign this to an actual array of bytes! */ +/* Note: the buffer is designed as a pointer since some compilers + and microcontroller architectures have limits as to places to + hold contiguous memory. */ +static uint8_t *InputBuffer; +static uint8_t InputBufferSize; +/* Used to store the Source Address of a received frame. */ +static uint8_t SourceAddress; +/* "This Station," the MAC address of this node. TS is generally read from a */ +/* hardware DIP switch, or from nonvolatile memory. Valid values for TS are */ +/* 0 to 254. The value 255 is used to denote broadcast when used as a */ +/* destination address but is not allowed as a value for TS. */ +static uint8_t This_Station; +/* This parameter represents the value of the Max_Info_Frames property of */ +/* the node's Device object. The value of Max_Info_Frames specifies the */ +/* maximum number of information frames the node may send before it must */ +/* pass the token. Max_Info_Frames may have different values on different */ +/* nodes. This may be used to allocate more or less of the available link */ +/* bandwidth to particular nodes. If Max_Info_Frames is not writable in a */ +/* node, its value shall be 1. */ +static uint8_t Nmax_info_frames; +/* This parameter represents the value of the Max_Master property of the */ +/* node's Device object. The value of Max_Master specifies the highest */ +/* allowable address for master nodes. The value of Max_Master shall be */ +/* less than or equal to 127. If Max_Master is not writable in a node, */ +/* its value shall be 127. */ +static uint8_t Nmax_master; +/* An array of octets, used to store octets for transmitting */ +/* OutputBuffer is indexed from 0 to OutputBufferSize-1. */ +/* The MAX_PDU size of a frame is MAX_APDU + MAX_NPDU octets. */ +/* FIXME: assign this to an actual array of bytes! */ +/* Note: the buffer is designed as a pointer since some compilers + and microcontroller architectures have limits as to places to + hold contiguous memory. */ +static uint8_t *TransmitPacket; +static uint16_t TransmitPacketLen; +static uint8_t TransmitPacketDest; + +/* The time without a DataAvailable or ReceiveError event before declaration */ +/* of loss of token: 500 milliseconds. */ +#define Tno_token 500 + +/* 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.) */ +#define Treply_timeout 260 + +/* 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.) */ +#define Tusage_timeout 25 + +/* The number of tokens received or used before a Poll For Master cycle */ +/* is executed: 50. */ +#define Npoll 50 + +/* The number of retries on sending Token: 1. */ +#define 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. */ +#define 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); */ +#define Tframe_abort 30 + +/* The maximum idle time a sending node may allow to elapse between octets */ +/* of a frame the node is transmitting: 20 bit times. */ +#define Tframe_gap 20 + +/* 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. */ +#define 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. */ +#define Treply_delay 250 + +/* The width of the time slot within which a node may generate a token: */ +/* 10 milliseconds. */ +#define 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. */ +#define Tusage_delay 15 + +/* we need to be able to increment without rolling over */ +#define INCREMENT_AND_LIMIT_UINT8(x) {if (x < 0xFF) x++;} bool dlmstp_init(char *ifname) { (void)ifname; - /* initialize packet */ - Receive_Packet.ready = false; - Receive_Packet.pdu_len = 0; /* initialize hardware */ RS485_Initialize(); - /* initialize MS/TP data structures */ - MSTP_Port.InputBuffer = &RxBuffer[0]; - MSTP_Port.InputBufferSize = sizeof(RxBuffer); - MSTP_Port.OutputBuffer = &TxBuffer[0]; - MSTP_Port.OutputBufferSize = sizeof(TxBuffer); - MSTP_Port.SilenceTimer = Timer_Silence; - MSTP_Port.SilenceTimerReset = Timer_Silence_Reset; - MSTP_Init(&MSTP_Port); - + return true; } @@ -75,88 +251,6 @@ void dlmstp_cleanup(void) /* nothing to do for static buffers */ } -/* returns number of bytes sent on success, zero on failure */ -int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ - BACNET_NPDU_DATA * npdu_data, /* network information */ - uint8_t * pdu, /* any data to be sent - may be null */ - unsigned pdu_len) /* number of bytes of data */ -{ - int bytes_sent = 0; - unsigned i = 0; /* loop counter */ - - if (Transmit_Packet.ready == false) { - if (npdu_data->data_expecting_reply) { - Transmit_Packet.frame_type = - FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - Transmit_Packet.frame_type = - FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - Transmit_Packet.pdu_len = pdu_len; - for (i = 0; i < pdu_len; i++) { - Transmit_Packet.pdu[i] = pdu[i]; - } - bacnet_address_copy(&Transmit_Packet.address, dest); - bytes_sent = sizeof(Transmit_Packet); - Transmit_Packet.ready = true; - } - - return bytes_sent; -} - -static void dlmstp_task(void) -{ - /* only do receive state machine while we don't have a frame */ - if ((MSTP_Port.ReceivedValidFrame == false) && - (MSTP_Port.ReceivedInvalidFrame == false)) { - do { - RS485_Check_UART_Data(&MSTP_Port); - MSTP_Receive_Frame_FSM(&MSTP_Port); - if (MSTP_Port.ReceivedValidFrame || - MSTP_Port.ReceivedInvalidFrame) - break; - } while (MSTP_Port.DataAvailable); - } else { - } - /* only do master state machine while rx is idle */ - if (MSTP_Port.receive_state == MSTP_RECEIVE_STATE_IDLE) { - while (MSTP_Master_Node_FSM(&MSTP_Port)) { - /* do nothing */ - }; - } - - return; -} - -/* copy the packet if one is received. - Return the length of the packet */ -uint16_t dlmstp_receive( - BACNET_ADDRESS * src, /* source address */ - uint8_t * pdu, /* PDU data */ - uint16_t max_pdu, /* amount of space available in the PDU */ - unsigned timeout) /* milliseconds to wait for a packet */ -{ - unsigned i = 0; /* loop counter */ - uint16_t pdu_len = 0; /* return value */ - - dlmstp_task(); - /* see if there is a packet available, and a place - to put the reply (if necessary) and process it */ - if (Receive_Packet.ready) { - if (Receive_Packet.pdu_len) { - MSTP_Packets++; - for (i = 0; i < Receive_Packet.pdu_len; i++) { - pdu[i] = Receive_Packet.pdu[i]; - } - bacnet_address_copy(src, &Receive_Packet.address); - pdu_len = Receive_Packet.pdu_len; - } - Receive_Packet.ready = false; - } - - return pdu_len; -} - void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) { int i = 0; @@ -180,73 +274,13 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS * src, uint8_t mstp_address) } } -/* for the MS/TP state machine to use for putting received data */ -uint16_t MSTP_Put_Receive( - volatile struct mstp_port_struct_t *mstp_port) -{ - DLMSTP_PACKET packet; - uint16_t pdu_len = mstp_port->DataLength; - unsigned i = 0; - - /* bounds check - maybe this should send an abort? */ - if (pdu_len > sizeof(packet.pdu)) - pdu_len = sizeof(packet.pdu); - if (pdu_len) { - MSTP_Packets++; - for (i = 0; i < Receive_Packet.pdu_len; i++) { - Receive_Packet.pdu[i] = mstp_port->InputBuffer[i]; - } - dlmstp_fill_bacnet_address(&Receive_Packet.address, - mstp_port->SourceAddress); - Receive_Packet.pdu_len = pdu_len; - Receive_Packet.ready = true; - } - - return pdu_len; -} - -/* for the MS/TP state machine to use for getting data to send */ -/* Return: amount of PDU data */ -uint16_t MSTP_Get_Send( - volatile struct mstp_port_struct_t *mstp_port, - unsigned timeout) /* milliseconds to wait for a packet */ -{ - uint16_t pdu_len = 0; /* return value */ - uint8_t destination = 0; /* destination address */ - - if (!Transmit_Packet.ready) { - return 0; - } - /* load destination MAC address */ - if (Transmit_Packet.address.mac_len == 1) { - destination = Transmit_Packet.address.mac[0]; - } else { - return 0; - } - if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) { - return 0; - } - /* convert the PDU into the MSTP Frame */ - pdu_len = MSTP_Create_Frame( - &mstp_port->OutputBuffer[0], /* <-- loading this */ - mstp_port->OutputBufferSize, - Transmit_Packet.frame_type, - destination, - mstp_port->This_Station, - &Transmit_Packet.pdu[0], - Transmit_Packet.pdu_len); - Transmit_Packet.ready = false; - - return pdu_len; -} - -bool dlmstp_compare_data_expecting_reply( +static bool dlmstp_compare_data_expecting_reply( uint8_t *request_pdu, uint16_t request_pdu_len, uint8_t src_address, uint8_t *reply_pdu, uint16_t reply_pdu_len, - BACNET_ADDRESS *dest_address) + uint8_t dest_address) { uint16_t offset; /* One way to check the message is to compare NPDU @@ -281,7 +315,8 @@ bool dlmstp_compare_data_expecting_reply( else request.service_choice = request_pdu[offset+3]; /* decode the reply data */ - bacnet_address_copy(&reply.address, dest_address); + reply.address.mac[0] = dest_address; + reply.address.mac_len = 1; offset = npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data); if (reply.npdu_data.network_layer_message) { @@ -349,51 +384,867 @@ bool dlmstp_compare_data_expecting_reply( return true; } -/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */ -uint16_t MSTP_Get_Reply( - volatile struct mstp_port_struct_t *mstp_port, +/* 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' */ +static void MSTP_Send_Frame( + 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 */ + uint16_t data_len) +{ /* number of bytes of data (up to 501) */ + uint8_t crc8 = 0xFF; /* used to calculate the crc value */ + uint16_t crc16 = 0xFFFF; /* used to calculate the crc value */ + uint8_t buffer[8]; /* stores the header and data crc */ + uint16_t i = 0; /* used to calculate CRC for data */ + + /* create the MS/TP header */ + 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; + RS485_Turnaround_Delay(); + RS485_Transmitter_Enable(true); + RS485_Send_Data(buffer,8); + /* send any data */ + if (data_len) { + /* calculate CRC for any data */ + for (i = 0; i < data_len; i++) + { + crc16 = CRC_Calc_Data(data[i], crc16); + } + crc16 = ~crc16; + buffer[0] = (crc16 & 0x00FF); + buffer[1] = ((crc16 & 0xFF00) >> 8); + RS485_Send_Data(data, data_len); + RS485_Send_Data(buffer, 2); + } + RS485_Transmitter_Enable(false); +} + +static void MSTP_Receive_Frame_FSM(void) +{ + /* stores the latest received data octet */ + uint8_t DataRegister = 0; + /* Used to accumulate the CRC on the data field of a frame. */ + static uint16_t DataCRC = 0; + /* Used to accumulate the CRC on the header of a frame. */ + static uint8_t HeaderCRC = 0; + /* Used as an index by the Receive State Machine, + up to a maximum value of the MPDU */ + static uint8_t Index = 0; + + switch (Receive_State) { + case MSTP_RECEIVE_STATE_IDLE: + /* In the IDLE state, the node waits for the beginning of a frame. */ + if (RS485_ReceiveError()) { + /* EatAnError */ + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + } else if (RS485_DataAvailable(&DataRegister)) { + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + if (DataRegister == 0x55) { + /* Preamble1 */ + /* receive the remainder of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_PREAMBLE; + } + } + break; + case MSTP_RECEIVE_STATE_PREAMBLE: + /* In the PREAMBLE state, the node waits for the + second octet of the preamble. */ + if (Timer_Silence() > Tframe_abort) { + /* Timeout */ + /* a correct preamble has not been received */ + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + if (DataRegister == 0xFF) { + /* Preamble2 */ + Index = 0; + HeaderCRC = 0xFF; + /* receive the remainder of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_HEADER; + } else if (DataRegister == 0x55) { + /* ignore RepeatedPreamble1 */ + /* wait for the second preamble octet. */ + Receive_State = MSTP_RECEIVE_STATE_PREAMBLE; + } else { + /* NotPreamble */ + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + case MSTP_RECEIVE_STATE_HEADER: + /* In the HEADER state, the node waits for the fixed message header. */ + if (Timer_Silence() > Tframe_abort) { + /* Timeout */ + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + if (Index == 0) { + /* FrameType */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + FrameType = DataRegister; + Index = 1; + } else if (Index == 1) { + /* Destination */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DestinationAddress = DataRegister; + Index = 2; + } else if (Index == 2) { + /* Source */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + SourceAddress = DataRegister; + Index = 3; + } else if (Index == 3) { + /* Length1 */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DataLength = DataRegister * 256; + Index = 4; + } else if (Index == 4) { + /* Length2 */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + DataLength += DataRegister; + Index = 5; + } else if (Index == 5) { + /* HeaderCRC */ + HeaderCRC = CRC_Calc_Header(DataRegister, HeaderCRC); + /* In the HEADER_CRC state, the node validates the CRC + on the fixed message header. */ + if (HeaderCRC != 0x55) { + /* BadCRC */ + /* indicate that an error has occurred during + the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else { + /* Note: proposed change to BACnet MSTP state machine! + If we don't decode data that is not for us, we could + get confused about the start if the Preamble 55 FF + is part of the data. */ + if ((DataLength) && + (DataLength <= InputBufferSize)) { + /* Data */ + Index = 0; + DataCRC = 0xFFFF; + /* receive the data portion of the frame. */ + Receive_State = MSTP_RECEIVE_STATE_DATA; + } else { + if (DataLength == 0) { + /* NoData */ + if ((DestinationAddress == This_Station) || + (DestinationAddress == MSTP_BROADCAST_ADDRESS)) { + /* ForUs */ + /* indicate that a frame with + no data has been received */ + MSTP_Flag.ReceivedValidFrame = true; + } else { + /* NotForUs - drop */ + } + } else { + /* FrameTooLong */ + /* indicate that a frame with an illegal or */ + /* unacceptable data length has been received */ + MSTP_Flag.ReceivedInvalidFrame = true; + } + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + } else { + /* indicate that an error has occurred during */ + /* the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of a frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + case MSTP_RECEIVE_STATE_DATA: + /* In the DATA state, the node waits for the data portion of a frame. */ + if (Timer_Silence() > Tframe_abort) { + /* Timeout */ + /* indicate that an error has occurred during the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_ReceiveError()) { + /* Error */ + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + /* indicate that an error has occurred during + the reception of a frame */ + MSTP_Flag.ReceivedInvalidFrame = true; + /* wait for the start of the next frame. */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } else if (RS485_DataAvailable(&DataRegister)) { + Timer_Silence_Reset(); + INCREMENT_AND_LIMIT_UINT8(EventCount); + if (Index < DataLength) { + /* DataOctet */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + InputBuffer[Index] = DataRegister; + Index++; + } else if (Index == DataLength) { + /* CRC1 */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + Index++; + } else if (Index == (DataLength + 1)) { + /* CRC2 */ + DataCRC = CRC_Calc_Data(DataRegister, DataCRC); + /* STATE DATA CRC - no need for new state */ + /* indicate the complete reception of a valid frame */ + if (DataCRC == 0xF0B8) { + if ((DestinationAddress == This_Station) || + (DestinationAddress == MSTP_BROADCAST_ADDRESS)) { + /* ForUs */ + /* indicate that a frame with no data + has been received */ + MSTP_Flag.ReceivedValidFrame = true; + } + } else { + MSTP_Flag.ReceivedInvalidFrame = true; + } + Receive_State = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + default: + /* shouldn't get here - but if we do... */ + Receive_State = MSTP_RECEIVE_STATE_IDLE; + break; + } + + return; +} + +/* returns true if we need to transition immediately */ +static bool MSTP_Master_Node_FSM(void) +{ + /* The number of frames sent by this node during a single token hold. */ + /* When this counter reaches the value Nmax_info_frames, the node must */ + /* pass the token. */ + static uint8_t FrameCount; + /* "Next Station," the MAC address of the node to which This Station passes */ + /* the token. If the Next_Station is unknown, Next_Station shall be equal to */ + /* This_Station. */ + static uint8_t Next_Station; + /* "Poll Station," the MAC address of the node to which This Station last */ + /* sent a Poll For Master. This is used during token maintenance. */ + static uint8_t Poll_Station; + /* A counter of transmission retries used for Token and Poll For Master */ + /* transmission. */ + static unsigned RetryCount; + /* The number of tokens received by this node. When this counter reaches the */ + /* value Npoll, the node polls the address range between TS and NS for */ + /* additional master nodes. TokenCount is set to zero at the end of the */ + /* polling process. */ + static unsigned TokenCount; + /* next-x-station calculations */ + uint8_t next_poll_station = 0; + uint8_t next_this_station = 0; + uint8_t next_next_station = 0; + /* timeout values */ + uint16_t my_timeout = 10, ns_timeout = 0; + bool matched; + /* transition immediately to the next state */ + bool transition_now = false; + + /* some calculations that several states need */ + next_poll_station = (Poll_Station + 1) % (Nmax_master + 1); + next_this_station = (This_Station + 1) % (Nmax_master + 1); + next_next_station = (Next_Station + 1) % (Nmax_master + 1); + switch (Master_State) { + case MSTP_MASTER_STATE_INITIALIZE: + /* DoneInitializing */ + /* indicate that the next station is unknown */ + Next_Station = This_Station; + Poll_Station = This_Station; + /* cause a Poll For Master to be sent when this node first */ + /* receives the token */ + TokenCount = Npoll; + MSTP_Flag.SoleMaster = false; + MSTP_Flag.ReceivedValidFrame = false; + MSTP_Flag.ReceivedInvalidFrame = false; + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + break; + case MSTP_MASTER_STATE_IDLE: + /* In the IDLE state, the node waits for a frame. */ + if (Timer_Silence() >= Tno_token) { + /* LostToken */ + /* assume that the token has been lost */ + EventCount = 0; /* Addendum 135-2004d-8 */ + Master_State = MSTP_MASTER_STATE_NO_TOKEN; + transition_now = true; + } else if (MSTP_Flag.ReceivedInvalidFrame == true) { + /* ReceivedInvalidFrame */ + /* invalid frame was received */ + MSTP_Flag.ReceivedInvalidFrame = false; + /* wait for the next frame - remain in IDLE */ + } else if (MSTP_Flag.ReceivedValidFrame == true) { + switch (FrameType) { + case FRAME_TYPE_TOKEN: + /* ReceivedToken */ + /* tokens can't be broadcast */ + if (DestinationAddress == MSTP_BROADCAST_ADDRESS) + break; + MSTP_Flag.ReceivedValidFrame = false; + FrameCount = 0; + MSTP_Flag.SoleMaster = false; + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + break; + case FRAME_TYPE_POLL_FOR_MASTER: + /* ReceivedPFM */ + MSTP_Send_Frame( + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, + SourceAddress, This_Station, + NULL, 0); + break; + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + /* indicate successful reception to the higher layers */ + MSTP_Flag.ReceivePacketPending = true; + break; + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* indicate successful reception to the higher layers */ + MSTP_Flag.ReceivePacketPending = true; + /* broadcast DER just remains IDLE */ + if (DestinationAddress != + MSTP_BROADCAST_ADDRESS) { + Master_State = + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; + } + break; + case FRAME_TYPE_TEST_REQUEST: + MSTP_Send_Frame( + FRAME_TYPE_TEST_RESPONSE, + SourceAddress, This_Station, + NULL, 0); + break; + case FRAME_TYPE_TEST_RESPONSE: + default: + break; + } + /* For DATA_EXPECTING_REPLY, we will keep the Rx Frame for + reference, and the flag will be cleared in the next state */ + if (Master_State != + MSTP_MASTER_STATE_ANSWER_DATA_REQUEST) { + MSTP_Flag.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: + /* Note: We could wait for up to Tusage_delay */ + if (!MSTP_Flag.TransmitPacketPending) { + /* NothingToSend */ + FrameCount = Nmax_info_frames; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else { + uint8_t frame_type; + if (MSTP_Flag.TransmitPacketDER) { + frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + } else { + frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + } + MSTP_Send_Frame( + frame_type, + TransmitPacketDest, + This_Station, + (uint8_t *) & TransmitPacket[0], + TransmitPacketLen); + MSTP_Flag.TransmitPacketPending = false; + FrameCount++; + switch (frame_type) { + case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: + /* SendAndWait */ + if (TransmitPacketDest == MSTP_BROADCAST_ADDRESS) + Master_State = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + else + Master_State = + MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_REQUEST: + Master_State = MSTP_MASTER_STATE_WAIT_FOR_REPLY; + break; + case FRAME_TYPE_TEST_RESPONSE: + case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: + default: + /* SendNoWait */ + Master_State = + MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + } + } + break; + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + /* In the WAIT_FOR_REPLY state, the node waits for */ + /* a reply from another node. */ + if (Timer_Silence() >= Treply_timeout) { + /* ReplyTimeout */ + /* assume that the request has failed */ + FrameCount = Nmax_info_frames; + 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_Flag.ReceivedInvalidFrame == true) { + /* InvalidFrame */ + /* error in frame reception */ + MSTP_Flag.ReceivedInvalidFrame = false; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + transition_now = true; + } else if (MSTP_Flag.ReceivedValidFrame == true) { + if (DestinationAddress == This_Station) { + /* What did we receive? */ + switch (FrameType) { + case FRAME_TYPE_REPLY_POSTPONED: + /* ReceivedReplyPostponed */ + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + case FRAME_TYPE_TEST_RESPONSE: + Master_State = MSTP_MASTER_STATE_IDLE; + 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 */ + MSTP_Flag.ReceivePacketPending = true; + Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + break; + default: + /* if proprietary frame was expected, you might + need to transition to DONE WITH TOKEN */ + Master_State = MSTP_MASTER_STATE_IDLE; + break; + } + } else { + /* ReceivedUnexpectedFrame */ + /* an unexpected frame was received */ + /* This may indicate the presence of multiple tokens */ + /* or a device that didn't see activity after passing */ + /* a token (how lame!). */ + /* Synchronize with the network. */ + /* This action drops the token. */ + Master_State = MSTP_MASTER_STATE_IDLE; + } + MSTP_Flag.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 (FrameCount < Nmax_info_frames) { + /* then this node may send another information frame */ + /* before passing the token. */ + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + /* Npoll changed in Errata SSPC-135-2004 */ + else if (TokenCount < (Npoll - 1)) { + if ((MSTP_Flag.SoleMaster == true) && + (Next_Station != next_this_station)) { + /* SoleMaster */ + /* there are no other known master nodes to */ + /* which the token may be sent (true master-slave operation). */ + FrameCount = 0; + TokenCount++; + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } 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. */ + TokenCount++; + /* transmit a Token frame to NS */ + MSTP_Send_Frame( + FRAME_TYPE_TOKEN, + Next_Station, + This_Station, NULL, 0); + RetryCount = 0; + EventCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else if (next_poll_station == Next_Station) { + if (MSTP_Flag.SoleMaster == true) { + /* SoleMasterRestartMaintenancePFM */ + Poll_Station = next_poll_station; + MSTP_Send_Frame( + FRAME_TYPE_POLL_FOR_MASTER, Poll_Station, + This_Station, NULL, 0); + /* no known successor node */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + /* EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + Master_State = + MSTP_MASTER_STATE_POLL_FOR_MASTER; + } else { + /* ResetMaintenancePFM */ + Poll_Station = This_Station; + /* transmit a Token frame to NS */ + MSTP_Send_Frame( + FRAME_TYPE_TOKEN, + Next_Station, + This_Station, NULL, 0); + RetryCount = 0; + TokenCount = 1; /* changed in Errata SSPC-135-2004 */ + EventCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } + } else { + /* SendMaintenancePFM */ + Poll_Station = next_poll_station; + MSTP_Send_Frame( + FRAME_TYPE_POLL_FOR_MASTER, + Poll_Station, This_Station, NULL, 0); + RetryCount = 0; + Master_State = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + 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 (Timer_Silence() <= Tusage_timeout) { + if (EventCount > Nmin_octets) { + /* SawTokenUser */ + /* Assume that a frame has been sent by the new token user. */ + /* Enter the IDLE state to process the frame. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } else { + if (RetryCount < Nretry_token) { + /* RetrySendToken */ + RetryCount++; + /* Transmit a Token frame to NS */ + MSTP_Send_Frame( + FRAME_TYPE_TOKEN, + Next_Station, This_Station, NULL, + 0); + EventCount = 0; + /* re-enter the current state to listen for NS */ + /* to begin using the token. */ + } else { + /* FindNewSuccessor */ + /* Assume that NS has failed. */ + Poll_Station = next_next_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame( + FRAME_TYPE_POLL_FOR_MASTER, + Poll_Station, This_Station, NULL, + 0); + /* no known successor node */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 0; + /* EventCount = 0; removed in Addendum 135-2004d-8 */ + /* find a new successor to TS */ + Master_State = + MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + } + break; + /* The NO_TOKEN state is entered if Timer_Silence() 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 * This_Station); + if (Timer_Silence() < my_timeout) { + if (EventCount > Nmin_octets) { + /* SawFrame */ + /* Some other node exists at a lower address. */ + /* Enter the IDLE state to receive and process the incoming frame. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + } else { + ns_timeout = + Tno_token + (Tslot * (This_Station + 1)); + if (Timer_Silence() < ns_timeout) { + /* GenerateToken */ + /* Assume that this node is the lowest numerical address */ + /* on the network and is empowered to create a token. */ + Poll_Station = next_this_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame( + FRAME_TYPE_POLL_FOR_MASTER, + Poll_Station, This_Station, NULL, + 0); + /* indicate that the next station is unknown */ + Next_Station = This_Station; + RetryCount = 0; + TokenCount = 0; + /* EventCount = 0; removed Addendum 135-2004d-8 */ + /* enter the POLL_FOR_MASTER state to find a new successor to TS. */ + 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: + if (MSTP_Flag.ReceivedValidFrame == true) { + if ((DestinationAddress == This_Station) + && (FrameType == + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) { + /* ReceivedReplyToPFM */ + MSTP_Flag.SoleMaster = false; + Next_Station = SourceAddress; + EventCount = 0; + /* Transmit a Token frame to NS */ + MSTP_Send_Frame( + FRAME_TYPE_TOKEN, + Next_Station, This_Station, NULL, + 0); + Poll_Station = This_Station; + TokenCount = 0; + RetryCount = 0; + 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. */ + Master_State = MSTP_MASTER_STATE_IDLE; + transition_now = true; + } + MSTP_Flag.ReceivedValidFrame = false; + } else if ((Timer_Silence() > Tusage_timeout) || + (MSTP_Flag.ReceivedInvalidFrame == true)) { + if (MSTP_Flag.SoleMaster == true) { + /* SoleMaster */ + /* There was no valid reply to the periodic poll */ + /* by the sole known master for other masters. */ + FrameCount = 0; + /* TokenCount++; removed in 2004 */ + Master_State = MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } else { + if (Next_Station != This_Station) { + /* DoneWithPFM */ + /* There was no valid reply to the maintenance */ + /* poll for a master at address PS. */ + EventCount = 0; + /* transmit a Token frame to NS */ + MSTP_Send_Frame( + FRAME_TYPE_TOKEN, + Next_Station, This_Station, + NULL, 0); + RetryCount = 0; + Master_State = MSTP_MASTER_STATE_PASS_TOKEN; + } else { + if (next_poll_station != This_Station) { + /* SendNextPFM */ + Poll_Station = next_poll_station; + /* Transmit a Poll For Master frame to PS. */ + MSTP_Send_Frame( + FRAME_TYPE_POLL_FOR_MASTER, + Poll_Station, + This_Station, NULL, 0); + RetryCount = 0; + /* Re-enter the current state. */ + } else { + /* DeclareSoleMaster */ + /* to indicate that this station is the only master */ + MSTP_Flag.SoleMaster = true; + FrameCount = 0; + Master_State = + MSTP_MASTER_STATE_USE_TOKEN; + transition_now = true; + } + } + } + MSTP_Flag.ReceivedInvalidFrame = false; + } + 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: + /* Note: we could wait for up to Treply_delay */ + if (MSTP_Flag.TransmitPacketPending) { + matched = dlmstp_compare_data_expecting_reply( + &InputBuffer[0], + DataLength, + SourceAddress, + &TransmitPacket[0], + TransmitPacketLen, + TransmitPacketDest); + } + if (MSTP_Flag.TransmitPacketPending && matched) { + /* 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_Send_Frame to transmit the reply frame */ + /* and enter the IDLE state to wait for the next frame. */ + uint8_t frame_type; + if (MSTP_Flag.TransmitPacketDER) { + frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; + } else { + frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; + } + MSTP_Send_Frame( + frame_type, + TransmitPacketDest, + This_Station, + (uint8_t *) & TransmitPacket[0], + TransmitPacketLen); + MSTP_Flag.TransmitPacketPending = false; + Master_State = MSTP_MASTER_STATE_IDLE; + } else { + /* DeferredReply */ + /* If no reply will be available from the higher layers */ + /* within Treply_delay after the reception of the */ + /* final octet of the requesting frame (the mechanism */ + /* used to determine this is a local matter), */ + /* then an immediate reply is not possible. */ + /* Any reply shall wait until this node receives the token. */ + /* Call MSTP_Send_Frame to transmit a Reply Postponed frame, */ + /* and enter the IDLE state. */ + MSTP_Send_Frame( + FRAME_TYPE_REPLY_POSTPONED, + SourceAddress, + This_Station, NULL, 0); + Master_State = MSTP_MASTER_STATE_IDLE; + } + /* clear our flag we were holding for comparison */ + MSTP_Flag.ReceivedValidFrame = false; + break; + default: + Master_State = MSTP_MASTER_STATE_IDLE; + break; + } + + return transition_now; +} + +/* returns number of bytes sent on success, zero on failure */ +int dlmstp_send_pdu(BACNET_ADDRESS * dest, /* destination address */ + BACNET_NPDU_DATA * npdu_data, /* network information */ + uint8_t * pdu, /* any data to be sent - may be null */ + unsigned pdu_len) /* number of bytes of data */ +{ + int bytes_sent = 0; + + if (MSTP_Flag.TransmitPacketPending == false) { + MSTP_Flag.TransmitPacketDER = npdu_data->data_expecting_reply; + TransmitPacket = pdu; + TransmitPacketLen = pdu_len; + bytes_sent = pdu_len; + TransmitPacketDest = dest->mac[0]; + MSTP_Flag.TransmitPacketPending = true; + } + + return bytes_sent; +} + +/* Return the length of the packet */ +uint16_t dlmstp_receive( + BACNET_ADDRESS * src, /* source address */ + uint8_t * pdu, /* PDU data */ + uint16_t max_pdu, /* amount of space available in the PDU */ unsigned timeout) /* milliseconds to wait for a packet */ { uint16_t pdu_len = 0; /* return value */ - uint8_t destination = 0; /* destination address */ - bool matched = false; - if (!Transmit_Packet.ready) { - return 0; + /* set the input buffer to the same data storage for zero copy */ + if (!InputBuffer) { + InputBuffer = pdu; + InputBufferSize = max_pdu; } - /* load destination MAC address */ - if (Transmit_Packet.address.mac_len == 1) { - destination = Transmit_Packet.address.mac[0]; - } else { - return 0; + /* only do receive state machine while we don't have a frame */ + if ((MSTP_Flag.ReceivedValidFrame == false) && + (MSTP_Flag.ReceivedInvalidFrame == false)) { + for (;;) { + MSTP_Receive_Frame_FSM(); + if (MSTP_Flag.ReceivedValidFrame || + MSTP_Flag.ReceivedInvalidFrame) + break; + /* if we are not idle, then we are + receiving a frame or timing out */ + if (Receive_State == MSTP_RECEIVE_STATE_IDLE) + break; + } } - if ((MAX_HEADER + Transmit_Packet.pdu_len) > MAX_MPDU) { - return 0; + /* only do master state machine while rx is idle */ + if (Receive_State == MSTP_RECEIVE_STATE_IDLE) { + while (MSTP_Master_Node_FSM()) { + /* do nothing while some states fast transition */ + }; + } + /* if there is a packet that needs processed, do it now. */ + if (MSTP_Flag.ReceivePacketPending) { + MSTP_Flag.ReceivePacketPending = false; + pdu_len = DataLength; + src->mac_len = 1; + src->mac[0] = SourceAddress; + /* data is already in the pdu pointer */ } - /* does destination match source? */ - if (mstp_port->SourceAddress != destination) { - return 0; - } - /* is this the reply to the DER? */ - matched = dlmstp_compare_data_expecting_reply( - &mstp_port->InputBuffer[0], - mstp_port->DataLength, - mstp_port->SourceAddress, - &Transmit_Packet.pdu[0], - Transmit_Packet.pdu_len, - &Transmit_Packet.address); - if (!matched) - return 0; - /* convert the PDU into the MSTP Frame */ - pdu_len = MSTP_Create_Frame( - &mstp_port->OutputBuffer[0], /* <-- loading this */ - mstp_port->OutputBufferSize, - Transmit_Packet.frame_type, - destination, - mstp_port->This_Station, - &Transmit_Packet.pdu[0], - Transmit_Packet.pdu_len); - Transmit_Packet.ready = false; return pdu_len; } @@ -402,13 +1253,13 @@ void dlmstp_set_mac_address(uint8_t mac_address) { /* Master Nodes can only have address 0-127 */ if (mac_address <= 127) { - MSTP_Port.This_Station = mac_address; + This_Station = mac_address; /* FIXME: implement your data storage */ /* I2C_Write_Byte( EEPROM_DEVICE_ADDRESS, mac_address, EEPROM_MSTP_MAC_ADDR); */ - if (mac_address > MSTP_Port.Nmax_master) + if (mac_address > Nmax_master) dlmstp_set_max_master(mac_address); } @@ -417,7 +1268,7 @@ void dlmstp_set_mac_address(uint8_t mac_address) uint8_t dlmstp_mac_address(void) { - return MSTP_Port.This_Station; + return This_Station; } /* This parameter represents the value of the Max_Info_Frames property of */ @@ -430,7 +1281,7 @@ uint8_t dlmstp_mac_address(void) void dlmstp_set_max_info_frames(uint8_t max_info_frames) { if (max_info_frames >= 1) { - MSTP_Port.Nmax_info_frames = max_info_frames; + Nmax_info_frames = max_info_frames; /* FIXME: implement your data storage */ /* I2C_Write_Byte( EEPROM_DEVICE_ADDRESS, @@ -443,7 +1294,7 @@ void dlmstp_set_max_info_frames(uint8_t max_info_frames) uint8_t dlmstp_max_info_frames(void) { - return MSTP_Port.Nmax_info_frames; + return Nmax_info_frames; } /* This parameter represents the value of the Max_Master property of the */ @@ -454,8 +1305,8 @@ uint8_t dlmstp_max_info_frames(void) void dlmstp_set_max_master(uint8_t max_master) { if (max_master <= 127) { - if (MSTP_Port.This_Station <= max_master) { - MSTP_Port.Nmax_master = max_master; + if (This_Station <= max_master) { + Nmax_master = max_master; /* FIXME: implement your data storage */ /* I2C_Write_Byte( EEPROM_DEVICE_ADDRESS, @@ -469,7 +1320,7 @@ void dlmstp_set_max_master(uint8_t max_master) uint8_t dlmstp_max_master(void) { - return MSTP_Port.Nmax_master; + return Nmax_master; } void dlmstp_get_my_address(BACNET_ADDRESS * my_address) @@ -477,7 +1328,7 @@ void dlmstp_get_my_address(BACNET_ADDRESS * my_address) int i = 0; /* counter */ my_address->mac_len = 1; - my_address->mac[0] = MSTP_Port.This_Station; + my_address->mac[0] = This_Station; my_address->net = 0; /* local only, no routing */ my_address->len = 0; for (i = 0; i < MAX_MAC_LEN; i++) { diff --git a/bacnet-stack/ports/at91sam7s/makefile b/bacnet-stack/ports/at91sam7s/makefile index 08ddb461..9eb7033c 100644 --- a/bacnet-stack/ports/at91sam7s/makefile +++ b/bacnet-stack/ports/at91sam7s/makefile @@ -18,10 +18,14 @@ BACNET_FLAGS += -DPRINT_ENABLED=0 BACNET_FLAGS += -DMAX_APDU=480 #BACNET_FLAGS += -DDLMSTP_TEST -INCLUDES = -I. -I../.. -I../../demo/handler -I../../demo/object +BACNET_ROOT = ../.. +INCLUDES = -I. +INCLUDES += -I$(BACNET_ROOT) +INCLUDES += -I$(BACNET_ROOT)/demo/handler +INCLUDES += -I$(BACNET_ROOT)/demo/object #OPTIMIZATION = -O0 OPTIMIZATION = -Os -CFLAGS = -fno-common $(OPTIMIZATION) $(INCLUDES) $(BACNET_FLAGS) -Wall -g +CFLAGS = -fno-common $(INCLUDES) $(BACNET_FLAGS) -Wall -g LIBRARY = lib$(TARGET).a # -Wa, Pass comma-separated on to the assembler AFLAGS = -Wa,-ahls,-mapcs-32,-adhlns=$(<:.s=.lst) @@ -40,8 +44,7 @@ PORTSRC = main.c \ blinker.c \ rs485.c \ dlmstp.c \ - ../../crc.c \ - ../../mstp.c + $(BACNET_ROOT)/crc.c DEMOSRC = ai.c \ av.c \ @@ -50,29 +53,29 @@ DEMOSRC = ai.c \ h_rp.c \ h_wp.c \ device.c \ - ../../demo/handler/txbuf.c \ - ../../demo/handler/h_whois.c \ - ../../demo/handler/h_rd.c \ - ../../demo/handler/h_dcc.c + $(BACNET_ROOT)/demo/handler/txbuf.c \ + $(BACNET_ROOT)/demo/handler/h_whois.c \ + $(BACNET_ROOT)/demo/handler/h_rd.c \ + $(BACNET_ROOT)/demo/handler/h_dcc.c -CORESRC = ../../npdu.c \ - ../../bacint.c \ - ../../apdu.c \ - ../../bacdcode.c \ - ../../bacaddr.c \ - ../../bacstr.c \ - ../../abort.c \ - ../../bacerror.c \ - ../../reject.c \ - ../../bacapp.c \ - ../../datetime.c \ - ../../rp.c \ - ../../wp.c \ - ../../dcc.c \ - ../../rd.c \ - ../../whois.c \ - ../../iam.c \ - ../../version.c +CORESRC = $(BACNET_ROOT)/npdu.c \ + $(BACNET_ROOT)/bacint.c \ + $(BACNET_ROOT)/apdu.c \ + $(BACNET_ROOT)/bacdcode.c \ + $(BACNET_ROOT)/bacaddr.c \ + $(BACNET_ROOT)/bacstr.c \ + $(BACNET_ROOT)/abort.c \ + $(BACNET_ROOT)/bacerror.c \ + $(BACNET_ROOT)/reject.c \ + $(BACNET_ROOT)/bacapp.c \ + $(BACNET_ROOT)/datetime.c \ + $(BACNET_ROOT)/rp.c \ + $(BACNET_ROOT)/wp.c \ + $(BACNET_ROOT)/dcc.c \ + $(BACNET_ROOT)/rd.c \ + $(BACNET_ROOT)/whois.c \ + $(BACNET_ROOT)/iam.c \ + $(BACNET_ROOT)/version.c CSRC = $(PORTSRC) $(DEMOSRC) #CSRC = $(PORTSRC) @@ -96,8 +99,21 @@ lib: $(LIBRARY) $(LIBRARY): $(COREOBJ) Makefile $(AR) rcs $@ $(COREOBJ) +# allow a single file to be unoptimized for debugging purposes +#dlmstp.o: +# $(CC) -c $(CFLAGS) $*.c -o $@ +# +#main.o: +# $(CC) -c $(CFLAGS) $*.c -o $@ +# +#$(BACNET_ROOT)/npdu.o: +# $(CC) -c $(CFLAGS) $*.c -o $@ +# +#$(BACNET_ROOT)/apdu.o: +# $(CC) -c $(CFLAGS) $*.c -o $@ + .c.o: - $(CC) -c $(CFLAGS) $*.c -o $@ + $(CC) -c $(OPTIMIZATION) $(CFLAGS) $*.c -o $@ .s.o: $(CC) -c $(AFLAGS) $*.s -o $@ diff --git a/bacnet-stack/ports/at91sam7s/rs485.c b/bacnet-stack/ports/at91sam7s/rs485.c index 96996ff0..788e3776 100644 --- a/bacnet-stack/ports/at91sam7s/rs485.c +++ b/bacnet-stack/ports/at91sam7s/rs485.c @@ -32,7 +32,6 @@ #include #include #include -#include "mstp.h" #include "timer.h" /* This file has been customized for use with UART0 @@ -44,16 +43,17 @@ static volatile AT91S_USART *RS485_Interface = AT91C_BASE_US0; /* baud rate */ static int RS485_Baud = 38400; -/**************************************************************************** -* DESCRIPTION: Sets the interface - UART0 or UART1 or... -* RETURN: none -* ALGORITHM: none -* NOTES: none -*****************************************************************************/ -void RS485_Set_Interface(char *ifname) -{ - RS485_Interface = (volatile AT91S_USART *)ifname; -} +/* The minimum time after the end of the stop bit of the final octet of a */ +/* received frame before a node may enable its EIA-485 driver: 40 bit times. */ +/* At 9600 baud, 40 bit times would be about 4.166 milliseconds */ +/* At 19200 baud, 40 bit times would be about 2.083 milliseconds */ +/* At 38400 baud, 40 bit times would be about 1.041 milliseconds */ +/* At 57600 baud, 40 bit times would be about 0.694 milliseconds */ +/* At 76800 baud, 40 bit times would be about 0.520 milliseconds */ +/* At 115200 baud, 40 bit times would be about 0.347 milliseconds */ +/* 40 bits is 4 octets including a start and stop bit with each octet */ +#define Tturnaround (40UL) +/* turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ /**************************************************************************** * DESCRIPTION: Initializes the RS485 hardware and variables, and starts in @@ -152,27 +152,51 @@ bool RS485_Set_Baud_Rate(uint32_t baud) return valid; } -/* Transmits a Frame on the wire */ -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) */ +/**************************************************************************** +* DESCRIPTION: Waits on the SilenceTimer for 40 bits. +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Turnaround_Delay(void) { - uint8_t turnaround_time; + uint16_t turnaround_time; + + /* delay after reception before trasmitting - per MS/TP spec */ + /* wait a minimum 40 bit times since reception */ + /* at least 1 ms for errors: rounding, clock tick */ + turnaround_time = 1 + ((Tturnaround*1000UL)/RS485_Baud); + while (Timer_Silence() < turnaround_time) { + /* do nothing - wait for timer to increment */ + }; +} - /* delay after reception - per MS/TP spec */ - if (mstp_port) { - /* wait a minimum 40 bit times since reception */ - /* at least 1 ms for errors: rounding, clock tick */ - turnaround_time = 1 + ((Tturnaround*1000)/RS485_Baud); - while (mstp_port->SilenceTimer() < turnaround_time) { - /* do nothing - wait for timer to increment */ - }; - } - /* toggle LED on send */ +/**************************************************************************** +* DESCRIPTION: Enable or disable the transmitter +* RETURN: none +* ALGORITHM: none +* NOTES: The Atmel ARM7 has an automatic enable/disable in RS485 mode. +*****************************************************************************/ +void RS485_Transmitter_Enable(bool enable) +{ + (void)enable; +} + +/**************************************************************************** +* DESCRIPTION: Send some data and wait until it is sent +* RETURN: none +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +void RS485_Send_Data( + uint8_t * buffer, /* data to send */ + uint16_t nbytes) /* number of bytes of data */ +{ + /* LED on send */ volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; /* LED ON */ pPIO->PIO_CODR = LED1; + /* send all the bytes */ while (nbytes) { while (!(RS485_Interface->US_CSR & AT91C_US_TXRDY)) { /* do nothing - wait until Tx buffer is empty */ @@ -180,60 +204,78 @@ void RS485_Send_Frame( RS485_Interface->US_THR = *buffer; buffer++; nbytes--; - /* per MSTP spec */ - if (mstp_port) { - mstp_port->SilenceTimerReset(); - } } while (!(RS485_Interface->US_CSR & AT91C_US_TXRDY)) { /* do nothing - wait until Tx buffer is empty */ } - - return; + /* per MSTP spec */ + Timer_Silence_Reset(); } -/* called by timer, interrupt(?) or other thread */ -void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port) +/**************************************************************************** +* DESCRIPTION: Return true if a framing or overrun error is present +* RETURN: true if error +* ALGORITHM: none +* NOTES: Clears any error flags. +*****************************************************************************/ +bool RS485_ReceiveError(void) { + bool ReceiveError = false; + /* LED on send */ volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; - if (mstp_port->ReceiveError == true) { - /* wait for state machine to clear this */ - } else if (mstp_port->DataAvailable == false) { - /* check for data or error */ - if (RS485_Interface->US_CSR & (AT91C_US_OVRE | AT91C_US_FRAME)) { - /* clear the error flag */ - RS485_Interface->US_CR = AT91C_US_RSTSTA; - mstp_port->ReceiveError = true; - /* LED ON */ - pPIO->PIO_CODR = LED2; - } else if ( RS485_Interface->US_CSR & AT91C_US_RXRDY) { - /* data is available */ - mstp_port->DataRegister = RS485_Interface->US_RHR; - mstp_port->DataAvailable = true; - /* LED ON */ - pPIO->PIO_CODR = LED2; - } + /* check for data or error */ + if (RS485_Interface->US_CSR & (AT91C_US_OVRE | AT91C_US_FRAME)) { + /* clear the error flag */ + RS485_Interface->US_CR = AT91C_US_RSTSTA; + ReceiveError = true; + /* LED ON */ + pPIO->PIO_CODR = LED2; } + + return ReceiveError; +} + +/**************************************************************************** +* DESCRIPTION: Return true if data is available +* RETURN: true if data is available, with the data in the parameter set +* ALGORITHM: none +* NOTES: none +*****************************************************************************/ +bool RS485_DataAvailable(uint8_t *DataRegister) +{ + bool DataAvailable = false; + /* LED on send */ + volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA; + + if ( RS485_Interface->US_CSR & AT91C_US_RXRDY) { + /* data is available */ + *DataRegister = RS485_Interface->US_RHR; + DataAvailable = true; + /* LED ON */ + pPIO->PIO_CODR = LED2; + } + + return DataAvailable; } #ifdef TEST_RS485 -static struct mstp_port_struct_t MSTP_Port; - int main(void) { unsigned i = 0; + uint8_t DataRegister; RS485_Set_Baud_Rate(38400); RS485_Initialize(); /* receive task */ for (;;) { - RS485_Check_UART_Data(&MSTP_Port); - if (MSTP_Port.DataAvailable) { - fprintf(stderr,"%02X ",MSTP_Port.DataRegister); - MSTP_Port.DataAvailable = false; + if (RS485_DataAvailable(&DataRegister)) { + fprintf(stderr,"%02X ",DataRegister); + } else if (RS485_ReceiveError()) { + fprintf(stderr,"ERROR "); } + } } -#endif /* TEST_ABORT */ +#endif diff --git a/bacnet-stack/ports/at91sam7s/rs485.h b/bacnet-stack/ports/at91sam7s/rs485.h index 23a1e6c9..b8e9e01b 100644 --- a/bacnet-stack/ports/at91sam7s/rs485.h +++ b/bacnet-stack/ports/at91sam7s/rs485.h @@ -27,24 +27,24 @@ #define RS485_H #include -#include "mstp.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - void RS485_Set_Interface(char *ifname); - void RS485_Initialize(void); - 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 RS485_Transmitter_Enable(bool enable); - uint8_t RS485_Check_UART_Data( - volatile struct mstp_port_struct_t *mstp_port); /* port specific data */ + /* NOTE: Only able to send up to 255 bytes at a time */ + void RS485_Send_Data( + uint8_t * buffer, /* data to send */ + uint16_t nbytes); /* number of bytes of data */ + bool RS485_ReceiveError(void); + bool RS485_DataAvailable(uint8_t *data); + + void RS485_Turnaround_Delay(void); uint32_t RS485_Get_Baud_Rate(void); bool RS485_Set_Baud_Rate(uint32_t baud); diff --git a/bacnet-stack/ports/at91sam7s/timer.c b/bacnet-stack/ports/at91sam7s/timer.c index 6a49fc20..04a33725 100644 --- a/bacnet-stack/ports/at91sam7s/timer.c +++ b/bacnet-stack/ports/at91sam7s/timer.c @@ -48,7 +48,7 @@ /* global variable counts interrupts */ volatile unsigned long Timer_Milliseconds; /* MS/TP Silence Timer */ -static volatile uint16_t SilenceTime; +static volatile int SilenceTime; static void Timer0_Setup(int milliseconds) { // TC Block Control Register TC_BCR (read/write) @@ -306,11 +306,11 @@ static void Timer0IrqHandler (void) { dummy = pTC->TC_SR; // increment the tick count Timer_Milliseconds++; - if (SilenceTime < 0xFFFF) + if (SilenceTime < 60000) SilenceTime++; } -uint16_t Timer_Silence(void) +int Timer_Silence(void) { return SilenceTime; } diff --git a/bacnet-stack/ports/at91sam7s/timer.h b/bacnet-stack/ports/at91sam7s/timer.h index 7a359e68..76c3c62b 100644 --- a/bacnet-stack/ports/at91sam7s/timer.h +++ b/bacnet-stack/ports/at91sam7s/timer.h @@ -35,7 +35,7 @@ extern "C" { #endif /* __cplusplus */ void TimerInit(void); - uint16_t Timer_Silence(void); + int Timer_Silence(void); void Timer_Silence_Reset(void); #ifdef __cplusplus diff --git a/bacnet-stack/ports/atmega168/dlmstp.c b/bacnet-stack/ports/atmega168/dlmstp.c index 22a74a1f..433b9acc 100644 --- a/bacnet-stack/ports/atmega168/dlmstp.c +++ b/bacnet-stack/ports/atmega168/dlmstp.c @@ -441,7 +441,6 @@ static void MSTP_Send_Frame( RS485_Send_Data(buffer, 2); } RS485_Transmitter_Enable(false); - Timer_Silence_Reset(); } static void MSTP_Receive_Frame_FSM(void) @@ -1243,6 +1242,9 @@ uint16_t dlmstp_receive( if (MSTP_Flag.ReceivePacketPending) { MSTP_Flag.ReceivePacketPending = false; pdu_len = DataLength; + src->mac_len = 1; + src->mac[0] = SourceAddress; + /* data is already in the pdu pointer */ } return pdu_len; diff --git a/bacnet-stack/ports/atmega168/rs485.c b/bacnet-stack/ports/atmega168/rs485.c index b5294d15..38993a5b 100644 --- a/bacnet-stack/ports/atmega168/rs485.c +++ b/bacnet-stack/ports/atmega168/rs485.c @@ -180,6 +180,8 @@ void RS485_Send_Data( /* do nothing - wait until the entire frame in the Transmit Shift Register has been shifted out */ } + /* per MSTP spec */ + Timer_Silence_Reset(); } @@ -191,25 +193,25 @@ void RS485_Send_Data( *****************************************************************************/ bool RS485_ReceiveError(void) { - bool uart_error = false; + bool ReceiveError = false; uint8_t dummy_data; /* check for framing error */ if (BIT_CHECK(UCSR0A,FE0)) { - uart_error = true; + ReceiveError = true; } /* check for overrun error */ if (BIT_CHECK(UCSR0A,DOR0)) { - uart_error = true; + ReceiveError = true; } /* flush the receive buffer */ - if (uart_error) { + if (ReceiveError) { while (BIT_CHECK(UCSR0A,RXC0)) { dummy_data = UDR0; } } - return uart_error; + return ReceiveError; } /**************************************************************************** @@ -230,3 +232,24 @@ bool RS485_DataAvailable(uint8_t *data) return uart_data; } + +#ifdef TEST_RS485 +int main(void) +{ + unsigned i = 0; + uint8_t DataRegister; + + RS485_Set_Baud_Rate(38400); + RS485_Initialize(); + /* receive task */ + for (;;) { + if (RS485_DataAvailable(&DataRegister)) { + fprintf(stderr,"%02X ",DataRegister); + } else if (RS485_ReceiveError()) { + fprintf(stderr,"ERROR "); + } + + } +} +#endif /* TEST_ABORT */ + diff --git a/bacnet-stack/tsm.c b/bacnet-stack/tsm.c index 48b2e92a..bb554b2c 100644 --- a/bacnet-stack/tsm.c +++ b/bacnet-stack/tsm.c @@ -35,7 +35,6 @@ #include #include #include -#include /* memmove() */ #include "bits.h" #include "apdu.h" #include "bacdef.h"