From 9a9e31ace666fde9c11d9513b115493a16b7037c Mon Sep 17 00:00:00 2001 From: skarg Date: Wed, 22 Sep 2004 19:08:48 +0000 Subject: [PATCH] Initial revision --- bacnet-stack/.svn/README.txt | 2 + bacnet-stack/.svn/empty-file | 0 bacnet-stack/.svn/entries | 157 ++ bacnet-stack/.svn/format | 1 + bacnet-stack/.svn/prop-base/Makefile.svn-base | 1 + bacnet-stack/.svn/prop-base/bytes.h.svn-base | 1 + bacnet-stack/.svn/prop-base/crc.c.svn-base | 1 + bacnet-stack/.svn/prop-base/crc.h.svn-base | 1 + bacnet-stack/.svn/prop-base/crc.ide.svn-base | 5 + bacnet-stack/.svn/prop-base/main.c.svn-base | 1 + bacnet-stack/.svn/prop-base/mstp.c.svn-base | 1 + bacnet-stack/.svn/prop-base/mstp.h.svn-base | 1 + bacnet-stack/.svn/prop-base/mstp.ide.svn-base | 5 + .../.svn/prop-base/ringbuf.c.svn-base | 1 + .../.svn/prop-base/ringbuf.h.svn-base | 1 + bacnet-stack/.svn/prop-base/rs485.h.svn-base | 1 + .../.svn/prop-base/stdbool.h.svn-base | 1 + bacnet-stack/.svn/prop-base/stdint.h.svn-base | 1 + bacnet-stack/.svn/prop-base/test.sh.svn-base | 5 + bacnet-stack/.svn/props/Makefile.svn-work | 1 + bacnet-stack/.svn/props/bytes.h.svn-work | 1 + bacnet-stack/.svn/props/crc.c.svn-work | 1 + bacnet-stack/.svn/props/crc.h.svn-work | 1 + bacnet-stack/.svn/props/crc.ide.svn-work | 5 + bacnet-stack/.svn/props/main.c.svn-work | 1 + bacnet-stack/.svn/props/mstp.c.svn-work | 1 + bacnet-stack/.svn/props/mstp.h.svn-work | 1 + bacnet-stack/.svn/props/mstp.ide.svn-work | 5 + bacnet-stack/.svn/props/ringbuf.c.svn-work | 1 + bacnet-stack/.svn/props/ringbuf.h.svn-work | 1 + bacnet-stack/.svn/props/rs485.h.svn-work | 1 + bacnet-stack/.svn/props/stdbool.h.svn-work | 1 + bacnet-stack/.svn/props/stdint.h.svn-work | 1 + bacnet-stack/.svn/props/test.sh.svn-work | 5 + bacnet-stack/.svn/text-base/Makefile.svn-base | 29 + bacnet-stack/.svn/text-base/bytes.h.svn-base | 42 + bacnet-stack/.svn/text-base/crc.c.svn-base | 153 ++ bacnet-stack/.svn/text-base/crc.h.svn-base | 44 + bacnet-stack/.svn/text-base/crc.ide.svn-base | Bin 0 -> 29482 bytes bacnet-stack/.svn/text-base/crc.mak.svn-base | 29 + bacnet-stack/.svn/text-base/main.c.svn-base | 63 + bacnet-stack/.svn/text-base/mstp.c.svn-base | 1671 +++++++++++++++++ bacnet-stack/.svn/text-base/mstp.h.svn-base | 240 +++ bacnet-stack/.svn/text-base/mstp.ide.svn-base | Bin 0 -> 32618 bytes bacnet-stack/.svn/text-base/mstp.mak.svn-base | 29 + .../.svn/text-base/ringbuf.c.svn-base | 287 +++ .../.svn/text-base/ringbuf.h.svn-base | 66 + .../.svn/text-base/ringbuf.mak.svn-base | 29 + bacnet-stack/.svn/text-base/rs485.h.svn-base | 53 + .../.svn/text-base/stdbool.h.svn-base | 28 + bacnet-stack/.svn/text-base/stdint.h.svn-base | 26 + bacnet-stack/.svn/text-base/test.sh.svn-base | 19 + bacnet-stack/Makefile | 29 + bacnet-stack/bytes.h | 42 + bacnet-stack/crc.c | 153 ++ bacnet-stack/crc.h | 44 + bacnet-stack/crc.ide | Bin 0 -> 29482 bytes bacnet-stack/crc.mak | 29 + bacnet-stack/main.c | 63 + bacnet-stack/mstp.c | 1671 +++++++++++++++++ bacnet-stack/mstp.h | 240 +++ bacnet-stack/mstp.ide | Bin 0 -> 32618 bytes bacnet-stack/mstp.mak | 29 + bacnet-stack/ports/.svn/README.txt | 2 + bacnet-stack/ports/.svn/empty-file | 0 bacnet-stack/ports/.svn/entries | 21 + bacnet-stack/ports/.svn/format | 1 + bacnet-stack/ports/linux/.svn/README.txt | 2 + bacnet-stack/ports/linux/.svn/empty-file | 0 bacnet-stack/ports/linux/.svn/entries | 28 + bacnet-stack/ports/linux/.svn/format | 1 + .../linux/.svn/prop-base/readme.txt.svn-base | 1 + .../linux/.svn/prop-base/rs485.c.svn-base | 1 + .../linux/.svn/props/readme.txt.svn-work | 1 + .../ports/linux/.svn/props/rs485.c.svn-work | 1 + .../linux/.svn/text-base/readme.txt.svn-base | 2 + .../linux/.svn/text-base/rs485.c.svn-base | 115 ++ bacnet-stack/ports/linux/readme.txt | 2 + bacnet-stack/ports/linux/rs485.c | 115 ++ bacnet-stack/ports/pic18/.svn/README.txt | 2 + bacnet-stack/ports/pic18/.svn/empty-file | 0 bacnet-stack/ports/pic18/.svn/entries | 19 + bacnet-stack/ports/pic18/.svn/format | 1 + .../pic18/.svn/prop-base/rs485.c.svn-base | 1 + .../ports/pic18/.svn/props/rs485.c.svn-work | 1 + .../pic18/.svn/text-base/rs485.c.svn-base | 119 ++ bacnet-stack/ports/pic18/rs485.c | 119 ++ bacnet-stack/ports/rtos32/.svn/README.txt | 2 + bacnet-stack/ports/rtos32/.svn/empty-file | 0 bacnet-stack/ports/rtos32/.svn/entries | 12 + bacnet-stack/ports/rtos32/.svn/format | 1 + bacnet-stack/ringbuf.c | 287 +++ bacnet-stack/ringbuf.h | 66 + bacnet-stack/ringbuf.mak | 29 + bacnet-stack/rs485.h | 53 + bacnet-stack/stdbool.h | 28 + bacnet-stack/stdint.h | 26 + bacnet-stack/test.sh | 19 + bacnet-stack/test/.svn/README.txt | 2 + bacnet-stack/test/.svn/empty-file | 0 bacnet-stack/test/.svn/entries | 28 + bacnet-stack/test/.svn/format | 1 + .../test/.svn/prop-base/ctest.c.svn-base | 1 + .../test/.svn/prop-base/ctest.h.svn-base | 1 + bacnet-stack/test/.svn/props/ctest.c.svn-work | 1 + bacnet-stack/test/.svn/props/ctest.h.svn-work | 1 + .../test/.svn/text-base/ctest.c.svn-base | 182 ++ .../test/.svn/text-base/ctest.h.svn-base | 61 + bacnet-stack/test/ctest.c | 182 ++ bacnet-stack/test/ctest.h | 61 + 110 files changed, 6921 insertions(+) create mode 100644 bacnet-stack/.svn/README.txt create mode 100644 bacnet-stack/.svn/empty-file create mode 100644 bacnet-stack/.svn/entries create mode 100644 bacnet-stack/.svn/format create mode 100644 bacnet-stack/.svn/prop-base/Makefile.svn-base create mode 100644 bacnet-stack/.svn/prop-base/bytes.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/crc.c.svn-base create mode 100644 bacnet-stack/.svn/prop-base/crc.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/crc.ide.svn-base create mode 100644 bacnet-stack/.svn/prop-base/main.c.svn-base create mode 100644 bacnet-stack/.svn/prop-base/mstp.c.svn-base create mode 100644 bacnet-stack/.svn/prop-base/mstp.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/mstp.ide.svn-base create mode 100644 bacnet-stack/.svn/prop-base/ringbuf.c.svn-base create mode 100644 bacnet-stack/.svn/prop-base/ringbuf.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/rs485.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/stdbool.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/stdint.h.svn-base create mode 100644 bacnet-stack/.svn/prop-base/test.sh.svn-base create mode 100644 bacnet-stack/.svn/props/Makefile.svn-work create mode 100644 bacnet-stack/.svn/props/bytes.h.svn-work create mode 100644 bacnet-stack/.svn/props/crc.c.svn-work create mode 100644 bacnet-stack/.svn/props/crc.h.svn-work create mode 100644 bacnet-stack/.svn/props/crc.ide.svn-work create mode 100644 bacnet-stack/.svn/props/main.c.svn-work create mode 100644 bacnet-stack/.svn/props/mstp.c.svn-work create mode 100644 bacnet-stack/.svn/props/mstp.h.svn-work create mode 100644 bacnet-stack/.svn/props/mstp.ide.svn-work create mode 100644 bacnet-stack/.svn/props/ringbuf.c.svn-work create mode 100644 bacnet-stack/.svn/props/ringbuf.h.svn-work create mode 100644 bacnet-stack/.svn/props/rs485.h.svn-work create mode 100644 bacnet-stack/.svn/props/stdbool.h.svn-work create mode 100644 bacnet-stack/.svn/props/stdint.h.svn-work create mode 100644 bacnet-stack/.svn/props/test.sh.svn-work create mode 100644 bacnet-stack/.svn/text-base/Makefile.svn-base create mode 100644 bacnet-stack/.svn/text-base/bytes.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/crc.c.svn-base create mode 100644 bacnet-stack/.svn/text-base/crc.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/crc.ide.svn-base create mode 100644 bacnet-stack/.svn/text-base/crc.mak.svn-base create mode 100644 bacnet-stack/.svn/text-base/main.c.svn-base create mode 100644 bacnet-stack/.svn/text-base/mstp.c.svn-base create mode 100644 bacnet-stack/.svn/text-base/mstp.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/mstp.ide.svn-base create mode 100644 bacnet-stack/.svn/text-base/mstp.mak.svn-base create mode 100644 bacnet-stack/.svn/text-base/ringbuf.c.svn-base create mode 100644 bacnet-stack/.svn/text-base/ringbuf.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/ringbuf.mak.svn-base create mode 100644 bacnet-stack/.svn/text-base/rs485.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/stdbool.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/stdint.h.svn-base create mode 100644 bacnet-stack/.svn/text-base/test.sh.svn-base create mode 100644 bacnet-stack/Makefile create mode 100644 bacnet-stack/bytes.h create mode 100644 bacnet-stack/crc.c create mode 100644 bacnet-stack/crc.h create mode 100644 bacnet-stack/crc.ide create mode 100644 bacnet-stack/crc.mak create mode 100644 bacnet-stack/main.c create mode 100644 bacnet-stack/mstp.c create mode 100644 bacnet-stack/mstp.h create mode 100644 bacnet-stack/mstp.ide create mode 100644 bacnet-stack/mstp.mak create mode 100644 bacnet-stack/ports/.svn/README.txt create mode 100644 bacnet-stack/ports/.svn/empty-file create mode 100644 bacnet-stack/ports/.svn/entries create mode 100644 bacnet-stack/ports/.svn/format create mode 100644 bacnet-stack/ports/linux/.svn/README.txt create mode 100644 bacnet-stack/ports/linux/.svn/empty-file create mode 100644 bacnet-stack/ports/linux/.svn/entries create mode 100644 bacnet-stack/ports/linux/.svn/format create mode 100644 bacnet-stack/ports/linux/.svn/prop-base/readme.txt.svn-base create mode 100644 bacnet-stack/ports/linux/.svn/prop-base/rs485.c.svn-base create mode 100644 bacnet-stack/ports/linux/.svn/props/readme.txt.svn-work create mode 100644 bacnet-stack/ports/linux/.svn/props/rs485.c.svn-work create mode 100644 bacnet-stack/ports/linux/.svn/text-base/readme.txt.svn-base create mode 100644 bacnet-stack/ports/linux/.svn/text-base/rs485.c.svn-base create mode 100644 bacnet-stack/ports/linux/readme.txt create mode 100644 bacnet-stack/ports/linux/rs485.c create mode 100644 bacnet-stack/ports/pic18/.svn/README.txt create mode 100644 bacnet-stack/ports/pic18/.svn/empty-file create mode 100644 bacnet-stack/ports/pic18/.svn/entries create mode 100644 bacnet-stack/ports/pic18/.svn/format create mode 100644 bacnet-stack/ports/pic18/.svn/prop-base/rs485.c.svn-base create mode 100644 bacnet-stack/ports/pic18/.svn/props/rs485.c.svn-work create mode 100644 bacnet-stack/ports/pic18/.svn/text-base/rs485.c.svn-base create mode 100644 bacnet-stack/ports/pic18/rs485.c create mode 100644 bacnet-stack/ports/rtos32/.svn/README.txt create mode 100644 bacnet-stack/ports/rtos32/.svn/empty-file create mode 100644 bacnet-stack/ports/rtos32/.svn/entries create mode 100644 bacnet-stack/ports/rtos32/.svn/format create mode 100644 bacnet-stack/ringbuf.c create mode 100644 bacnet-stack/ringbuf.h create mode 100644 bacnet-stack/ringbuf.mak create mode 100644 bacnet-stack/rs485.h create mode 100644 bacnet-stack/stdbool.h create mode 100644 bacnet-stack/stdint.h create mode 100755 bacnet-stack/test.sh create mode 100644 bacnet-stack/test/.svn/README.txt create mode 100644 bacnet-stack/test/.svn/empty-file create mode 100644 bacnet-stack/test/.svn/entries create mode 100644 bacnet-stack/test/.svn/format create mode 100644 bacnet-stack/test/.svn/prop-base/ctest.c.svn-base create mode 100644 bacnet-stack/test/.svn/prop-base/ctest.h.svn-base create mode 100644 bacnet-stack/test/.svn/props/ctest.c.svn-work create mode 100644 bacnet-stack/test/.svn/props/ctest.h.svn-work create mode 100644 bacnet-stack/test/.svn/text-base/ctest.c.svn-base create mode 100644 bacnet-stack/test/.svn/text-base/ctest.h.svn-base create mode 100644 bacnet-stack/test/ctest.c create mode 100644 bacnet-stack/test/ctest.h diff --git a/bacnet-stack/.svn/README.txt b/bacnet-stack/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/.svn/empty-file b/bacnet-stack/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/.svn/entries b/bacnet-stack/.svn/entries new file mode 100644 index 00000000..7a4728e7 --- /dev/null +++ b/bacnet-stack/.svn/entries @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bacnet-stack/.svn/format b/bacnet-stack/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/.svn/prop-base/Makefile.svn-base b/bacnet-stack/.svn/prop-base/Makefile.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/Makefile.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/bytes.h.svn-base b/bacnet-stack/.svn/prop-base/bytes.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/bytes.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/crc.c.svn-base b/bacnet-stack/.svn/prop-base/crc.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/crc.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/crc.h.svn-base b/bacnet-stack/.svn/prop-base/crc.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/crc.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/crc.ide.svn-base b/bacnet-stack/.svn/prop-base/crc.ide.svn-base new file mode 100644 index 00000000..5e9587e6 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/crc.ide.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/bacnet-stack/.svn/prop-base/main.c.svn-base b/bacnet-stack/.svn/prop-base/main.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/main.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/mstp.c.svn-base b/bacnet-stack/.svn/prop-base/mstp.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/mstp.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/mstp.h.svn-base b/bacnet-stack/.svn/prop-base/mstp.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/mstp.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/mstp.ide.svn-base b/bacnet-stack/.svn/prop-base/mstp.ide.svn-base new file mode 100644 index 00000000..5e9587e6 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/mstp.ide.svn-base @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/bacnet-stack/.svn/prop-base/ringbuf.c.svn-base b/bacnet-stack/.svn/prop-base/ringbuf.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/ringbuf.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/ringbuf.h.svn-base b/bacnet-stack/.svn/prop-base/ringbuf.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/ringbuf.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/rs485.h.svn-base b/bacnet-stack/.svn/prop-base/rs485.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/rs485.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/stdbool.h.svn-base b/bacnet-stack/.svn/prop-base/stdbool.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/stdbool.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/stdint.h.svn-base b/bacnet-stack/.svn/prop-base/stdint.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/prop-base/stdint.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/prop-base/test.sh.svn-base b/bacnet-stack/.svn/prop-base/test.sh.svn-base new file mode 100644 index 00000000..869ac71c --- /dev/null +++ b/bacnet-stack/.svn/prop-base/test.sh.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/bacnet-stack/.svn/props/Makefile.svn-work b/bacnet-stack/.svn/props/Makefile.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/Makefile.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/bytes.h.svn-work b/bacnet-stack/.svn/props/bytes.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/bytes.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/crc.c.svn-work b/bacnet-stack/.svn/props/crc.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/crc.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/crc.h.svn-work b/bacnet-stack/.svn/props/crc.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/crc.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/crc.ide.svn-work b/bacnet-stack/.svn/props/crc.ide.svn-work new file mode 100644 index 00000000..5e9587e6 --- /dev/null +++ b/bacnet-stack/.svn/props/crc.ide.svn-work @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/bacnet-stack/.svn/props/main.c.svn-work b/bacnet-stack/.svn/props/main.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/main.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/mstp.c.svn-work b/bacnet-stack/.svn/props/mstp.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/mstp.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/mstp.h.svn-work b/bacnet-stack/.svn/props/mstp.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/mstp.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/mstp.ide.svn-work b/bacnet-stack/.svn/props/mstp.ide.svn-work new file mode 100644 index 00000000..5e9587e6 --- /dev/null +++ b/bacnet-stack/.svn/props/mstp.ide.svn-work @@ -0,0 +1,5 @@ +K 13 +svn:mime-type +V 24 +application/octet-stream +END diff --git a/bacnet-stack/.svn/props/ringbuf.c.svn-work b/bacnet-stack/.svn/props/ringbuf.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/ringbuf.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/ringbuf.h.svn-work b/bacnet-stack/.svn/props/ringbuf.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/ringbuf.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/rs485.h.svn-work b/bacnet-stack/.svn/props/rs485.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/rs485.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/stdbool.h.svn-work b/bacnet-stack/.svn/props/stdbool.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/stdbool.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/stdint.h.svn-work b/bacnet-stack/.svn/props/stdint.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/.svn/props/stdint.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/.svn/props/test.sh.svn-work b/bacnet-stack/.svn/props/test.sh.svn-work new file mode 100644 index 00000000..869ac71c --- /dev/null +++ b/bacnet-stack/.svn/props/test.sh.svn-work @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/bacnet-stack/.svn/text-base/Makefile.svn-base b/bacnet-stack/.svn/text-base/Makefile.svn-base new file mode 100644 index 00000000..a555ed31 --- /dev/null +++ b/bacnet-stack/.svn/text-base/Makefile.svn-base @@ -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 + diff --git a/bacnet-stack/.svn/text-base/bytes.h.svn-base b/bacnet-stack/.svn/text-base/bytes.h.svn-base new file mode 100644 index 00000000..97dce0bd --- /dev/null +++ b/bacnet-stack/.svn/text-base/bytes.h.svn-base @@ -0,0 +1,42 @@ +// Defines the bit/byte/word/long conversions that are used in code + +#ifndef BYTES_H +#define BYTES_H + +#include + +#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 diff --git a/bacnet-stack/.svn/text-base/crc.c.svn-base b/bacnet-stack/.svn/text-base/crc.c.svn-base new file mode 100644 index 00000000..6c429155 --- /dev/null +++ b/bacnet-stack/.svn/text-base/crc.c.svn-base @@ -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 +#include +#include + +// 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 +#include +#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 diff --git a/bacnet-stack/.svn/text-base/crc.h.svn-base b/bacnet-stack/.svn/text-base/crc.h.svn-base new file mode 100644 index 00000000..afc0d6d4 --- /dev/null +++ b/bacnet-stack/.svn/text-base/crc.h.svn-base @@ -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 +#include + +uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue); +uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue); + +#endif diff --git a/bacnet-stack/.svn/text-base/crc.ide.svn-base b/bacnet-stack/.svn/text-base/crc.ide.svn-base new file mode 100644 index 0000000000000000000000000000000000000000..d7b2030c0a8affcc080f4ca37a959c5ec8bf8fc2 GIT binary patch literal 29482 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 literal 0 HcmV?d00001 diff --git a/bacnet-stack/.svn/text-base/crc.mak.svn-base b/bacnet-stack/.svn/text-base/crc.mak.svn-base new file mode 100644 index 00000000..e5bb862f --- /dev/null +++ b/bacnet-stack/.svn/text-base/crc.mak.svn-base @@ -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 + diff --git a/bacnet-stack/.svn/text-base/main.c.svn-base b/bacnet-stack/.svn/text-base/main.c.svn-base new file mode 100644 index 00000000..c54fdc5b --- /dev/null +++ b/bacnet-stack/.svn/text-base/main.c.svn-base @@ -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 +#include +#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); + + } +} diff --git a/bacnet-stack/.svn/text-base/mstp.c.svn-base b/bacnet-stack/.svn/text-base/mstp.c.svn-base new file mode 100644 index 00000000..a1214073 --- /dev/null +++ b/bacnet-stack/.svn/text-base/mstp.c.svn-base @@ -0,0 +1,1671 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2003 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +// This clause describes a Master-Slave/Token-Passing (MS/TP) data link +// protocol, which provides the same services to the network layer as +// ISO 8802-2 Logical Link Control. It uses services provided by the +// EIA-485 physical layer. Relevant clauses of EIA-485 are deemed to be +// included in this standard by reference. The following hardware is assumed: +// (a) A UART (Universal Asynchronous Receiver/Transmitter) capable of +// transmitting and receiving eight data bits with one stop bit +// and no parity. +// (b) An EIA-485 transceiver whose driver may be disabled. +// (c) A timer with a resolution of five milliseconds or less + +#include +#include +#include "mstp.h" +#include "bytes.h" +#include "crc.h" +#include "rs485.h" +#include "ringbuf.h" + +// MS/TP Frame Format +// All frames are of the following format: +// +// Preamble: two octet preamble: X`55', X`FF' +// Frame Type: one octet +// Destination Address: one octet address +// Source Address: one octet address +// Length: two octets, most significant octet first, of the Data field +// Header CRC: one octet +// Data: (present only if Length is non-zero) +// Data CRC: (present only if Length is non-zero) two octets, +// least significant octet first +// (pad): (optional) at most one octet of padding: X'FF' + + // The number of tokens received or used before a Poll For Master cycle +// is executed: 50. +const unsigned Npoll = 50; + +// The number of retries on sending Token: 1. +const unsigned Nretry_token = 1; + +// The minimum number of DataAvailable or ReceiveError events that must be +// seen by a receiving node in order to declare the line "active": 4. +const unsigned 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 unsigned Tframe_abort = 1 + ((1000 * 60) / 9600); + +// The maximum idle time a sending node may allow to elapse between octets +// of a frame the node is transmitting: 20 bit times. +const unsigned Tframe_gap = 20; + +// The time without a DataAvailable or ReceiveError event before declaration +// of loss of token: 500 milliseconds. +const unsigned Tno_token = 500; + +// The maximum time after the end of the stop bit of the final +// octet of a transmitted frame before a node must disable its +// EIA-485 driver: 15 bit times. +const unsigned Tpostdrive = 15; + +// The maximum time a node may wait after reception of a frame that expects +// a reply before sending the first octet of a reply or Reply Postponed +// frame: 250 milliseconds. +const unsigned Treply_delay = 225; + +// The minimum time without a DataAvailable or ReceiveError event +// that a node must wait for a station to begin replying to a +// confirmed request: 255 milliseconds. (Implementations may use +// larger values for this timeout, not to exceed 300 milliseconds.) +const unsigned Treply_timeout = 255; + +// Repeater turnoff delay. The duration of a continuous logical one state +// at the active input port of an MS/TP repeater after which the repeater +// will enter the IDLE state: 29 bit times < Troff < 40 bit times. +const unsigned Troff = 30; + +// The width of the time slot within which a node may generate a token: +// 10 milliseconds. +const unsigned Tslot = 10; + +// The maximum time a node may wait after reception of the token or +// a Poll For Master frame before sending the first octet of a frame: +// 15 milliseconds. +const unsigned Tusage_delay = 15; + +// The minimum time without a DataAvailable or ReceiveError event that a +// node must wait for a remote node to begin using a token or replying to +// a Poll For Master frame: 20 milliseconds. (Implementations may use +// larger values for this timeout, not to exceed 100 milliseconds.) +const unsigned Tusage_timeout = 20; + +// Millisecond Timer - called every millisecond +void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port) +{ + if (mstp_port->SilenceTimer < 255) + mstp_port->SilenceTimer++; + if (mstp_port->ReplyPostponedTimer < 255) + mstp_port->ReplyPostponedTimer++; + + return; +} + +void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port) +{ + switch (mstp_port->receive_state) + { + // In the IDLE state, the node waits for the beginning of a frame. + case MSTP_RECEIVE_STATE_IDLE: + // EatAnError + if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if (mstp_port->DataAvailable == TRUE) + { + // Preamble1 + if (mstp_port->DataRegister == 0x55) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // receive the remainder of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + // EatAnOctet + else + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + } + break; + // In the PREAMBLE state, the node waits for the second octet of the preamble. + case MSTP_RECEIVE_STATE_PREAMBLE: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // a correct preamble has not been received + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if (mstp_port->DataAvailable == TRUE) + { + // Preamble2 + if (mstp_port->DataRegister == 0xFF) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->Index = 0; + mstp_port->HeaderCRC = 0xFF; + // receive the remainder of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // ignore RepeatedPreamble1 + else if (mstp_port->DataRegister == 0x55) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the second preamble octet. + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + // NotPreamble + else + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + } + break; + // In the HEADER state, the node waits for the fixed message header. + case MSTP_RECEIVE_STATE_HEADER: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else if (mstp_port->DataAvailable == TRUE) + { + // FrameType + if (mstp_port->Index == 0) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->FrameType = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 1; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Destination + else if (mstp_port->Index == 1) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DestinationAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 2; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Source + else if (mstp_port->Index == 2) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->SourceAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 3; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Length1 + else if (mstp_port->Index == 3) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength = mstp_port->DataRegister * 256; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 4; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Length2 + else if (mstp_port->Index == 4) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength += mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 5; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // HeaderCRC + else if (mstp_port->Index == 5) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER_CRC; + } + // not per MS/TP standard, but it is a case not covered + else + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // indicate that an error has occurred during + // the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + // In the HEADER_CRC state, the node validates the CRC on the fixed + // message header. + case MSTP_RECEIVE_STATE_HEADER_CRC: + // BadCRC + if (mstp_port->HeaderCRC != 0x55) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if ((mstp_port->DestinationAddress == mstp_port->This_Station) || + (mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) + { + // FrameTooLong + if (mstp_port->DataLength > INPUT_BUFFER_SIZE) + { + // indicate that a frame with an illegal or + // unacceptable data length has been received + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // NoData + else if (mstp_port->DataLength == 0) + { + // indicate that a frame with no data has been received + mstp_port->ReceivedValidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // Data + else + { + mstp_port->Index = 0; + mstp_port->DataCRC = 0xFFFF; + // receive the data portion of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + } + // NotForUs + else + { + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + // In the DATA state, the node waits for the data portion of a frame. + case MSTP_RECEIVE_STATE_DATA: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else if (mstp_port->DataAvailable == TRUE) + { + // DataOctet + if (mstp_port->Index < mstp_port->DataLength) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->InputBuffer[mstp_port->Index] = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index++; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + // CRC1 + else if (mstp_port->Index == mstp_port->DataLength) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->Index++; // Index now becomes the number of data octets + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + // CRC2 + else if (mstp_port->Index == (mstp_port->DataLength + 1)) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA_CRC; + } + } + break; + // In the DATA_CRC state, the node validates the CRC of the message data. + case MSTP_RECEIVE_STATE_DATA_CRC: + // GoodCRC + if (mstp_port->DataCRC == 0xF0B8) + { + // indicate the complete reception of a valid frame + mstp_port->ReceivedValidFrame = TRUE; + + // now might be a good time to process the message or + // copy the data to a buffer so that we can process the message + + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // BadCRC + else + { + // to indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + break; + default: + // shouldn't get here - but if we do... + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + break; + } + + return; +} + +void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port) +{ + + switch (mstp_port->master_state) + { + case MSTP_MASTER_STATE_INITIALIZE: + // DoneInitializing + mstp_port->This_Station = 0; // FIXME: the node's station address + // indicate that the next station is unknown + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->Poll_Station = mstp_port->This_Station; + // cause a Poll For Master to be sent when this node first + // receives the token + mstp_port->TokenCount = Npoll; + mstp_port->SoleMaster = FALSE; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + // In the IDLE state, the node waits for a frame. + case MSTP_MASTER_STATE_IDLE: + // LostToken + if (mstp_port->SilenceTimer >= Tno_token) + { + // assume that the token has been lost + mstp_port->master_state = MSTP_MASTER_STATE_NO_TOKEN; + } + // mstp_port->ReceivedInvalidFrame + else if (mstp_port->ReceivedInvalidFrame == TRUE) + { + // invalid frame was received + mstp_port->ReceivedInvalidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedUnwantedFrame + else if (mstp_port->ReceivedValidFrame == TRUE) + { + if ((mstp_port->DestinationAddress != mstp_port->This_Station) || + (mstp_port->DestinationAddress != MSTP_BROADCAST_ADDRESS)) + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // DestinationAddress is equal to 255 (broadcast) and + // FrameType has a value of Token, BACnet Data Expecting Reply, Test_Request, + // or a proprietary type known to this node that expects a reply + // (such frames may not be broadcast), or + else if ((mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS) && + ((mstp_port->FrameType == FRAME_TYPE_TOKEN) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) || + (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // FrameType has a value that indicates a standard or proprietary type + // that is not known to this node. + // FIXME: change this if you add a proprietary type + else if /*(*/(mstp_port->FrameType >= FRAME_TYPE_PROPRIETARY_MIN) /*&&*/ + /*(FrameType <= FRAME_TYPE_PROPRIETARY_MAX))*/ + /* unnecessary if FrameType is uint8_t with max of 255 */ + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedToken + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_TOKEN)) + { + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->FrameCount = 0; + mstp_port->SoleMaster = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // ReceivedPFM + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_POLL_FOR_MASTER)) + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, + mstp_port->SourceAddress, + mstp_port->This_Station, + NULL,0); + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedDataNoReply + // or a proprietary type known to this node that does not expect a reply + else if (((mstp_port->DestinationAddress == mstp_port->This_Station) || + (mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) && + ((mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY) || + // (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE))) + { + // FIXME: indicate successful reception to the higher layers + // i.e. Process this frame! + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedDataNeedingReply + // or a proprietary type known to this node that expects a reply + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + ((mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) || + // (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY) || + (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) + { + mstp_port->ReplyPostponedTimer = 0; + // indicate successful reception to the higher layers + // (management entity in the case of Test_Request); + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; + } + } + break; + // In the USE_TOKEN state, the node is allowed to send one or + // more data frames. These may be BACnet Data frames or + // proprietary frames. + case MSTP_MASTER_STATE_USE_TOKEN: + // NothingToSend + // FIXME: If there is no data frame awaiting transmission, + { + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // SendNoWait + // FIXME: If there is a frame awaiting transmission that + // is of type Test_Response, BACnet Data Not Expecting Reply, + // or a proprietary type that does not expect a reply, +// { +// // transmit the data frame +// RS485_Send_Frame(?????????????); +// FrameCount++; +// mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; +// } + // SendAndWait + // FIXME: If there is a frame awaiting transmission that is of + // type Test_Request, BACnet Data Expecting Reply, or + // a proprietary type that expects a reply, +// { +// // transmit the data frame +// RS485_Send_Frame(); +// FrameCount++; +// mstp_port->master_state = MSTP_MASTER_STATE_WAIT_FOR_REPLY; +// } + // In the WAIT_FOR_REPLY state, the node waits for + // a reply from another node. + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + // ReplyTimeout + if (mstp_port->SilenceTimer >= Treply_timeout) + { + // assume that the request has failed + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + // Any retry of the data frame shall await the next entry + // to the USE_TOKEN state. (Because of the length of the timeout, + // this transition will cause the token to be passed regardless + // of the initial value of FrameCount.) + } + // InvalidFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedInvalidFrame == TRUE)) + { + // error in frame reception + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedReply + // or a proprietary type that indicates a reply + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + ((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) || + //(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) + { + // FIXME: indicate successful reception to the higher layers + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedPostpone + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_REPLY_POSTPONED)) + { + // FIXME: then the reply to the message has been postponed until a later time. + // So, what does this really mean? + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress != mstp_port->This_Station)) + //the expected reply should not be broadcast) + { + // an unexpected frame was received + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // Synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + ((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) || + //(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) + { + // An unexpected frame was received. + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // Synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + break; + // The DONE_WITH_TOKEN state either sends another data frame, + // passes the token, or initiates a Poll For Master cycle. + case MSTP_MASTER_STATE_DONE_WITH_TOKEN: + // SendAnotherFrame + if (mstp_port->FrameCount < mstp_port->Nmax_info_frames) + { + // then this node may send another information frame + // before passing the token. + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // mstp_port->SoleMaster + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount < Npoll) && + (mstp_port->SoleMaster == TRUE)) + { + // there are no other known master nodes to + // which the token may be sent (true master-slave operation). + mstp_port->FrameCount = 0; + mstp_port->TokenCount++; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // SendToken + else if (((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount < Npoll) && + (mstp_port->SoleMaster == FALSE)) || + // The comparison of NS and TS+1 eliminates the Poll For Master + // if there are no addresses between TS and NS, since there is no + // address at which a new master node may be found in that case. + (mstp_port->Next_Station == + (uint8_t)((mstp_port->This_Station +1) % (mstp_port->Nmax_master + 1)))) + { + mstp_port->TokenCount++; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SendMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) != mstp_port->Next_Station)) + { + mstp_port->Poll_Station = (mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1); + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + // ResetMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) == mstp_port->Next_Station) && + (mstp_port->SoleMaster == FALSE)) + { + mstp_port->Poll_Station = mstp_port->This_Station; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SoleMasterRestartMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) == mstp_port->Next_Station) && + (mstp_port->SoleMaster == TRUE)) + { + mstp_port->Poll_Station = (mstp_port->Next_Station +1) % (mstp_port->Nmax_master + 1); + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // no known successor node + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // find a new successor to TS + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + // The PASS_TOKEN state listens for a successor to begin using + // the token that this node has just attempted to pass. + case MSTP_MASTER_STATE_PASS_TOKEN: + // SawTokenUser + if ((mstp_port->SilenceTimer < Tusage_timeout) && + (mstp_port->EventCount > Nmin_octets)) + { + // Assume that a frame has been sent by the new token user. + // Enter the IDLE state to process the frame. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // RetrySendToken + else if ((mstp_port->SilenceTimer >= Tusage_timeout) && + (mstp_port->RetryCount < Nretry_token)) + { + mstp_port->RetryCount++; + // Transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->EventCount = 0; + // re-enter the current state to listen for NS + // to begin using the token. + } + // FindNewSuccessor + else if ((mstp_port->SilenceTimer >= Tusage_timeout) && + (mstp_port->RetryCount >= Nretry_token)) + { + // Assume that NS has failed. + mstp_port->Poll_Station = (mstp_port->Next_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // no known successor node + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // find a new successor to TS + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + // The NO_TOKEN state is entered if mstp_port->SilenceTimer becomes greater + // than Tno_token, indicating that there has been no network activity + // for that period of time. The timeout is continued to determine + // whether or not this node may create a token. + case MSTP_MASTER_STATE_NO_TOKEN: + // SawFrame + if ((mstp_port->SilenceTimer < (Tno_token + (Tslot * mstp_port->This_Station))) && + (mstp_port->EventCount > Nmin_octets)) + { + // Some other node exists at a lower address. + // Enter the IDLE state to receive and process the incoming frame. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // GenerateToken + else if ((mstp_port->SilenceTimer >= (Tno_token + (Tslot * mstp_port->This_Station))) && + (mstp_port->SilenceTimer < (Tno_token + (Tslot * (mstp_port->This_Station + 1))))) + { + // Assume that this node is the lowest numerical address + // on the network and is empowered to create a token. + mstp_port->Poll_Station = (mstp_port->This_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // indicate that the next station is unknown + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // enter the POLL_FOR_MASTER state to find a new successor to TS. + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + // In the POLL_FOR_MASTER state, the node listens for a reply to + // a previously sent Poll For Master frame in order to find + // a successor node. + case MSTP_MASTER_STATE_POLL_FOR_MASTER: + // ReceivedReplyToPFM + if ((mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) + { + mstp_port->SoleMaster = FALSE; + mstp_port->Next_Station = mstp_port->SourceAddress; + mstp_port->EventCount = 0; + // Transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->Poll_Station = mstp_port->This_Station; + mstp_port->TokenCount = 0; + mstp_port->RetryCount = 0; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->ReceivedValidFrame == TRUE) && + ((mstp_port->DestinationAddress != mstp_port->This_Station) || + (mstp_port->FrameType != FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER))) + { + // An unexpected frame was received. + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // enter the IDLE state to synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // mstp_port->SoleMaster + else if ((mstp_port->SoleMaster == TRUE) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // There was no valid reply to the periodic poll + // by the sole known master for other masters. + mstp_port->FrameCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // DoneWithPFM + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station != mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // There was no valid reply to the maintenance + // poll for a master at address PS. + mstp_port->EventCount = 0; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SendNextPFM + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station == mstp_port->This_Station) && // no known successor node + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) != mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + mstp_port->Poll_Station = + (mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + // Re-enter the current state. + } + // DeclareSoleMaster + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station == mstp_port->This_Station) && // no known successor node + ((uint8_t)((mstp_port->Poll_Station + 1) % + (mstp_port->Nmax_master + 1)) == mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // to indicate that this station is the only master + mstp_port->SoleMaster = TRUE; + mstp_port->FrameCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + break; + // The ANSWER_DATA_REQUEST state is entered when a + // BACnet Data Expecting Reply, a Test_Request, or + // a proprietary frame that expects a reply is received. + case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: + if (mstp_port->ReplyPostponedTimer <= Treply_delay) + { + // Reply + // If a reply is available from the higher layers + // within Treply_delay after the reception of the + // final octet of the requesting frame + // (the mechanism used to determine this is a local matter), + // then call RS485_Send_Frame to transmit the reply frame + // and enter the IDLE state to wait for the next frame. + + // Test Request + // If a receiving node can successfully receive and return + // the information field, it shall do so. If it cannot receive + // and return the entire information field but can detect + // the reception of a valid Test_Request frame + // (for example, by computing the CRC on octets as + // they are received), then the receiving node shall discard + // the information field and return a Test_Response containing + // no information field. If the receiving node cannot detect + // the valid reception of frames with overlength information fields, + // then no response shall be returned. + if (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST) + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TEST_RESPONSE, + mstp_port->SourceAddress, + mstp_port->This_Station, + mstp_port->InputBuffer, + mstp_port->Index); + } + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + + // + // DeferredReply + // If no reply will be available from the higher layers + // within Treply_delay after the reception of the + // final octet of the requesting frame (the mechanism + // used to determine this is a local matter), + // then an immediate reply is not possible. + // Any reply shall wait until this node receives the token. + // Call RS485_Send_Frame to transmit a Reply Postponed frame, + // and enter the IDLE state. + + else + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_REPLY_POSTPONED, + mstp_port->SourceAddress, + mstp_port->This_Station, + NULL,0); + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + break; + default: + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + } + + return; +} + +void MSTP_Init( + struct mstp_port_struct_t *mstp_port, + uint8_t this_station_mac) +{ + int i; //loop counter + + if (mstp_port) + { + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE; + mstp_port->ReceiveError = FALSE; + mstp_port->DataAvailable = FALSE; + mstp_port->DataRegister = 0; + mstp_port->DataCRC = 0; + mstp_port->DataCRC = 0; + mstp_port->DataLength = 0; + mstp_port->DestinationAddress = 0; + mstp_port->EventCount = 0; + mstp_port->FrameType = FRAME_TYPE_TOKEN; + mstp_port->FrameCount = 0; + mstp_port->HeaderCRC = 0; + mstp_port->Index = 0; + mstp_port->Index = 0; + for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) + { + mstp_port->InputBuffer[i] = 0; + } + mstp_port->Next_Station = this_station_mac; + mstp_port->Poll_Station = this_station_mac; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->RetryCount = 0; + mstp_port->SilenceTimer = 0; + mstp_port->ReplyPostponedTimer = 0; + mstp_port->SoleMaster = FALSE; + mstp_port->SourceAddress = 0; + mstp_port->TokenCount = 0; + mstp_port->This_Station = this_station_mac; + mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; + mstp_port->Nmax_master = DEFAULT_MAX_MASTER; + } +} + +unsigned MSTP_Create_Frame( + uint8_t *buffer, // where frame is loaded + unsigned buffer_len, // amount of space available + uint8_t frame_type, // type of frame to send - see defines + uint8_t destination, // destination address + uint8_t source, // source address + uint8_t *data, // any data to be sent - may be null + unsigned data_len) // number of bytes of data (up to 501) +{ + uint8_t crc8 = 0xFF; // used to calculate the crc value + uint16_t crc16 = 0xFFFF; // used to calculate the crc value + unsigned index = 0; // used to load the data portion of the frame + + // not enough to do a header + if (buffer_len < 8) + return 0; + + buffer[0] = 0x55; + buffer[1] = 0xFF; + buffer[2] = frame_type; + crc8 = CRC_Calc_Header(buffer[2],crc8); + buffer[3] = destination; + crc8 = CRC_Calc_Header(buffer[3],crc8); + buffer[4] = source; + crc8 = CRC_Calc_Header(buffer[4],crc8); + buffer[5] = data_len / 256; + crc8 = CRC_Calc_Header(buffer[5],crc8); + buffer[6] = data_len % 256; + crc8 = CRC_Calc_Header(buffer[6],crc8); + buffer[7] = ~crc8; + + index = 8; + while (data_len && data && (index < buffer_len)) + { + buffer[index] = *data; + crc16 = CRC_Calc_Data(buffer[index],crc16); + data++; + index++; + data_len--; + } + // append the data CRC if necessary + if (index > 8) + { + if ((index + 2) <= buffer_len) + { + crc16 = ~crc16; + buffer[index] = LO_BYTE(crc16); + index++; + buffer[index] = HI_BYTE(crc16); + index++; + } + else + return 0; + } + + return index; // returns the frame length +} + + +#ifdef TEST +#include +#include +#include "ctest.h" + +// test stub functions +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)mstp_port; + (void)frame_type; + (void)destination; + (void)source; + (void)data; + (void)data_len; +} + +#define RING_BUFFER_DATA_SIZE 1 +#define RING_BUFFER_SIZE INPUT_BUFFER_SIZE +static RING_BUFFER Test_Buffer; +static uint8_t Test_Buffer_Data[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE]; +static void Load_Input_Buffer(uint8_t *buffer,size_t len) +{ + static bool initialized = FALSE; // tracks our init + + + if (!initialized) + { + initialized = TRUE; + Ringbuf_Init( + &Test_Buffer, + (char *)Test_Buffer_Data, + RING_BUFFER_DATA_SIZE, + RING_BUFFER_SIZE); + } + + // empty any the existing data + while (!Ringbuf_Empty(&Test_Buffer)) + { + (void)Ringbuf_Pop_Front(&Test_Buffer); + } + + if (buffer) + { + while (len) + { + (void)Ringbuf_Put(&Test_Buffer,(char *)buffer); + len--; + buffer++; + } + } +} + +void RS485_Check_UART_Data( + struct mstp_port_struct_t *mstp_port) // port specific data +{ + char *data; + if (!Ringbuf_Empty(&Test_Buffer) && mstp_port && + (mstp_port->DataAvailable == FALSE)) + { + data = Ringbuf_Pop_Front(&Test_Buffer); + if (data) + { + mstp_port->DataRegister = *data; + mstp_port->DataAvailable = TRUE; + } + } +} + +void testReceiveNodeFSM(Test* pTest) +{ + struct mstp_port_struct_t mstp_port; // port data + unsigned EventCount = 0; // local counter + uint8_t my_mac = 0x05; // local MAC address + uint8_t HeaderCRC = 0; // for local CRC calculation + uint8_t FrameType = 0; // type of packet that was sent + unsigned len; // used for the size of the message packet + size_t i; // used to loop through the message bytes + uint8_t buffer[INPUT_BUFFER_SIZE] = {0}; + uint8_t data[INPUT_BUFFER_SIZE - 8 /*header*/ - 2 /*CRC*/] = {0}; + + MSTP_Init(&mstp_port,my_mac); + + // check the receive error during idle + mstp_port.receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port.ReceiveError = TRUE; + mstp_port.SilenceTimer = 255; + mstp_port.EventCount = 0; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for bad packet header + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x11; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header, but timeout + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // force the timeout + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble, but receive error + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // force the error + mstp_port.ReceiveError = TRUE; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble1, but bad preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // no change of state if no data yet + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // repeated preamble1 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // repeated preamble1 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // bad data + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x11; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble, but timeout in packet + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // force the timeout + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + + // check for good packet header preamble, but error in packet + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // force the error + mstp_port.ReceiveError = TRUE; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // no change of state if no data yet + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // Data is received - index is incremented + // FrameType + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = FRAME_TYPE_TOKEN; + HeaderCRC = 0xFF; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 1); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,FrameType == FRAME_TYPE_TOKEN); + // Destination + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x10; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 2); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DestinationAddress == 0x10); + // Source + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = my_mac; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 3); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.SourceAddress == my_mac); + // Length1 = length*256 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 4); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DataLength == 0); + // Length2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 5); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DataLength == 0); + // HeaderCRC + mstp_port.DataAvailable = TRUE; + ct_test(pTest,HeaderCRC == 0x73); // per Annex G example + mstp_port.DataRegister = ~HeaderCRC; // one's compliment of CRC is sent + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 5); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + ct_test(pTest,mstp_port.HeaderCRC == 0x55); + // NotForUs + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // BadCRC in header check + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + 0x10, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + // make the header CRC bad + buffer[7] = 0x00; + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + ct_test(pTest,mstp_port.ReceivedValidFrame == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // NoData for us + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + my_mac, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == FALSE); + ct_test(pTest,mstp_port.ReceivedValidFrame == TRUE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // FrameTooLong + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + my_mac, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + // make the header data length bad + buffer[5] = 0x02; + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + ct_test(pTest,mstp_port.ReceivedValidFrame == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // Data + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + memset(data,0,sizeof(data)); + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_PROPRIETARY_MIN, + my_mac, // destination + my_mac, // source + data, // data + sizeof(data)); // data size + ct_test(pTest,len > 0); + Load_Input_Buffer(buffer,len); + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + while (mstp_port.receive_state != MSTP_RECEIVE_STATE_IDLE) + { + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + } + ct_test(pTest,mstp_port.DataLength == sizeof(data)); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == FALSE); + ct_test(pTest,mstp_port.ReceivedValidFrame == TRUE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + return; +} + +void testMasterNodeFSM(Test* pTest) +{ + struct mstp_port_struct_t mstp_port; // port data + uint8_t my_mac = 0x05; // local MAC address + + MSTP_Init(&mstp_port,my_mac); + ct_test(pTest,mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE); + +} + +#endif + +#ifdef TEST_MSTP +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("mstp", NULL); + + /* individual tests */ + rc = ct_addTestFunction(pTest, testReceiveNodeFSM); + assert(rc); + rc = ct_addTestFunction(pTest, testMasterNodeFSM); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void)ct_report(pTest); + + ct_destroy(pTest); + + return 0; +} +#endif diff --git a/bacnet-stack/.svn/text-base/mstp.h.svn-base b/bacnet-stack/.svn/text-base/mstp.h.svn-base new file mode 100644 index 00000000..6ec810c3 --- /dev/null +++ b/bacnet-stack/.svn/text-base/mstp.h.svn-base @@ -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 +#include +#include + +// 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 diff --git a/bacnet-stack/.svn/text-base/mstp.ide.svn-base b/bacnet-stack/.svn/text-base/mstp.ide.svn-base new file mode 100644 index 0000000000000000000000000000000000000000..986ae620e955c969ec744a59789437d9b6f90257 GIT binary patch literal 32618 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 Mz1d-~x{xye2e+6(n*aa+ literal 0 HcmV?d00001 diff --git a/bacnet-stack/.svn/text-base/mstp.mak.svn-base b/bacnet-stack/.svn/text-base/mstp.mak.svn-base new file mode 100644 index 00000000..d93124de --- /dev/null +++ b/bacnet-stack/.svn/text-base/mstp.mak.svn-base @@ -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 + diff --git a/bacnet-stack/.svn/text-base/ringbuf.c.svn-base b/bacnet-stack/.svn/text-base/ringbuf.c.svn-base new file mode 100644 index 00000000..ea3745b4 --- /dev/null +++ b/bacnet-stack/.svn/text-base/ringbuf.c.svn-base @@ -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 +#include + +#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 + diff --git a/bacnet-stack/.svn/text-base/ringbuf.h.svn-base b/bacnet-stack/.svn/text-base/ringbuf.h.svn-base new file mode 100644 index 00000000..68b9ae34 --- /dev/null +++ b/bacnet-stack/.svn/text-base/ringbuf.h.svn-base @@ -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 diff --git a/bacnet-stack/.svn/text-base/ringbuf.mak.svn-base b/bacnet-stack/.svn/text-base/ringbuf.mak.svn-base new file mode 100644 index 00000000..26c685c4 --- /dev/null +++ b/bacnet-stack/.svn/text-base/ringbuf.mak.svn-base @@ -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 + diff --git a/bacnet-stack/.svn/text-base/rs485.h.svn-base b/bacnet-stack/.svn/text-base/rs485.h.svn-base new file mode 100644 index 00000000..59b0c55f --- /dev/null +++ b/bacnet-stack/.svn/text-base/rs485.h.svn-base @@ -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 +#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 diff --git a/bacnet-stack/.svn/text-base/stdbool.h.svn-base b/bacnet-stack/.svn/text-base/stdbool.h.svn-base new file mode 100644 index 00000000..29b9a5e4 --- /dev/null +++ b/bacnet-stack/.svn/text-base/stdbool.h.svn-base @@ -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 diff --git a/bacnet-stack/.svn/text-base/stdint.h.svn-base b/bacnet-stack/.svn/text-base/stdint.h.svn-base new file mode 100644 index 00000000..b66446d4 --- /dev/null +++ b/bacnet-stack/.svn/text-base/stdint.h.svn-base @@ -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 + +#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 diff --git a/bacnet-stack/.svn/text-base/test.sh.svn-base b/bacnet-stack/.svn/text-base/test.sh.svn-base new file mode 100644 index 00000000..4e7739f1 --- /dev/null +++ b/bacnet-stack/.svn/text-base/test.sh.svn-base @@ -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 + + diff --git a/bacnet-stack/Makefile b/bacnet-stack/Makefile new file mode 100644 index 00000000..11fde245 --- /dev/null +++ b/bacnet-stack/Makefile @@ -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 + diff --git a/bacnet-stack/bytes.h b/bacnet-stack/bytes.h new file mode 100644 index 00000000..97dce0bd --- /dev/null +++ b/bacnet-stack/bytes.h @@ -0,0 +1,42 @@ +// Defines the bit/byte/word/long conversions that are used in code + +#ifndef BYTES_H +#define BYTES_H + +#include + +#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 diff --git a/bacnet-stack/crc.c b/bacnet-stack/crc.c new file mode 100644 index 00000000..6c429155 --- /dev/null +++ b/bacnet-stack/crc.c @@ -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 +#include +#include + +// 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 +#include +#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 diff --git a/bacnet-stack/crc.h b/bacnet-stack/crc.h new file mode 100644 index 00000000..afc0d6d4 --- /dev/null +++ b/bacnet-stack/crc.h @@ -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 +#include + +uint8_t CRC_Calc_Header(uint8_t dataValue, uint8_t crcValue); +uint16_t CRC_Calc_Data(uint8_t dataValue, uint16_t crcValue); + +#endif diff --git a/bacnet-stack/crc.ide b/bacnet-stack/crc.ide new file mode 100644 index 0000000000000000000000000000000000000000..d7b2030c0a8affcc080f4ca37a959c5ec8bf8fc2 GIT binary patch literal 29482 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 literal 0 HcmV?d00001 diff --git a/bacnet-stack/crc.mak b/bacnet-stack/crc.mak new file mode 100644 index 00000000..e5bb862f --- /dev/null +++ b/bacnet-stack/crc.mak @@ -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 + diff --git a/bacnet-stack/main.c b/bacnet-stack/main.c new file mode 100644 index 00000000..c54fdc5b --- /dev/null +++ b/bacnet-stack/main.c @@ -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 +#include +#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); + + } +} diff --git a/bacnet-stack/mstp.c b/bacnet-stack/mstp.c new file mode 100644 index 00000000..a1214073 --- /dev/null +++ b/bacnet-stack/mstp.c @@ -0,0 +1,1671 @@ +/*####COPYRIGHTBEGIN#### + ------------------------------------------- + Copyright (C) 2003 Steve Karg + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + The Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307 + USA. + + As a special exception, if other files instantiate templates or + use macros or inline functions from this file, or you compile + this file and link it with other works to produce a work based + on this file, this file does not by itself cause the resulting + work to be covered by the GNU General Public License. However + the source code for this file must still be made available in + accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work + based on this file might be covered by the GNU General Public + License. + ------------------------------------------- +####COPYRIGHTEND####*/ + +// This clause describes a Master-Slave/Token-Passing (MS/TP) data link +// protocol, which provides the same services to the network layer as +// ISO 8802-2 Logical Link Control. It uses services provided by the +// EIA-485 physical layer. Relevant clauses of EIA-485 are deemed to be +// included in this standard by reference. The following hardware is assumed: +// (a) A UART (Universal Asynchronous Receiver/Transmitter) capable of +// transmitting and receiving eight data bits with one stop bit +// and no parity. +// (b) An EIA-485 transceiver whose driver may be disabled. +// (c) A timer with a resolution of five milliseconds or less + +#include +#include +#include "mstp.h" +#include "bytes.h" +#include "crc.h" +#include "rs485.h" +#include "ringbuf.h" + +// MS/TP Frame Format +// All frames are of the following format: +// +// Preamble: two octet preamble: X`55', X`FF' +// Frame Type: one octet +// Destination Address: one octet address +// Source Address: one octet address +// Length: two octets, most significant octet first, of the Data field +// Header CRC: one octet +// Data: (present only if Length is non-zero) +// Data CRC: (present only if Length is non-zero) two octets, +// least significant octet first +// (pad): (optional) at most one octet of padding: X'FF' + + // The number of tokens received or used before a Poll For Master cycle +// is executed: 50. +const unsigned Npoll = 50; + +// The number of retries on sending Token: 1. +const unsigned Nretry_token = 1; + +// The minimum number of DataAvailable or ReceiveError events that must be +// seen by a receiving node in order to declare the line "active": 4. +const unsigned 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 unsigned Tframe_abort = 1 + ((1000 * 60) / 9600); + +// The maximum idle time a sending node may allow to elapse between octets +// of a frame the node is transmitting: 20 bit times. +const unsigned Tframe_gap = 20; + +// The time without a DataAvailable or ReceiveError event before declaration +// of loss of token: 500 milliseconds. +const unsigned Tno_token = 500; + +// The maximum time after the end of the stop bit of the final +// octet of a transmitted frame before a node must disable its +// EIA-485 driver: 15 bit times. +const unsigned Tpostdrive = 15; + +// The maximum time a node may wait after reception of a frame that expects +// a reply before sending the first octet of a reply or Reply Postponed +// frame: 250 milliseconds. +const unsigned Treply_delay = 225; + +// The minimum time without a DataAvailable or ReceiveError event +// that a node must wait for a station to begin replying to a +// confirmed request: 255 milliseconds. (Implementations may use +// larger values for this timeout, not to exceed 300 milliseconds.) +const unsigned Treply_timeout = 255; + +// Repeater turnoff delay. The duration of a continuous logical one state +// at the active input port of an MS/TP repeater after which the repeater +// will enter the IDLE state: 29 bit times < Troff < 40 bit times. +const unsigned Troff = 30; + +// The width of the time slot within which a node may generate a token: +// 10 milliseconds. +const unsigned Tslot = 10; + +// The maximum time a node may wait after reception of the token or +// a Poll For Master frame before sending the first octet of a frame: +// 15 milliseconds. +const unsigned Tusage_delay = 15; + +// The minimum time without a DataAvailable or ReceiveError event that a +// node must wait for a remote node to begin using a token or replying to +// a Poll For Master frame: 20 milliseconds. (Implementations may use +// larger values for this timeout, not to exceed 100 milliseconds.) +const unsigned Tusage_timeout = 20; + +// Millisecond Timer - called every millisecond +void MSTP_Millisecond_Timer(struct mstp_port_struct_t *mstp_port) +{ + if (mstp_port->SilenceTimer < 255) + mstp_port->SilenceTimer++; + if (mstp_port->ReplyPostponedTimer < 255) + mstp_port->ReplyPostponedTimer++; + + return; +} + +void MSTP_Receive_Frame_FSM(struct mstp_port_struct_t *mstp_port) +{ + switch (mstp_port->receive_state) + { + // In the IDLE state, the node waits for the beginning of a frame. + case MSTP_RECEIVE_STATE_IDLE: + // EatAnError + if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if (mstp_port->DataAvailable == TRUE) + { + // Preamble1 + if (mstp_port->DataRegister == 0x55) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // receive the remainder of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + // EatAnOctet + else + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + } + break; + // In the PREAMBLE state, the node waits for the second octet of the preamble. + case MSTP_RECEIVE_STATE_PREAMBLE: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // a correct preamble has not been received + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if (mstp_port->DataAvailable == TRUE) + { + // Preamble2 + if (mstp_port->DataRegister == 0xFF) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->Index = 0; + mstp_port->HeaderCRC = 0xFF; + // receive the remainder of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // ignore RepeatedPreamble1 + else if (mstp_port->DataRegister == 0x55) + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the second preamble octet. + mstp_port->receive_state = MSTP_RECEIVE_STATE_PREAMBLE; + } + // NotPreamble + else + { + mstp_port->DataAvailable = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + } + break; + // In the HEADER state, the node waits for the fixed message header. + case MSTP_RECEIVE_STATE_HEADER: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else if (mstp_port->DataAvailable == TRUE) + { + // FrameType + if (mstp_port->Index == 0) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->FrameType = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 1; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Destination + else if (mstp_port->Index == 1) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DestinationAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 2; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Source + else if (mstp_port->Index == 2) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->SourceAddress = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 3; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Length1 + else if (mstp_port->Index == 3) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength = mstp_port->DataRegister * 256; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 4; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // Length2 + else if (mstp_port->Index == 4) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataLength += mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index = 5; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER; + } + // HeaderCRC + else if (mstp_port->Index == 5) + { + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + mstp_port->HeaderCRC = CRC_Calc_Header( + mstp_port->DataRegister, + mstp_port->HeaderCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->receive_state = MSTP_RECEIVE_STATE_HEADER_CRC; + } + // not per MS/TP standard, but it is a case not covered + else + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + mstp_port->EventCount++; + // indicate that an error has occurred during + // the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of a frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + // In the HEADER_CRC state, the node validates the CRC on the fixed + // message header. + case MSTP_RECEIVE_STATE_HEADER_CRC: + // BadCRC + if (mstp_port->HeaderCRC != 0x55) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else + { + if ((mstp_port->DestinationAddress == mstp_port->This_Station) || + (mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) + { + // FrameTooLong + if (mstp_port->DataLength > INPUT_BUFFER_SIZE) + { + // indicate that a frame with an illegal or + // unacceptable data length has been received + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // NoData + else if (mstp_port->DataLength == 0) + { + // indicate that a frame with no data has been received + mstp_port->ReceivedValidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // Data + else + { + mstp_port->Index = 0; + mstp_port->DataCRC = 0xFFFF; + // receive the data portion of the frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + } + // NotForUs + else + { + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + } + break; + // In the DATA state, the node waits for the data portion of a frame. + case MSTP_RECEIVE_STATE_DATA: + // Timeout + if (mstp_port->SilenceTimer > Tframe_abort) + { + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // Error + else if (mstp_port->ReceiveError == TRUE) + { + mstp_port->ReceiveError = FALSE; + mstp_port->SilenceTimer = 0; + // indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + else if (mstp_port->DataAvailable == TRUE) + { + // DataOctet + if (mstp_port->Index < mstp_port->DataLength) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->InputBuffer[mstp_port->Index] = mstp_port->DataRegister; + mstp_port->DataAvailable = FALSE; + mstp_port->Index++; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + // CRC1 + else if (mstp_port->Index == mstp_port->DataLength) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->Index++; // Index now becomes the number of data octets + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA; + } + // CRC2 + else if (mstp_port->Index == (mstp_port->DataLength + 1)) + { + mstp_port->SilenceTimer = 0; + mstp_port->DataCRC = CRC_Calc_Data( + mstp_port->DataRegister, + mstp_port->DataCRC); + mstp_port->DataAvailable = FALSE; + mstp_port->receive_state = MSTP_RECEIVE_STATE_DATA_CRC; + } + } + break; + // In the DATA_CRC state, the node validates the CRC of the message data. + case MSTP_RECEIVE_STATE_DATA_CRC: + // GoodCRC + if (mstp_port->DataCRC == 0xF0B8) + { + // indicate the complete reception of a valid frame + mstp_port->ReceivedValidFrame = TRUE; + + // now might be a good time to process the message or + // copy the data to a buffer so that we can process the message + + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + // BadCRC + else + { + // to indicate that an error has occurred during the reception of a frame + mstp_port->ReceivedInvalidFrame = TRUE; + // wait for the start of the next frame. + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + } + break; + default: + // shouldn't get here - but if we do... + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + break; + } + + return; +} + +void MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port) +{ + + switch (mstp_port->master_state) + { + case MSTP_MASTER_STATE_INITIALIZE: + // DoneInitializing + mstp_port->This_Station = 0; // FIXME: the node's station address + // indicate that the next station is unknown + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->Poll_Station = mstp_port->This_Station; + // cause a Poll For Master to be sent when this node first + // receives the token + mstp_port->TokenCount = Npoll; + mstp_port->SoleMaster = FALSE; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + // In the IDLE state, the node waits for a frame. + case MSTP_MASTER_STATE_IDLE: + // LostToken + if (mstp_port->SilenceTimer >= Tno_token) + { + // assume that the token has been lost + mstp_port->master_state = MSTP_MASTER_STATE_NO_TOKEN; + } + // mstp_port->ReceivedInvalidFrame + else if (mstp_port->ReceivedInvalidFrame == TRUE) + { + // invalid frame was received + mstp_port->ReceivedInvalidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedUnwantedFrame + else if (mstp_port->ReceivedValidFrame == TRUE) + { + if ((mstp_port->DestinationAddress != mstp_port->This_Station) || + (mstp_port->DestinationAddress != MSTP_BROADCAST_ADDRESS)) + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // DestinationAddress is equal to 255 (broadcast) and + // FrameType has a value of Token, BACnet Data Expecting Reply, Test_Request, + // or a proprietary type known to this node that expects a reply + // (such frames may not be broadcast), or + else if ((mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS) && + ((mstp_port->FrameType == FRAME_TYPE_TOKEN) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) || + (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // FrameType has a value that indicates a standard or proprietary type + // that is not known to this node. + // FIXME: change this if you add a proprietary type + else if /*(*/(mstp_port->FrameType >= FRAME_TYPE_PROPRIETARY_MIN) /*&&*/ + /*(FrameType <= FRAME_TYPE_PROPRIETARY_MAX))*/ + /* unnecessary if FrameType is uint8_t with max of 255 */ + { + // an unexpected or unwanted frame was received. + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedToken + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_TOKEN)) + { + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->FrameCount = 0; + mstp_port->SoleMaster = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // ReceivedPFM + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_POLL_FOR_MASTER)) + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, + mstp_port->SourceAddress, + mstp_port->This_Station, + NULL,0); + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedDataNoReply + // or a proprietary type known to this node that does not expect a reply + else if (((mstp_port->DestinationAddress == mstp_port->This_Station) || + (mstp_port->DestinationAddress == MSTP_BROADCAST_ADDRESS)) && + ((mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY) || + // (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE))) + { + // FIXME: indicate successful reception to the higher layers + // i.e. Process this frame! + mstp_port->ReceivedValidFrame = FALSE; + // wait for the next frame + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedDataNeedingReply + // or a proprietary type known to this node that expects a reply + else if ((mstp_port->DestinationAddress == mstp_port->This_Station) && + ((mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_EXPECTING_REPLY) || + // (mstp_port->FrameType == FRAME_TYPE_PROPRIETARY) || + (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST))) + { + mstp_port->ReplyPostponedTimer = 0; + // indicate successful reception to the higher layers + // (management entity in the case of Test_Request); + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_ANSWER_DATA_REQUEST; + } + } + break; + // In the USE_TOKEN state, the node is allowed to send one or + // more data frames. These may be BACnet Data frames or + // proprietary frames. + case MSTP_MASTER_STATE_USE_TOKEN: + // NothingToSend + // FIXME: If there is no data frame awaiting transmission, + { + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // SendNoWait + // FIXME: If there is a frame awaiting transmission that + // is of type Test_Response, BACnet Data Not Expecting Reply, + // or a proprietary type that does not expect a reply, +// { +// // transmit the data frame +// RS485_Send_Frame(?????????????); +// FrameCount++; +// mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; +// } + // SendAndWait + // FIXME: If there is a frame awaiting transmission that is of + // type Test_Request, BACnet Data Expecting Reply, or + // a proprietary type that expects a reply, +// { +// // transmit the data frame +// RS485_Send_Frame(); +// FrameCount++; +// mstp_port->master_state = MSTP_MASTER_STATE_WAIT_FOR_REPLY; +// } + // In the WAIT_FOR_REPLY state, the node waits for + // a reply from another node. + case MSTP_MASTER_STATE_WAIT_FOR_REPLY: + // ReplyTimeout + if (mstp_port->SilenceTimer >= Treply_timeout) + { + // assume that the request has failed + mstp_port->FrameCount = mstp_port->Nmax_info_frames; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + // Any retry of the data frame shall await the next entry + // to the USE_TOKEN state. (Because of the length of the timeout, + // this transition will cause the token to be passed regardless + // of the initial value of FrameCount.) + } + // InvalidFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedInvalidFrame == TRUE)) + { + // error in frame reception + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedReply + // or a proprietary type that indicates a reply + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + ((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) || + //(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) + { + // FIXME: indicate successful reception to the higher layers + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedPostpone + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_REPLY_POSTPONED)) + { + // FIXME: then the reply to the message has been postponed until a later time. + // So, what does this really mean? + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_DONE_WITH_TOKEN; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress != mstp_port->This_Station)) + //the expected reply should not be broadcast) + { + // an unexpected frame was received + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // Synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->SilenceTimer < Treply_timeout) && + (mstp_port->ReceivedValidFrame == TRUE) && + ((mstp_port->FrameType == FRAME_TYPE_TEST_RESPONSE) || + //(mstp_port->FrameType == FRAME_TYPE_PROPRIETARY_0) || + (mstp_port->FrameType == FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY))) + { + // An unexpected frame was received. + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // Synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + break; + // The DONE_WITH_TOKEN state either sends another data frame, + // passes the token, or initiates a Poll For Master cycle. + case MSTP_MASTER_STATE_DONE_WITH_TOKEN: + // SendAnotherFrame + if (mstp_port->FrameCount < mstp_port->Nmax_info_frames) + { + // then this node may send another information frame + // before passing the token. + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // mstp_port->SoleMaster + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount < Npoll) && + (mstp_port->SoleMaster == TRUE)) + { + // there are no other known master nodes to + // which the token may be sent (true master-slave operation). + mstp_port->FrameCount = 0; + mstp_port->TokenCount++; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // SendToken + else if (((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount < Npoll) && + (mstp_port->SoleMaster == FALSE)) || + // The comparison of NS and TS+1 eliminates the Poll For Master + // if there are no addresses between TS and NS, since there is no + // address at which a new master node may be found in that case. + (mstp_port->Next_Station == + (uint8_t)((mstp_port->This_Station +1) % (mstp_port->Nmax_master + 1)))) + { + mstp_port->TokenCount++; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SendMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) != mstp_port->Next_Station)) + { + mstp_port->Poll_Station = (mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1); + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + // ResetMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) == mstp_port->Next_Station) && + (mstp_port->SoleMaster == FALSE)) + { + mstp_port->Poll_Station = mstp_port->This_Station; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SoleMasterRestartMaintenancePFM + else if ((mstp_port->FrameCount >= mstp_port->Nmax_info_frames) && + (mstp_port->TokenCount >= Npoll) && + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) == mstp_port->Next_Station) && + (mstp_port->SoleMaster == TRUE)) + { + mstp_port->Poll_Station = (mstp_port->Next_Station +1) % (mstp_port->Nmax_master + 1); + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // no known successor node + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // find a new successor to TS + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + // The PASS_TOKEN state listens for a successor to begin using + // the token that this node has just attempted to pass. + case MSTP_MASTER_STATE_PASS_TOKEN: + // SawTokenUser + if ((mstp_port->SilenceTimer < Tusage_timeout) && + (mstp_port->EventCount > Nmin_octets)) + { + // Assume that a frame has been sent by the new token user. + // Enter the IDLE state to process the frame. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // RetrySendToken + else if ((mstp_port->SilenceTimer >= Tusage_timeout) && + (mstp_port->RetryCount < Nretry_token)) + { + mstp_port->RetryCount++; + // Transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->EventCount = 0; + // re-enter the current state to listen for NS + // to begin using the token. + } + // FindNewSuccessor + else if ((mstp_port->SilenceTimer >= Tusage_timeout) && + (mstp_port->RetryCount >= Nretry_token)) + { + // Assume that NS has failed. + mstp_port->Poll_Station = (mstp_port->Next_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // no known successor node + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // find a new successor to TS + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + // The NO_TOKEN state is entered if mstp_port->SilenceTimer becomes greater + // than Tno_token, indicating that there has been no network activity + // for that period of time. The timeout is continued to determine + // whether or not this node may create a token. + case MSTP_MASTER_STATE_NO_TOKEN: + // SawFrame + if ((mstp_port->SilenceTimer < (Tno_token + (Tslot * mstp_port->This_Station))) && + (mstp_port->EventCount > Nmin_octets)) + { + // Some other node exists at a lower address. + // Enter the IDLE state to receive and process the incoming frame. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // GenerateToken + else if ((mstp_port->SilenceTimer >= (Tno_token + (Tslot * mstp_port->This_Station))) && + (mstp_port->SilenceTimer < (Tno_token + (Tslot * (mstp_port->This_Station + 1))))) + { + // Assume that this node is the lowest numerical address + // on the network and is empowered to create a token. + mstp_port->Poll_Station = (mstp_port->This_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + // indicate that the next station is unknown + mstp_port->Next_Station = mstp_port->This_Station; + mstp_port->RetryCount = 0; + mstp_port->TokenCount = 0; + mstp_port->EventCount = 0; + // enter the POLL_FOR_MASTER state to find a new successor to TS. + mstp_port->master_state = MSTP_MASTER_STATE_POLL_FOR_MASTER; + } + break; + // In the POLL_FOR_MASTER state, the node listens for a reply to + // a previously sent Poll For Master frame in order to find + // a successor node. + case MSTP_MASTER_STATE_POLL_FOR_MASTER: + // ReceivedReplyToPFM + if ((mstp_port->ReceivedValidFrame == TRUE) && + (mstp_port->DestinationAddress == mstp_port->This_Station) && + (mstp_port->FrameType == FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER)) + { + mstp_port->SoleMaster = FALSE; + mstp_port->Next_Station = mstp_port->SourceAddress; + mstp_port->EventCount = 0; + // Transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->Poll_Station = mstp_port->This_Station; + mstp_port->TokenCount = 0; + mstp_port->RetryCount = 0; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // ReceivedUnexpectedFrame + else if ((mstp_port->ReceivedValidFrame == TRUE) && + ((mstp_port->DestinationAddress != mstp_port->This_Station) || + (mstp_port->FrameType != FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER))) + { + // An unexpected frame was received. + // This may indicate the presence of multiple tokens. + mstp_port->ReceivedValidFrame = FALSE; + // enter the IDLE state to synchronize with the network. + // This action drops the token. + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + // mstp_port->SoleMaster + else if ((mstp_port->SoleMaster == TRUE) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // There was no valid reply to the periodic poll + // by the sole known master for other masters. + mstp_port->FrameCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + // DoneWithPFM + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station != mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // There was no valid reply to the maintenance + // poll for a master at address PS. + mstp_port->EventCount = 0; + // transmit a Token frame to NS + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TOKEN, + mstp_port->Next_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_PASS_TOKEN; + } + // SendNextPFM + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station == mstp_port->This_Station) && // no known successor node + ((uint8_t)((mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1)) != mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + mstp_port->Poll_Station = + (mstp_port->Poll_Station + 1) % (mstp_port->Nmax_master + 1); + // Transmit a Poll For Master frame to PS. + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_POLL_FOR_MASTER, + mstp_port->Poll_Station, + mstp_port->This_Station, + NULL,0); + mstp_port->RetryCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + // Re-enter the current state. + } + // DeclareSoleMaster + else if ((mstp_port->SoleMaster == FALSE) && + (mstp_port->Next_Station == mstp_port->This_Station) && // no known successor node + ((uint8_t)((mstp_port->Poll_Station + 1) % + (mstp_port->Nmax_master + 1)) == mstp_port->This_Station) && + ((mstp_port->SilenceTimer >= Tusage_timeout) || + (mstp_port->ReceivedInvalidFrame == TRUE))) + { + // to indicate that this station is the only master + mstp_port->SoleMaster = TRUE; + mstp_port->FrameCount = 0; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->master_state = MSTP_MASTER_STATE_USE_TOKEN; + } + break; + // The ANSWER_DATA_REQUEST state is entered when a + // BACnet Data Expecting Reply, a Test_Request, or + // a proprietary frame that expects a reply is received. + case MSTP_MASTER_STATE_ANSWER_DATA_REQUEST: + if (mstp_port->ReplyPostponedTimer <= Treply_delay) + { + // Reply + // If a reply is available from the higher layers + // within Treply_delay after the reception of the + // final octet of the requesting frame + // (the mechanism used to determine this is a local matter), + // then call RS485_Send_Frame to transmit the reply frame + // and enter the IDLE state to wait for the next frame. + + // Test Request + // If a receiving node can successfully receive and return + // the information field, it shall do so. If it cannot receive + // and return the entire information field but can detect + // the reception of a valid Test_Request frame + // (for example, by computing the CRC on octets as + // they are received), then the receiving node shall discard + // the information field and return a Test_Response containing + // no information field. If the receiving node cannot detect + // the valid reception of frames with overlength information fields, + // then no response shall be returned. + if (mstp_port->FrameType == FRAME_TYPE_TEST_REQUEST) + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_TEST_RESPONSE, + mstp_port->SourceAddress, + mstp_port->This_Station, + mstp_port->InputBuffer, + mstp_port->Index); + } + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + + // + // DeferredReply + // If no reply will be available from the higher layers + // within Treply_delay after the reception of the + // final octet of the requesting frame (the mechanism + // used to determine this is a local matter), + // then an immediate reply is not possible. + // Any reply shall wait until this node receives the token. + // Call RS485_Send_Frame to transmit a Reply Postponed frame, + // and enter the IDLE state. + + else + { + RS485_Send_Frame( + mstp_port, + FRAME_TYPE_REPLY_POSTPONED, + mstp_port->SourceAddress, + mstp_port->This_Station, + NULL,0); + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + } + break; + default: + mstp_port->master_state = MSTP_MASTER_STATE_IDLE; + break; + } + + return; +} + +void MSTP_Init( + struct mstp_port_struct_t *mstp_port, + uint8_t this_station_mac) +{ + int i; //loop counter + + if (mstp_port) + { + mstp_port->receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port->master_state = MSTP_MASTER_STATE_INITIALIZE; + mstp_port->ReceiveError = FALSE; + mstp_port->DataAvailable = FALSE; + mstp_port->DataRegister = 0; + mstp_port->DataCRC = 0; + mstp_port->DataCRC = 0; + mstp_port->DataLength = 0; + mstp_port->DestinationAddress = 0; + mstp_port->EventCount = 0; + mstp_port->FrameType = FRAME_TYPE_TOKEN; + mstp_port->FrameCount = 0; + mstp_port->HeaderCRC = 0; + mstp_port->Index = 0; + mstp_port->Index = 0; + for (i = 0; i < sizeof(mstp_port->InputBuffer); i++) + { + mstp_port->InputBuffer[i] = 0; + } + mstp_port->Next_Station = this_station_mac; + mstp_port->Poll_Station = this_station_mac; + mstp_port->ReceivedInvalidFrame = FALSE; + mstp_port->ReceivedValidFrame = FALSE; + mstp_port->RetryCount = 0; + mstp_port->SilenceTimer = 0; + mstp_port->ReplyPostponedTimer = 0; + mstp_port->SoleMaster = FALSE; + mstp_port->SourceAddress = 0; + mstp_port->TokenCount = 0; + mstp_port->This_Station = this_station_mac; + mstp_port->Nmax_info_frames = DEFAULT_MAX_INFO_FRAMES; + mstp_port->Nmax_master = DEFAULT_MAX_MASTER; + } +} + +unsigned MSTP_Create_Frame( + uint8_t *buffer, // where frame is loaded + unsigned buffer_len, // amount of space available + uint8_t frame_type, // type of frame to send - see defines + uint8_t destination, // destination address + uint8_t source, // source address + uint8_t *data, // any data to be sent - may be null + unsigned data_len) // number of bytes of data (up to 501) +{ + uint8_t crc8 = 0xFF; // used to calculate the crc value + uint16_t crc16 = 0xFFFF; // used to calculate the crc value + unsigned index = 0; // used to load the data portion of the frame + + // not enough to do a header + if (buffer_len < 8) + return 0; + + buffer[0] = 0x55; + buffer[1] = 0xFF; + buffer[2] = frame_type; + crc8 = CRC_Calc_Header(buffer[2],crc8); + buffer[3] = destination; + crc8 = CRC_Calc_Header(buffer[3],crc8); + buffer[4] = source; + crc8 = CRC_Calc_Header(buffer[4],crc8); + buffer[5] = data_len / 256; + crc8 = CRC_Calc_Header(buffer[5],crc8); + buffer[6] = data_len % 256; + crc8 = CRC_Calc_Header(buffer[6],crc8); + buffer[7] = ~crc8; + + index = 8; + while (data_len && data && (index < buffer_len)) + { + buffer[index] = *data; + crc16 = CRC_Calc_Data(buffer[index],crc16); + data++; + index++; + data_len--; + } + // append the data CRC if necessary + if (index > 8) + { + if ((index + 2) <= buffer_len) + { + crc16 = ~crc16; + buffer[index] = LO_BYTE(crc16); + index++; + buffer[index] = HI_BYTE(crc16); + index++; + } + else + return 0; + } + + return index; // returns the frame length +} + + +#ifdef TEST +#include +#include +#include "ctest.h" + +// test stub functions +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)mstp_port; + (void)frame_type; + (void)destination; + (void)source; + (void)data; + (void)data_len; +} + +#define RING_BUFFER_DATA_SIZE 1 +#define RING_BUFFER_SIZE INPUT_BUFFER_SIZE +static RING_BUFFER Test_Buffer; +static uint8_t Test_Buffer_Data[RING_BUFFER_DATA_SIZE * RING_BUFFER_SIZE]; +static void Load_Input_Buffer(uint8_t *buffer,size_t len) +{ + static bool initialized = FALSE; // tracks our init + + + if (!initialized) + { + initialized = TRUE; + Ringbuf_Init( + &Test_Buffer, + (char *)Test_Buffer_Data, + RING_BUFFER_DATA_SIZE, + RING_BUFFER_SIZE); + } + + // empty any the existing data + while (!Ringbuf_Empty(&Test_Buffer)) + { + (void)Ringbuf_Pop_Front(&Test_Buffer); + } + + if (buffer) + { + while (len) + { + (void)Ringbuf_Put(&Test_Buffer,(char *)buffer); + len--; + buffer++; + } + } +} + +void RS485_Check_UART_Data( + struct mstp_port_struct_t *mstp_port) // port specific data +{ + char *data; + if (!Ringbuf_Empty(&Test_Buffer) && mstp_port && + (mstp_port->DataAvailable == FALSE)) + { + data = Ringbuf_Pop_Front(&Test_Buffer); + if (data) + { + mstp_port->DataRegister = *data; + mstp_port->DataAvailable = TRUE; + } + } +} + +void testReceiveNodeFSM(Test* pTest) +{ + struct mstp_port_struct_t mstp_port; // port data + unsigned EventCount = 0; // local counter + uint8_t my_mac = 0x05; // local MAC address + uint8_t HeaderCRC = 0; // for local CRC calculation + uint8_t FrameType = 0; // type of packet that was sent + unsigned len; // used for the size of the message packet + size_t i; // used to loop through the message bytes + uint8_t buffer[INPUT_BUFFER_SIZE] = {0}; + uint8_t data[INPUT_BUFFER_SIZE - 8 /*header*/ - 2 /*CRC*/] = {0}; + + MSTP_Init(&mstp_port,my_mac); + + // check the receive error during idle + mstp_port.receive_state = MSTP_RECEIVE_STATE_IDLE; + mstp_port.ReceiveError = TRUE; + mstp_port.SilenceTimer = 255; + mstp_port.EventCount = 0; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for bad packet header + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x11; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header, but timeout + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // force the timeout + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble, but receive error + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // force the error + mstp_port.ReceiveError = TRUE; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble1, but bad preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // no change of state if no data yet + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // repeated preamble1 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // repeated preamble1 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + // bad data + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x11; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble, but timeout in packet + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // force the timeout + mstp_port.SilenceTimer = Tframe_abort + 1; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + + // check for good packet header preamble, but error in packet + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // force the error + mstp_port.ReceiveError = TRUE; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceiveError == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // check for good packet header preamble + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x55; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_PREAMBLE); + MSTP_Receive_Frame_FSM(&mstp_port); + // preamble2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0xFF; + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 0); + ct_test(pTest,mstp_port.HeaderCRC == 0xFF); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // no change of state if no data yet + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + // Data is received - index is incremented + // FrameType + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = FRAME_TYPE_TOKEN; + HeaderCRC = 0xFF; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 1); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,FrameType == FRAME_TYPE_TOKEN); + // Destination + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0x10; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 2); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DestinationAddress == 0x10); + // Source + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = my_mac; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 3); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.SourceAddress == my_mac); + // Length1 = length*256 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 4); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DataLength == 0); + // Length2 + mstp_port.DataAvailable = TRUE; + mstp_port.DataRegister = 0; + HeaderCRC = CRC_Calc_Header(mstp_port.DataRegister,HeaderCRC); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 5); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER); + ct_test(pTest,mstp_port.DataLength == 0); + // HeaderCRC + mstp_port.DataAvailable = TRUE; + ct_test(pTest,HeaderCRC == 0x73); // per Annex G example + mstp_port.DataRegister = ~HeaderCRC; // one's compliment of CRC is sent + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + ct_test(pTest,mstp_port.Index == 5); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + ct_test(pTest,mstp_port.HeaderCRC == 0x55); + // NotForUs + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // BadCRC in header check + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + 0x10, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + // make the header CRC bad + buffer[7] = 0x00; + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + ct_test(pTest,mstp_port.ReceivedValidFrame == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // NoData for us + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + my_mac, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == FALSE); + ct_test(pTest,mstp_port.ReceivedValidFrame == TRUE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // FrameTooLong + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_TOKEN, + my_mac, // destination + my_mac, // source + NULL, // data + 0); // data size + ct_test(pTest,len > 0); + // make the header data length bad + buffer[5] = 0x02; + Load_Input_Buffer(buffer,len); + for (i = 0; i < len; i++) + { + RS485_Check_UART_Data(&mstp_port); + EventCount++; + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.DataAvailable == FALSE); + ct_test(pTest,mstp_port.SilenceTimer == 0); + ct_test(pTest,mstp_port.EventCount == EventCount); + } + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_HEADER_CRC); + MSTP_Receive_Frame_FSM(&mstp_port); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == TRUE); + ct_test(pTest,mstp_port.ReceivedValidFrame == FALSE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + // Data + mstp_port.ReceivedInvalidFrame = FALSE; + mstp_port.ReceivedValidFrame = FALSE; + memset(data,0,sizeof(data)); + len = MSTP_Create_Frame( + buffer, + sizeof(buffer), + FRAME_TYPE_PROPRIETARY_MIN, + my_mac, // destination + my_mac, // source + data, // data + sizeof(data)); // data size + ct_test(pTest,len > 0); + Load_Input_Buffer(buffer,len); + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + while (mstp_port.receive_state != MSTP_RECEIVE_STATE_IDLE) + { + RS485_Check_UART_Data(&mstp_port); + MSTP_Receive_Frame_FSM(&mstp_port); + } + ct_test(pTest,mstp_port.DataLength == sizeof(data)); + ct_test(pTest,mstp_port.ReceivedInvalidFrame == FALSE); + ct_test(pTest,mstp_port.ReceivedValidFrame == TRUE); + ct_test(pTest,mstp_port.receive_state == MSTP_RECEIVE_STATE_IDLE); + + return; +} + +void testMasterNodeFSM(Test* pTest) +{ + struct mstp_port_struct_t mstp_port; // port data + uint8_t my_mac = 0x05; // local MAC address + + MSTP_Init(&mstp_port,my_mac); + ct_test(pTest,mstp_port.master_state == MSTP_MASTER_STATE_INITIALIZE); + +} + +#endif + +#ifdef TEST_MSTP +int main(void) +{ + Test *pTest; + bool rc; + + pTest = ct_create("mstp", NULL); + + /* individual tests */ + rc = ct_addTestFunction(pTest, testReceiveNodeFSM); + assert(rc); + rc = ct_addTestFunction(pTest, testMasterNodeFSM); + assert(rc); + + ct_setStream(pTest, stdout); + ct_run(pTest); + (void)ct_report(pTest); + + ct_destroy(pTest); + + return 0; +} +#endif diff --git a/bacnet-stack/mstp.h b/bacnet-stack/mstp.h new file mode 100644 index 00000000..6ec810c3 --- /dev/null +++ b/bacnet-stack/mstp.h @@ -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 +#include +#include + +// 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 diff --git a/bacnet-stack/mstp.ide b/bacnet-stack/mstp.ide new file mode 100644 index 0000000000000000000000000000000000000000..986ae620e955c969ec744a59789437d9b6f90257 GIT binary patch literal 32618 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 Mz1d-~x{xye2e+6(n*aa+ literal 0 HcmV?d00001 diff --git a/bacnet-stack/mstp.mak b/bacnet-stack/mstp.mak new file mode 100644 index 00000000..d93124de --- /dev/null +++ b/bacnet-stack/mstp.mak @@ -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 + diff --git a/bacnet-stack/ports/.svn/README.txt b/bacnet-stack/ports/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/ports/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/ports/.svn/empty-file b/bacnet-stack/ports/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/ports/.svn/entries b/bacnet-stack/ports/.svn/entries new file mode 100644 index 00000000..c9a3bd67 --- /dev/null +++ b/bacnet-stack/ports/.svn/entries @@ -0,0 +1,21 @@ + + + + + + + diff --git a/bacnet-stack/ports/.svn/format b/bacnet-stack/ports/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/ports/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/ports/linux/.svn/README.txt b/bacnet-stack/ports/linux/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/ports/linux/.svn/empty-file b/bacnet-stack/ports/linux/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/ports/linux/.svn/entries b/bacnet-stack/ports/linux/.svn/entries new file mode 100644 index 00000000..ac53629f --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/entries @@ -0,0 +1,28 @@ + + + + + + diff --git a/bacnet-stack/ports/linux/.svn/format b/bacnet-stack/ports/linux/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/ports/linux/.svn/prop-base/readme.txt.svn-base b/bacnet-stack/ports/linux/.svn/prop-base/readme.txt.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/prop-base/readme.txt.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/linux/.svn/prop-base/rs485.c.svn-base b/bacnet-stack/ports/linux/.svn/prop-base/rs485.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/prop-base/rs485.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/linux/.svn/props/readme.txt.svn-work b/bacnet-stack/ports/linux/.svn/props/readme.txt.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/props/readme.txt.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/linux/.svn/props/rs485.c.svn-work b/bacnet-stack/ports/linux/.svn/props/rs485.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/props/rs485.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/linux/.svn/text-base/readme.txt.svn-base b/bacnet-stack/ports/linux/.svn/text-base/readme.txt.svn-base new file mode 100644 index 00000000..c24be5af --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/text-base/readme.txt.svn-base @@ -0,0 +1,2 @@ +This is a port to Linux for testing. +The unit tests can be run via the test.sh script. \ No newline at end of file diff --git a/bacnet-stack/ports/linux/.svn/text-base/rs485.c.svn-base b/bacnet-stack/ports/linux/.svn/text-base/rs485.c.svn-base new file mode 100644 index 00000000..710828f2 --- /dev/null +++ b/bacnet-stack/ports/linux/.svn/text-base/rs485.c.svn-base @@ -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 +#include +#include +#include + +#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; + } +} + diff --git a/bacnet-stack/ports/linux/readme.txt b/bacnet-stack/ports/linux/readme.txt new file mode 100644 index 00000000..c24be5af --- /dev/null +++ b/bacnet-stack/ports/linux/readme.txt @@ -0,0 +1,2 @@ +This is a port to Linux for testing. +The unit tests can be run via the test.sh script. \ No newline at end of file diff --git a/bacnet-stack/ports/linux/rs485.c b/bacnet-stack/ports/linux/rs485.c new file mode 100644 index 00000000..710828f2 --- /dev/null +++ b/bacnet-stack/ports/linux/rs485.c @@ -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 +#include +#include +#include + +#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; + } +} + diff --git a/bacnet-stack/ports/pic18/.svn/README.txt b/bacnet-stack/ports/pic18/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/ports/pic18/.svn/empty-file b/bacnet-stack/ports/pic18/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/ports/pic18/.svn/entries b/bacnet-stack/ports/pic18/.svn/entries new file mode 100644 index 00000000..bfcc4103 --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/entries @@ -0,0 +1,19 @@ + + + + + diff --git a/bacnet-stack/ports/pic18/.svn/format b/bacnet-stack/ports/pic18/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/ports/pic18/.svn/prop-base/rs485.c.svn-base b/bacnet-stack/ports/pic18/.svn/prop-base/rs485.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/prop-base/rs485.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/pic18/.svn/props/rs485.c.svn-work b/bacnet-stack/ports/pic18/.svn/props/rs485.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/props/rs485.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/ports/pic18/.svn/text-base/rs485.c.svn-base b/bacnet-stack/ports/pic18/.svn/text-base/rs485.c.svn-base new file mode 100644 index 00000000..f5ae17d1 --- /dev/null +++ b/bacnet-stack/ports/pic18/.svn/text-base/rs485.c.svn-base @@ -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 +#include +#include + +#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; + } +} + diff --git a/bacnet-stack/ports/pic18/rs485.c b/bacnet-stack/ports/pic18/rs485.c new file mode 100644 index 00000000..f5ae17d1 --- /dev/null +++ b/bacnet-stack/ports/pic18/rs485.c @@ -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 +#include +#include + +#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; + } +} + diff --git a/bacnet-stack/ports/rtos32/.svn/README.txt b/bacnet-stack/ports/rtos32/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/ports/rtos32/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/ports/rtos32/.svn/empty-file b/bacnet-stack/ports/rtos32/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/ports/rtos32/.svn/entries b/bacnet-stack/ports/rtos32/.svn/entries new file mode 100644 index 00000000..dc828c7b --- /dev/null +++ b/bacnet-stack/ports/rtos32/.svn/entries @@ -0,0 +1,12 @@ + + + + diff --git a/bacnet-stack/ports/rtos32/.svn/format b/bacnet-stack/ports/rtos32/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/ports/rtos32/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/ringbuf.c b/bacnet-stack/ringbuf.c new file mode 100644 index 00000000..ea3745b4 --- /dev/null +++ b/bacnet-stack/ringbuf.c @@ -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 +#include + +#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 + diff --git a/bacnet-stack/ringbuf.h b/bacnet-stack/ringbuf.h new file mode 100644 index 00000000..68b9ae34 --- /dev/null +++ b/bacnet-stack/ringbuf.h @@ -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 diff --git a/bacnet-stack/ringbuf.mak b/bacnet-stack/ringbuf.mak new file mode 100644 index 00000000..26c685c4 --- /dev/null +++ b/bacnet-stack/ringbuf.mak @@ -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 + diff --git a/bacnet-stack/rs485.h b/bacnet-stack/rs485.h new file mode 100644 index 00000000..59b0c55f --- /dev/null +++ b/bacnet-stack/rs485.h @@ -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 +#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 diff --git a/bacnet-stack/stdbool.h b/bacnet-stack/stdbool.h new file mode 100644 index 00000000..29b9a5e4 --- /dev/null +++ b/bacnet-stack/stdbool.h @@ -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 diff --git a/bacnet-stack/stdint.h b/bacnet-stack/stdint.h new file mode 100644 index 00000000..b66446d4 --- /dev/null +++ b/bacnet-stack/stdint.h @@ -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 + +#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 diff --git a/bacnet-stack/test.sh b/bacnet-stack/test.sh new file mode 100755 index 00000000..4e7739f1 --- /dev/null +++ b/bacnet-stack/test.sh @@ -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 + + diff --git a/bacnet-stack/test/.svn/README.txt b/bacnet-stack/test/.svn/README.txt new file mode 100644 index 00000000..271a8ce9 --- /dev/null +++ b/bacnet-stack/test/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/bacnet-stack/test/.svn/empty-file b/bacnet-stack/test/.svn/empty-file new file mode 100644 index 00000000..e69de29b diff --git a/bacnet-stack/test/.svn/entries b/bacnet-stack/test/.svn/entries new file mode 100644 index 00000000..4f4cef45 --- /dev/null +++ b/bacnet-stack/test/.svn/entries @@ -0,0 +1,28 @@ + + + + + + diff --git a/bacnet-stack/test/.svn/format b/bacnet-stack/test/.svn/format new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/bacnet-stack/test/.svn/format @@ -0,0 +1 @@ +4 diff --git a/bacnet-stack/test/.svn/prop-base/ctest.c.svn-base b/bacnet-stack/test/.svn/prop-base/ctest.c.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/test/.svn/prop-base/ctest.c.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/test/.svn/prop-base/ctest.h.svn-base b/bacnet-stack/test/.svn/prop-base/ctest.h.svn-base new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/test/.svn/prop-base/ctest.h.svn-base @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/test/.svn/props/ctest.c.svn-work b/bacnet-stack/test/.svn/props/ctest.c.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/test/.svn/props/ctest.c.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/test/.svn/props/ctest.h.svn-work b/bacnet-stack/test/.svn/props/ctest.h.svn-work new file mode 100644 index 00000000..dce2c1d5 --- /dev/null +++ b/bacnet-stack/test/.svn/props/ctest.h.svn-work @@ -0,0 +1 @@ +END diff --git a/bacnet-stack/test/.svn/text-base/ctest.c.svn-base b/bacnet-stack/test/.svn/text-base/ctest.c.svn-base new file mode 100644 index 00000000..e31e867e --- /dev/null +++ b/bacnet-stack/test/.svn/text-base/ctest.c.svn-base @@ -0,0 +1,182 @@ +/* ctest.c: Implements the CTest Framework */ + +#include "ctest.h" +#include +#include +#include +#include + +/* Number of tests to hold incrementally */ +enum {CHUNK = 10}; + +Test* ct_create(const char* name, void (*init)(Test*)) +{ + int backOutLevel = 0; + Test* pTest = malloc(sizeof(Test)); + if (pTest) + { + pTest->nPass = pTest->nFail = pTest->nTests = 0; + pTest->pStream = stdout; + + /* Allocate array of fptrs: */ + assert(CHUNK); + pTest->pTestFuns = calloc(CHUNK, sizeof(TestFunc)); + if (pTest->pTestFuns) + { + pTest->maxTests = CHUNK; + /* Allocate test name: */ + assert(name); + pTest->name = malloc(strlen(name) + 1); + if (pTest->name) + strcpy(pTest->name, name); + else + ++backOutLevel; + } + else + ++backOutLevel; + } + + /* Back-out allocations if memory failed: */ + if (backOutLevel) + { + switch(backOutLevel) + { + case 2: + free(pTest->pTestFuns); + pTest->pTestFuns = NULL; + case 1: + free(pTest); + pTest = NULL; + } + } + else if (init) + { + assert(pTest); + init(pTest); + } + return pTest; +} + +void ct_destroy(Test* pTest) +{ + assert(pTest); + assert(pTest->pTestFuns); + free(pTest->pTestFuns); + pTest->pTestFuns = NULL; + assert(pTest->name); + free(pTest->name); + pTest->name = NULL; + free(pTest); +} + +bool ct_addTestFunction(Test* pTest, TestFunc tfun) +{ + assert(pTest); + assert(pTest->pTestFuns); + if (pTest->nTests == pTest->maxTests) + { + size_t newSize = pTest->nTests + CHUNK; + TestFunc* new_pTestFuns = + realloc(pTest->pTestFuns, + newSize * sizeof(TestFunc)); + if (!new_pTestFuns) + return FALSE; + pTest->pTestFuns = new_pTestFuns; + pTest->maxTests += CHUNK; + } + assert(pTest->nTests < pTest->maxTests); + pTest->pTestFuns[pTest->nTests++] = tfun; + return TRUE; +} + +void ct_setStream(Test* pTest, FILE* pStream) +{ + pTest->pStream = pStream; +} + +FILE* ct_getStream(Test* pTest) +{ + return pTest->pStream; +} + +long ct_report(Test* pTest) +{ + assert(pTest); + if (pTest->pStream) + { + fprintf(pTest->pStream, + "Test \"%s\":\n\tPassed: %ld\n\tFailed: %ld\n", + pTest->name, pTest->nPass, pTest->nFail); + } + return pTest->nFail; +} + + +void ct_succeed(Test* pTest) +{ + assert(pTest); + ++pTest->nPass; +} + +void ct_do_test(Test* pTest, const char* str, + bool cond, const char* file, long line) +{ + assert(pTest); + if (!cond) + ct_do_fail(pTest, str, file, line); + else + ct_succeed(pTest); +} + +void ct_do_fail(Test* pTest, const char* str, + const char* file, long line) +{ + assert(pTest); + ++pTest->nFail; + if (pTest->pStream) + { + fprintf(pTest->pStream, + "%s failure: (%s), %s (line %ld)\n", + pTest->name, str, file, line); + } +} + +long ct_getNumPassed(Test* pTest) +{ + assert(pTest); + return pTest->nPass; +} + +long ct_getNumFailed(Test* pTest) +{ + assert(pTest); + return pTest->nFail; +} + +long ct_run(Test* pTest) +{ + size_t testNum; + assert(pTest); + for (testNum = 0; testNum < pTest->nTests; ++testNum) + pTest->pTestFuns[testNum](pTest); + return pTest->nFail; +} + +void ct_reset(Test* pTest) +{ + assert(pTest); + pTest->nFail = pTest->nPass = 0; +} + +const char* ct_getName(Test* pTest) +{ + assert(pTest); + return (pTest->name); +} + +long ct_getNumTests(Test* pTest) +{ + assert(pTest); + return pTest->nTests; +} + diff --git a/bacnet-stack/test/.svn/text-base/ctest.h.svn-base b/bacnet-stack/test/.svn/text-base/ctest.h.svn-base new file mode 100644 index 00000000..376a5c41 --- /dev/null +++ b/bacnet-stack/test/.svn/text-base/ctest.h.svn-base @@ -0,0 +1,61 @@ +/* ctest.h + * + * Defines a test framework for C projects. + */ +#ifndef CTEST_H +#define CTEST_H + +#include +#include + +#define ct_test(test, cond) \ + ct_do_test(test, #cond, cond, __FILE__, __LINE__) +#define ct_fail(test, str) \ + ct_do_fail(test, str, __FILE__, __LINE__) + +typedef struct _Test Test; + +typedef void (*TestFunc)(Test*); + +struct _Test +{ + char* name; + FILE* pStream; + size_t nTests; + size_t maxTests; + TestFunc* pTestFuns; + long nPass; + long nFail; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +Test* ct_create(const char* name, void (*init)(Test*)); +void ct_destroy(Test* pTest); + +const char* ct_getName(Test* pTest); +long ct_getNumPassed(Test* pTest); +long ct_getNumFailed(Test* pTest); +long ct_getNumTests(Test* pTest); +FILE* ct_getStream(Test* pTest); +void ct_setStream(Test* pTest, FILE* stream); + +bool ct_addTestFunction(Test* pTest, TestFunc tfun); +void ct_succeed(Test* pTest); +long ct_run(Test* pTest); +long ct_report(Test* pTest); +void ct_reset(Test* pTest); + +/* Not intended for end-users: */ +void ct_do_test(Test* pTest, const char* str, + bool cond, const char* file, long line); +void ct_do_fail(Test* pTest, const char* str, + const char* file, long line); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bacnet-stack/test/ctest.c b/bacnet-stack/test/ctest.c new file mode 100644 index 00000000..e31e867e --- /dev/null +++ b/bacnet-stack/test/ctest.c @@ -0,0 +1,182 @@ +/* ctest.c: Implements the CTest Framework */ + +#include "ctest.h" +#include +#include +#include +#include + +/* Number of tests to hold incrementally */ +enum {CHUNK = 10}; + +Test* ct_create(const char* name, void (*init)(Test*)) +{ + int backOutLevel = 0; + Test* pTest = malloc(sizeof(Test)); + if (pTest) + { + pTest->nPass = pTest->nFail = pTest->nTests = 0; + pTest->pStream = stdout; + + /* Allocate array of fptrs: */ + assert(CHUNK); + pTest->pTestFuns = calloc(CHUNK, sizeof(TestFunc)); + if (pTest->pTestFuns) + { + pTest->maxTests = CHUNK; + /* Allocate test name: */ + assert(name); + pTest->name = malloc(strlen(name) + 1); + if (pTest->name) + strcpy(pTest->name, name); + else + ++backOutLevel; + } + else + ++backOutLevel; + } + + /* Back-out allocations if memory failed: */ + if (backOutLevel) + { + switch(backOutLevel) + { + case 2: + free(pTest->pTestFuns); + pTest->pTestFuns = NULL; + case 1: + free(pTest); + pTest = NULL; + } + } + else if (init) + { + assert(pTest); + init(pTest); + } + return pTest; +} + +void ct_destroy(Test* pTest) +{ + assert(pTest); + assert(pTest->pTestFuns); + free(pTest->pTestFuns); + pTest->pTestFuns = NULL; + assert(pTest->name); + free(pTest->name); + pTest->name = NULL; + free(pTest); +} + +bool ct_addTestFunction(Test* pTest, TestFunc tfun) +{ + assert(pTest); + assert(pTest->pTestFuns); + if (pTest->nTests == pTest->maxTests) + { + size_t newSize = pTest->nTests + CHUNK; + TestFunc* new_pTestFuns = + realloc(pTest->pTestFuns, + newSize * sizeof(TestFunc)); + if (!new_pTestFuns) + return FALSE; + pTest->pTestFuns = new_pTestFuns; + pTest->maxTests += CHUNK; + } + assert(pTest->nTests < pTest->maxTests); + pTest->pTestFuns[pTest->nTests++] = tfun; + return TRUE; +} + +void ct_setStream(Test* pTest, FILE* pStream) +{ + pTest->pStream = pStream; +} + +FILE* ct_getStream(Test* pTest) +{ + return pTest->pStream; +} + +long ct_report(Test* pTest) +{ + assert(pTest); + if (pTest->pStream) + { + fprintf(pTest->pStream, + "Test \"%s\":\n\tPassed: %ld\n\tFailed: %ld\n", + pTest->name, pTest->nPass, pTest->nFail); + } + return pTest->nFail; +} + + +void ct_succeed(Test* pTest) +{ + assert(pTest); + ++pTest->nPass; +} + +void ct_do_test(Test* pTest, const char* str, + bool cond, const char* file, long line) +{ + assert(pTest); + if (!cond) + ct_do_fail(pTest, str, file, line); + else + ct_succeed(pTest); +} + +void ct_do_fail(Test* pTest, const char* str, + const char* file, long line) +{ + assert(pTest); + ++pTest->nFail; + if (pTest->pStream) + { + fprintf(pTest->pStream, + "%s failure: (%s), %s (line %ld)\n", + pTest->name, str, file, line); + } +} + +long ct_getNumPassed(Test* pTest) +{ + assert(pTest); + return pTest->nPass; +} + +long ct_getNumFailed(Test* pTest) +{ + assert(pTest); + return pTest->nFail; +} + +long ct_run(Test* pTest) +{ + size_t testNum; + assert(pTest); + for (testNum = 0; testNum < pTest->nTests; ++testNum) + pTest->pTestFuns[testNum](pTest); + return pTest->nFail; +} + +void ct_reset(Test* pTest) +{ + assert(pTest); + pTest->nFail = pTest->nPass = 0; +} + +const char* ct_getName(Test* pTest) +{ + assert(pTest); + return (pTest->name); +} + +long ct_getNumTests(Test* pTest) +{ + assert(pTest); + return pTest->nTests; +} + diff --git a/bacnet-stack/test/ctest.h b/bacnet-stack/test/ctest.h new file mode 100644 index 00000000..376a5c41 --- /dev/null +++ b/bacnet-stack/test/ctest.h @@ -0,0 +1,61 @@ +/* ctest.h + * + * Defines a test framework for C projects. + */ +#ifndef CTEST_H +#define CTEST_H + +#include +#include + +#define ct_test(test, cond) \ + ct_do_test(test, #cond, cond, __FILE__, __LINE__) +#define ct_fail(test, str) \ + ct_do_fail(test, str, __FILE__, __LINE__) + +typedef struct _Test Test; + +typedef void (*TestFunc)(Test*); + +struct _Test +{ + char* name; + FILE* pStream; + size_t nTests; + size_t maxTests; + TestFunc* pTestFuns; + long nPass; + long nFail; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +Test* ct_create(const char* name, void (*init)(Test*)); +void ct_destroy(Test* pTest); + +const char* ct_getName(Test* pTest); +long ct_getNumPassed(Test* pTest); +long ct_getNumFailed(Test* pTest); +long ct_getNumTests(Test* pTest); +FILE* ct_getStream(Test* pTest); +void ct_setStream(Test* pTest, FILE* stream); + +bool ct_addTestFunction(Test* pTest, TestFunc tfun); +void ct_succeed(Test* pTest); +long ct_run(Test* pTest); +long ct_report(Test* pTest); +void ct_reset(Test* pTest); + +/* Not intended for end-users: */ +void ct_do_test(Test* pTest, const char* str, + bool cond, const char* file, long line); +void ct_do_fail(Test* pTest, const char* str, + const char* file, long line); + +#ifdef __cplusplus +} +#endif + +#endif