diff --git a/ports/xplained/Makefile b/ports/xplained/Makefile index 24b8e074..2dba01f0 100644 --- a/ports/xplained/Makefile +++ b/ports/xplained/Makefile @@ -45,7 +45,6 @@ CSRC = main.c \ bacnet.c \ bname.c \ device.c \ - dlmstp.c \ led.c \ mstimer-init.c \ netport.c \ @@ -79,7 +78,6 @@ BASICSRC = $(BACNET_BASIC)/tsm/tsm.c \ # core BACnet stack files CORESRC = \ - $(BACNET_CORE)/datalink/crc.c \ $(BACNET_CORE)/abort.c \ $(BACNET_CORE)/bacaddr.c \ $(BACNET_CORE)/bacapp.c \ @@ -90,9 +88,15 @@ CORESRC = \ $(BACNET_CORE)/bacreal.c \ $(BACNET_CORE)/bacstr.c \ $(BACNET_CORE)/datetime.c \ + $(BACNET_CORE)/datalink/cobs.c \ + $(BACNET_CORE)/datalink/crc.c \ + $(BACNET_CORE)/datalink/dlmstp.c \ + $(BACNET_CORE)/datalink/mstp.c \ + $(BACNET_CORE)/datalink/mstptext.c \ $(BACNET_CORE)/dcc.c \ $(BACNET_CORE)/iam.c \ $(BACNET_CORE)/ihave.c \ + $(BACNET_CORE)/indtext.c \ $(BACNET_CORE)/memcopy.c \ $(BACNET_CORE)/hostnport.c \ $(BACNET_CORE)/npdu.c \ diff --git a/ports/xplained/adc-hdw.c b/ports/xplained/adc-hdw.c index efaa52a8..e15c0338 100644 --- a/ports/xplained/adc-hdw.c +++ b/ports/xplained/adc-hdw.c @@ -1,27 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2014 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. - * - *********************************************************************/ +/** + * @file + * @brief ADC configuration + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT + */ #include #include #include diff --git a/ports/xplained/adc-hdw.h b/ports/xplained/adc-hdw.h index 0d0cce68..38ac6b4d 100644 --- a/ports/xplained/adc-hdw.h +++ b/ports/xplained/adc-hdw.h @@ -1,26 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2014 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. -*********************************************************************/ +/** + * @file + * @brief ADC configuration + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef ADC_HDW_H #define ADC_HDW_H diff --git a/ports/xplained/ai.c b/ports/xplained/ai.c index 8bb58df2..583f8f06 100644 --- a/ports/xplained/ai.c +++ b/ports/xplained/ai.c @@ -1,30 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2005 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. - * - *********************************************************************/ - -/* Analog Input Objects customize for your use */ - +/** + * @file + * @brief Analog Input objects, customize for your use as required. + * @author Steve Karg + * @date 2005 + * @copyright SPDX-License-Identifier: MIT + */ #include #include #include diff --git a/ports/xplained/bacnet.c b/ports/xplained/bacnet.c index 39a49755..acbbb259 100644 --- a/ports/xplained/bacnet.c +++ b/ports/xplained/bacnet.c @@ -1,27 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2013 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. - * - *********************************************************************/ +/** + * @file + * @brief BACnet task and initialization for the Xplained board + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #include #include #include diff --git a/ports/xplained/bacnet.cproj b/ports/xplained/bacnet.cproj index 2c5bb34d..320f033d 100644 --- a/ports/xplained/bacnet.cproj +++ b/ports/xplained/bacnet.cproj @@ -707,11 +707,6 @@ compile - - compile - - - compile bacnet-stack\h_dcc.c @@ -800,10 +795,26 @@ compile bacnet-stack\bacstr.c + + compile + bacnet-stack\cobs.c + compile bacnet-stack\crc.c + + compile + bacnet-stack\dlmstp.c + + + compile + bacnet-stack\mstptext.c + + + compile + bacnet-stack\mstp.c + compile bacnet-stack\dcc.c @@ -820,6 +831,10 @@ compile bacnet-stack\ihave.c + + compile + bacnet-stack\indtext.c + compile bacnet-stack\memcopy.c diff --git a/ports/xplained/bacnet.h b/ports/xplained/bacnet.h index 027e280a..29ff501f 100644 --- a/ports/xplained/bacnet.h +++ b/ports/xplained/bacnet.h @@ -1,26 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2010 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. -*********************************************************************/ +/** + * @file + * @brief API for BACnet task and initialization for the Xplained board + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef BACNET_H #define BACNET_H diff --git a/ports/xplained/bname.c b/ports/xplained/bname.c index 4aea5f81..52815a56 100644 --- a/ports/xplained/bname.c +++ b/ports/xplained/bname.c @@ -1,27 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2011 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. - * - *********************************************************************/ +/** + * @file + * @brief API for BACnet device name handling for the Xplained board + * @author Steve Karg + * @date 2010 + * @copyright SPDX-License-Identifier: MIT + */ #include #include #include diff --git a/ports/xplained/bname.h b/ports/xplained/bname.h index 70ae63ec..18fb0967 100644 --- a/ports/xplained/bname.h +++ b/ports/xplained/bname.h @@ -1,26 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2010 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. -*********************************************************************/ +/** + * @file + * @brief API for BACnet device name handling for the Xplained board + * @author Steve Karg + * @date 2010 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef BACNET_NAME_H #define BACNET_NAME_H diff --git a/ports/xplained/device.c b/ports/xplained/device.c index e318aa81..8642146a 100644 --- a/ports/xplained/device.c +++ b/ports/xplained/device.c @@ -1,27 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2015 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. - * - *********************************************************************/ +/** + * @file + * @brief BACnet device object handling for the Xplained board + * @author Steve Karg + * @date 2015 + * @copyright SPDX-License-Identifier: MIT + */ #include #include #include diff --git a/ports/xplained/dlmstp.c b/ports/xplained/dlmstp.c deleted file mode 100644 index 84e551d5..00000000 --- a/ports/xplained/dlmstp.c +++ /dev/null @@ -1,1487 +0,0 @@ -/*####COPYRIGHTBEGIN#### - ------------------------------------------- - Copyright (C) 2010 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 -/* BACnet Stack defines - first */ -#include "bacnet/bacdef.h" -/* BACnet Stack API */ -#include "bacnet/datalink/dlmstp.h" -#include "bacnet/datalink/mstpdef.h" -#include "bacnet/datalink/crc.h" -#include "bacnet/npdu.h" -#include "bacnet/bacaddr.h" -#include "bacnet/basic/sys/ringbuf.h" -#include "bacnet/basic/sys/mstimer.h" -/* port specific */ -#include "rs485.h" - -/* This file has been customized for use with small microprocessors */ -/* Assumptions: - Only one MS/TP datalink layer -*/ - -/* count must be a power of 2 for ringbuf library */ -#ifndef MSTP_PDU_PACKET_COUNT -#define MSTP_PDU_PACKET_COUNT 2 -#endif - -/* The state of the Receive State Machine */ -static volatile MSTP_RECEIVE_STATE Receive_State; -/* When a master node is powered up or reset, */ -/* it shall unconditionally enter the INITIALIZE state. */ -static volatile MSTP_MASTER_STATE Master_State; -/* bit-sized boolean flags */ -static volatile 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; - /* set to TRUE when we get a frame not for us */ - unsigned ReceivedValidFrameNotForUs : 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 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 volatile uint32_t DataLength; -/* Used to store the destination address of a received frame. */ -static volatile 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 volatile uint8_t EventCount; -/* Used to store the frame type of a received frame. */ -static volatile 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 volatile uint16_t InputBufferSize; -/* Used to store the Source Address of a received frame. */ -static volatile 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 volatile 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 volatile uint8_t Nmax_info_frames = MSTP_PDU_PACKET_COUNT; -/* 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 volatile uint8_t Nmax_master = 127; - -/* 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.) */ -#ifndef Treply_timeout -#define Treply_timeout 260 -#endif - -/* The 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 35 milliseconds.) */ -#ifndef Tusage_timeout -#define Tusage_timeout 30 -#endif - -/* 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); */ -#ifndef Tframe_abort -#define Tframe_abort 30 -#endif - -/* 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. */ -#ifndef Treply_delay -#define Treply_delay (250 - 50) -#endif - -/* we need to be able to increment without rolling over */ -#define INCREMENT_AND_LIMIT_UINT8(x) \ - { \ - if (x < 0xFF) \ - x++; \ - } - -/* data structure for MS/TP PDU Queue */ -struct mstp_pdu_packet { - bool data_expecting_reply; - uint8_t destination_mac; - uint16_t length; - uint8_t buffer[DLMSTP_MPDU_MAX]; -}; -static volatile struct mstp_pdu_packet PDU_Buffer[MSTP_PDU_PACKET_COUNT]; -static RING_BUFFER PDU_Queue; - -bool dlmstp_init(char *ifname) -{ - ifname = ifname; - - Ringbuf_Init(&PDU_Queue, (uint8_t *)&PDU_Buffer, - sizeof(struct mstp_pdu_packet), MSTP_PDU_PACKET_COUNT); - - return true; -} - -void dlmstp_cleanup(void) -{ - /* nothing to do for static buffers */ -} - -void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address) -{ - int i = 0; - - if (mstp_address == MSTP_BROADCAST_ADDRESS) { - /* mac_len = 0 if broadcast address */ - src->mac_len = 0; - src->mac[0] = 0; - } else { - src->mac_len = 1; - src->mac[0] = mstp_address; - } - /* fill with 0's starting with index 1; index 0 filled above */ - for (i = 1; i < MAX_MAC_LEN; i++) { - src->mac[i] = 0; - } - src->net = 0; - src->len = 0; - for (i = 0; i < MAX_MAC_LEN; i++) { - src->adr[i] = 0; - } -} - -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, - uint8_t dest_address) -{ - uint16_t offset; - /* One way to check the message is to compare NPDU - src, dest, along with the APDU type, invoke id. - Seems a bit overkill */ - struct DER_compare_t { - BACNET_NPDU_DATA npdu_data; - BACNET_ADDRESS address; - uint8_t pdu_type; - uint8_t invoke_id; - uint8_t service_choice; - }; - struct DER_compare_t request; - struct DER_compare_t reply; - - /* decode the request data */ - request.address.mac[0] = src_address; - request.address.mac_len = 1; - offset = bacnet_npdu_decode(request_pdu, request_pdu_len, NULL, - &request.address, &request.npdu_data); - if (request.npdu_data.network_layer_message) { - return false; - } - request.pdu_type = request_pdu[offset] & 0xF0; - if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) { - return false; - } - request.invoke_id = request_pdu[offset + 2]; - /* segmented message? */ - if (request_pdu[offset] & BIT(3)) - request.service_choice = request_pdu[offset + 5]; - else - request.service_choice = request_pdu[offset + 3]; - /* decode the reply data */ - reply.address.mac[0] = dest_address; - reply.address.mac_len = 1; - offset = bacnet_npdu_decode( - reply_pdu, reply_pdu_len, &reply.address, NULL, &reply.npdu_data); - if (reply.npdu_data.network_layer_message) { - return false; - } - /* reply could be a lot of things: - confirmed, simple ack, abort, reject, error */ - reply.pdu_type = reply_pdu[offset] & 0xF0; - switch (reply.pdu_type) { - case PDU_TYPE_SIMPLE_ACK: - reply.invoke_id = reply_pdu[offset + 1]; - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_COMPLEX_ACK: - reply.invoke_id = reply_pdu[offset + 1]; - /* segmented message? */ - if (reply_pdu[offset] & BIT(3)) - reply.service_choice = reply_pdu[offset + 4]; - else - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_ERROR: - reply.invoke_id = reply_pdu[offset + 1]; - reply.service_choice = reply_pdu[offset + 2]; - break; - case PDU_TYPE_REJECT: - case PDU_TYPE_ABORT: - reply.invoke_id = reply_pdu[offset + 1]; - break; - default: - return false; - } - if (request.invoke_id != reply.invoke_id) { - return false; - } - /* these services don't have service choice included */ - if ((reply.pdu_type != PDU_TYPE_REJECT) && - (reply.pdu_type != PDU_TYPE_ABORT)) { - if (request.service_choice != reply.service_choice) { - return false; - } - } - if (request.npdu_data.protocol_version != - reply.npdu_data.protocol_version) { - return false; - } -#if 0 - /* the NDPU priority doesn't get passed through the stack, and - all outgoing messages have NORMAL priority */ - if (request.npdu_data.priority != reply.npdu_data.priority) { - return false; - } -#endif - if (!bacnet_address_same(&request.address, &reply.address)) { - return false; - } - - return true; -} - -/* 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 header crc */ - uint8_t buffer_crc[2]; /* stores the 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] = 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; - 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_crc[0] = (crc16 & 0x00FF); - buffer_crc[1] = ((crc16 & 0xFF00) >> 8); - } - /* on a slower processor, we don't want to calculate - the CRC after we send the header because there - will be a gap */ - rs485_bytes_send(buffer, 8); - if (data_len) { - rs485_bytes_send(data, data_len); - rs485_bytes_send(buffer_crc, 2); - } -} - -static void MSTP_Receive_Frame_FSM(void) -{ - /* stores the latest received data octet */ - uint8_t DataRegister = 0; - /* incoming address */ - uint8_t Address = 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 uint16_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_receive_error()) { - /* EatAnError */ - rs485_silence_reset(); - INCREMENT_AND_LIMIT_UINT8(EventCount); - } else if (rs485_byte_available(&DataRegister)) { - rs485_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 (rs485_silence_elapsed(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_receive_error()) { - /* Error */ - rs485_silence_reset(); - INCREMENT_AND_LIMIT_UINT8(EventCount); - /* wait for the start of a frame. */ - Receive_State = MSTP_RECEIVE_STATE_IDLE; - } else if (rs485_byte_available(&DataRegister)) { - rs485_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 (rs485_silence_elapsed(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_receive_error()) { - /* Error */ - rs485_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_byte_available(&DataRegister)) { - rs485_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 { - Address = DestinationAddress; - if (DataLength == 0) { - /* NoData */ - if ((Address == This_Station) || - (Address == MSTP_BROADCAST_ADDRESS)) { - /* ForUs */ - /* indicate that a frame with - no data has been received */ - MSTP_Flag.ReceivedValidFrame = true; - } else { - /* NotForUs */ - MSTP_Flag.ReceivedValidFrameNotForUs = true; - } - /* wait for the start of the next frame. */ - Receive_State = MSTP_RECEIVE_STATE_IDLE; - } else { - /* receive the data portion of the frame. */ - if ((Address == This_Station) || - (Address == MSTP_BROADCAST_ADDRESS)) { - if (DataLength <= InputBufferSize) { - /* Data */ - Receive_State = MSTP_RECEIVE_STATE_DATA; - } else { - /* FrameTooLong */ - Receive_State = - MSTP_RECEIVE_STATE_SKIP_DATA; - } - } else { - /* NotForUs */ - Receive_State = MSTP_RECEIVE_STATE_SKIP_DATA; - } - Index = 0; - DataCRC = 0xFFFF; - } - } - } 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: - case MSTP_RECEIVE_STATE_SKIP_DATA: - /* In the DATA state, the node waits - for the data portion of a frame. */ - if (rs485_silence_elapsed(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_receive_error()) { - /* Error */ - rs485_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_byte_available(&DataRegister)) { - rs485_silence_reset(); - INCREMENT_AND_LIMIT_UINT8(EventCount); - if (Index < DataLength) { - /* DataOctet */ - DataCRC = CRC_Calc_Data(DataRegister, DataCRC); - if (Index < InputBufferSize) { - 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 (Receive_State == MSTP_RECEIVE_STATE_DATA) { - /* ForUs */ - MSTP_Flag.ReceivedValidFrame = true; - } else { - /* NotForUs */ - MSTP_Flag.ReceivedValidFrameNotForUs = true; - } - - } else { - MSTP_Flag.ReceivedInvalidFrame = true; - } - Receive_State = MSTP_RECEIVE_STATE_IDLE; - } 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; -} - -#ifdef MSTP_DEBUG_STATES -static MSTP_MASTER_STATE Master_State_Log[128]; -static unsigned master_state_log_index = 0; -void log_master_state(MSTP_MASTER_STATE state) -{ - Master_State_Log[master_state_log_index] = state; - master_state_log_index++; - if (master_state_log_index > 128) { - master_state_log_index = 0; - } -} -#else -#define log_master_state(n) (void)n; -#endif - -static void MSTP_Slave_Node_FSM(void) -{ - Master_State = MSTP_MASTER_STATE_IDLE; - if (MSTP_Flag.ReceivedInvalidFrame == true) { - /* ReceivedInvalidFrame */ - /* invalid frame was received */ - MSTP_Flag.ReceivedInvalidFrame = false; - } else if (MSTP_Flag.ReceivedValidFrame) { - MSTP_Flag.ReceivedValidFrame = false; - switch (FrameType) { - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - if (DestinationAddress != MSTP_BROADCAST_ADDRESS) { - /* indicate successful reception to the higher layers */ - MSTP_Flag.ReceivePacketPending = true; - } - break; - case FRAME_TYPE_TEST_REQUEST: - MSTP_Send_Frame(FRAME_TYPE_TEST_RESPONSE, SourceAddress, - This_Station, &InputBuffer[0], DataLength); - break; - case FRAME_TYPE_TOKEN: - case FRAME_TYPE_POLL_FOR_MASTER: - case FRAME_TYPE_TEST_RESPONSE: - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - default: - break; - } - } else if (MSTP_Flag.ReceivePacketPending) { - if (!Ringbuf_Empty(&PDU_Queue)) { - /* packet from the PDU Queue */ - struct mstp_pdu_packet *pkt; - /* did the frame in the queue match the last request? */ - bool matched; - - pkt = (struct mstp_pdu_packet *)Ringbuf_Peek(&PDU_Queue); - matched = dlmstp_compare_data_expecting_reply(&InputBuffer[0], - DataLength, SourceAddress, &pkt->buffer[0], pkt->length, - pkt->destination_mac); - if (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 (pkt->data_expecting_reply) { - frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - MSTP_Send_Frame(frame_type, pkt->destination_mac, This_Station, - (uint8_t *)&pkt->buffer[0], pkt->length); - (void)Ringbuf_Pop(&PDU_Queue, NULL); - } - /* clear our flag we were holding for comparison */ - MSTP_Flag.ReceivePacketPending = false; - } else if ((rs485_silence_elapsed(Treply_delay))) { - /* 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 no reply is possible. */ - /* clear our flag we were holding for comparison */ - MSTP_Flag.ReceivePacketPending = false; - } - } -} - -/* 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 = 0; - /* "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 = 0; - /* "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 = 0; - /* 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 = 0; - /* next-x-station calculations */ - uint8_t next_poll_station = 0; - uint8_t next_this_station = 0; - uint8_t next_next_station = 0; - /* destination address */ - uint8_t destination; - /* source address */ - uint8_t source; - /* any data to be sent - may be null */ - uint8_t *data; - /* amount of data to be sent - may be 0 */ - uint16_t data_len; - /* timeout values */ - uint16_t my_timeout = 10, ns_timeout = 0; - bool matched = false; - bool timeout = false; - /* transition immediately to the next state */ - bool transition_now = false; - /* packet from the PDU Queue */ - struct mstp_pdu_packet *pkt = NULL; - - /* some calculations that several states need */ - next_poll_station = (Poll_Station + 1) % (Nmax_master + 1); - /* jump hoops for volatile */ - source = This_Station; - next_this_station = (source + 1) % (Nmax_master + 1); - next_next_station = (Next_Station + 1) % (Nmax_master + 1); - log_master_state(Master_State); - 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; - 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 (rs485_silence_elapsed(Tno_token)) { - /* LostToken */ - /* assume that the token has been lost */ - EventCount = 0; /* Addendum 135-2004d-8 */ - /* set the receive frame flags to false in case we received - some bytes and had a timeout for some reason */ - MSTP_Flag.ReceivedValidFrame = false; - MSTP_Flag.ReceivedInvalidFrame = false; - MSTP_Flag.ReceivedValidFrameNotForUs = false; - 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 */ - destination = SourceAddress; - source = This_Station; - if (DestinationAddress == This_Station) { - MSTP_Send_Frame(FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, - destination, source, NULL, 0); - } - break; - case FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY: - if ((DestinationAddress == MSTP_BROADCAST_ADDRESS) && - (npdu_confirmed_service(InputBuffer, DataLength))) { - /* BTL test: verifies that the IUT will quietly - discard any Confirmed-Request-PDU, whose - destination address is a multicast or - broadcast address, received from the - network layer. */ - } else { - /* indicate successful reception to higher layer */ - MSTP_Flag.ReceivePacketPending = true; - } - break; - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - if (DestinationAddress == MSTP_BROADCAST_ADDRESS) { - /* broadcast DER just remains IDLE */ - } else { - /* indicate successful reception to higher layers */ - MSTP_Flag.ReceivePacketPending = true; - Master_State = - MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; - } - break; - case FRAME_TYPE_TEST_REQUEST: - destination = SourceAddress; - source = This_Station; - data = &InputBuffer[0]; - data_len = DataLength; - MSTP_Send_Frame(FRAME_TYPE_TEST_RESPONSE, destination, - source, data, data_len); - 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 (Ringbuf_Empty(&PDU_Queue)) { - /* NothingToSend */ - FrameCount = Nmax_info_frames; - Master_State = MSTP_MASTER_STATE_DONE_WITH_TOKEN; - transition_now = true; - } else { - uint8_t frame_type; - pkt = (struct mstp_pdu_packet *)Ringbuf_Peek(&PDU_Queue); - if (pkt->data_expecting_reply) { - frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - MSTP_Send_Frame(frame_type, pkt->destination_mac, This_Station, - (uint8_t *)&pkt->buffer[0], pkt->length); - FrameCount++; - switch (frame_type) { - case FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY: - /* SendAndWait */ - if (pkt->destination_mac == 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; - } - (void)Ringbuf_Pop(&PDU_Queue, NULL); - } - break; - case MSTP_MASTER_STATE_WAIT_FOR_REPLY: - /* In the WAIT_FOR_REPLY state, the node waits for */ - /* a reply from another node. */ - if (rs485_silence_elapsed(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) { - destination = DestinationAddress; - if (destination == 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_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 */ - 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; - } else if ((MSTP_Flag.SoleMaster == false) && - (Next_Station == This_Station)) { - /* NextStationUnknown - added in Addendum 135-2008v-1 */ - /* then the next station to which the token - should be sent is unknown - so PollForMaster */ - Poll_Station = next_this_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; - } - /* 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_next_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 (rs485_silence_elapsed(Tusage_timeout)) { - 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. */ - /* note: if NS=TS-1, this node could send PFM to self! */ - 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; - } - } else { - 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; - } - } - break; - /* The NO_TOKEN state is entered if Silence Timer - 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 (rs485_silence_elapsed(my_timeout)) { - ns_timeout = Tno_token + (Tslot * (This_Station + 1)); - if (rs485_silence_elapsed(ns_timeout)) { - /* should never get here unless timer resolution is bad */ - rs485_silence_reset(); - Master_State = MSTP_MASTER_STATE_IDLE; - } else { - /* 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; - } - } else { - 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; - } - } - 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) { - destination = DestinationAddress; - if ((destination == 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 ((rs485_silence_elapsed(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: - destination = SourceAddress; - source = This_Station; - data = &InputBuffer[0]; - data_len = DataLength; - timeout = rs485_silence_elapsed(Treply_delay); - if (!timeout) { - pkt = (struct mstp_pdu_packet *)Ringbuf_Peek(&PDU_Queue); - if (pkt != NULL) { - matched = dlmstp_compare_data_expecting_reply(data, - data_len, destination, &pkt->buffer[0], pkt->length, - pkt->destination_mac); - } else { - matched = false; - } - } - if (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 (pkt->data_expecting_reply) { - frame_type = FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY; - } else { - frame_type = FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY; - } - MSTP_Send_Frame(frame_type, pkt->destination_mac, This_Station, - (uint8_t *)&pkt->buffer[0], pkt->length); - Master_State = MSTP_MASTER_STATE_IDLE; - /* clear our flag we were holding for comparison */ - MSTP_Flag.ReceivedValidFrame = false; - /* clear the queue */ - (void)Ringbuf_Pop(&PDU_Queue, NULL); - } else if ((pkt != NULL) || timeout) { - /* 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, destination, source, 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 true if the Send PDU Queue is Empty */ -bool dlmstp_send_pdu_queue_empty(void) -{ - return Ringbuf_Empty(&PDU_Queue); -} - -/* returns true if the Send PDU Queue is Full */ -bool dlmstp_send_pdu_queue_full(void) -{ - return Ringbuf_Full(&PDU_Queue); -} - -/* 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; - struct mstp_pdu_packet *pkt; - uint16_t i = 0; - - pkt = (struct mstp_pdu_packet *)Ringbuf_Data_Peek(&PDU_Queue); - if (pkt) { - pkt->data_expecting_reply = npdu_data->data_expecting_reply; - for (i = 0; i < pdu_len; i++) { - pkt->buffer[i] = pdu[i]; - } - pkt->length = pdu_len; - if (dest->mac_len == 0) { - pkt->destination_mac = MSTP_BROADCAST_ADDRESS; - } else { - pkt->destination_mac = dest->mac[0]; - } - if (Ringbuf_Data_Put(&PDU_Queue, (volatile uint8_t *)pkt)) { - bytes_sent = pdu_len; - } - } - - return bytes_sent; -} -/** - * Handle the running of the MS/TP state machine by receiving bytes - * and placing them into packets. If a packet is received, the number of - * bytes returned is non-zero. - * - * @param src [out] - the source address of the packet received - * @param pdu [out] - the PDU buffer which is filled with the packet. - * @param max_pdu [in] - the size of the PDU buffer - * @param timeout [in] - the number of milliseconds to wait for a packet - * - * @return Return the length of the packet - */ -uint16_t dlmstp_receive( - BACNET_ADDRESS *src, uint8_t *pdu, uint16_t max_pdu, unsigned timeout) -{ - uint16_t pdu_len = 0; /* return value */ - bool transmitting = false; - - (void)timeout; - /* set the input buffer to the same data storage for zero copy */ - if (!InputBuffer) { - InputBuffer = pdu; - InputBufferSize = max_pdu; - } - transmitting = rs485_rts_enabled(); - if (!transmitting) { - while ((MSTP_Flag.ReceivedValidFrame == false) && - (MSTP_Flag.ReceivedValidFrameNotForUs == false) && - (MSTP_Flag.ReceivedInvalidFrame == false)) { - /* only do receive state machine while we don't have a frame */ - MSTP_Receive_Frame_FSM(); - /* process another byte, if available, since this handler - may not get called often enough to process fast baud long - messages. */ - if (!rs485_byte_available(NULL)) { - break; - } - } - } - /* only do master state machine while rx is idle */ - if ((Receive_State == MSTP_RECEIVE_STATE_IDLE) && (transmitting == false)) { - if (MSTP_Flag.ReceivedValidFrameNotForUs) { - MSTP_Flag.ReceivedValidFrameNotForUs = false; - } else if (MSTP_Flag.ReceivedValidFrame) { - if (rs485_turnaround_elapsed()) { - if ((This_Station > 127) && (This_Station < 255)) { - MSTP_Slave_Node_FSM(); - } else if (This_Station <= 127) { - while (MSTP_Master_Node_FSM()) { - /* do nothing while some states fast transition */ - }; - } - } - } else { - if ((This_Station > 127) && (This_Station < 255)) { - MSTP_Slave_Node_FSM(); - } else if (This_Station <= 127) { - 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) { - if (This_Station <= 127) { - /* master nodes clear immediately */ - 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; -} - -void dlmstp_set_mac_address(uint8_t mac_address) -{ - /* Master Nodes can only have address 0-127 */ - /* Slave Nodes can only have address 0-254 */ - if (mac_address < 255) { - This_Station = mac_address; - } - - return; -} - -uint8_t dlmstp_mac_address(void) -{ - return 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. */ -void dlmstp_set_max_info_frames(uint8_t max_info_frames) -{ - if ((max_info_frames >= 1) && (max_info_frames <= MSTP_PDU_PACKET_COUNT)) { - Nmax_info_frames = max_info_frames; - } - - return; -} - -uint8_t dlmstp_max_info_frames(void) -{ - return 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. */ -void dlmstp_set_max_master(uint8_t max_master) -{ - if (max_master <= 127) { - Nmax_master = max_master; - } - - return; -} - -uint8_t dlmstp_max_master(void) -{ - return Nmax_master; -} - -void dlmstp_get_my_address(BACNET_ADDRESS *my_address) -{ - int i = 0; /* counter */ - - my_address->mac_len = 1; - 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++) { - my_address->adr[i] = 0; - } - - return; -} - -void dlmstp_get_broadcast_address(BACNET_ADDRESS *dest) -{ /* destination address */ - int i = 0; /* counter */ - - if (dest) { - dest->mac_len = 1; - dest->mac[0] = MSTP_BROADCAST_ADDRESS; - dest->net = BACNET_BROADCAST_NETWORK; - dest->len = 0; /* always zero when DNET is broadcast */ - for (i = 0; i < MAX_MAC_LEN; i++) { - dest->adr[i] = 0; - } - } - - return; -} - -bool dlmstp_sole_master(void) -{ - if (MSTP_Flag.SoleMaster) { - return true; - } - - return false; -} - -uint8_t dlmstp_max_info_frames_limit(void) -{ - return MSTP_PDU_PACKET_COUNT; -} - -uint8_t dlmstp_max_master_limit(void) -{ - return 127; -} diff --git a/ports/xplained/led.c b/ports/xplained/led.c index 99833ca1..e33c90ad 100644 --- a/ports/xplained/led.c +++ b/ports/xplained/led.c @@ -1,26 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2009 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. - *********************************************************************/ +/** + * @file + * @brief LED configuration and operation + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT + */ #include #include "board.h" #include "ioport.h" diff --git a/ports/xplained/led.h b/ports/xplained/led.h index c80f16f1..bc0c5b5f 100644 --- a/ports/xplained/led.h +++ b/ports/xplained/led.h @@ -1,26 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2009 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. -*********************************************************************/ +/** + * @file + * @brief LED configuration and operation + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef LED_H #define LED_H diff --git a/ports/xplained/main.c b/ports/xplained/main.c index f5f76d93..d0ebcfd4 100644 --- a/ports/xplained/main.c +++ b/ports/xplained/main.c @@ -1,19 +1,66 @@ /** - * \file - * - * \brief XMEGA-A3BU BACnet application - * + * @file + * @brief XMEGA-A3BU BACnet application + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT */ #include #include "bacnet/basic/sys/mstimer.h" +#include "bacnet/datalink/datalink.h" +#include "bacnet/datalink/dlmstp.h" +#include "bacnet/datalink/mstp.h" #include "rs485.h" #include "led.h" #include "adc-hdw.h" -#include "bacnet/datalink/dlmstp.h" #include "bacnet.h" static struct mstimer_callback_data_t BACnet_Callback; +/* MS/TP port */ +static struct mstp_port_struct_t MSTP_Port; +static struct dlmstp_rs485_driver RS485_Driver = { + .init = rs485_init, + .send = rs485_bytes_send, + .read = rs485_byte_available, + .transmitting = rs485_rts_enabled, + .baud_rate = rs485_baud_rate, + .baud_rate_set = rs485_baud_rate_set, + .silence_milliseconds = rs485_silence_milliseconds, + .silence_reset = rs485_silence_reset +}; +static struct dlmstp_user_data_t MSTP_User_Data; +static uint8_t Input_Buffer[DLMSTP_MPDU_MAX]; +static uint8_t Output_Buffer[DLMSTP_MPDU_MAX]; + +/** + * @brief MS/TP configuraiton + */ +static void dlmstp_configure(void) +{ + /* initialize MSTP datalink layer */ + MSTP_Port.Nmax_info_frames = DLMSTP_MAX_INFO_FRAMES; + MSTP_Port.Nmax_master = DLMSTP_MAX_MASTER; + MSTP_Port.InputBuffer = Input_Buffer; + MSTP_Port.InputBufferSize = sizeof(Input_Buffer); + MSTP_Port.OutputBuffer = Output_Buffer; + MSTP_Port.OutputBufferSize = sizeof(Output_Buffer); + /* user data */ + MSTP_Port.ZeroConfigEnabled = true; + MSTP_Port.SlaveNodeEnabled = false; + MSTP_User_Data.RS485_Driver = &RS485_Driver; + MSTP_Port.UserData = &MSTP_User_Data; + dlmstp_init((char *)&MSTP_Port); + if (MSTP_Port.ZeroConfigEnabled) { + dlmstp_set_mac_address(255); + } else { + /* FIXME: get the address from hardware DIP or from EEPROM */ + dlmstp_set_mac_address(1); + } + /* FIXME: get the baud rate from hardware DIP or from EEPROM */ + dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT); +} + /** * \brief Main function. * @@ -41,6 +88,7 @@ int main(void) cpu_irq_enable(); /* application initialization */ rs485_baud_rate_set(38400); + dlmstp_configure(); bacnet_init(); /* run forever - timed tasks */ mstimer_callback(&BACnet_Callback, bacnet_task_timed, 5); diff --git a/ports/xplained/mstimer-init.c b/ports/xplained/mstimer-init.c index cf03069f..510fc357 100644 --- a/ports/xplained/mstimer-init.c +++ b/ports/xplained/mstimer-init.c @@ -1,33 +1,9 @@ -/* +/** * @file - * * @brief 1ms timer configuration - * - * Copyright (C) 2009 Steve Karg - * - * Created: 10/24/2013 8:58:56 PM - * Author: Steve - * - * @page License - * - * 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. + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT */ #include #include diff --git a/ports/xplained/netport.c b/ports/xplained/netport.c index f0d48ddb..583bab36 100644 --- a/ports/xplained/netport.c +++ b/ports/xplained/netport.c @@ -1,34 +1,11 @@ /** * @file - * @author Steve Karg - * @date 2016 * @brief Network port objects, customize for your use - * - * @section DESCRIPTION - * - * The Network Port object provides access to the configuration + * @details The Network Port object provides access to the configuration * and properties of network ports of a device. - * - * @section LICENSE - * - * 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. + * @author Steve Karg + * @date 2014 + * @copyright SPDX-License-Identifier: MIT */ #include #include diff --git a/ports/xplained/nvmdata.c b/ports/xplained/nvmdata.c index 04e321f4..46420ac7 100644 --- a/ports/xplained/nvmdata.c +++ b/ports/xplained/nvmdata.c @@ -1,9 +1,9 @@ /** * @file + * @brief Store and retrieve non-volatile data * @author Steve Karg * @date 2013 - * @brief Store and retrieve non-volatile data - * + * @copyright SPDX-License-Identifier: MIT */ #include #include diff --git a/ports/xplained/nvmdata.h b/ports/xplained/nvmdata.h index ac7167de..be1ec6a0 100644 --- a/ports/xplained/nvmdata.h +++ b/ports/xplained/nvmdata.h @@ -1,27 +1,10 @@ -/************************************************************************ -* -* Copyright (C) 2013 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. -* -*************************************************************************/ +/** + * @file + * @brief Store and retrieve non-volatile data + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef NVM_DATA_H #define NVM_DATA_H diff --git a/ports/xplained/rs485.c b/ports/xplained/rs485.c index 4a95c1e4..d3eba4bc 100644 --- a/ports/xplained/rs485.c +++ b/ports/xplained/rs485.c @@ -1,30 +1,9 @@ /** * @file - * * @brief RS-485 Interface - * - * Copyright (C) 2013 Steve Karg - * - * @page License - * - * 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. + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT */ #include #include @@ -71,11 +50,14 @@ static FIFO_BUFFER Transmit_Queue; static uint32_t Baud_Rate; /* timer for measuring line silence */ static struct mstimer Silence_Timer; -/* flag to track RTS status */ -static volatile bool RTS_Status; +/* flag to track transmit status */ +static volatile bool Transmitting; +/* statistics */ +static volatile uint32_t RS485_Transmit_Bytes; +static volatile uint32_t RS485_Receive_Bytes; /** - * Resets the silence timer + * @brief Reset the silence on the wire timer. */ void rs485_silence_reset(void) { @@ -83,15 +65,12 @@ void rs485_silence_reset(void) } /** - * Determine the amount of silence on the wire from the timer. - * - * @param interval - amount of time in milliseconds that line could be silent - * - * @return true if the line has been silent for the interval + * @brief Return the RS-485 silence time in milliseconds + * @return silence time in milliseconds */ -bool rs485_silence_elapsed(uint32_t interval) +uint32_t rs485_silence_milliseconds(void) { - return (mstimer_elapsed(&Silence_Timer) > interval); + return mstimer_elapsed(&Silence_Timer); } /** @@ -106,13 +85,13 @@ void rs485_rts_enable(bool enable) ioport_set_value(RS485_RE, 1); ioport_set_value(RS485_DE, 1); led_on(LED_RS485_TX); - RTS_Status = true; + Transmitting = true; } else { /* Turn Tx enable off */ ioport_set_value(RS485_RE, 0); ioport_set_value(RS485_DE, 0); led_off_delay(LED_RS485_TX, 10); - RTS_Status = false; + Transmitting = false; } } @@ -123,39 +102,7 @@ void rs485_rts_enable(bool enable) */ bool rs485_rts_enabled(void) { - return RTS_Status; -} - -/** - * Baud rate determines turnaround time. - * 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 - * - * @return: amount of milliseconds to wait - */ -static uint16_t rs485_turnaround_time(void) -{ - /* delay after reception before transmitting - per MS/TP spec */ - /* wait a minimum 40 bit times since reception */ - /* at least 2 ms for errors: rounding, clock tick */ - return (2 + ((Tturnaround * 1000) / Baud_Rate)); -} - -/** - * Use the silence timer to determine turnaround time. - * - * @return true if the line has been silent for the turnaround interval - */ -bool rs485_turnaround_elapsed(void) -{ - return (mstimer_elapsed(&Silence_Timer) > rs485_turnaround_time()); + return Transmitting; } /** @@ -175,6 +122,7 @@ bool rs485_byte_available(uint8_t *data_register) led_on(LED_RS485_RX); if (data_register) { *data_register = FIFO_Get(&Receive_Queue); + RS485_Receive_Bytes++; } data_available = true; } @@ -192,16 +140,6 @@ bool rs485_receive_error(void) return false; } -/** - * Determines if the entire frame is sent from USART FIFO - * - * @return true if the USART FIFO is empty - */ -bool rs485_frame_sent(void) -{ - return usart_tx_is_complete(&RS485_USART); -} - /** * Transmit one or more bytes on RS-485. Can be called while transmitting to * add additional bytes to transmit queue. @@ -209,7 +147,7 @@ bool rs485_frame_sent(void) * @param buffer - array of one or more bytes to transmit * @param nbytes - number of bytes to transmit */ -bool rs485_bytes_send(uint8_t *buffer, uint16_t nbytes) +void rs485_bytes_send(uint8_t *buffer, uint16_t nbytes) { bool status = false; bool start_required = false; @@ -227,10 +165,9 @@ bool rs485_bytes_send(uint8_t *buffer, uint16_t nbytes) usart_clear_tx_complete(&RS485_USART); usart_set_tx_interrupt_level(&RS485_USART, USART_INT_LVL_LO); usart_putchar(&RS485_USART, ch); + RS485_Transmit_Bytes++; } } - - return status; } /** @@ -306,6 +243,24 @@ bool rs485_baud_rate_set(uint32_t baud) return valid; } +/** + * @brief Return the RS-485 statistics for transmit bytes + * @return number of bytes transmitted + */ +uint32_t rs485_bytes_transmitted(void) +{ + return RS485_Transmit_Bytes; +} + +/** + * @brief Return the RS-485 statistics for receive bytes + * @return number of bytes received + */ +uint32_t rs485_bytes_received(void) +{ + return RS485_Receive_Bytes; +} + /** * Initialize the RS-485 UART interface, receive interrupts enabled */ diff --git a/ports/xplained/rs485.h b/ports/xplained/rs485.h index 7b5506f1..362dd8a0 100644 --- a/ports/xplained/rs485.h +++ b/ports/xplained/rs485.h @@ -1,26 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2009 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. -*********************************************************************/ +/** + * @file + * @brief RS-485 Interface + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef RS485_H #define RS485_H @@ -30,32 +14,24 @@ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ - void rs485_rts_enable( - bool enable); - bool rs485_rts_enabled( - void); - bool rs485_byte_available( - uint8_t * data_register); - bool rs485_receive_error( - void); - bool rs485_bytes_send( - uint8_t * buffer, /* data to send */ - uint16_t nbytes); /* number of bytes of data */ - bool rs485_frame_sent(void); - bool rs485_turnaround_elapsed( - void); - uint32_t rs485_baud_rate( - void); - bool rs485_baud_rate_set( - uint32_t baud); +void rs485_rts_enable(bool enable); +bool rs485_rts_enabled(void); +bool rs485_byte_available(uint8_t *data_register); +bool rs485_receive_error(void); - void rs485_silence_reset( - void); - bool rs485_silence_elapsed( - uint32_t interval); +void rs485_bytes_send(uint8_t *buffer, uint16_t nbytes); - void rs485_init(void); +uint32_t rs485_baud_rate(void); +bool rs485_baud_rate_set(uint32_t baud); + +uint32_t rs485_silence_milliseconds(void); +void rs485_silence_reset(void); + +uint32_t rs485_bytes_transmitted(void); +uint32_t rs485_bytes_received(void); + +void rs485_init(void); #ifdef __cplusplus } diff --git a/ports/xplained/stack.c b/ports/xplained/stack.c index eaf6592c..6adc9846 100644 --- a/ports/xplained/stack.c +++ b/ports/xplained/stack.c @@ -1,27 +1,10 @@ -/************************************************************************** - * - * Copyright (C) 2009 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. - * - *********************************************************************/ +/** + * @file + * @brief AVR C-Stack Tracking for stack overflow detection + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #include "board.h" /* me */ #include "stack.h" diff --git a/ports/xplained/stack.h b/ports/xplained/stack.h index a306317d..6defa025 100644 --- a/ports/xplained/stack.h +++ b/ports/xplained/stack.h @@ -1,27 +1,10 @@ -/************************************************************************** -* -* Copyright (C) 2009 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. -* -*********************************************************************/ +/** + * @file + * @brief API for AVR C-Stack Tracking for stack overflow detection + * @author Steve Karg + * @date 2013 + * @copyright SPDX-License-Identifier: MIT + */ #ifndef STACK_H #define STACK_H diff --git a/src/bacnet/basic/sys/platform.h b/src/bacnet/basic/sys/platform.h index a983fed3..d93aafef 100644 --- a/src/bacnet/basic/sys/platform.h +++ b/src/bacnet/basic/sys/platform.h @@ -22,6 +22,14 @@ #define islessgreater(x, y) ((x) < (y) || (x) > (y)) #endif +#ifndef isgreaterequal +#define isgreaterequal(x, y) ((x) > (y) || !islessgreater((x),(y))) +#endif + +#ifndef islessequal +#define islessequal(x, y) ((x) < (y) || !islessgreater((x),(y))) +#endif + #ifndef ARRAY_SIZE #define ARRAY_SIZE(array) ((size_t)(sizeof(array) / sizeof((array)[0]))) #endif