Initial revision

This commit is contained in:
skarg
2004-09-22 19:08:48 +00:00
parent f9c8dc61be
commit 9a9e31ace6
110 changed files with 6921 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
View File
+157
View File
@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="utf-8"?>
<wc-entries
xmlns="svn:">
<entry
committed-rev="512"
name=""
committed-date="2004-09-21T18:56:56.876624Z"
url="svn://potter/mstp/current"
kind="dir"
uuid="f7de03cf-50d5-0310-9ee6-baecd260521e"
revision="512"/>
<entry
name="test"
kind="dir"/>
<entry
committed-rev="504"
name="ringbuf.h"
text-time="2004-09-16T12:55:47.000000Z"
committed-date="2004-09-16T12:58:13.686683Z"
checksum="6a2c59836ce3dd3ad6a9b12bb5dec5f8"
kind="file"/>
<entry
committed-rev="506"
name="mstp.ide"
text-time="2004-09-16T13:12:37.000000Z"
committed-date="2004-09-16T13:13:12.501031Z"
checksum="500f584e7ef36868ad5f13dc29579de1"
kind="file"
prop-time="2004-09-16T13:12:37.000000Z"/>
<entry
committed-rev="505"
name="test.sh"
text-time="2004-09-16T13:06:51.000000Z"
committed-date="2004-09-16T13:08:45.619586Z"
checksum="14511d7e0a2fbf5b1fcd6b0e132bf5e1"
kind="file"
prop-time="2004-09-16T13:07:26.000000Z"/>
<entry
committed-rev="500"
name="crc.c"
text-time="2004-09-16T12:25:10.000000Z"
committed-date="2004-09-15T18:55:50.360066Z"
checksum="f051b500d5619e2dc841473463cc723a"
kind="file"
prop-time="2004-09-16T12:25:10.000000Z"/>
<entry
committed-rev="505"
name="mstp.mak"
text-time="2004-09-16T13:01:31.000000Z"
committed-date="2004-09-16T13:08:45.619586Z"
checksum="36c0cac576ec7243bd2cadbb4d24187b"
kind="file"/>
<entry
committed-rev="494"
name="stdint.h"
text-time="2004-09-15T13:53:13.000000Z"
committed-date="2004-09-14T19:22:18.445142Z"
checksum="f9581e03267903b1fe558b45f2e7b2fe"
kind="file"
prop-time="2004-09-15T13:53:13.000000Z"/>
<entry
committed-rev="494"
name="stdbool.h"
text-time="2004-09-15T13:53:13.000000Z"
committed-date="2004-09-14T19:22:18.445142Z"
checksum="692dbefeca755102be5bef998cba11c6"
kind="file"
prop-time="2004-09-15T13:53:13.000000Z"/>
<entry
committed-rev="494"
name="crc.h"
text-time="2004-09-15T13:53:13.000000Z"
committed-date="2004-09-14T19:22:18.445142Z"
checksum="613fc4f106eb15511cd78dd6bd019ff8"
kind="file"
prop-time="2004-09-15T13:53:13.000000Z"/>
<entry
committed-rev="505"
name="ringbuf.mak"
text-time="2004-09-16T13:00:05.000000Z"
committed-date="2004-09-16T13:08:45.619586Z"
checksum="0347088621cfd45d358d5f4c27603a78"
kind="file"/>
<entry
committed-rev="502"
name="mstp.c"
text-time="2004-09-16T12:36:27.000000Z"
committed-date="2004-09-16T12:37:51.418188Z"
checksum="26e168bc74c2cf6759d15b57d1b27313"
kind="file"
prop-time="2004-09-16T12:25:10.000000Z"/>
<entry
committed-rev="508"
name="main.c"
text-time="2004-09-17T14:32:16.000000Z"
committed-date="2004-09-17T08:46:07.996351Z"
checksum="996a714c7450e522b943d2de762b12b0"
kind="file"
prop-time="2004-09-17T14:32:16.000000Z"/>
<entry
committed-rev="500"
name="crc.ide"
text-time="2004-09-16T12:25:10.000000Z"
committed-date="2004-09-15T18:55:50.360066Z"
checksum="a634ef6eb3f0e56a1083c41deda4ea69"
kind="file"
prop-time="2004-09-16T12:25:10.000000Z"/>
<entry
name="ports"
kind="dir"/>
<entry
committed-rev="509"
name="mstp.h"
text-time="2004-09-17T14:57:32.000000Z"
committed-date="2004-09-17T15:14:53.274461Z"
checksum="3ede6253d48ba42fb0754bd8618e75e6"
kind="file"
prop-time="2004-09-16T13:12:37.000000Z"/>
<entry
committed-rev="494"
name="rs485.h"
text-time="2004-09-15T13:53:13.000000Z"
committed-date="2004-09-14T19:22:18.445142Z"
checksum="7b9f476c2b0c7f6edec88a45baed16bd"
kind="file"
prop-time="2004-09-15T13:53:13.000000Z"/>
<entry
committed-rev="500"
name="bytes.h"
text-time="2004-09-16T12:25:10.000000Z"
committed-date="2004-09-15T18:55:50.360066Z"
checksum="bafe1cb50a3d676f6e4d1c9c74911fb4"
kind="file"
prop-time="2004-09-16T12:25:10.000000Z"/>
<entry
committed-rev="508"
name="Makefile"
text-time="2004-09-17T14:32:16.000000Z"
committed-date="2004-09-17T08:46:07.996351Z"
checksum="0f99fe5f7f7b2d837e77e545ef44594e"
kind="file"
prop-time="2004-09-17T14:32:16.000000Z"/>
<entry
committed-rev="504"
name="ringbuf.c"
text-time="2004-09-16T12:55:43.000000Z"
committed-date="2004-09-16T12:58:13.686683Z"
checksum="996a8dcef95477542791ef64ab959d06"
kind="file"/>
<entry
committed-rev="505"
name="crc.mak"
text-time="2004-09-16T12:59:14.000000Z"
committed-date="2004-09-16T13:08:45.619586Z"
checksum="89d218d56919ad6afa52e566b332e711"
kind="file"/>
</wc-entries>
+1
View File
@@ -0,0 +1 @@
4
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1,5 @@
K 13
svn:mime-type
V 24
application/octet-stream
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1,5 @@
K 13
svn:mime-type
V 24
application/octet-stream
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1,5 @@
K 14
svn:executable
V 1
*
END
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
+5
View File
@@ -0,0 +1,5 @@
K 13
svn:mime-type
V 24
application/octet-stream
END
+1
View File
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
@@ -0,0 +1,5 @@
K 13
svn:mime-type
V 24
application/octet-stream
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
+1
View File
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
+5
View File
@@ -0,0 +1,5 @@
K 14
svn:executable
V 1
*
END
@@ -0,0 +1,29 @@
#Makefile to build BACnet Application
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -g
OBJS = main.o mstp.o crc.o ringbuf.o ports/linux/rs485.o
TARGET = bacnet
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
@@ -0,0 +1,42 @@
// Defines the bit/byte/word/long conversions that are used in code
#ifndef BYTES_H
#define BYTES_H
#include <stdint.h>
#ifndef LO_NIB
#define LO_NIB(b) ((b) & 0xF)
#endif
#ifndef HI_NIB
#define HI_NIB(b) ((b) >> 4)
#endif
#ifndef LO_BYTE
#define LO_BYTE(w) ((uint8_t)(w))
#endif
#ifndef HI_BYTE
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
#endif
#ifndef LO_WORD
#define LO_WORD(x) ((uint16_t)(x))
#endif
#ifndef HI_WORD
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
#endif
#ifndef MAKE_WORD
#define MAKE_WORD(lo,hi) \
((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8)))
#endif
#ifndef MAKE_LONG
#define MAKE_LONG(lo,hi) \
((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16)))
#endif
#endif // end of header file
+153
View File
@@ -0,0 +1,153 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// Accumulate "dataValue" into the CRC in crcValue.
// Return value is updated CRC
//
// The ^ operator means exclusive OR.
// Note: This function is copied directly from the BACnet standard.
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
{
uint16_t crc;
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
^ (crc << 7);
/* Combine bits shifted out left hand end */
return (crc & 0xfe) ^ ((crc >> 8) & 1);
}
// Accumulate "dataValue" into the CRC in crcValue.
// Return value is updated CRC
//
// The ^ operator means exclusive OR.
// Note: This function is copied directly from the BACnet standard.
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
{
uint16_t crcLow;
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
return (crcValue >>8) ^ (crcLow << 8) ^ (crcLow <<3)
^ (crcLow <<12) ^ (crcLow >> 4)
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
#include "bytes.h"
// test from Annex G 1.0 of BACnet Standard
void testCRC8(Test* pTest)
{
uint8_t crc = 0xff; // accumulates the crc value
uint8_t frame_crc; // appended to the end of the frame
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x55);
crc = CRC_Calc_Header(0x10,crc);
ct_test(pTest,crc == 0xC2);
crc = CRC_Calc_Header(0x05,crc);
ct_test(pTest,crc == 0xBC);
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x95);
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x73);
// send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0x55.
frame_crc = ~crc;
ct_test(pTest,frame_crc == 0x8C);
// use the ones complement value and the next to last CRC value
crc = CRC_Calc_Header(frame_crc,crc);
ct_test(pTest,crc == 0x55);
}
// test from Annex G 2.0 of BACnet Standard
void testCRC16(Test* pTest)
{
uint16_t crc = 0xffff;
uint16_t data_crc;
crc = CRC_Calc_Data(0x01,crc);
ct_test(pTest,crc == 0x1E0E);
crc = CRC_Calc_Data(0x22,crc);
ct_test(pTest,crc == 0xEB70);
crc = CRC_Calc_Data(0x30,crc);
ct_test(pTest,crc == 0x42EF);
// send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0xF0B8.
data_crc = ~crc;
ct_test(pTest,data_crc == 0xBD10);
crc = CRC_Calc_Data(LO_BYTE(data_crc),crc);
ct_test(pTest,crc == 0x0F3A);
crc = CRC_Calc_Data(HI_BYTE(data_crc),crc);
ct_test(pTest,crc == 0xF0B8);
}
#endif
#ifdef TEST_CRC
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("crc", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testCRC8);
assert(rc);
rc = ct_addTestFunction(pTest, testCRC16);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
@@ -0,0 +1,44 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef CRC_H
#define CRC_H
#include <stddef.h>
#include <stdint.h>
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
#endif
Binary file not shown.
@@ -0,0 +1,29 @@
#Makefile to build CRC tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_CRC -g
OBJS = crc.o test/ctest.o
TARGET = crc
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
@@ -0,0 +1,63 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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 <stddef.h>
#include <stdint.h>
#include "mstp.h"
#include "bytes.h"
#include "crc.h"
#include "rs485.h"
#include "ringbuf.h"
void main(void)
{
struct mstp_port_struct_t mstp_port; // port data
uint8_t my_mac = 0x05; // local MAC address
MSTP_Init(&mstp_port,my_mac);
// loop forever
for (;;)
{
// input
RS485_Check_UART_Data(&mstp_port);
MSTP_Receive_Frame_FSM(&mstp_port);
// process
// output
MSTP_Master_Node_FSM(&mstp_port);
}
}
File diff suppressed because it is too large Load Diff
+240
View File
@@ -0,0 +1,240 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef MSTP_H
#define MSTP_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// The number of elements in the array InputBuffer[].
#define INPUT_BUFFER_SIZE (501)
// The value 255 is used to denote broadcast when used as a
// destination address but is not allowed as a value for a station.
#define MSTP_BROADCAST_ADDRESS 255
// MS/TP Frame Type
// Frame Types 8 through 127 are reserved by ASHRAE.
#define FRAME_TYPE_TOKEN 0
#define FRAME_TYPE_POLL_FOR_MASTER 1
#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2
#define FRAME_TYPE_TEST_REQUEST 3
#define FRAME_TYPE_TEST_RESPONSE 4
#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5
#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define FRAME_TYPE_REPLY_POSTPONED 7
// Frame Types 128 through 255: Proprietary Frames
// These frames are available to vendors as proprietary (non-BACnet) frames.
// The first two octets of the Data field shall specify the unique vendor
// identification code, most significant octet first, for the type of
// vendor-proprietary frame to be conveyed. The length of the data portion
// of a Proprietary frame shall be in the range of 2 to 501 octets.
#define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255
// receive FSM states
typedef enum
{
MSTP_RECEIVE_STATE_IDLE,
MSTP_RECEIVE_STATE_PREAMBLE,
MSTP_RECEIVE_STATE_HEADER,
MSTP_RECEIVE_STATE_HEADER_CRC,
MSTP_RECEIVE_STATE_DATA,
MSTP_RECEIVE_STATE_DATA_CRC,
} MSTP_RECEIVE_STATE;
// master node FSM states
typedef enum
{
MSTP_MASTER_STATE_INITIALIZE,
MSTP_MASTER_STATE_IDLE,
MSTP_MASTER_STATE_USE_TOKEN,
MSTP_MASTER_STATE_WAIT_FOR_REPLY,
MSTP_MASTER_STATE_DONE_WITH_TOKEN,
MSTP_MASTER_STATE_PASS_TOKEN,
MSTP_MASTER_STATE_NO_TOKEN,
MSTP_MASTER_STATE_POLL_FOR_MASTER,
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST,
} MSTP_MASTER_STATE;
// data for a given MS/TP port
struct mstp_port_struct_t
{
MSTP_RECEIVE_STATE receive_state;
// When a master node is powered up or reset,
// it shall unconditionally enter the INITIALIZE state.
MSTP_MASTER_STATE master_state;
bool ReceiveError; // TRUE when error detected during Rx octet
bool DataAvailable; // There is data in the buffer
uint8_t DataRegister; // stores the latest data
// Used to accumulate the CRC on the data field of a frame.
uint16_t DataCRC;
// Used to store the data length of a received frame.
unsigned DataLength;
// Used to store the destination address of a received frame.
uint8_t DestinationAddress;
// Used to count the number of received octets or errors.
// This is used in the detection of link activity.
unsigned EventCount;
// Used to store the frame type of a received frame.
uint8_t FrameType;
// 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.
unsigned FrameCount;
// Used to accumulate the CRC on the header of a frame.
uint8_t HeaderCRC;
// Used as an index by the Receive State Machine, up to a maximum value of
// InputBufferSize.
unsigned Index;
// An array of octets, used to store octets as they are received.
// InputBuffer is indexed from 0 to InputBufferSize-1.
// The maximum size of a frame is 501 octets.
// A smaller value for InputBufferSize may be used by some implementations.
uint8_t InputBuffer[INPUT_BUFFER_SIZE];
// "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.
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.
uint8_t Poll_Station;
// A Boolean flag set to TRUE by the Receive State Machine if an error is
// detected during the reception of a frame. Set to FALSE by the main
// state machine.
bool ReceivedInvalidFrame;
// 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.
bool ReceivedValidFrame;
// A counter of transmission retries used for Token and Poll For Master
// transmission.
unsigned RetryCount;
// A timer with nominal 5 millisecond resolution used to measure and
// generate silence on the medium between octets. It is incremented by a
// timer process and is cleared by the Receive State Machine when activity
// is detected and by the SendFrame procedure as each octet is transmitted.
// Since the timer resolution is limited and the timer is not necessarily
// synchronized to other machine events, a timer value of N will actually
// denote intervals between N-1 and N
unsigned SilenceTimer;
// A timer used to measure and generate Reply Postponed frames. It is
// incremented by a timer process and is cleared by the Master Node State
// Machine when a Data Expecting Reply Answer activity is completed.
unsigned ReplyPostponedTimer;
// A Boolean flag set to TRUE by the master machine if this node is the
// only known master node.
bool SoleMaster;
// Used to store the Source Address of a received frame.
uint8_t SourceAddress;
// 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.
unsigned TokenCount;
// "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.
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.
unsigned 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.
unsigned Nmax_master;
// After receiving a frame this value will be TRUE until Tturnaround
// has expired
bool Turn_Around_Waiting;
};
#define DEFAULT_MAX_INFO_FRAMES 1
#define DEFAULT_MAX_MASTER 127
// 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
#define Tturnaround 40;
void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port);
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
unsigned MSTP_Create_Frame(
uint8_t *buffer, // where frame is loaded
unsigned buffer_len, // amount of space available
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len); // number of bytes of data (up to 501)
#endif
Binary file not shown.
@@ -0,0 +1,29 @@
#Makefile to build BACnet MS/TP tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_MSTP -g
OBJS = mstp.o crc.o ringbuf.o test/ctest.o
TARGET = mstp
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
@@ -0,0 +1,287 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 by 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####*/
/* Functional Description: Generic ring buffer library for deeply
embedded system. See the unit tests for usage examples. */
#include "stdint.h"
#include "ringbuf.h"
/****************************************************************************
* DESCRIPTION: Returns the empty/full status of the ring buffer
* RETURN: TRUE if the ring buffer is empty, FALSE if it is not.
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
bool Ringbuf_Empty(RING_BUFFER const *b)
{
return (b->count == 0);
}
/****************************************************************************
* DESCRIPTION: Looks at the data from the head of the list without removing it
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char *Ringbuf_Get_Front(RING_BUFFER const *b)
{
return (b->count ? &(b->data[b->head * b->element_size]) : NULL);
}
/****************************************************************************
* DESCRIPTION: Gets the data from the front of the list, and removes it
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char *Ringbuf_Pop_Front(RING_BUFFER *b)
{
char *data = NULL; // return value
if (b->count)
{
data = &(b->data[b->head * b->element_size]);
b->head++;
if (b->head >= b->element_count)
b->head = 0;
b->count--;
}
return data;
}
/****************************************************************************
* DESCRIPTION: Adds an element of data to the ring buffer
* RETURN: TRUE on succesful add, FALSE if not added
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
bool Ringbuf_Put(
RING_BUFFER *b, // ring buffer structure
char *data_element) // one element to add to the ring
{
bool status = FALSE; // return value
unsigned offset = 0; // offset into array of data
char *ring_data = NULL; // used to help point ring data
unsigned i; // loop counter
if (b && data_element)
{
// limit the amount of data that we accept
if (b->count < b->element_count)
{
offset = b->head + b->count;
if (offset >= b->element_count)
offset -= b->element_count;
ring_data = b->data + offset * b->element_size;
for(i = 0; i < b->element_size; i++)
{
ring_data[i] = data_element[i];
}
b->count++;
status = TRUE;
}
}
return status;
}
/****************************************************************************
* DESCRIPTION: Configures the ring buffer
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void Ringbuf_Init(
RING_BUFFER *b, // ring buffer structure
char *data, // data block or array of data
unsigned element_size, // size of one element in the data block
unsigned element_count) // number of elements in the data block
{
b->head = 0;
b->count = 0;
b->data = data;
b->element_size = element_size;
b->element_count = element_count;
return;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
// test the FIFO
#define RING_BUFFER_DATA_SIZE 5
#define RING_BUFFER_SIZE 16
void testRingBuf(Test* pTest)
{
RING_BUFFER test_buffer;
char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
char data[RING_BUFFER_DATA_SIZE];
char *test_data;
unsigned index;
unsigned data_index;
unsigned count;
unsigned dummy;
bool status;
Ringbuf_Init(&test_buffer,data_store,RING_BUFFER_DATA_SIZE,RING_BUFFER_SIZE);
ct_test(pTest,Ringbuf_Empty(&test_buffer));
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = data_index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == data[data_index]);
}
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == data[data_index]);
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
// fill to max
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
}
// verify actions on full buffer
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == FALSE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
}
// check buffer full
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == index);
}
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == index);
}
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
// test the ring around the buffer
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (count = 1; count < 4; count++)
{
dummy = index * count;
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = dummy;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
}
for (count = 1; count < 4; count++)
{
dummy = index * count;
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == dummy);
}
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == dummy);
}
}
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
return;
}
#ifdef TEST_RINGBUF
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("ringbuf", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testRingBuf);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
#endif
@@ -0,0 +1,66 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 by 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####*/
/* Functional Description: Generic ring buffer library for deeply
embedded system. See the unit tests for usage examples. */
#ifndef RINGBUF_H
#define RINGBUF_H
#include "stdint.h"
struct ring_buffer_t
{
char *data; // block of memory or array of data
unsigned element_size; // how many bytes for each chunk
unsigned element_count; // number of chunks of data
unsigned head; // first chunk of data
unsigned count; // number of chunks in use
};
typedef struct ring_buffer_t RING_BUFFER;
extern bool Ringbuf_Empty(RING_BUFFER const *b);
extern char *Ringbuf_Get_Front(RING_BUFFER const *b);
extern char *Ringbuf_Pop_Front(RING_BUFFER *b);
extern bool Ringbuf_Put(
RING_BUFFER *b, // ring buffer structure
char *data_element); // one element to add to the ring
extern void Ringbuf_Init(
RING_BUFFER *b, // ring buffer structure
char *data, // data block or array of data
unsigned element_size, // size of one element in the data block
unsigned element_count); // number of elements in the data block
#endif
@@ -0,0 +1,29 @@
#Makefile to build ringbuf tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_RINGBUF -g
OBJS = ringbuf.o test/ctest.o
TARGET = ringbuf
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
@@ -0,0 +1,53 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef RS485_H
#define RS485_H
#include <stdint.h>
#include "mstp.h"
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port specific data
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len); // number of bytes of data (up to 501)
void RS485_Check_UART_Data(
struct mstp_port_struct_t *mstp_port); // port specific data
#endif
@@ -0,0 +1,28 @@
#ifndef STDBOOL_H
#define STDBOOL_H
// C99 Boolean types for compilers without C99 support
#ifndef __cplusplus
typedef int _Bool;
#ifndef bool
#define bool _Bool
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define __bool_true_false_are_defined 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#endif
@@ -0,0 +1,26 @@
// Defines the standard integer types that are used in code
// for the x86 processor and Borland Compiler
#ifndef STDINT_H
#define STDINT_H
#include <stddef.h>
#define TRUE 1
#define FALSE 0
#define MSB 7
#define LSB 0
typedef int bool;
typedef unsigned char uint8_t; // 1 byte 0 to 255
typedef signed char int8_t; // 1 byte -127 to 127
typedef unsigned short uint16_t; // 2 bytes 0 to 65535
typedef signed short int16_t; // 2 bytes -32767 to 32767
//typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215
typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295
typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647
// typedef signed long long int64_t;
// typedef unsigned long long uint64_t;
#endif // STDINT_H
@@ -0,0 +1,19 @@
#!/bin/sh
# Unit tests builder / runner for this project
rm test.log
touch test.log
make -f crc.mak
./crc >> test.log
make -f crc.mak clean
make -f ringbuf.mak
./ringbuf >> test.log
make -f ringbuf.mak clean
make -f mstp.mak
./mstp >> test.log
make -f mstp.mak clean
+29
View File
@@ -0,0 +1,29 @@
#Makefile to build BACnet Application
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -g
OBJS = main.o mstp.o crc.o ringbuf.o ports/linux/rs485.o
TARGET = bacnet
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak ports/linux/*.bak *.1 *.ini
include: .depend
+42
View File
@@ -0,0 +1,42 @@
// Defines the bit/byte/word/long conversions that are used in code
#ifndef BYTES_H
#define BYTES_H
#include <stdint.h>
#ifndef LO_NIB
#define LO_NIB(b) ((b) & 0xF)
#endif
#ifndef HI_NIB
#define HI_NIB(b) ((b) >> 4)
#endif
#ifndef LO_BYTE
#define LO_BYTE(w) ((uint8_t)(w))
#endif
#ifndef HI_BYTE
#define HI_BYTE(w) ((uint8_t)((uint16_t)(w) >> 8))
#endif
#ifndef LO_WORD
#define LO_WORD(x) ((uint16_t)(x))
#endif
#ifndef HI_WORD
#define HI_WORD(x) ((uint16_t)((uint32_t)(x) >> 16))
#endif
#ifndef MAKE_WORD
#define MAKE_WORD(lo,hi) \
((uint16_t)(((uint8_t)(lo))|(((uint16_t)((uint8_t)(hi)))<<8)))
#endif
#ifndef MAKE_LONG
#define MAKE_LONG(lo,hi) \
((uint32_t)(((uint16_t)(lo))|(((uint32_t)((uint16_t)(hi)))<<16)))
#endif
#endif // end of header file
+153
View File
@@ -0,0 +1,153 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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 <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// Accumulate "dataValue" into the CRC in crcValue.
// Return value is updated CRC
//
// The ^ operator means exclusive OR.
// Note: This function is copied directly from the BACnet standard.
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue)
{
uint16_t crc;
crc = crcValue ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
crc = crc ^ (crc << 1) ^ (crc << 2) ^ (crc << 3)
^ (crc << 4) ^ (crc << 5) ^ (crc << 6)
^ (crc << 7);
/* Combine bits shifted out left hand end */
return (crc & 0xfe) ^ ((crc >> 8) & 1);
}
// Accumulate "dataValue" into the CRC in crcValue.
// Return value is updated CRC
//
// The ^ operator means exclusive OR.
// Note: This function is copied directly from the BACnet standard.
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue)
{
uint16_t crcLow;
crcLow = (crcValue & 0xff) ^ dataValue; /* XOR C7..C0 with D7..D0 */
/* Exclusive OR the terms in the table (top down) */
return (crcValue >>8) ^ (crcLow << 8) ^ (crcLow <<3)
^ (crcLow <<12) ^ (crcLow >> 4)
^ (crcLow & 0x0f) ^ ((crcLow & 0x0f) << 7);
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
#include "bytes.h"
// test from Annex G 1.0 of BACnet Standard
void testCRC8(Test* pTest)
{
uint8_t crc = 0xff; // accumulates the crc value
uint8_t frame_crc; // appended to the end of the frame
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x55);
crc = CRC_Calc_Header(0x10,crc);
ct_test(pTest,crc == 0xC2);
crc = CRC_Calc_Header(0x05,crc);
ct_test(pTest,crc == 0xBC);
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x95);
crc = CRC_Calc_Header(0x00,crc);
ct_test(pTest,crc == 0x73);
// send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0x55.
frame_crc = ~crc;
ct_test(pTest,frame_crc == 0x8C);
// use the ones complement value and the next to last CRC value
crc = CRC_Calc_Header(frame_crc,crc);
ct_test(pTest,crc == 0x55);
}
// test from Annex G 2.0 of BACnet Standard
void testCRC16(Test* pTest)
{
uint16_t crc = 0xffff;
uint16_t data_crc;
crc = CRC_Calc_Data(0x01,crc);
ct_test(pTest,crc == 0x1E0E);
crc = CRC_Calc_Data(0x22,crc);
ct_test(pTest,crc == 0xEB70);
crc = CRC_Calc_Data(0x30,crc);
ct_test(pTest,crc == 0x42EF);
// send the ones complement of the CRC in place of
// the CRC, and the resulting CRC will always equal 0xF0B8.
data_crc = ~crc;
ct_test(pTest,data_crc == 0xBD10);
crc = CRC_Calc_Data(LO_BYTE(data_crc),crc);
ct_test(pTest,crc == 0x0F3A);
crc = CRC_Calc_Data(HI_BYTE(data_crc),crc);
ct_test(pTest,crc == 0xF0B8);
}
#endif
#ifdef TEST_CRC
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("crc", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testCRC8);
assert(rc);
rc = ct_addTestFunction(pTest, testCRC16);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
+44
View File
@@ -0,0 +1,44 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef CRC_H
#define CRC_H
#include <stddef.h>
#include <stdint.h>
uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue);
uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue);
#endif
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
#Makefile to build CRC tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_CRC -g
OBJS = crc.o test/ctest.o
TARGET = crc
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
+63
View File
@@ -0,0 +1,63 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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 <stddef.h>
#include <stdint.h>
#include "mstp.h"
#include "bytes.h"
#include "crc.h"
#include "rs485.h"
#include "ringbuf.h"
void main(void)
{
struct mstp_port_struct_t mstp_port; // port data
uint8_t my_mac = 0x05; // local MAC address
MSTP_Init(&mstp_port,my_mac);
// loop forever
for (;;)
{
// input
RS485_Check_UART_Data(&mstp_port);
MSTP_Receive_Frame_FSM(&mstp_port);
// process
// output
MSTP_Master_Node_FSM(&mstp_port);
}
}
+1671
View File
File diff suppressed because it is too large Load Diff
+240
View File
@@ -0,0 +1,240 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef MSTP_H
#define MSTP_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// The number of elements in the array InputBuffer[].
#define INPUT_BUFFER_SIZE (501)
// The value 255 is used to denote broadcast when used as a
// destination address but is not allowed as a value for a station.
#define MSTP_BROADCAST_ADDRESS 255
// MS/TP Frame Type
// Frame Types 8 through 127 are reserved by ASHRAE.
#define FRAME_TYPE_TOKEN 0
#define FRAME_TYPE_POLL_FOR_MASTER 1
#define FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER 2
#define FRAME_TYPE_TEST_REQUEST 3
#define FRAME_TYPE_TEST_RESPONSE 4
#define FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY 5
#define FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY 6
#define FRAME_TYPE_REPLY_POSTPONED 7
// Frame Types 128 through 255: Proprietary Frames
// These frames are available to vendors as proprietary (non-BACnet) frames.
// The first two octets of the Data field shall specify the unique vendor
// identification code, most significant octet first, for the type of
// vendor-proprietary frame to be conveyed. The length of the data portion
// of a Proprietary frame shall be in the range of 2 to 501 octets.
#define FRAME_TYPE_PROPRIETARY_MIN 128
#define FRAME_TYPE_PROPRIETARY_MAX 255
// receive FSM states
typedef enum
{
MSTP_RECEIVE_STATE_IDLE,
MSTP_RECEIVE_STATE_PREAMBLE,
MSTP_RECEIVE_STATE_HEADER,
MSTP_RECEIVE_STATE_HEADER_CRC,
MSTP_RECEIVE_STATE_DATA,
MSTP_RECEIVE_STATE_DATA_CRC,
} MSTP_RECEIVE_STATE;
// master node FSM states
typedef enum
{
MSTP_MASTER_STATE_INITIALIZE,
MSTP_MASTER_STATE_IDLE,
MSTP_MASTER_STATE_USE_TOKEN,
MSTP_MASTER_STATE_WAIT_FOR_REPLY,
MSTP_MASTER_STATE_DONE_WITH_TOKEN,
MSTP_MASTER_STATE_PASS_TOKEN,
MSTP_MASTER_STATE_NO_TOKEN,
MSTP_MASTER_STATE_POLL_FOR_MASTER,
MSTP_MASTER_STATE_ANSWER_DATA_REQUEST,
} MSTP_MASTER_STATE;
// data for a given MS/TP port
struct mstp_port_struct_t
{
MSTP_RECEIVE_STATE receive_state;
// When a master node is powered up or reset,
// it shall unconditionally enter the INITIALIZE state.
MSTP_MASTER_STATE master_state;
bool ReceiveError; // TRUE when error detected during Rx octet
bool DataAvailable; // There is data in the buffer
uint8_t DataRegister; // stores the latest data
// Used to accumulate the CRC on the data field of a frame.
uint16_t DataCRC;
// Used to store the data length of a received frame.
unsigned DataLength;
// Used to store the destination address of a received frame.
uint8_t DestinationAddress;
// Used to count the number of received octets or errors.
// This is used in the detection of link activity.
unsigned EventCount;
// Used to store the frame type of a received frame.
uint8_t FrameType;
// 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.
unsigned FrameCount;
// Used to accumulate the CRC on the header of a frame.
uint8_t HeaderCRC;
// Used as an index by the Receive State Machine, up to a maximum value of
// InputBufferSize.
unsigned Index;
// An array of octets, used to store octets as they are received.
// InputBuffer is indexed from 0 to InputBufferSize-1.
// The maximum size of a frame is 501 octets.
// A smaller value for InputBufferSize may be used by some implementations.
uint8_t InputBuffer[INPUT_BUFFER_SIZE];
// "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.
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.
uint8_t Poll_Station;
// A Boolean flag set to TRUE by the Receive State Machine if an error is
// detected during the reception of a frame. Set to FALSE by the main
// state machine.
bool ReceivedInvalidFrame;
// 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.
bool ReceivedValidFrame;
// A counter of transmission retries used for Token and Poll For Master
// transmission.
unsigned RetryCount;
// A timer with nominal 5 millisecond resolution used to measure and
// generate silence on the medium between octets. It is incremented by a
// timer process and is cleared by the Receive State Machine when activity
// is detected and by the SendFrame procedure as each octet is transmitted.
// Since the timer resolution is limited and the timer is not necessarily
// synchronized to other machine events, a timer value of N will actually
// denote intervals between N-1 and N
unsigned SilenceTimer;
// A timer used to measure and generate Reply Postponed frames. It is
// incremented by a timer process and is cleared by the Master Node State
// Machine when a Data Expecting Reply Answer activity is completed.
unsigned ReplyPostponedTimer;
// A Boolean flag set to TRUE by the master machine if this node is the
// only known master node.
bool SoleMaster;
// Used to store the Source Address of a received frame.
uint8_t SourceAddress;
// 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.
unsigned TokenCount;
// "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.
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.
unsigned 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.
unsigned Nmax_master;
// After receiving a frame this value will be TRUE until Tturnaround
// has expired
bool Turn_Around_Waiting;
};
#define DEFAULT_MAX_INFO_FRAMES 1
#define DEFAULT_MAX_MASTER 127
// 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
#define Tturnaround 40;
void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port);
void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port);
void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port);
unsigned MSTP_Create_Frame(
uint8_t *buffer, // where frame is loaded
unsigned buffer_len, // amount of space available
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len); // number of bytes of data (up to 501)
#endif
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
#Makefile to build BACnet MS/TP tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_MSTP -g
OBJS = mstp.o crc.o ringbuf.o test/ctest.o
TARGET = mstp
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
+2
View File
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
View File
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<wc-entries
xmlns="svn:">
<entry
committed-rev="512"
name=""
committed-date="2004-09-21T18:56:56.876624Z"
url="svn://potter/mstp/current/ports"
kind="dir"
uuid="f7de03cf-50d5-0310-9ee6-baecd260521e"
revision="512"/>
<entry
name="linux"
kind="dir"/>
<entry
name="pic18"
kind="dir"/>
<entry
name="rtos32"
kind="dir"/>
</wc-entries>
+1
View File
@@ -0,0 +1 @@
4
+2
View File
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<wc-entries
xmlns="svn:">
<entry
committed-rev="512"
name=""
committed-date="2004-09-21T18:56:56.876624Z"
url="svn://potter/mstp/current/ports/linux"
kind="dir"
uuid="f7de03cf-50d5-0310-9ee6-baecd260521e"
revision="512"/>
<entry
committed-rev="509"
name="rs485.c"
text-time="2004-09-17T15:00:12.000000Z"
committed-date="2004-09-17T15:14:53.274461Z"
checksum="951c78029b0b2b91de3a50f2d0df61ea"
kind="file"
prop-time="2004-09-17T14:32:16.000000Z"/>
<entry
committed-rev="512"
name="readme.txt"
text-time="2004-09-22T18:43:16.000000Z"
committed-date="2004-09-21T18:56:56.876624Z"
checksum="11c4959d8785de75452c56457aaa3c30"
kind="file"
prop-time="2004-09-22T18:43:16.000000Z"/>
</wc-entries>
+1
View File
@@ -0,0 +1 @@
4
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1,2 @@
This is a port to Linux for testing.
The unit tests can be run via the test.sh script.
@@ -0,0 +1,115 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
// The module handles sending data out the RS-485 port
// and handles receiving data from the RS-485 port.
// Customize this file for your specific hardware
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "mstp.h"
// Transmits a Frame on the wire
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port to send from
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len) // number of bytes of data (up to 501)
{
uint8_t buffer[INPUT_BUFFER_SIZE] = {0};
uint8_t *pbuf = NULL; // used for pointer arithmatic
unsigned len = 0; // number of bytes to send
// in order to avoid line contention
while (mstp_port->Turn_Around_Waiting)
{
// wait, yield, or whatever
}
// Disable the receiver, and enable the transmit line driver.
len = MSTP_Create_Frame(
buffer, // where frame is loaded
sizeof(buffer), // amount of space available
frame_type, // type of frame to send - see defines
destination, // destination address
source, // source address
data, // any data to be sent - may be null
data_len); // number of bytes of data (up to 501)
pbuf = &buffer[0];
while (len)
{
putc(*pbuf,stderr);
pbuf++;
len--;
}
// Wait until the final stop bit of the most significant CRC octet
// has been transmitted but not more than Tpostdrive.
// Disable the transmit line driver.
return;
}
// called by timer, interrupt(?) or other thread
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{
if (mstp_port->ReceiveError == true)
{
// wait for state machine to clear this
}
// wait for state machine to read from the DataRegister
else if (mstp_port->DataAvailable == false)
{
// check for data
// if error,
// ReceiveError = TRUE;
// return;
mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer
// if data is ready,
// DataAvailable = TRUE;
// return;
}
}
+2
View File
@@ -0,0 +1,2 @@
This is a port to Linux for testing.
The unit tests can be run via the test.sh script.
+115
View File
@@ -0,0 +1,115 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
// The module handles sending data out the RS-485 port
// and handles receiving data from the RS-485 port.
// Customize this file for your specific hardware
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "mstp.h"
// Transmits a Frame on the wire
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port to send from
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len) // number of bytes of data (up to 501)
{
uint8_t buffer[INPUT_BUFFER_SIZE] = {0};
uint8_t *pbuf = NULL; // used for pointer arithmatic
unsigned len = 0; // number of bytes to send
// in order to avoid line contention
while (mstp_port->Turn_Around_Waiting)
{
// wait, yield, or whatever
}
// Disable the receiver, and enable the transmit line driver.
len = MSTP_Create_Frame(
buffer, // where frame is loaded
sizeof(buffer), // amount of space available
frame_type, // type of frame to send - see defines
destination, // destination address
source, // source address
data, // any data to be sent - may be null
data_len); // number of bytes of data (up to 501)
pbuf = &buffer[0];
while (len)
{
putc(*pbuf,stderr);
pbuf++;
len--;
}
// Wait until the final stop bit of the most significant CRC octet
// has been transmitted but not more than Tpostdrive.
// Disable the transmit line driver.
return;
}
// called by timer, interrupt(?) or other thread
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{
if (mstp_port->ReceiveError == true)
{
// wait for state machine to clear this
}
// wait for state machine to read from the DataRegister
else if (mstp_port->DataAvailable == false)
{
// check for data
// if error,
// ReceiveError = TRUE;
// return;
mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer
// if data is ready,
// DataAvailable = TRUE;
// return;
}
}
+2
View File
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<wc-entries
xmlns="svn:">
<entry
committed-rev="504"
name=""
committed-date="2004-09-16T12:58:13.686683Z"
url="svn://potter/mstp/current/ports/pic18"
kind="dir"
uuid="f7de03cf-50d5-0310-9ee6-baecd260521e"
revision="512"/>
<entry
committed-rev="504"
name="rs485.c"
text-time="2004-09-16T12:55:13.000000Z"
committed-date="2004-09-16T12:58:13.686683Z"
checksum="9dc1c381333c134b8c6708b475224ca5"
kind="file"/>
</wc-entries>
+1
View File
@@ -0,0 +1 @@
4
@@ -0,0 +1 @@
END
@@ -0,0 +1 @@
END
@@ -0,0 +1,119 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
// The module handles sending data out the RS-485 port
// and handles receiving data from the RS-485 port.
// Customize this file for your specific hardware
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "mstp.h"
// Transmits a Frame on the wire
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port to send from
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len) // number of bytes of data (up to 501)
{
uint8_t HeaderCRC; // used for running CRC calculation
(void)frame_type; // FIXME: temp until we implement this code
(void)destination; // FIXME: temp until we implement this code
(void)source; // FIXME: temp until we implement this code
(void)data; // FIXME: temp until we implement this code
(void)data_len; // FIXME: temp until we implement this code
// in order to avoid line contention
while (mstp_port->SilenceTimer < Tturnaround)
{
// wait, yield, or whatever
}
// Disable the receiver, and enable the transmit line driver.
// Transmit the preamble octets X'55', X'FF'.
// As each octet is transmitted, set SilenceTimer to zero.
HeaderCRC = 0xFF;
// Transmit the Frame Type, Destination Address, Source Address,
// and Data Length octets. Accumulate each octet into HeaderCRC.
// As each octet is transmitted, set SilenceTimer to zero.
// Transmit the ones-complement of HeaderCRC. Set SilenceTimer to zero.
// If there are data octets, initialize DataCRC to X'FFFF'.
// Transmit any data octets. Accumulate each octet into DataCRC.
// As each octet is transmitted, set SilenceTimer to zero.
// Transmit the ones-complement of DataCRC, least significant octet first.
// As each octet is transmitted, set SilenceTimer to zero.
// Wait until the final stop bit of the most significant CRC octet
// has been transmitted but not more than Tpostdrive.
// Disable the transmit line driver.
return;
}
// called by timer, interrupt(?) or other thread
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{
if (mstp_port->ReceiveError == true)
{
// wait for state machine to clear this
}
// wait for state machine to read from the DataRegister
else if (mstp_port->DataAvailable == false)
{
// check for data
// if error,
// ReceiveError = TRUE;
// return;
mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer
// if data is ready,
// DataAvailable = TRUE;
// return;
}
}
+119
View File
@@ -0,0 +1,119 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
// The module handles sending data out the RS-485 port
// and handles receiving data from the RS-485 port.
// Customize this file for your specific hardware
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "mstp.h"
// Transmits a Frame on the wire
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port to send from
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len) // number of bytes of data (up to 501)
{
uint8_t HeaderCRC; // used for running CRC calculation
(void)frame_type; // FIXME: temp until we implement this code
(void)destination; // FIXME: temp until we implement this code
(void)source; // FIXME: temp until we implement this code
(void)data; // FIXME: temp until we implement this code
(void)data_len; // FIXME: temp until we implement this code
// in order to avoid line contention
while (mstp_port->SilenceTimer < Tturnaround)
{
// wait, yield, or whatever
}
// Disable the receiver, and enable the transmit line driver.
// Transmit the preamble octets X'55', X'FF'.
// As each octet is transmitted, set SilenceTimer to zero.
HeaderCRC = 0xFF;
// Transmit the Frame Type, Destination Address, Source Address,
// and Data Length octets. Accumulate each octet into HeaderCRC.
// As each octet is transmitted, set SilenceTimer to zero.
// Transmit the ones-complement of HeaderCRC. Set SilenceTimer to zero.
// If there are data octets, initialize DataCRC to X'FFFF'.
// Transmit any data octets. Accumulate each octet into DataCRC.
// As each octet is transmitted, set SilenceTimer to zero.
// Transmit the ones-complement of DataCRC, least significant octet first.
// As each octet is transmitted, set SilenceTimer to zero.
// Wait until the final stop bit of the most significant CRC octet
// has been transmitted but not more than Tpostdrive.
// Disable the transmit line driver.
return;
}
// called by timer, interrupt(?) or other thread
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{
if (mstp_port->ReceiveError == true)
{
// wait for state machine to clear this
}
// wait for state machine to read from the DataRegister
else if (mstp_port->DataAvailable == false)
{
// check for data
// if error,
// ReceiveError = TRUE;
// return;
mstp_port->DataRegister = 0; // FIXME: Get this data from UART or buffer
// if data is ready,
// DataAvailable = TRUE;
// return;
}
}
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<wc-entries
xmlns="svn:">
<entry
committed-rev="503"
name=""
committed-date="2004-09-16T12:45:02.597419Z"
url="svn://potter/mstp/current/ports/rtos32"
kind="dir"
uuid="f7de03cf-50d5-0310-9ee6-baecd260521e"
revision="512"/>
</wc-entries>
+1
View File
@@ -0,0 +1 @@
4
+287
View File
@@ -0,0 +1,287 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 by 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####*/
/* Functional Description: Generic ring buffer library for deeply
embedded system. See the unit tests for usage examples. */
#include "stdint.h"
#include "ringbuf.h"
/****************************************************************************
* DESCRIPTION: Returns the empty/full status of the ring buffer
* RETURN: TRUE if the ring buffer is empty, FALSE if it is not.
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
bool Ringbuf_Empty(RING_BUFFER const *b)
{
return (b->count == 0);
}
/****************************************************************************
* DESCRIPTION: Looks at the data from the head of the list without removing it
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char *Ringbuf_Get_Front(RING_BUFFER const *b)
{
return (b->count ? &(b->data[b->head * b->element_size]) : NULL);
}
/****************************************************************************
* DESCRIPTION: Gets the data from the front of the list, and removes it
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
char *Ringbuf_Pop_Front(RING_BUFFER *b)
{
char *data = NULL; // return value
if (b->count)
{
data = &(b->data[b->head * b->element_size]);
b->head++;
if (b->head >= b->element_count)
b->head = 0;
b->count--;
}
return data;
}
/****************************************************************************
* DESCRIPTION: Adds an element of data to the ring buffer
* RETURN: TRUE on succesful add, FALSE if not added
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
bool Ringbuf_Put(
RING_BUFFER *b, // ring buffer structure
char *data_element) // one element to add to the ring
{
bool status = FALSE; // return value
unsigned offset = 0; // offset into array of data
char *ring_data = NULL; // used to help point ring data
unsigned i; // loop counter
if (b && data_element)
{
// limit the amount of data that we accept
if (b->count < b->element_count)
{
offset = b->head + b->count;
if (offset >= b->element_count)
offset -= b->element_count;
ring_data = b->data + offset * b->element_size;
for(i = 0; i < b->element_size; i++)
{
ring_data[i] = data_element[i];
}
b->count++;
status = TRUE;
}
}
return status;
}
/****************************************************************************
* DESCRIPTION: Configures the ring buffer
* RETURN: none
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void Ringbuf_Init(
RING_BUFFER *b, // ring buffer structure
char *data, // data block or array of data
unsigned element_size, // size of one element in the data block
unsigned element_count) // number of elements in the data block
{
b->head = 0;
b->count = 0;
b->data = data;
b->element_size = element_size;
b->element_count = element_count;
return;
}
#ifdef TEST
#include <assert.h>
#include <string.h>
#include "ctest.h"
// test the FIFO
#define RING_BUFFER_DATA_SIZE 5
#define RING_BUFFER_SIZE 16
void testRingBuf(Test* pTest)
{
RING_BUFFER test_buffer;
char data_store[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE];
char data[RING_BUFFER_DATA_SIZE];
char *test_data;
unsigned index;
unsigned data_index;
unsigned count;
unsigned dummy;
bool status;
Ringbuf_Init(&test_buffer,data_store,RING_BUFFER_DATA_SIZE,RING_BUFFER_SIZE);
ct_test(pTest,Ringbuf_Empty(&test_buffer));
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = data_index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == data[data_index]);
}
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == data[data_index]);
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
// fill to max
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
}
// verify actions on full buffer
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = index;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == FALSE);
ct_test(pTest,!Ringbuf_Empty(&test_buffer));
}
// check buffer full
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == index);
}
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == index);
}
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
// test the ring around the buffer
for (index = 0; index < RING_BUFFER_SIZE; index++)
{
for (count = 1; count < 4; count++)
{
dummy = index * count;
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
data[data_index] = dummy;
}
status = Ringbuf_Put(&test_buffer, data);
ct_test(pTest,status == TRUE);
}
for (count = 1; count < 4; count++)
{
dummy = index * count;
test_data = Ringbuf_Get_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == dummy);
}
test_data = Ringbuf_Pop_Front(&test_buffer);
for (data_index = 0; data_index < RING_BUFFER_DATA_SIZE; data_index++)
{
ct_test(pTest,test_data[data_index] == dummy);
}
}
}
ct_test(pTest,Ringbuf_Empty(&test_buffer));
return;
}
#ifdef TEST_RINGBUF
int main(void)
{
Test *pTest;
bool rc;
pTest = ct_create("ringbuf", NULL);
/* individual tests */
rc = ct_addTestFunction(pTest, testRingBuf);
assert(rc);
ct_setStream(pTest, stdout);
ct_run(pTest);
(void)ct_report(pTest);
ct_destroy(pTest);
return 0;
}
#endif
#endif
+66
View File
@@ -0,0 +1,66 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 by 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####*/
/* Functional Description: Generic ring buffer library for deeply
embedded system. See the unit tests for usage examples. */
#ifndef RINGBUF_H
#define RINGBUF_H
#include "stdint.h"
struct ring_buffer_t
{
char *data; // block of memory or array of data
unsigned element_size; // how many bytes for each chunk
unsigned element_count; // number of chunks of data
unsigned head; // first chunk of data
unsigned count; // number of chunks in use
};
typedef struct ring_buffer_t RING_BUFFER;
extern bool Ringbuf_Empty(RING_BUFFER const *b);
extern char *Ringbuf_Get_Front(RING_BUFFER const *b);
extern char *Ringbuf_Pop_Front(RING_BUFFER *b);
extern bool Ringbuf_Put(
RING_BUFFER *b, // ring buffer structure
char *data_element); // one element to add to the ring
extern void Ringbuf_Init(
RING_BUFFER *b, // ring buffer structure
char *data, // data block or array of data
unsigned element_size, // size of one element in the data block
unsigned element_count); // number of elements in the data block
#endif
+29
View File
@@ -0,0 +1,29 @@
#Makefile to build ringbuf tests
CC = gcc
BASEDIR = .
#CFLAGS = -Wall -I.
# -g for debugging with gdb
#CFLAGS = -Wall -I. -g
CFLAGS = -Wall -I. -Itest -DTEST -DTEST_RINGBUF -g
OBJS = ringbuf.o test/ctest.o
TARGET = ringbuf
all: ${TARGET}
${TARGET}: ${OBJS}
${CC} -o $@ ${OBJS}
.c.o:
${CC} -c ${CFLAGS} $*.c -o $@
depend:
rm -f .depend
${CC} -MM ${CFLAGS} *.c >> .depend
clean:
rm -rf core ${TARGET} $(OBJS) *.bak *.1 *.ini
include: .depend
+53
View File
@@ -0,0 +1,53 @@
/*####COPYRIGHTBEGIN####
-------------------------------------------
Copyright (C) 2004 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####*/
#ifndef RS485_H
#define RS485_H
#include <stdint.h>
#include "mstp.h"
void RS485_Send_Frame(
struct mstp_port_struct_t *mstp_port, // port specific data
uint8_t frame_type, // type of frame to send - see defines
uint8_t destination, // destination address
uint8_t source, // source address
uint8_t *data, // any data to be sent - may be null
unsigned data_len); // number of bytes of data (up to 501)
void RS485_Check_UART_Data(
struct mstp_port_struct_t *mstp_port); // port specific data
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef STDBOOL_H
#define STDBOOL_H
// C99 Boolean types for compilers without C99 support
#ifndef __cplusplus
typedef int _Bool;
#ifndef bool
#define bool _Bool
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define __bool_true_false_are_defined 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#endif
+26
View File
@@ -0,0 +1,26 @@
// Defines the standard integer types that are used in code
// for the x86 processor and Borland Compiler
#ifndef STDINT_H
#define STDINT_H
#include <stddef.h>
#define TRUE 1
#define FALSE 0
#define MSB 7
#define LSB 0
typedef int bool;
typedef unsigned char uint8_t; // 1 byte 0 to 255
typedef signed char int8_t; // 1 byte -127 to 127
typedef unsigned short uint16_t; // 2 bytes 0 to 65535
typedef signed short int16_t; // 2 bytes -32767 to 32767
//typedef unsigned short long uint24_t; // 3 bytes 0 to 16777215
typedef unsigned long uint32_t; // 4 bytes 0 to 4294967295
typedef signed long int32_t; // 4 bytes -2147483647 to 2147483647
// typedef signed long long int64_t;
// typedef unsigned long long uint64_t;
#endif // STDINT_H
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
# Unit tests builder / runner for this project
rm test.log
touch test.log
make -f crc.mak
./crc >> test.log
make -f crc.mak clean
make -f ringbuf.mak
./ringbuf >> test.log
make -f ringbuf.mak clean
make -f mstp.mak
./mstp >> test.log
make -f mstp.mak clean
+2
View File
@@ -0,0 +1,2 @@
This is a Subversion working copy administrative directory.
Visit http://subversion.tigris.org/ for more information.
View File

Some files were not shown because too many files have changed in this diff Show More