├── .circleci ├── config.yml └── images │ └── Dockerfile ├── .codecov.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── TUTORIAL.md ├── examples ├── blink.il ├── ctu.il ├── factorial.il ├── fb.il ├── rpiface-updown.il ├── rpiface.il ├── rtc.il ├── sine.il └── tutorial │ ├── example1.il │ ├── example2.il │ └── example3.il ├── media ├── logo.jpg ├── raspberrypi.gif ├── tutorial.gif └── tutorial.png ├── protobuf ├── .gitignore └── format.proto ├── src ├── .gitignore ├── Makefile ├── block.c ├── bytecode.c ├── bytecode │ ├── Makefile │ ├── generate.c │ ├── label.c │ └── stack.c ├── callback.c ├── cast.c ├── config.c ├── echidna.c ├── file.c ├── frame.c ├── function.c ├── grammar.y ├── hardware.c ├── hardware │ ├── Makefile │ └── piface.c ├── hex.c ├── include │ ├── block.h │ ├── bytecode.h │ ├── bytecode │ │ ├── generate.h │ │ ├── label.h │ │ └── stack.h │ ├── callback.h │ ├── cast.h │ ├── config.h │ ├── echidna.h │ ├── file.h │ ├── frame.h │ ├── function.h │ ├── hardware.h │ ├── hardware │ │ └── piface.h │ ├── hex.h │ ├── json.h │ ├── lexer.h │ ├── ll.h │ ├── log.h │ ├── macros.h │ ├── operator.h │ ├── operator │ │ ├── arithmetic.h │ │ ├── boolean.h │ │ ├── call.h │ │ ├── comparison.h │ │ ├── inputs.h │ │ ├── jump.h │ │ ├── logical.h │ │ ├── operand.h │ │ ├── parameter.h │ │ └── return.h │ ├── parameter.h │ ├── parse.h │ ├── protobuf.h │ ├── protobuf │ │ ├── config.h │ │ ├── file.h │ │ ├── pou.h │ │ ├── symbol.h │ │ └── value.h │ ├── queue.h │ ├── runtime.h │ ├── runtime │ │ ├── bytecode.h │ │ ├── call.h │ │ ├── context.h │ │ ├── error.h │ │ ├── exit.h │ │ ├── function.h │ │ ├── parameter.h │ │ └── task.h │ ├── sha256.h │ ├── standard.h │ ├── standard │ │ ├── arithmetic.h │ │ ├── bitstring.h │ │ ├── bitwise.h │ │ ├── comparison.h │ │ ├── fb.h │ │ ├── numeric.h │ │ ├── select.h │ │ ├── string.h │ │ ├── time.h │ │ └── type.h │ ├── stats.h │ ├── strl.h │ ├── symbol.h │ ├── token.h │ ├── tree.h │ ├── unit.h │ └── value.h ├── json.c ├── lexer.l ├── ll.c ├── log.c ├── main.c ├── operator │ ├── Makefile │ ├── op_arithmetic.c │ ├── op_boolean.c │ ├── op_call.c │ ├── op_comparison.c │ ├── op_inputs.c │ ├── op_jump.c │ ├── op_logical.c │ ├── op_operand.c │ ├── op_parameter.c │ └── op_return.c ├── parameter.c ├── parse.c ├── port │ ├── deps.h │ ├── lock.c │ ├── lock.h │ └── port_msvc.c ├── protobuf │ ├── Makefile │ ├── pb_config.c │ ├── pb_file.c │ ├── pb_pou.c │ ├── pb_symbol.c │ └── pb_value.c ├── queue.c ├── runtime.c ├── runtime │ ├── Makefile │ ├── rt_bytecode.c │ ├── rt_call.c │ ├── rt_context.c │ ├── rt_error.c │ ├── rt_exit.c │ ├── rt_function.c │ ├── rt_parameter.c │ └── rt_task.c ├── sha256.c ├── standard.c ├── standard │ ├── Makefile │ ├── std_arithmetic.c │ ├── std_bistable.c │ ├── std_bitstring.c │ ├── std_bitwise.c │ ├── std_comparison.c │ ├── std_counters.c │ ├── std_edge.c │ ├── std_numeric.c │ ├── std_rtc.c │ ├── std_select.c │ ├── std_string.c │ ├── std_time.c │ ├── std_timers.c │ └── std_type.c ├── stats.c ├── strl.c ├── symbol.c ├── token.c ├── tree.c ├── unit.c └── value.c └── tests ├── .gitignore ├── Makefile ├── block ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── callback ├── Makefile ├── callback.c ├── suite.c └── tests.h ├── cast ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── echidna ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── grammar ├── Makefile ├── comments.c ├── divide.c ├── function.c ├── literals.c ├── modulus.c ├── src │ ├── divide.txt │ ├── factorial.txt │ └── modulus.txt ├── subrange.c ├── suite.c ├── tests.h └── type.c ├── ll ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── main.c ├── operator ├── Makefile ├── arithmetic.c ├── boolean.c ├── comparison.c ├── logical.c ├── operand.c ├── src │ └── boolean.txt ├── suite.c └── tests.h ├── queue ├── Makefile ├── priority.c ├── suite.c ├── tests.c └── tests.h ├── sha256 ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── standard ├── Makefile ├── arithmetic │ ├── Makefile │ ├── add.c │ ├── div.c │ ├── expt.c │ ├── mod.c │ ├── mul.c │ ├── sub.c │ ├── suite.c │ ├── tests.c │ └── tests.h ├── bistable │ ├── Makefile │ ├── bistable.c │ ├── src │ │ ├── rs.txt │ │ └── sr.txt │ ├── suite.c │ └── tests.h ├── bitstring │ ├── Makefile │ ├── roll.c │ ├── shift.c │ ├── suite.c │ └── tests.h ├── bitwise │ ├── Makefile │ ├── suite.c │ ├── tests.c │ └── tests.h ├── comparison │ ├── Makefile │ ├── suite.c │ ├── tests.c │ └── tests.h ├── counters │ ├── Makefile │ ├── ctd.c │ ├── ctu.c │ ├── src │ │ ├── ctd.txt │ │ ├── ctd_type.txt │ │ ├── ctu.txt │ │ └── ctu_type.txt │ ├── suite.c │ ├── tests.c │ └── tests.h ├── edge │ ├── Makefile │ ├── edge.c │ ├── src │ │ └── edge.txt │ ├── suite.c │ └── tests.h ├── numeric │ ├── Makefile │ ├── abs.c │ ├── cosine.c │ ├── exp.c │ ├── log.c │ ├── sine.c │ ├── sqrt.c │ ├── suite.c │ ├── tangent.c │ ├── tests.c │ └── tests.h ├── rtc │ ├── Makefile │ ├── rtc.c │ ├── src │ │ └── rtc.txt │ ├── suite.c │ └── tests.h ├── select │ ├── Makefile │ ├── limit.c │ ├── max.c │ ├── min.c │ ├── mux.c │ ├── select.c │ ├── suite.c │ └── tests.h ├── string │ ├── Makefile │ ├── suite.c │ ├── tests.c │ └── tests.h ├── time │ ├── Makefile │ ├── suite.c │ ├── tests.h │ └── time.c ├── timers │ ├── Makefile │ ├── src │ │ └── timers.txt │ ├── suite.c │ ├── tests.h │ └── timers.c └── type │ ├── Makefile │ ├── suite.c │ ├── tests.h │ └── type.c ├── stats ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── strl ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── stub ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── suite.h ├── tree ├── Makefile ├── suite.c ├── tests.c └── tests.h ├── unit ├── Makefile ├── suite.c ├── tests.c └── tests.h └── value ├── Makefile ├── assign.c ├── cast.c ├── istype.c ├── suite.c ├── tests.c └── tests.h /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | codecov: codecov/codecov@1.0.2 5 | 6 | defaults: &defaults 7 | docker: 8 | - image: robcasey/dev:echidna 9 | 10 | workflows: 11 | build-pipeline: 12 | jobs: 13 | - test 14 | 15 | jobs: 16 | test: 17 | <<: *defaults 18 | steps: 19 | - checkout 20 | - run: make tests 21 | - codecov/upload: 22 | file: gcovr.xml 23 | token: d84db9b8-dbbe-4fb8-8d60-a93985c1e766 24 | 25 | build: 26 | <<: *defaults 27 | steps: 28 | - run: make 29 | -------------------------------------------------------------------------------- /.circleci/images/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM buildpack-deps:stretch 2 | RUN apt-get update \ 3 | && apt-get install -y --no-install-recommends bison gcovr flex libev-dev libev4 libjansson-dev libjansson4 libprotobuf-c-dev libprotobuf-c1 \ 4 | && apt-get clean \ 5 | && rm -rf /var/lib/apt/lists/* || true 6 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: yes 3 | 4 | coverage: 5 | precision: 2 6 | round: down 7 | range: "40..90" 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | core 2 | *.gcda 3 | *.gcno 4 | *.gcov 5 | *.o 6 | gcovr.xml 7 | grammar.c 8 | grammar.h 9 | grammar.output 10 | lexer.c 11 | libechidna.a 12 | echidna 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Rob Casey 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: src tests 4 | 5 | all: clean 6 | make -C src 7 | test -x src/echidna && ln -s src/echidna echidna 8 | 9 | clean: 10 | test -L echidna && rm echidna || true 11 | make -C src clean 12 | make -C tests clean 13 | rm -f core gcovr.xml || true 14 | 15 | tests: clean 16 | make -C src libechidna.a 17 | make -C tests 18 | gcovr -r . -x -o gcovr.xml 2>/dev/null || true 19 | 20 | docker: 21 | docker build -t echidna .circleci/images 22 | docker tag echidna:latest robcasey/dev:echidna 23 | docker push robcasey/dev:echidna 24 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Makefile: Remove -g from CFLAGS 2 | - src/grammar.y: Fix assignment/type of derived types 3 | - src/grammar.y: Continue parsing after error 4 | - src/grammar.y: Handle VAR_ACCESS, VAR_CONFIG definitions 5 | - src/grammar.y: Review grammar error messages 6 | - src/grammar.y: Review grammar to ensure all tokens are freed 7 | - src/bytecode.c: Add support for negated output from functions 8 | - src/standard.c: Add support for character string functions 9 | - src: Determine method for system configuration beyond command line invocation? 10 | - src: Simplify where possible and reduce dependency on dynamically allocated memory 11 | - src: Fix function block instances within function blocks 12 | - src: Add support for loading function block definitions from hexadecimal file 13 | - src: Add support for function block signature validation 14 | - src: Add Modbus server/client functionality 15 | - src: Add DNP3 slave functionality 16 | - src: Add MQTT client functionality 17 | -------------------------------------------------------------------------------- /examples/blink.il: -------------------------------------------------------------------------------- 1 | (* Incrementally toggling 0/1 output driven by ton/ton/f_trig/r_trig *) 2 | 3 | program test 4 | var inp: bool; end_var 5 | var cycle: time := t#500ms; end_var 6 | var t1, t2: ton; end_var 7 | var redge: r_trig; end_var 8 | var fedge: f_trig; end_var 9 | 10 | ldn t2.q 11 | st inp 12 | cal t1( 13 | in := inp, 14 | pt := cycle 15 | ) 16 | cal t2( 17 | in := t1.q, 18 | pt := cycle 19 | ) 20 | 21 | cal redge( 22 | clk := t1.q 23 | ) 24 | ld redge.q 25 | jmpcn down 26 | dbg 1 (* Print 1 *) 27 | down: cal fedge( 28 | clk := t1.q 29 | ) 30 | ld fedge.q 31 | retcn 32 | dbg 0 (* Print 0 *) 33 | 34 | end_program 35 | 36 | configuration config1 37 | task task1 (interval := t#10ms, priority := 1); 38 | program program1 with task1: test; 39 | end_configuration 40 | 41 | -------------------------------------------------------------------------------- /examples/ctu.il: -------------------------------------------------------------------------------- 1 | program test 2 | var count: ctu; end_var 3 | var maxval: sint := 10; end_var 4 | 5 | cal count( 6 | cu := true, 7 | pv := maxval, 8 | r := count.q 9 | ) 10 | dbg count.q 11 | 12 | end_program 13 | 14 | 15 | configuration config1 16 | 17 | task task1 (interval := t#100ms, priority := 1); 18 | program program1 with task1: test; 19 | 20 | end_configuration 21 | -------------------------------------------------------------------------------- /examples/factorial.il: -------------------------------------------------------------------------------- 1 | function fact: udint 2 | var_input inp: udint; end_var 3 | var_output out: udint; end_var 4 | var local: udint; end_var 5 | 6 | ld inp 7 | ge 1 8 | jmpc nonzero 9 | ld 1 10 | ret 11 | nonzero: ld inp 12 | sub 1 13 | st local 14 | fact local 15 | mul inp 16 | st out 17 | ret 18 | 19 | end_function 20 | 21 | program test 22 | var cycle, result: udint := 0; end_var 23 | 24 | fact cycle 25 | st result 26 | dbg cycle, result 27 | 28 | add cycle, 1 29 | st cycle 30 | le 10 (* Limit execution to 11 cycles *) 31 | retc 32 | _exit 33 | 34 | end_program 35 | 36 | configuration config1 37 | task task1 (interval := t#50ms, priority := 1); 38 | program program1 with task1: test; 39 | end_configuration 40 | 41 | -------------------------------------------------------------------------------- /examples/fb.il: -------------------------------------------------------------------------------- 1 | (* 2 | This is a non-functional instruction list application which is the subject 3 | of further echidna virtual machine development. 4 | *) 5 | 6 | function_block toggle 7 | var_input run: bool; end_var 8 | var_input cycle: time; end_var 9 | var_output q: bool; end_var 10 | 11 | ld run 12 | st q 13 | 14 | end_function_block 15 | 16 | 17 | program test 18 | var blink: toggle; end_var 19 | var count: uint := 0; end_var 20 | 21 | cal blink( 22 | run := true, 23 | cycle := t#500ms 24 | ) 25 | dbg blink.q 26 | 27 | add count, 1 28 | st count 29 | eq 5 30 | retcn 31 | _exit 32 | 33 | end_program 34 | 35 | 36 | configuration config1 37 | 38 | task task1 (interval := t#1s, priority := 1); 39 | program program1 with task1: test; 40 | 41 | end_configuration 42 | 43 | -------------------------------------------------------------------------------- /examples/rpiface-updown.il: -------------------------------------------------------------------------------- 1 | program test 2 | var val: byte := 1; end_var 3 | var dir: bool := true; end_var 4 | 5 | piface_write val 6 | 7 | ld dir 8 | jmpcn rshift 9 | 10 | lshift: shl val, 1 11 | st val 12 | eq 128 13 | r dir 14 | ret 15 | 16 | rshift: shr val, 1 17 | st val 18 | eq 1 19 | s dir 20 | ret 21 | 22 | end_program 23 | 24 | configuration config1 25 | task task1 (interval := t#80ms, priority := 1); 26 | program program1 with task1: test; 27 | end_configuration 28 | 29 | -------------------------------------------------------------------------------- /examples/rpiface.il: -------------------------------------------------------------------------------- 1 | program test 2 | var inp, val: byte := 1; end_var 3 | var res: bool; end_var 4 | 5 | piface_read 6 | st inp 7 | eq 0 8 | jmpc roll 9 | 10 | ld inp 11 | and val 12 | eq val 13 | jmpcn roll 14 | piface_write inp (* Mirror inputs if asserted *) 15 | ret 16 | 17 | roll: piface_write val (* Otherwise roll outputs *) 18 | rol val, 1 19 | st val 20 | 21 | end_program 22 | 23 | configuration config1 24 | task task1 (interval := t#100ms, priority := 1); 25 | program program1 with task1: test; 26 | end_configuration 27 | 28 | -------------------------------------------------------------------------------- /examples/rtc.il: -------------------------------------------------------------------------------- 1 | (* Output current time once per second *) 2 | 3 | program test 4 | var clock: rtc; end_var 5 | 6 | cal clock 7 | dbg clock.cdt 8 | 9 | end_program 10 | 11 | configuration config1 12 | task task1 (interval := t#1s, priority := 1); 13 | program program1 with task1: test; 14 | end_configuration 15 | 16 | -------------------------------------------------------------------------------- /examples/sine.il: -------------------------------------------------------------------------------- 1 | PROGRAM prog1 2 | VAR cycle: UINT := 0; END_VAR 3 | VAR bias: REAL := 0; END_VAR 4 | VAR magnitude: REAL := 100; END_VAR 5 | VAR samples: REAL := 200; END_VAR 6 | VAR value: REAL; END_VAR 7 | 8 | LD cycle 9 | ADD 1 10 | ST cycle 11 | uint_to_real cycle 12 | MUL 6.2831854 (* 2pi *) 13 | DIV samples 14 | ST value 15 | sin value 16 | MUL magnitude 17 | ADD bias 18 | ST value 19 | dbg value 20 | 21 | END_PROGRAM 22 | 23 | CONFIGURATION config1 24 | TASK task1 (INTERVAL := t#50ms, PRIORITY := 1); 25 | PROGRAM program1 WITH task1: prog1; 26 | END_CONFIGURATION 27 | 28 | -------------------------------------------------------------------------------- /examples/tutorial/example1.il: -------------------------------------------------------------------------------- 1 | (* Toggle LED on Raspberry Pi 1 PiFace Digital I/O *) 2 | 3 | program tutorial 4 | var output: byte := false; end_var 5 | 6 | ld output 7 | xor 1 8 | st output 9 | piface_write output 10 | 11 | end_program 12 | 13 | configuration config1 14 | task task1 (interval := t#500ms, priority := 1); 15 | program program1 with task1: tutorial; 16 | end_configuration 17 | 18 | -------------------------------------------------------------------------------- /examples/tutorial/example2.il: -------------------------------------------------------------------------------- 1 | (* Toggle LED on Raspberry Pi 1 PiFace Digital I/O *) 2 | 3 | program tutorial 4 | var cycle: time := t#500ms; end_var 5 | var q: bool; end_var 6 | var output: byte := false; end_var 7 | var t1, t2: ton; end_var 8 | 9 | ldn t2.q 10 | st q 11 | cal t1( 12 | in := q, 13 | pt := cycle 14 | ) 15 | cal t2( 16 | in := t1.q, 17 | pt := cycle 18 | ) 19 | bool_to_byte t1.q 20 | st output 21 | piface_write output 22 | 23 | end_program 24 | 25 | configuration config1 26 | task task1 (interval := t#50ms, priority := 1); 27 | program program1 with task1: tutorial; 28 | end_configuration 29 | 30 | -------------------------------------------------------------------------------- /examples/tutorial/example3.il: -------------------------------------------------------------------------------- 1 | (* Toggle LED on Raspberry Pi 1 PiFace Digital I/O *) 2 | 3 | function_block blink 4 | var_input cycle: time; end_var 5 | var_output q: bool; end_var 6 | var t1, t2: ton; end_var 7 | 8 | ldn t2.q 9 | st q 10 | cal t1( 11 | in := q, 12 | pt := cycle 13 | ) 14 | cal t2( 15 | in := t1.q, 16 | pt := cycle 17 | ) 18 | 19 | end_function_block 20 | 21 | program tutorial 22 | var output: byte := false; end_var 23 | var fb: blink; end_var 24 | 25 | cal fb( 26 | cycle := t#500ms 27 | ) 28 | 29 | bool_to_byte fb.q 30 | st output 31 | dbg output (* piface_write output *) 32 | 33 | end_program 34 | 35 | configuration config1 36 | task task1 (interval := t#50ms, priority := 1); 37 | program program1 with task1: tutorial; 38 | end_configuration 39 | 40 | -------------------------------------------------------------------------------- /media/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/61131/echidna/bc3946bedaae0308b719231ed67d52736b716c9a/media/logo.jpg -------------------------------------------------------------------------------- /media/raspberrypi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/61131/echidna/bc3946bedaae0308b719231ed67d52736b716c9a/media/raspberrypi.gif -------------------------------------------------------------------------------- /media/tutorial.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/61131/echidna/bc3946bedaae0308b719231ed67d52736b716c9a/media/tutorial.gif -------------------------------------------------------------------------------- /media/tutorial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/61131/echidna/bc3946bedaae0308b719231ed67d52736b716c9a/media/tutorial.png -------------------------------------------------------------------------------- /protobuf/.gitignore: -------------------------------------------------------------------------------- 1 | *.pb-c.[ch] 2 | -------------------------------------------------------------------------------- /protobuf/format.proto: -------------------------------------------------------------------------------- 1 | /* 2 | This file describes the data structures and format employed for the storing 3 | of compiled bytecode and configurations for the echidna IEC 61131-3 virtual 4 | machine. The Google Protocol Buffers binary format generated by this message 5 | definition is subsequent written in an Intel HEX file format. 6 | */ 7 | 8 | message Index { 9 | 10 | required int32 Lower = 1; 11 | required int32 Upper = 2; 12 | } 13 | 14 | message Value { 15 | 16 | required uint32 Type = 1; 17 | /* reserved 2; */ 18 | /* reserved "Cast"; */ 19 | /* optional uint32 Cast = 2 */ 20 | required int32 Length = 3; 21 | required uint32 Flags = 4; 22 | optional bytes Maximum = 5; 23 | optional bytes Minimum = 6; 24 | required bytes Value = 7; 25 | optional bytes Meta = 8; 26 | optional Index Array = 9; 27 | } 28 | 29 | message Symbol { 30 | 31 | required uint32 Id = 1; 32 | required uint32 Offset = 2; 33 | required Value Value = 3; 34 | optional string Name = 4; 35 | optional string POU = 5; 36 | optional string Resource = 6; 37 | optional string Configuration = 7; 38 | } 39 | 40 | message POU { 41 | 42 | required string Name = 1; 43 | required uint32 Type = 2; 44 | required bytes Code = 3; 45 | } 46 | 47 | message Program { 48 | 49 | required string Name = 1; 50 | required string POU = 2; 51 | optional string Task = 3; 52 | } 53 | 54 | message Task { 55 | 56 | required string Name = 1; 57 | required uint32 Priority = 2; 58 | /* Task.Interval = Symbol.Id */ 59 | optional uint32 Interval = 3; 60 | /* Task.Single = Symbol.Id */ 61 | optional uint32 Single = 4; 62 | repeated Program Program = 5; 63 | } 64 | 65 | message Resource { 66 | 67 | required string Name = 1; 68 | optional string Type = 2; 69 | repeated Task Task = 3; 70 | repeated Program Program = 4; 71 | } 72 | 73 | message Configuration { 74 | 75 | required string Name = 1; 76 | repeated Resource Resource = 2; 77 | } 78 | 79 | message File { 80 | required uint32 Magic = 1 [default = 61131]; 81 | required uint32 Format = 2 [default = 0]; 82 | repeated Symbol Symbols = 3; 83 | repeated POU POUs = 4; 84 | repeated Configuration Configurations = 5; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | echidna 2 | libechidna.a 3 | grammar.c 4 | grammar.h 5 | grammar.log 6 | grammar.output 7 | lexer.c 8 | *.o 9 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | SUBDIRS:= bytecode hardware operator protobuf runtime standard 4 | 5 | .PHONY: $(SUBDIRS) 6 | 7 | CC ?= $(CROSS)gcc 8 | AR ?= $(CROSS)ar 9 | STRIP ?= $(CROSS)strip 10 | 11 | GIT_VERSION := $(shell git --no-pager describe --tags --always --dirty) 12 | TIMESTAMP := $(shell date +'%Y%m%d') 13 | 14 | CFLAGS := -Wall -g -std=c99 -fPIC 15 | DEFINES += $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 16 | INCLUDES := -I. -Iinclude 17 | LIBS := $(foreach VAR,config ev jansson m protobuf-c pthread,-l$(VAR)) 18 | 19 | TARGET := echidna 20 | LIBRARY := libechidna.a 21 | 22 | OBJS:= grammar.o lexer.o block.o bytecode.o bytecode/generate.o bytecode/label.o bytecode/stack.o callback.o cast.o config.o echidna.o file.o frame.o function.o hex.o json.o ll.o log.o operator/arithmetic.o operator/boolean.o operator/call.o operator/comparison.o operator/inputs.o operator/jump.o operator/logical.o operator/operand.o operator/parameter.o operator/return.o parameter.o parse.o protobuf/config.o protobuf/file.o protobuf/pou.o protobuf/symbol.o protobuf/value.o queue.o runtime.o runtime/bytecode.o runtime/call.o runtime/context.o runtime/error.o runtime/exit.o runtime/function.o runtime/parameter.o runtime/task.o sha256.o standard.o standard/arithmetic.o standard/bistable.o standard/bitstring.o standard/bitwise.o standard/comparison.o standard/counters.o standard/edge.o standard/numeric.o standard/rtc.o standard/select.o standard/string.o standard/time.o standard/timers.o standard/type.o stats.o strl.o symbol.o token.o tree.o unit.o value.o 23 | 24 | ifdef HARDWARE_PIFACE 25 | CFLAGS += -DHARDWARE_PIFACE 26 | OBJS += hardware/piface.o hardware.o 27 | endif 28 | 29 | ifneq ($(filter $(LIBRARY),$(MAKECMDGOALS)),) 30 | CFLAGS += -fprofile-arcs -ftest-coverage -DNDEBUG 31 | endif 32 | 33 | all: clean grammar.o $(SUBDIRS) $(TARGET) 34 | 35 | $(TARGET): $(OBJS) main.o 36 | $(CC) $(CFLAGS) $(DEFINES) $^ -o $@ $(LIBS) 37 | 38 | $(LIBRARY): clean $(OBJS) 39 | $(AR) rcs $@ $(OBJS) 40 | 41 | .c.o: 42 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 43 | 44 | grammar.c: grammar.y 45 | bison -Wall -t -v $^ -o $@ 2>&1 46 | #bison -Wall $^ -o $@ 2>&1 47 | 48 | grammar.o: grammar.c 49 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 50 | 51 | lexer.c: lexer.l 52 | flex -o $@ $^ 53 | 54 | bytecode: 55 | make -C $@ 56 | 57 | hardware: 58 | make -C $@ 59 | 60 | operator: 61 | make -C $@ 62 | 63 | protobuf: 64 | make -C $@ 65 | 66 | runtime: 67 | make -C $@ 68 | 69 | standard: 70 | make -C $@ 71 | 72 | link: 73 | $(CC) $(CFLAGS) $(DEFINES) $^ -o $@ $(LIBS) 74 | 75 | clean: 76 | for SUBDIR in $(SUBDIRS); do make -C $$SUBDIR $@ ; done 77 | rm -f grammar.c grammar.h grammar.log grammar.output lexer.c *.o *.gcda *.gcno *.gcov 78 | rm -f $(TARGET) $(LIBRARY) core 79 | 80 | -------------------------------------------------------------------------------- /src/bytecode/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= generate.o label.o stack.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/bytecode/label.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifndef _MSC_VER 4 | #include 5 | #else 6 | #include "deps.h" 7 | #endif 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | int 17 | bytecode_label_compare(void *A, void *B) { 18 | BYTECODE_LABEL *pA, *pB; 19 | 20 | pA = (BYTECODE_LABEL *) A; 21 | assert(pA != NULL); 22 | pB = (BYTECODE_LABEL *) B; 23 | assert(pB != NULL); 24 | return strcasecmp(pA->Name, pB->Name); 25 | } 26 | 27 | 28 | void 29 | bytecode_label_destroy(void *Arg) { 30 | BYTECODE_LABEL *pLabel; 31 | 32 | if((pLabel = (BYTECODE_LABEL *) Arg) == NULL) 33 | return; 34 | free(pLabel->Position); 35 | free(pLabel); 36 | } 37 | 38 | 39 | void 40 | bytecode_label_initialise(BYTECODE_LABEL *Label, char *Name) { 41 | Label->Name = Name; 42 | Label->PC = 0; 43 | Label->Count = 0; 44 | Label->Position = NULL; 45 | } 46 | 47 | 48 | BYTECODE_LABEL * 49 | bytecode_label_new(char *Name) { 50 | BYTECODE_LABEL *pLabel; 51 | 52 | if((pLabel = (BYTECODE_LABEL *) calloc(1, sizeof(BYTECODE_LABEL))) == NULL) { 53 | log_critical( "Failed to allocate memory: %s", strerror(errno)); 54 | return NULL; 55 | } 56 | bytecode_label_initialise(pLabel, Name); 57 | return pLabel; 58 | } 59 | -------------------------------------------------------------------------------- /src/hardware.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void 5 | hardware_destroy(ECHIDNA *Context) { 6 | } 7 | 8 | 9 | int 10 | hardware_initialise(ECHIDNA *Context) { 11 | int nResult; 12 | 13 | nResult = 0; 14 | #ifdef HARDWARE_PIFACE 15 | nResult = piface_initialise(Context); 16 | #endif 17 | return nResult; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/hardware/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= piface.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/include/block.h: -------------------------------------------------------------------------------- 1 | #ifndef _BLOCK_H 2 | #define _BLOCK_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #ifdef _MSC_VER 12 | #define ssize_t ptrdiff_t 13 | #endif 14 | 15 | #define BLOCK_BLK_SIZE (1024) 16 | 17 | #define block_end(...) _block_end(_NARG(__VA_ARGS__), __VA_ARGS__) 18 | 19 | #define block_initialise(...) _block_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 20 | 21 | #define block_name(...) _block_name(_NARG(__VA_ARGS__), __VA_ARGS__) 22 | 23 | #define block_pointer(...) _block_pointer(_NARG(__VA_ARGS__), __VA_ARGS__) 24 | 25 | #define block_size(...) _block_size(_NARG(__VA_ARGS__), __VA_ARGS__) 26 | 27 | 28 | typedef struct _BLOCK { 29 | 30 | char * Name; 31 | 32 | char * Data; 33 | 34 | size_t End; 35 | 36 | size_t Size; 37 | 38 | uint8_t Alloc; 39 | } 40 | BLOCK; 41 | 42 | 43 | size_t _block_end(size_t Arg, BLOCK *Block, ...); 44 | 45 | void _block_initialise(size_t Arg, BLOCK *Block, ...); 46 | 47 | char * _block_name(size_t Arg, BLOCK *Block, ...); 48 | 49 | char * _block_pointer(size_t Arg, BLOCK *Block, ...); 50 | 51 | ssize_t _block_size(size_t Arg, BLOCK *Block, ...); 52 | 53 | int block_append(BLOCK *Block, size_t Count, char *Data); 54 | 55 | int block_compare(void *A, void *B); 56 | 57 | void block_destroy(void *Arg); 58 | 59 | void block_dump(BLOCK *Block); 60 | 61 | BLOCK * block_new(void); 62 | 63 | int block_read(BLOCK *Block, size_t Index, size_t Count, char *Data); 64 | 65 | int block_write(BLOCK *Block, size_t Index, size_t Count, char *Data); 66 | 67 | 68 | #endif /* _BLOCK_H */ 69 | 70 | -------------------------------------------------------------------------------- /src/include/bytecode/generate.h: -------------------------------------------------------------------------------- 1 | #ifndef _BYTECODE_GENERATE_H 2 | #define _BYTECODE_GENERATE_H 3 | 4 | 5 | #include 6 | 7 | 8 | int bytecode_generate(ECHIDNA *Context); 9 | 10 | 11 | #endif // _BYTECODE_GENERATE_H 12 | -------------------------------------------------------------------------------- /src/include/bytecode/label.h: -------------------------------------------------------------------------------- 1 | #ifndef _BYTECODE_LABEL_H 2 | #define _BYTECODE_LABEL_H 3 | 4 | 5 | #include 6 | 7 | 8 | typedef struct _BYTECODE_LABEL { 9 | 10 | char * Name; 11 | 12 | uint32_t PC; 13 | 14 | uint32_t Count; 15 | 16 | uint32_t * Position; 17 | } 18 | BYTECODE_LABEL; 19 | 20 | 21 | int bytecode_label_compare(void *A, void *B); 22 | 23 | void bytecode_label_destroy(void *Arg); 24 | 25 | void bytecode_label_initialise(BYTECODE_LABEL *Label, char *Name); 26 | 27 | BYTECODE_LABEL * bytecode_label_new(char *Name); 28 | 29 | 30 | #endif // _BYTECODE_LABEL_H 31 | -------------------------------------------------------------------------------- /src/include/bytecode/stack.h: -------------------------------------------------------------------------------- 1 | #ifndef _BYTECODE_STACK_H 2 | #define _BYTECODE_STACK_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #define bytecode_stack_initialise(...) _bytecode_stack_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 16 | 17 | 18 | typedef struct _BYTECODE_STACK { 19 | 20 | TOKEN_LIST * List; 21 | 22 | uint32_t BC; 23 | 24 | VALUE_TYPE Type; 25 | 26 | VALUE CR; 27 | 28 | int Position; 29 | 30 | int Id; 31 | 32 | uint32_t Line; 33 | 34 | uint32_t Column; 35 | } 36 | BYTECODE_STACK; 37 | 38 | 39 | void _bytecode_stack_initialise(size_t Arg, BYTECODE_STACK *Stack, TOKEN_LIST *List, ...); 40 | 41 | int bytecode_stack_cast(BYTECODE_STACK *Stack, TOKEN *Token); 42 | 43 | void bytecode_stack_set(BYTECODE_STACK *Stack, TOKEN *Token); 44 | 45 | void bytecode_stack_type(BYTECODE_STACK *Stack, TOKEN *Token); 46 | 47 | 48 | #endif // _BYTECODE_STACK_H 49 | -------------------------------------------------------------------------------- /src/include/callback.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALLBACK_H 2 | #define _CALLBACK_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | #define callback_register(...) _callback_register(_NARG(__VA_ARGS__), __VA_ARGS__) 11 | 12 | 13 | typedef struct _ECHIDNA ECHIDNA; 14 | 15 | typedef void (*CALLBACK_CALLBACK)(ECHIDNA *Context, void *Arg, void *User); 16 | 17 | 18 | typedef enum _CALLBACK_TYPE { 19 | 20 | CALLBACK_NONE = 0, 21 | CALLBACK_CYCLE_START, 22 | CALLBACK_CYCLE_FINISH, 23 | CALLBACK_ERROR, 24 | CALLBACK_TASK_START, 25 | CALLBACK_TASK_STOP, 26 | } 27 | CALLBACK_TYPE; 28 | 29 | int _callback_register(size_t Arg, ECHIDNA *Context, CALLBACK_TYPE Type, ...); 30 | 31 | void callback_destroy(void *Arg); 32 | 33 | int callback_execute(ECHIDNA *Context, CALLBACK_TYPE Type, void *Arg); 34 | 35 | 36 | #endif // _CALLBACK_H 37 | -------------------------------------------------------------------------------- /src/include/cast.h: -------------------------------------------------------------------------------- 1 | #ifndef _CAST_H 2 | #define _CAST_H 3 | 4 | 5 | #include 6 | 7 | 8 | int cast_lreal(VALUE *Value); 9 | 10 | int cast_real(VALUE *Value); 11 | 12 | int cast_lint(VALUE *Value); 13 | 14 | int cast_dint(VALUE *Value); 15 | 16 | int cast_int(VALUE *Value); 17 | 18 | int cast_sint(VALUE *Value); 19 | 20 | int cast_ulint(VALUE *Value); 21 | 22 | int cast_udint(VALUE *Value); 23 | 24 | int cast_uint(VALUE *Value); 25 | 26 | int cast_usint(VALUE *Value); 27 | 28 | int cast_time(VALUE *Value); 29 | 30 | int cast_lword(VALUE *Value); 31 | 32 | int cast_dword(VALUE *Value); 33 | 34 | int cast_word(VALUE *Value); 35 | 36 | int cast_byte(VALUE *Value); 37 | 38 | int cast_bool(VALUE *Value); 39 | 40 | int cast_string(VALUE *Value); 41 | 42 | int cast_wstring(VALUE *Value); 43 | 44 | int cast_date(VALUE *Value); 45 | 46 | int cast_dt(VALUE *Value); 47 | 48 | int cast_tod(VALUE *Value); 49 | 50 | 51 | #endif /* _CAST_H */ 52 | -------------------------------------------------------------------------------- /src/include/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #define config_destroy(...) _config_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 14 | 15 | #define config_initialise(...) _config_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 16 | 17 | #define config_new(...) _config_new(_NARG(__VA_ARGS__), __VA_ARGS__) 18 | 19 | #define config_program(...) _config_program(_NARG(__VA_ARGS__), __VA_ARGS__) 20 | 21 | 22 | typedef struct _ECHIDNA ECHIDNA; 23 | 24 | typedef struct _PROTOBUF_FILE PROTOBUF_FILE; 25 | 26 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 27 | 28 | typedef struct _SYMBOL SYMBOL; 29 | 30 | typedef enum _CONFIG_TYPE { 31 | 32 | /* TYPE_NONE = 0, */ 33 | TYPE_CONFIG = 1, 34 | TYPE_RESOURCE, 35 | TYPE_TASK, 36 | TYPE_PROGRAM, 37 | } 38 | CONFIG_TYPE; 39 | 40 | typedef struct _CONFIG { 41 | 42 | CONFIG_TYPE Type; 43 | 44 | void * Parent; 45 | 46 | char * Name; 47 | 48 | char * Task; // Used by CONFIG_PROGRAM 49 | 50 | int Priority; // Used by CONFIG_TASK 51 | 52 | SYMBOL * Interval; // Used by CONFIG_TASK 53 | 54 | SYMBOL * Single; // Used by CONFIG_TASK 55 | 56 | SYMBOL * Limit; // Used by CONFIG_TASK 57 | 58 | RUNTIME_CONTEXT * Context; 59 | 60 | LL List; 61 | 62 | uint8_t Alloc; 63 | } 64 | CONFIG; 65 | 66 | 67 | void _config_destroy(size_t Arg, ...); 68 | 69 | void _config_initialise(size_t Arg, CONFIG *Config, ...); 70 | 71 | CONFIG * _config_new(size_t Arg, CONFIG_TYPE Type, ...); 72 | 73 | int config_generate(ECHIDNA *Context); 74 | 75 | int config_populate(ECHIDNA *Context, PROTOBUF_FILE *File); 76 | 77 | const char * config_typetostr(CONFIG_TYPE Type); 78 | 79 | 80 | #endif /* _CONFIG_H */ 81 | 82 | -------------------------------------------------------------------------------- /src/include/echidna.h: -------------------------------------------------------------------------------- 1 | #ifndef _ECHIDNA_H 2 | #define _ECHIDNA_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #define echidna_callback(...) _echidna_callback(_NARG(__VA_ARGS__), __VA_ARGS__) 16 | 17 | #define echidna_config(...) _echidna_config(_NARG(__VA_ARGS__), __VA_ARGS__) 18 | 19 | #define echidna_initialise(...) _echidna_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 20 | 21 | #define echidna_register(...) _echidna_register(_NARG(__VA_ARGS__), __VA_ARGS__) 22 | 23 | 24 | enum { 25 | OPTION_NONE = (0<<0), 26 | OPTION_DAEMON = (1<<1), 27 | OPTION_COMPILE = (1<<2), 28 | OPTION_NOFILE = (1<<3), 29 | OPTION_NOSIGNAL = (1<<4), 30 | OPTION_RUN = (1<<5), 31 | }; 32 | 33 | typedef struct _ECHIDNA { 34 | 35 | char * Name; 36 | 37 | char * Output; 38 | 39 | uint8_t Align; 40 | 41 | uint8_t Option; 42 | 43 | uint8_t Verbose; 44 | 45 | LL Callbacks; 46 | 47 | LL Config; 48 | 49 | TREE POU; 50 | 51 | FUNCTIONS Functions; 52 | 53 | SYMBOLS Symbols; 54 | 55 | PARSE Parse; 56 | 57 | RUNTIME * VM; 58 | 59 | /* 60 | The following member is employed to provide a monotonic time-stamp, relative 61 | to the start of the virtual machine run-time, of the start of the current 62 | cycle of execution. This is intended to be employed through the echidna_time 63 | function where such time reference is required within C-based functions and 64 | function blocks. 65 | */ 66 | 67 | double Time; 68 | } 69 | ECHIDNA; 70 | 71 | 72 | int _echidna_callback(size_t Arg, ECHIDNA *Context, CALLBACK_TYPE Type, ...); 73 | 74 | int _echidna_initialise(size_t Arg, ECHIDNA *Context, ...); 75 | 76 | int _echidna_register(size_t Arg, ECHIDNA *Context, const char *Name, VALUE_TYPE Type, ...); 77 | 78 | int echidna_compile(ECHIDNA *Context); 79 | 80 | void echidna_destroy(ECHIDNA *Context); 81 | 82 | int echidna_open(ECHIDNA *Context, char *Path); 83 | 84 | int echidna_run(ECHIDNA *Context); 85 | 86 | double echidna_time(ECHIDNA *Context); 87 | 88 | 89 | #endif /* _ECHIDNA_H */ 90 | 91 | -------------------------------------------------------------------------------- /src/include/file.h: -------------------------------------------------------------------------------- 1 | #ifndef _FILE_H 2 | #define _FILE_H 3 | 4 | 5 | #include 6 | 7 | 8 | int file_read(ECHIDNA *Context, char *Path); 9 | 10 | int file_write(ECHIDNA *Context, char *Path); 11 | 12 | 13 | #endif /* _FILE_H */ 14 | -------------------------------------------------------------------------------- /src/include/frame.h: -------------------------------------------------------------------------------- 1 | #ifndef _FRAME_H 2 | #define _FRAME_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | #define FRAME_MAX (32) 16 | 17 | #define frame_initialise(...) _frame_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 18 | 19 | #define frame_push(...) _frame_push(_NARG(__VA_ARGS__), __VA_ARGS__) 20 | 21 | 22 | enum { 23 | 24 | FRAME_CD = 0, 25 | FRAME_CLK, 26 | FRAME_CU, 27 | FRAME_IN, 28 | FRAME_PT, 29 | FRAME_PV, 30 | FRAME_R, 31 | FRAME_R1, 32 | FRAME_S, 33 | FRAME_S1 34 | }; 35 | 36 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 37 | 38 | typedef struct _RT_FUNCTION RT_FUNCTION; 39 | 40 | typedef struct _FRAME { 41 | 42 | uint32_t PC; // Program counter (PC) 43 | 44 | uint32_t ER; // Error register (ER) 45 | 46 | uint32_t BC; // Current bytecode (BC) 47 | 48 | VALUE CR; // Current register (CR) 49 | 50 | VALUE_TYPE Type; // Current type (Type) 51 | 52 | VALUE Inputs[10]; // Input parameters specified in current frame 53 | 54 | UNIT * POU; // Current program organisation unit (POU) 55 | 56 | struct _RT_FUNCTION * Function; 57 | 58 | uint32_t Parameter; // Parameter index 59 | 60 | LL Parameters; // Parameters to current POU 61 | 62 | BLOCK Data; 63 | } 64 | FRAME; 65 | 66 | 67 | void _frame_initialise(size_t Arg, FRAME *Frame, ...); 68 | 69 | int _frame_push(size_t Arg, RUNTIME_CONTEXT *Context, ...); 70 | 71 | FRAME * frame_current(RUNTIME_CONTEXT *Context); 72 | 73 | void frame_next(RUNTIME_CONTEXT *Context); 74 | 75 | int frame_pop(RUNTIME_CONTEXT *Context); 76 | 77 | FRAME * frame_previous(RUNTIME_CONTEXT *Context); 78 | 79 | void frame_restore(RUNTIME_CONTEXT *Context); 80 | 81 | void frame_store(RUNTIME_CONTEXT *Context); 82 | 83 | 84 | #endif // _FRAME_H 85 | -------------------------------------------------------------------------------- /src/include/function.h: -------------------------------------------------------------------------------- 1 | #ifndef _FUNCTION_H 2 | #define _FUNCTION_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #define function_register(...) _function_register(_NARG(__VA_ARGS__), __VA_ARGS__) 14 | 15 | 16 | typedef struct _ECHIDNA ECHIDNA; 17 | 18 | typedef struct _FUNCTION_BLOCK_FIELD { 19 | 20 | const char * Name; 21 | 22 | VALUE_TYPE Type; 23 | 24 | size_t Offset; 25 | 26 | void * Meta; 27 | } 28 | FUNCTION_BLOCK_FIELD; 29 | 30 | /* 31 | The more obscure data structure names of _FUNCTION and _FUNCTION_BLOCK are 32 | employed due to the equivalent without the leading underscore clashing with 33 | token definitions within the IEC 61131-3 grammar. 34 | */ 35 | 36 | typedef struct __FUNCTION_BLOCK _FUNCTION_BLOCK; 37 | 38 | struct __FUNCTION_BLOCK { 39 | 40 | const char * Name; 41 | 42 | size_t Size; 43 | 44 | size_t Count; 45 | 46 | FUNCTION_BLOCK_FIELD * Fields; 47 | 48 | void *(*Initialise)(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, void *User); 49 | 50 | void (*Destroy)(ECHIDNA *Context, char *Instance, void *User); 51 | 52 | int (*Execute)(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, void *User); 53 | }; 54 | 55 | typedef int (*_FUNCTION)(ECHIDNA *Context, const char *Name, LL *pParameters, VALUE *Result, void *User); 56 | 57 | typedef struct _FUNCTION_REGISTER { 58 | 59 | uint32_t Id; 60 | 61 | const char * Name; 62 | 63 | VALUE_TYPE Type; 64 | 65 | _FUNCTION_BLOCK * Block; 66 | 67 | _FUNCTION Function; 68 | 69 | void * Context; 70 | 71 | int Size; 72 | } 73 | FUNCTION_REGISTER; 74 | 75 | typedef struct _FUNCTIONS { 76 | 77 | FUNCTION_REGISTER ** Function; 78 | 79 | size_t Count; 80 | 81 | char Signature[65]; // ((SHA256_LENGTH << 1) + 1) 82 | 83 | uint8_t Lock; 84 | } 85 | FUNCTIONS; 86 | 87 | 88 | int _function_register(size_t Arg, FUNCTIONS *Context, const char *Name, VALUE_TYPE Type, ...); 89 | 90 | void function_destroy(void *Arg); 91 | 92 | void function_initialise(FUNCTIONS *Context); 93 | 94 | FUNCTION_REGISTER * function_search(FUNCTIONS *Context, const char *Name); 95 | 96 | void function_table_build(FUNCTIONS *Context); 97 | 98 | 99 | #endif /* _FUNCTION_H */ 100 | -------------------------------------------------------------------------------- /src/include/hardware.h: -------------------------------------------------------------------------------- 1 | #ifndef _HARDWARE_H 2 | #define _HARDWARE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | void hardware_destroy(ECHIDNA *Context); 11 | 12 | int hardware_initialise(ECHIDNA *Context); 13 | 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/include/hardware/piface.h: -------------------------------------------------------------------------------- 1 | #ifndef _HARDWARE_PIFACE_H 2 | #define _HARDWARE_PIFACE_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | typedef enum _PIFACE_REG { 10 | 11 | REG_IODIRA = 0, 12 | REG_IODIRB, 13 | REG_IPOLA, 14 | REG_IPOLB, 15 | REG_GPINTENA, 16 | REG_GPINTENB, 17 | REG_DEFVALA, 18 | REG_DEFVALB, 19 | REG_INTCONA, 20 | REG_INTCONB, 21 | REG_IOCON1, 22 | REG_IOCON2, 23 | REG_GPPUA, 24 | REG_GPPUB, 25 | REG_INTFA, 26 | REG_INTFB, 27 | REG_INTCAPA, 28 | REG_INTCAPB, 29 | REG_GPIOA, 30 | REG_GPIOB, 31 | REG_OLATA, 32 | REG_OLATB, 33 | 34 | REG_IOCON = REG_IOCON1, 35 | REG_OUTPUT = REG_GPIOA, 36 | REG_INPUT = REG_GPIOB, 37 | } 38 | PIFACE_REG; 39 | 40 | typedef struct _PIFACE { 41 | 42 | int Fd; 43 | 44 | int Address; 45 | 46 | int Bits; 47 | 48 | int Speed; 49 | } 50 | PIFACE; 51 | 52 | 53 | typedef struct _ECHIDNA ECHIDNA; 54 | 55 | 56 | int piface_initialise(ECHIDNA *Context); 57 | 58 | int piface_read(ECHIDNA *Context, const char *Name, LL *pParameters, VALUE *Result, void *User); 59 | 60 | int piface_write(ECHIDNA *Context, const char *Name, LL *pParameters, VALUE *Result, void *User); 61 | 62 | 63 | #endif // _HARDWARE_PIFACE_H 64 | -------------------------------------------------------------------------------- /src/include/hex.h: -------------------------------------------------------------------------------- 1 | #ifndef _HEX_H 2 | #define _HEX_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | typedef struct { 13 | 14 | uint32_t Start; 15 | 16 | uint32_t Address; 17 | 18 | BLOCK Data; 19 | } 20 | HEX_BLOCK; 21 | 22 | typedef struct { 23 | 24 | LL Blocks; 25 | 26 | FILE * File; 27 | 28 | uint8_t Alloc; 29 | } 30 | HEX; 31 | 32 | 33 | void hex_close(HEX *Hex); 34 | 35 | void hex_destroy(HEX *Hex); 36 | 37 | int hex_get(HEX *Hex, uint32_t Address, size_t Length, void *Data); 38 | 39 | void hex_initialise(HEX *Hex); 40 | 41 | HEX * hex_new(void); 42 | 43 | int hex_pointer(HEX *Hex, uint32_t Address, char **Pointer); 44 | 45 | int hex_read(HEX *Hex, char *Path); 46 | 47 | int hex_set(HEX *Hex, uint32_t Start, uint32_t Address, size_t Length, void *Data); 48 | 49 | int hex_write(HEX *Hex, char *Path); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/include/json.h: -------------------------------------------------------------------------------- 1 | #ifndef _JSON_H 2 | #define _JSON_H 3 | 4 | 5 | #include 6 | 7 | 8 | void json_symbol_dump(ECHIDNA *Context); 9 | 10 | void json_token_dump(TOKEN *Token); 11 | 12 | void json_value_dump(VALUE *Value); 13 | 14 | 15 | #endif /* _JSON_H */ 16 | -------------------------------------------------------------------------------- /src/include/lexer.h: -------------------------------------------------------------------------------- 1 | #ifndef _LEXER_H 2 | #define _LEXER_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | typedef struct _LEXER_TOKEN { 11 | 12 | const char * Text; 13 | 14 | int Id; 15 | } 16 | LEXER_TOKEN; 17 | 18 | 19 | extern YYSTYPE yylval; 20 | 21 | int yylex_destroy(void); 22 | 23 | 24 | void lexer_destroy(LEXER_TOKEN *Token); 25 | 26 | LEXER_TOKEN * lexer_new(int Id, const char *Str); 27 | 28 | void lexer_start(void *Context); 29 | 30 | 31 | #endif /* _LEXER_H */ 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/include/ll.h: -------------------------------------------------------------------------------- 1 | #ifndef _LL_H 2 | #define _LL_H 3 | 4 | #include 5 | #include 6 | 7 | 8 | #define ll_copy(...) _ll_copy(_NARG(__VA_ARGS__), __VA_ARGS__) 9 | 10 | #define ll_delete(...) _ll_delete(_NARG(__VA_ARGS__), __VA_ARGS__) 11 | 12 | #define ll_destroy(...) _ll_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 13 | 14 | #define ll_initialise(...) _ll_initialise(_NARG( __VA_ARGS__ ), __VA_ARGS__) 15 | 16 | #define ll_merge(...) _ll_merge(_NARG(__VA_ARGS__), __VA_ARGS__) 17 | 18 | 19 | typedef void (*LL_DESTROY)(void *pArg); 20 | 21 | struct _LLE; 22 | 23 | typedef struct _LLE { 24 | 25 | struct _LL * List; 26 | 27 | struct _LLE * Next; 28 | 29 | struct _LLE * Previous; 30 | 31 | void * Data; 32 | } 33 | LLE; 34 | 35 | typedef struct _LL { 36 | 37 | LL_DESTROY Destroy; 38 | 39 | LLE * Head; 40 | 41 | LLE * Tail; 42 | 43 | LLE * Item; 44 | 45 | size_t Size; 46 | 47 | uint8_t Alloc; 48 | void* Lock; 49 | } 50 | LL; 51 | 52 | typedef struct _LL_ITER { 53 | 54 | LLE * Item; 55 | 56 | LLE * Next; 57 | } 58 | LL_ITER; 59 | 60 | 61 | int _ll_copy(size_t Arg, LL *List, ...); 62 | 63 | void _ll_delete(size_t Arg, LLE *Element, ...); 64 | 65 | void _ll_destroy(size_t Arg, LL *List, ...); 66 | 67 | int _ll_initialise(size_t Arg, LL *List, ...); 68 | 69 | int _ll_merge(size_t Arg, LL *List, ...); 70 | 71 | int ll_insert(LL *List, void *Data); 72 | 73 | int ll_insert_head(LL *List, void *Data); 74 | 75 | int ll_insert_tail(LL *List, void *Data); 76 | 77 | void * ll_iterate(LL *List); 78 | 79 | void * ll_iterate_first(LL_ITER *Iter, LL *List); 80 | 81 | void * ll_iterate_last(LL_ITER *Iter, LL *List); 82 | 83 | void * ll_iterate_next(LL_ITER *Iter); 84 | 85 | void * ll_iterate_previous(LL_ITER *Iter ); 86 | 87 | LL * ll_new(void); 88 | 89 | void ll_reset(LL * List); 90 | 91 | 92 | #endif /* _LL_H */ 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_H 2 | #define _LOG_H 3 | 4 | 5 | /* Re-use log levels from syslog.h */ 6 | 7 | #ifdef _MSC_VER 8 | typedef enum { 9 | LOG_EMERG, 10 | LOG_ALERT, 11 | LOG_CRIT, 12 | LOG_ERR, 13 | LOG_WARNING, 14 | LOG_NOTICE, 15 | LOG_INFO, 16 | LOG_DEBUG, 17 | }log_e; 18 | #else 19 | #include 20 | #endif 21 | 22 | #define LOG_NONE (-1) 23 | 24 | #define log_emerg(...) log_message(LOG_EMERG, __VA_ARGS__) 25 | #define log_alert(...) log_message(LOG_ALERT, __VA_ARGS__) 26 | #define log_critical(...) log_message(LOG_CRIT, __VA_ARGS__) 27 | #define log_crit(...) log_message(LOG_CRIT, __VA_ARGS__) 28 | #define log_err(...) log_message(LOG_ERR, __VA_ARGS__) 29 | #define log_error(...) log_message(LOG_ERR, __VA_ARGS__) 30 | #define log_warning(...) log_message(LOG_WARNING, __VA_ARGS__) 31 | #define log_warn(...) log_message(LOG_WARNING, __VA_ARGS__) 32 | #define log_notice(...) log_message(LOG_NOTICE, __VA_ARGS__) 33 | #define log_info(...) log_message(LOG_INFO, __VA_ARGS__) 34 | #define log_debug(...) log_message(LOG_DEBUG, __VA_ARGS__) 35 | 36 | 37 | void log_message(int Priority, const char *Format, ...); 38 | 39 | extern int log_level; 40 | 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/include/operator.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_H 2 | #define _OPERATOR_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #endif // _OPERATOR_H 18 | -------------------------------------------------------------------------------- /src/include/operator/arithmetic.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_ARITHMETIC_H 2 | #define _OPERATOR_ARITHMETIC_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int operator_add(FRAME *Frame, VALUE *Value); 10 | 11 | int operator_div(FRAME *Frame, VALUE *Value); 12 | 13 | int operator_mod(FRAME *Frame, VALUE *Value); 14 | 15 | int operator_mul(FRAME *Frame, VALUE *Value); 16 | 17 | int operator_sub(FRAME *Frame, VALUE *Value); 18 | 19 | 20 | #endif // _OPERATOR_ARITHMETIC_H 21 | -------------------------------------------------------------------------------- /src/include/operator/boolean.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_BOOLEAN_H 2 | #define _OPERATOR_BOOLEAN_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | int operator_boolean(RUNTIME_CONTEXT *Context, SYMBOL *Symbol); 9 | 10 | 11 | #endif // _OPERATOR_BOOLEAN_H 12 | -------------------------------------------------------------------------------- /src/include/operator/call.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_CALL_H 2 | #define _OPERATOR_CALL_H 3 | 4 | 5 | #include 6 | 7 | 8 | int operator_call(RUNTIME_CONTEXT *Context); 9 | 10 | 11 | #endif // _OPERATOR_CALL_H 12 | -------------------------------------------------------------------------------- /src/include/operator/comparison.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_COMPARISON_H 2 | #define _OPERATOR_COMPARISON_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int operator_eq(FRAME *Frame, VALUE *Value); 10 | 11 | int operator_ge(FRAME *Frame, VALUE *Value); 12 | 13 | int operator_gt(FRAME *Frame, VALUE *Value); 14 | 15 | int operator_le(FRAME *Frame, VALUE *Value); 16 | 17 | int operator_lt(FRAME *Frame, VALUE *Value); 18 | 19 | int operator_ne(FRAME *Frame, VALUE *Value); 20 | 21 | 22 | #endif // _OPERATOR_COMPARISON_H 23 | -------------------------------------------------------------------------------- /src/include/operator/inputs.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_INPUTS_H 2 | #define _OPERATOR_INPUTS_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int operator_inputs(RUNTIME_CONTEXT *Context, SYMBOL *Symbol, VALUE *Value); 11 | 12 | 13 | #endif // _OPERATOR_INPUTS_H 14 | -------------------------------------------------------------------------------- /src/include/operator/jump.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_JUMP_H 2 | #define _OPERATOR_JUMP_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int operator_jump(FRAME *Frame, VALUE *Value); 10 | 11 | 12 | #endif // _OPERATOR_JUMP_H 13 | -------------------------------------------------------------------------------- /src/include/operator/logical.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_LOGICAL_H 2 | #define _OPERATOR_LOGICAL_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int operator_and(FRAME *Frame, VALUE *Value); 10 | 11 | int operator_not(FRAME *Frame, VALUE *Value); 12 | 13 | int operator_or(FRAME *Frame, VALUE *Value); 14 | 15 | int operator_xor(FRAME *Frame, VALUE *Value); 16 | 17 | 18 | #endif // _OPERATOR_LOGICAL_H 19 | -------------------------------------------------------------------------------- /src/include/operator/operand.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_OPERAND_H 2 | #define _OPERATOR_OPERAND_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int operand_invert(FRAME *Frame, VALUE *Value); 10 | 11 | int operand_subrange(VALUE *Value, VALUE *Range); 12 | 13 | 14 | #endif // _OPERATOR_OPERAND_H 15 | -------------------------------------------------------------------------------- /src/include/operator/parameter.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_PARAMETER_H 2 | #define _OPERATOR_PARAMETER_H 3 | 4 | 5 | #include 6 | 7 | int operator_parameter(RUNTIME_CONTEXT *Context); 8 | 9 | 10 | #endif // _OPERATOR_PARAMETER_H 11 | -------------------------------------------------------------------------------- /src/include/operator/return.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPERATOR_RETURN_H 2 | #define _OPERATOR_RETURN_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | void operator_return(FRAME *Frame); 10 | 11 | 12 | #endif // _OPERATOR_RETURN_H 13 | -------------------------------------------------------------------------------- /src/include/parameter.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARAMETER_H 2 | #define _PARAMETER_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #define parameter_read_values(...) _parameter_read_values(_NARG(__VA_ARGS__), __VA_ARGS__) 12 | 13 | #define parameter_write_values(...) _parameter_write_values(_NARG(__VA_ARGS__), __VA_ARGS__) 14 | 15 | 16 | typedef struct _ECHIDNA ECHIDNA; 17 | 18 | 19 | /* 20 | The following data structure is employed for the passing of parameters to 21 | functions and function blocks. 22 | */ 23 | 24 | typedef struct _PARAMETER { 25 | 26 | const char * Name; 27 | 28 | VALUE Value; 29 | } 30 | PARAMETER; 31 | 32 | 33 | int _parameter_read_values(size_t Arg, ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, ...); 34 | 35 | int _parameter_write_values(size_t Arg, ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, ...); 36 | 37 | void parameter_destroy(void *Arg); 38 | 39 | int parameter_read(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, const char *Name, VALUE *Value); 40 | 41 | int parameter_write(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, const char *Name, VALUE *Value); 42 | 43 | PARAMETER * parameter_new(PARAMETER *Parameter); 44 | 45 | 46 | #endif // _PARAMETER_H 47 | -------------------------------------------------------------------------------- /src/include/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef _PARSE_H 2 | #define _PARSE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | typedef struct _ECHIDNA ECHIDNA; 13 | 14 | typedef struct _LEXER_TOKEN LEXER_TOKEN; 15 | 16 | typedef struct _PARSE { 17 | 18 | TREE Identifiers; 19 | 20 | TOKEN_LIST Tokens; 21 | 22 | TOKEN_LIST Parse; 23 | 24 | char * File; 25 | 26 | TOKEN * Configuration; 27 | 28 | TOKEN * Resource; 29 | 30 | TOKEN * POU; 31 | 32 | uint8_t Identifier; 33 | 34 | uint8_t Preparse; 35 | 36 | uint8_t State; 37 | 38 | VALUE_TYPE Type; 39 | } 40 | PARSE; 41 | 42 | 43 | void parse_destroy(PARSE *Parse); 44 | 45 | int parse_file(ECHIDNA *Context, char *Path); 46 | 47 | int parse_initialise(ECHIDNA *Context, PARSE *Parse); 48 | 49 | void parse_reset(ECHIDNA *Context, PARSE *Parse); 50 | 51 | int parse_register(PARSE *Parse, int Id, char *Name); 52 | 53 | int parse_register_scope(PARSE *Parse, int Id, char *Name); 54 | 55 | char * parse_scope(PARSE *Parse, char *Name); 56 | 57 | LEXER_TOKEN * parse_search(PARSE *Parse, char *Name); 58 | 59 | 60 | #endif /* _PARSE_H */ 61 | -------------------------------------------------------------------------------- /src/include/protobuf.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOBUF_H 2 | #define _PROTOBUF_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #endif /* _PROTOBUF_H */ 13 | 14 | -------------------------------------------------------------------------------- /src/include/protobuf/file.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOBUF_FILE_H 2 | #define _PROTOBUF_FILE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | PROTOBUF_C__BEGIN_DECLS 13 | 14 | 15 | #define PROTOBUF_FILE_INITIALISE { PROTOBUF_C_MESSAGE_INIT(&PROTOBUF_FILE_DESCRIPTOR), 61131u, 0u, 0, NULL, 0, NULL, 0, NULL } 16 | 17 | 18 | typedef struct _PROTOBUF_FILE { 19 | 20 | ProtobufCMessage Base; 21 | uint32_t Magic; 22 | uint32_t Format; 23 | size_t Symbols; 24 | PROTOBUF_SYMBOL **Symbol; 25 | size_t POUs; 26 | PROTOBUF_POU **POU; 27 | size_t Configs; 28 | PROTOBUF_CONFIG **Config; 29 | } 30 | PROTOBUF_FILE; 31 | 32 | extern const ProtobufCMessageDescriptor PROTOBUF_FILE_DESCRIPTOR; 33 | 34 | 35 | PROTOBUF_FILE * protobuf_file_create(ECHIDNA *Context); 36 | 37 | void protobuf_file_free(PROTOBUF_FILE *File, ProtobufCAllocator *Alloc); 38 | 39 | void protobuf_file_initialise(PROTOBUF_FILE *File); 40 | 41 | size_t protobuf_file_pack(PROTOBUF_FILE *File, uint8_t *Data); 42 | 43 | size_t protobuf_file_size(PROTOBUF_FILE *File); 44 | 45 | PROTOBUF_FILE * protobuf_file_unpack(ProtobufCAllocator *Alloc, size_t Length, const uint8_t *Data); 46 | 47 | 48 | PROTOBUF_C__END_DECLS 49 | 50 | 51 | #endif // _PROTOBUF_FILE_H 52 | -------------------------------------------------------------------------------- /src/include/protobuf/pou.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOBUF_POU_H 2 | #define _PROTOBUF_POU_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | PROTOBUF_C__BEGIN_DECLS 11 | 12 | 13 | #define PROTOBUF_POU_INITIALISE { PROTOBUF_C_MESSAGE_INIT(&PROTOBUF_POU_DESCRIPTOR), NULL, 0, { 0, NULL } } 14 | 15 | 16 | typedef struct _PROTOBUF_POU { 17 | 18 | ProtobufCMessage Base; 19 | char *Name; 20 | uint32_t Type; 21 | ProtobufCBinaryData Code; 22 | } 23 | PROTOBUF_POU; 24 | 25 | extern const ProtobufCMessageDescriptor PROTOBUF_POU_DESCRIPTOR; 26 | 27 | 28 | PROTOBUF_POU * protobuf_pou_create(UNIT *Unit); 29 | 30 | void protobuf_pou_free(PROTOBUF_POU *POU, ProtobufCAllocator *Alloc); 31 | 32 | void protobuf_pou_initialise(PROTOBUF_POU *POU); 33 | 34 | size_t protobuf_pou_pack(PROTOBUF_POU *POU, uint8_t *Data); 35 | 36 | size_t protobuf_pou_size(PROTOBUF_POU *POU); 37 | 38 | PROTOBUF_POU * protobuf_pou_unpack(ProtobufCAllocator *Alloc, size_t Length, const uint8_t *Data); 39 | 40 | 41 | PROTOBUF_C__END_DECLS 42 | 43 | 44 | #endif // _PROTOBUF_POU_H 45 | -------------------------------------------------------------------------------- /src/include/protobuf/symbol.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOBUF_SYMBOL_H 2 | #define _PROTOBUF_SYMBOL_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | PROTOBUF_C__BEGIN_DECLS 12 | 13 | 14 | #define PROTOBUF_SYMBOL_INITIALISE { PROTOBUF_C_MESSAGE_INIT(&PROTOBUF_SYMBOL_DESCRIPTOR), 0, 0, NULL, NULL, NULL, NULL, NULL } 15 | 16 | 17 | typedef struct _PROTOBUF_SYMBOL { 18 | 19 | ProtobufCMessage Base; 20 | uint32_t Id; 21 | uint32_t Offset; 22 | PROTOBUF_VALUE *Value; 23 | char *Name; 24 | char *POU; 25 | char *Resource; 26 | char *Configuration; 27 | } 28 | PROTOBUF_SYMBOL; 29 | 30 | extern const ProtobufCMessageDescriptor PROTOBUF_SYMBOL_DESCRIPTOR; 31 | 32 | 33 | PROTOBUF_SYMBOL * protobuf_symbol_create(SYMBOL *Symbol); 34 | 35 | void protobuf_symbol_free(PROTOBUF_SYMBOL *Symbol, ProtobufCAllocator *Alloc); 36 | 37 | void protobuf_symbol_initialise(PROTOBUF_SYMBOL *Symbol); 38 | 39 | size_t protobuf_symbol_pack(PROTOBUF_SYMBOL *Symbol, uint8_t *Data); 40 | 41 | size_t protobuf_symbol_size(PROTOBUF_SYMBOL *Symbol); 42 | 43 | PROTOBUF_SYMBOL * protobuf_symbol_unpack(ProtobufCAllocator *Alloc, size_t Length, const uint8_t *Data); 44 | 45 | 46 | PROTOBUF_C__END_DECLS 47 | 48 | 49 | #endif // _PROTOBUF_SYMBOL_H 50 | -------------------------------------------------------------------------------- /src/include/protobuf/value.h: -------------------------------------------------------------------------------- 1 | #ifndef _PROTOBUF_VALUE_H 2 | #define _PROTOBUF_VALUE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | PROTOBUF_C__BEGIN_DECLS 10 | 11 | 12 | #define PROTOBUF_INDEX_INITIALISE { PROTOBUF_C_MESSAGE_INIT(&PROTOBUF_INDEX_DESCRIPTOR), 0, 0 } 13 | 14 | #define PROTOBUF_VALUE_INITIALISE { PROTOBUF_C_MESSAGE_INIT(&PROTOBUF_VALUE_DESCRIPTOR), 0, 0, 0, 0, { 0, NULL }, 0, {0, NULL }, { 0, NULL }, 0, { 0, NULL }, NULL } 15 | 16 | 17 | typedef struct _PROTOBUF_INDEX { 18 | 19 | ProtobufCMessage Base; 20 | int32_t Lower; 21 | int32_t Upper; 22 | } 23 | PROTOBUF_INDEX; 24 | 25 | typedef struct _PROTOBUF_VALUE { 26 | 27 | ProtobufCMessage Base; 28 | uint32_t Type; 29 | int32_t Length; 30 | uint32_t Flags; 31 | protobuf_c_boolean IncludeMaximum; 32 | ProtobufCBinaryData Maximum; 33 | protobuf_c_boolean IncludeMinimum; 34 | ProtobufCBinaryData Minimum; 35 | ProtobufCBinaryData Value; 36 | protobuf_c_boolean IncludeMeta; 37 | ProtobufCBinaryData Meta; 38 | PROTOBUF_INDEX *Array; 39 | } 40 | PROTOBUF_VALUE; 41 | 42 | extern const ProtobufCMessageDescriptor PROTOBUF_INDEX_DESCRIPTOR; 43 | 44 | extern const ProtobufCMessageDescriptor PROTOBUF_VALUE_DESCRIPTOR; 45 | 46 | 47 | PROTOBUF_VALUE * protobuf_value_create(VALUE *Value); 48 | 49 | void protobuf_value_free(PROTOBUF_VALUE *Value, ProtobufCAllocator *Alloc); 50 | 51 | void protobuf_value_initialise(PROTOBUF_VALUE *Value); 52 | 53 | size_t protobuf_value_pack(PROTOBUF_VALUE *Value, uint8_t *Data); 54 | 55 | size_t protobuf_value_size(PROTOBUF_VALUE *Value); 56 | 57 | PROTOBUF_VALUE * protobuf_value_unpack(ProtobufCAllocator *Alloc, size_t Length, const uint8_t *Data); 58 | 59 | 60 | PROTOBUF_C__END_DECLS 61 | 62 | #endif // _PROTOBUF_VALUE_H 63 | -------------------------------------------------------------------------------- /src/include/queue.h: -------------------------------------------------------------------------------- 1 | #ifndef _QUEUE_H 2 | #define _QUEUE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | #define queue_destroy(...) _queue_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 11 | 12 | #define queue_initialise(...) _queue_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 13 | 14 | #define queue_push(...) _queue_push(_NARG(__VA_ARGS__), __VA_ARGS__) 15 | 16 | #define queue_size(...) _queue_size(_NARG(__VA_ARGS__), __VA_ARGS__) 17 | 18 | 19 | typedef int (*_QUEUE_COMPARE)(const void *pA, const void *pB); 20 | 21 | typedef void (*_QUEUE_DESTROY)(void *pArg); 22 | 23 | typedef struct _QUEUE { 24 | 25 | _QUEUE_COMPARE Compare; 26 | 27 | _QUEUE_DESTROY Destroy; 28 | 29 | void ** Queue; 30 | 31 | size_t Count; 32 | 33 | size_t Size; 34 | 35 | uint8_t Alloc; 36 | } 37 | QUEUE; 38 | 39 | 40 | void _queue_destroy(size_t Arg, QUEUE *Queue, ...); 41 | 42 | void _queue_initialise(size_t Arg, QUEUE *Queue, ...); 43 | 44 | int _queue_push(size_t Arg, QUEUE *Queue, ...); 45 | 46 | size_t _queue_size(size_t Arg, QUEUE *Queue, ...); 47 | 48 | QUEUE * queue_new(void); 49 | 50 | void * queue_peek(QUEUE *Queue); 51 | 52 | void * queue_pop(QUEUE *Queue); 53 | 54 | 55 | #endif /* _QUEUE_H */ 56 | -------------------------------------------------------------------------------- /src/include/runtime/bytecode.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_BYTECODE_H 2 | #define _RUNTIME_BYTECODE_H 3 | 4 | 5 | #include 6 | 7 | 8 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 9 | 10 | 11 | int runtime_bytecode_execute(RUNTIME_CONTEXT *Context); 12 | 13 | int runtime_bytecode_operand(FRAME *Frame); 14 | 15 | 16 | #endif // _RUNTIME_BYTECODE_H 17 | -------------------------------------------------------------------------------- /src/include/runtime/call.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_CALL_H 2 | #define _RUNTIME_CALL_H 3 | 4 | 5 | #include 6 | 7 | 8 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 9 | 10 | typedef struct _RT_FUNCTION RT_FUNCTION; 11 | 12 | 13 | RT_FUNCTION * runtime_call_instance(RUNTIME_CONTEXT *Context); 14 | 15 | 16 | #endif // _RUNTIME_CALL_H 17 | -------------------------------------------------------------------------------- /src/include/runtime/context.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_CONTEXT_H 2 | #define _RUNTIME_CONTEXT_H 3 | 4 | 5 | typedef struct _RUNTIME RUNTIME; 6 | 7 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 8 | 9 | 10 | void runtime_context_destroy(void *Arg); 11 | 12 | void runtime_context_initialise(RUNTIME_CONTEXT *Context, RUNTIME *Run); 13 | 14 | RUNTIME_CONTEXT * runtime_context_new(RUNTIME *Run); 15 | 16 | 17 | #endif // _RUNTIME_CONTEXT_H 18 | -------------------------------------------------------------------------------- /src/include/runtime/error.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_ERROR_H 2 | #define _RUNTIME_ERROR_H 3 | 4 | 5 | typedef enum _RUNTIME_ERROR { 6 | 7 | RT_ERR_NONE = 0, 8 | RT_ERR_INTERNAL, 9 | RT_ERR_INTERNAL_ALLOCATION, 10 | RT_ERR_INTERNAL_READ, 11 | RT_ERR_INTERNAL_WRITE, 12 | RT_ERR_INVALID_BYTECODE, 13 | RT_ERR_INVALID_SYMBOL, 14 | RT_ERR_INVALID_FUNCTION, 15 | RT_ERR_INVALID_LENGTH, 16 | RT_ERR_DIVIDE_ZERO, 17 | RT_ERR_MODULUS_ZERO, 18 | RT_ERR_MATH_OVERFLOW, 19 | RT_ERR_OPERAND_TYPE, 20 | RT_ERR_PARAMETER_COUNT, 21 | RT_ERR_PARAMETER_MISMATCH, 22 | RT_ERR_PARAMETER_RANGE, 23 | RT_ERR_PARAMETER_TYPE, 24 | RT_ERR_PARAMETER_UNKNOWN, 25 | RT_ERR_STACK_OVERFLOW, 26 | RT_ERR_UNIMPLEMENTED, 27 | } 28 | RUNTIME_ERROR; 29 | 30 | 31 | const char * runtime_errortostr(int Error); 32 | 33 | 34 | #endif // _RUNTIME_ERROR_H 35 | -------------------------------------------------------------------------------- /src/include/runtime/exit.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_EXIT_H 2 | #define _RUNTIME_EXIT_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | int runtime_exit(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 10 | 11 | 12 | #endif // _RUNTIME_EXIT_H 13 | -------------------------------------------------------------------------------- /src/include/runtime/function.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_FUNCTION_H 2 | #define _RUNTIME_FUNCTION_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | typedef struct _ECHIDNA ECHIDNA; 14 | 15 | typedef struct _RT_FUNCTION RT_FUNCTION; 16 | 17 | 18 | int runtime_function(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int runtime_function_block(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, void *User); 21 | 22 | void runtime_function_destroy(void *Arg); 23 | 24 | RT_FUNCTION * runtime_function_new(VALUE_TYPE Type, UNIT *POU, uint32_t PC); 25 | 26 | 27 | #endif // _RUNTIME_FUNCTION_H 28 | -------------------------------------------------------------------------------- /src/include/runtime/parameter.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_PARAMETER_H 2 | #define _RUNTIME_PARAMETER_H 3 | 4 | 5 | typedef struct _RUNTIME_PARAMETER RUNTIME_PARAMETER; 6 | 7 | 8 | void runtime_parameter_destroy(void *Arg); 9 | 10 | RUNTIME_PARAMETER * runtime_parameter_new(void); 11 | 12 | 13 | #endif // _RUNTIME_PARAMETER_H 14 | -------------------------------------------------------------------------------- /src/include/runtime/task.h: -------------------------------------------------------------------------------- 1 | #ifndef _RUNTIME_TASK_H 2 | #define _RUNTIME_TASK_H 3 | 4 | 5 | #include 6 | 7 | 8 | typedef struct _RUNTIME RUNTIME; 9 | 10 | typedef struct _RUNTIME_CONTEXT RUNTIME_CONTEXT; 11 | 12 | 13 | void runtime_task_callback(struct ev_loop *Loop, ev_timer *Timer, int Events); 14 | 15 | int runtime_task_interval(RUNTIME *Run, RUNTIME_CONTEXT *Context); 16 | 17 | void runtime_task_limit(RUNTIME *Run, RUNTIME_CONTEXT *Context); 18 | 19 | int runtime_task_single(RUNTIME *Run, RUNTIME_CONTEXT *Context); 20 | 21 | void runtime_task_stop(RUNTIME *Run, RUNTIME_CONTEXT *Context); 22 | 23 | 24 | #endif // _RUNTIME_TASK_H 25 | -------------------------------------------------------------------------------- /src/include/sha256.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHA256_H 2 | #define _SHA256_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | 9 | #define SHA256_BE32_GET(x) \ 10 | ((((uint32_t)(x)[0]) << 24) | \ 11 | (((uint32_t)(x)[1]) << 16) | \ 12 | (((uint32_t)(x)[2]) << 8) | \ 13 | ((uint32_t)(x)[3])) 14 | 15 | #define SHA256_BE32_PUT(a, x) \ 16 | do { \ 17 | (a)[0] = (uint8_t)((((uint32_t)(x)) >> 24) & 0xff); \ 18 | (a)[1] = (uint8_t)((((uint32_t)(x)) >> 16) & 0xff); \ 19 | (a)[2] = (uint8_t)((((uint32_t)(x)) >> 8) & 0xff); \ 20 | (a)[3] = (uint8_t)(((uint32_t)(x)) & 0xff); \ 21 | } while(0) 22 | 23 | #define SHA256_BE64_GET(x) 24 | 25 | #define SHA256_BE64_PUT(a, x) \ 26 | do { \ 27 | (a)[0] = (uint8_t)(((uint64_t)(x)) >> 56); \ 28 | (a)[1] = (uint8_t)(((uint64_t)(x)) >> 48); \ 29 | (a)[2] = (uint8_t)(((uint64_t)(x)) >> 40); \ 30 | (a)[3] = (uint8_t)(((uint64_t)(x)) >> 32); \ 31 | (a)[4] = (uint8_t)(((uint64_t)(x)) >> 24); \ 32 | (a)[5] = (uint8_t)(((uint64_t)(x)) >> 16); \ 33 | (a)[6] = (uint8_t)(((uint64_t)(x)) >> 8); \ 34 | (a)[7] = (uint8_t)(((uint64_t)(x)) & 0xff); \ 35 | } while(0) 36 | 37 | 38 | typedef struct _SHA256 { 39 | 40 | uint8_t Buffer[64]; 41 | 42 | uint32_t Current; 43 | 44 | uint64_t Length; 45 | 46 | uint32_t State[8]; 47 | } 48 | SHA256; 49 | 50 | 51 | void sha256_final(SHA256 *Digest, char *Buffer); 52 | 53 | void sha256_initialise(SHA256 *Digest); 54 | 55 | void sha256_update(SHA256 *Digest, const char *Data, size_t Length); 56 | 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/include/standard.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_H 2 | #define _STANDARD_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | typedef struct _ECHIDNA ECHIDNA; 17 | 18 | 19 | int standard_initialise(ECHIDNA *Context); 20 | 21 | 22 | #endif /* _STANDARD_H */ 23 | -------------------------------------------------------------------------------- /src/include/standard/arithmetic.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_ARITHMETIC_H 2 | #define _STANDARD_ARITHMETIC_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_add(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_sub(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_mul(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_div(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_mod(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int standard_expt(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 21 | 22 | int standard_move(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 23 | 24 | 25 | #endif // _STANDARD_ARITHMETIC_H 26 | -------------------------------------------------------------------------------- /src/include/standard/bitstring.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_BITSTRING_H 2 | #define _STANDARD_BITSTRING_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_rol(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_ror(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_shl(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_shr(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | 19 | #endif // _STANDARD_BITSTRING_H 20 | -------------------------------------------------------------------------------- /src/include/standard/bitwise.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_BITWISE_H 2 | #define _STANDARD_BITWISE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_and(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_or(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_xor(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | 17 | #endif // _STANDARD_BITWISE_H 18 | -------------------------------------------------------------------------------- /src/include/standard/comparison.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_COMPARISON_H 2 | #define _STANDARD_COMPARISON_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_eq(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_ge(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_gt(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_le(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_lt(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int standard_ne(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 21 | 22 | 23 | #endif // _STANDARD_COMPARISON_H 24 | -------------------------------------------------------------------------------- /src/include/standard/fb.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_FB_H 2 | #define _STANDARD_FB_H 3 | 4 | 5 | typedef struct _ECHIDNA ECHIDNA; 6 | 7 | 8 | int standard_bistable(ECHIDNA *Context); 9 | 10 | int standard_counters(ECHIDNA *Context); 11 | 12 | int standard_edge(ECHIDNA *Context); 13 | 14 | int standard_rtc(ECHIDNA *Context); 15 | 16 | int standard_timers(ECHIDNA *Context); 17 | 18 | 19 | #endif // _STANDARD_FB_H 20 | -------------------------------------------------------------------------------- /src/include/standard/numeric.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_NUMERIC_H 2 | #define _STANDARD_NUMERIC_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_abs(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_acos(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_asin(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_atan(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_cos(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int standard_exp(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 21 | 22 | int standard_ln(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 23 | 24 | int standard_log(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 25 | 26 | int standard_sin(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 27 | 28 | int standard_sqrt(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 29 | 30 | int standard_tan(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 31 | 32 | 33 | #endif // _STANDARD_NUMERIC_H 34 | -------------------------------------------------------------------------------- /src/include/standard/select.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_SELECT_H 2 | #define _STANDARD_SELECT_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_limit(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_max(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_min(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_mux(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_sel(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | 21 | #endif // _STANDARD_SELECT_H 22 | -------------------------------------------------------------------------------- /src/include/standard/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_STRING_H 2 | #define _STANDARD_STRING_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_concat(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_delete(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_find(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_insert(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_left(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int standard_len(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 21 | 22 | int standard_mid(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 23 | 24 | int standard_replace(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 25 | 26 | int standard_right(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 27 | 28 | 29 | #endif // _STANDARD_STRING_H 30 | -------------------------------------------------------------------------------- /src/include/standard/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_TIME_H 2 | #define _STANDARD_TIME_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_add_dttime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_add_time(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_add_todtime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | int standard_concat_datetod(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 17 | 18 | int standard_divtime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 19 | 20 | int standard_multime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 21 | 22 | int standard_sub_datedate(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 23 | 24 | int standard_sub_dtdt(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 25 | 26 | int standard_sub_dttime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 27 | 28 | int standard_sub_time(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 29 | 30 | int standard_sub_todtime(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 31 | 32 | int standard_sub_todtod(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 33 | 34 | 35 | #endif // _STANDARD_TIME_H 36 | -------------------------------------------------------------------------------- /src/include/standard/type.h: -------------------------------------------------------------------------------- 1 | #ifndef _STANDARD_TYPE_H 2 | #define _STANDARD_TYPE_H 3 | 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | int standard_bcd(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 11 | 12 | int standard_trunc(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 13 | 14 | int standard_type(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User); 15 | 16 | 17 | #endif // _STANDARD_TYPE_H 18 | -------------------------------------------------------------------------------- /src/include/stats.h: -------------------------------------------------------------------------------- 1 | #ifndef _STATS_H 2 | #define _STATS_H 3 | 4 | 5 | #include 6 | 7 | 8 | typedef struct _STATS { 9 | 10 | uint64_t Cycle; 11 | 12 | uint64_t Overrun; 13 | 14 | double Start; 15 | 16 | double Latency; 17 | 18 | double Execution; 19 | 20 | double LatencyStart; 21 | 22 | double LatencyEnd; 23 | 24 | double Maximum; 25 | 26 | double ExecutionStart; 27 | 28 | /* double ExecutionEnd; */ 29 | } 30 | STATS; 31 | 32 | 33 | void stats_initialise(STATS *Stats); 34 | 35 | 36 | #endif /* _STATS_H */ 37 | -------------------------------------------------------------------------------- /src/include/strl.h: -------------------------------------------------------------------------------- 1 | #ifndef _STRL_H 2 | #define _STRL_H 3 | 4 | 5 | #include 6 | 7 | 8 | size_t strlcat(char *dst, const char *src, size_t dsize); 9 | 10 | size_t strlcpy(char *dst, const char *src, size_t dsize); 11 | 12 | 13 | #endif // _STRL_H 14 | -------------------------------------------------------------------------------- /src/include/symbol.h: -------------------------------------------------------------------------------- 1 | #ifndef _SYMBOL_H 2 | #define _SYMBOL_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #define SYMBOL_NAME_MAX (255) 15 | 16 | /* 17 | The following define specifies the depth of the stack to be used when 18 | attempting to resolve the size required within the symbol table for each 19 | program organisation unit. 20 | */ 21 | 22 | #define SYMBOL_STACK_MAX (16) 23 | 24 | #define symbol_build_path(...) _symbol_build_path(_NARG(__VA_ARGS__), __VA_ARGS__) 25 | 26 | #define symbol_split_path(...) _symbol_split_path(_NARG(__VA_ARGS__), __VA_ARGS__) 27 | 28 | #define symbol_table_initialise(...) _symbol_table_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 29 | 30 | #define symbol_table_iterate(...) _symbol_table_iterate(_NARG(__VA_ARGS__), __VA_ARGS__) 31 | 32 | 33 | typedef struct _ECHIDNA ECHIDNA; 34 | 35 | typedef struct _SYMBOL { 36 | 37 | char * Name; 38 | 39 | char * POU; 40 | 41 | char * Resource; 42 | 43 | char * Configuration; 44 | 45 | char * Path; 46 | 47 | int32_t Id; 48 | 49 | int32_t Offset; 50 | 51 | int32_t Ref; // TODO: Suppress inclusion in symbol table based on reference count 52 | 53 | VALUE Value; 54 | 55 | /* 56 | The following members of this data structure are employed in association with 57 | instances of function blocks. 58 | */ 59 | 60 | FUNCTION_REGISTER * Function; 61 | 62 | void * Context; 63 | } 64 | SYMBOL; 65 | 66 | typedef struct _SYMBOLS { 67 | 68 | SYMBOL ** Symbol; 69 | 70 | size_t Count; 71 | 72 | size_t Index; 73 | 74 | size_t Size; 75 | } 76 | SYMBOLS; 77 | 78 | typedef struct _SYMBOL_STACK { 79 | 80 | uint32_t Index; 81 | 82 | size_t Size; 83 | 84 | char * POU; 85 | 86 | SYMBOL * Symbol; 87 | } 88 | SYMBOL_STACK; 89 | 90 | 91 | char * _symbol_build_path(size_t Arg, ...); 92 | 93 | int _symbol_offset(size_t Arg, PARSE *Parse, ...); 94 | 95 | int _symbol_split_path(size_t Arg, char *Path, ...); 96 | 97 | int _symbol_table_initialise(size_t Arg, ECHIDNA *Context, ...); 98 | 99 | SYMBOL * _symbol_table_iterate(size_t Arg, ECHIDNA *Context, ...); 100 | 101 | void symbol_destroy(ECHIDNA *Context, SYMBOL *Symbol); 102 | 103 | int symbol_insert(ECHIDNA *Context, char *Config, char *Resource, char *POU, char *Name, VALUE *Value); 104 | 105 | SYMBOL * symbol_search(ECHIDNA *Context, char *Config, char *Resource, char *POU, char *Name); 106 | 107 | int symbol_table_build(ECHIDNA *Context); 108 | 109 | void symbol_table_destroy(ECHIDNA *Context); 110 | 111 | void symbol_table_reset(ECHIDNA *Context); 112 | 113 | unsigned int symbol_table_size(ECHIDNA *Context); 114 | 115 | 116 | #endif /* _SYMBOL_H */ 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/include/token.h: -------------------------------------------------------------------------------- 1 | #ifndef _TOKEN_H 2 | #define _TOKEN_H 3 | 4 | /* 5 | This header file and corresponding source are intended to implement the 6 | primary data structures and functions used when parsing source files. This 7 | implementation greatly simplifies that implemented within the master branch 8 | by reducing the number of token types to merely two - TOKEN and LIST. 9 | */ 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | #define token_cast(...) _token_cast(_NARG(__VA_ARGS__), __VA_ARGS__) 20 | 21 | #define token_destroy(...) _token_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 22 | 23 | #define token_list_cast(...) _token_list_cast(_NARG(__VA_ARGS__), __VA_ARGS__) 24 | 25 | #define token_list_insert(...) _token_list_insert(_NARG(__VA_ARGS__), __VA_ARGS__) 26 | 27 | #define token_list_merge(...) _token_list_merge(_NARG(__VA_ARGS__), __VA_ARGS__) 28 | 29 | #define token_list_new(...) _token_list_new(_NARG(__VA_ARGS__), __VA_ARGS__) 30 | 31 | #define token_new(...) _token_new(_NARG(__VA_ARGS__), __VA_ARGS__) 32 | 33 | #define TOKEN_NAME(x) ((x) ? (((TOKEN *) (x))->Name) : NULL) 34 | 35 | 36 | typedef enum { 37 | TYPE_TOKEN, 38 | TYPE_LIST, 39 | } 40 | TOKEN_TYPE; 41 | 42 | typedef struct _TOKEN { 43 | 44 | TOKEN_TYPE Type; 45 | 46 | uint8_t Alloc; 47 | 48 | uint32_t Id; 49 | 50 | uint32_t Line; 51 | 52 | uint32_t Column; 53 | 54 | char * Name; 55 | 56 | void * Scope; 57 | 58 | VALUE Value; 59 | } 60 | TOKEN; 61 | 62 | typedef struct _TOKEN_LIST { 63 | 64 | TOKEN Token; 65 | 66 | LL List; 67 | } 68 | TOKEN_LIST; 69 | 70 | 71 | TOKEN * _token_cast(size_t Arg, TOKEN *Token, uint32_t Id, ...); 72 | 73 | void _token_destroy(size_t Arg, ...); 74 | 75 | TOKEN_LIST * _token_list_cast(size_t Arg, TOKEN_LIST *List, uint32_t Id, ...); 76 | 77 | void _token_list_destroy(size_t Arg, ...); 78 | 79 | int _token_list_insert(size_t Arg, TOKEN_LIST *List, void *Item, ...); 80 | 81 | void _token_list_merge(size_t Arg, TOKEN_LIST *List, ...); 82 | 83 | TOKEN_LIST * _token_list_new(size_t Arg, ...); 84 | 85 | TOKEN * _token_new(size_t Arg, ...); 86 | 87 | void token_initialise(TOKEN *Token); 88 | 89 | TOKEN_LIST * token_list_convert(TOKEN *Token); 90 | 91 | void token_list_initialise(TOKEN_LIST *List); 92 | 93 | TOKEN * token_list_iterate(TOKEN_LIST *List); 94 | 95 | void token_list_reset(TOKEN_LIST *List); 96 | 97 | int token_list_unique(TOKEN_LIST *List); 98 | 99 | 100 | 101 | #endif /* _TOKEN_H */ 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/include/tree.h: -------------------------------------------------------------------------------- 1 | #ifndef _TREE_H 2 | #define _TREE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | #define TREE_PATH_MAX (128) 11 | 12 | #define tree_destroy(...) _tree_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 13 | 14 | #define tree_initialise(...) _tree_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 15 | 16 | #define tree_insert(...) _tree_insert(_NARG(__VA_ARGS__), __VA_ARGS__) 17 | 18 | #define tree_node_destroy(...) _tree_node_destroy(_NARG(__VA_ARGS__), __VA_ARGS__) 19 | 20 | 21 | typedef int (*_TREE_COMPARE)(void *A, void *B); 22 | 23 | typedef void (*_TREE_DESTROY)(void *Arg); 24 | 25 | typedef struct _TREE_NODE { 26 | 27 | int Direction; 28 | 29 | struct _TREE_NODE * Node[2]; 30 | 31 | void * Data; 32 | } 33 | TREE_NODE; 34 | 35 | typedef struct _TREE { 36 | 37 | struct _TREE_NODE * Root; 38 | 39 | _TREE_COMPARE Compare; 40 | 41 | _TREE_DESTROY Destroy; 42 | 43 | size_t Size; 44 | 45 | uint8_t Alloc; 46 | } 47 | TREE; 48 | 49 | typedef struct _TREE_ITER { 50 | 51 | TREE * Tree; 52 | 53 | TREE_NODE * Node; 54 | 55 | TREE_NODE * Path[TREE_PATH_MAX]; 56 | 57 | size_t Top; 58 | } 59 | TREE_ITER; 60 | 61 | 62 | void _tree_destroy(size_t Arg, TREE *Tree, ...); 63 | 64 | void _tree_initialise(size_t Arg, TREE *Tree, ...); 65 | 66 | int _tree_insert(size_t Arg, TREE *Tree, ...); 67 | 68 | void * tree_iterate(TREE_ITER *Iter); 69 | 70 | void * tree_iterate_first(TREE_ITER *Iter, TREE *Tree); 71 | 72 | void * tree_iterate_last(TREE_ITER *Iter, TREE *Tree); 73 | 74 | void * tree_iterate_next(TREE_ITER *Iter); 75 | 76 | void tree_iterate_reset(TREE_ITER *Iter, TREE *Tree); 77 | 78 | TREE_ITER * tree_iterate_new(TREE *Tree); 79 | 80 | void * tree_iterate_previous(TREE_ITER *Iter); 81 | 82 | TREE * tree_new(void); 83 | 84 | int tree_remove(TREE *Tree, void *Data); 85 | 86 | void * tree_search(TREE *Tree, void *Data); 87 | 88 | 89 | #endif /* _TREE_H */ 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/include/unit.h: -------------------------------------------------------------------------------- 1 | #ifndef _UNIT_H 2 | #define _UNIT_H 3 | 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | #define unit_initialise(...) _unit_initialise(_NARG(__VA_ARGS__), __VA_ARGS__) 14 | 15 | 16 | /* 17 | The following data structure has been created to represent and contain parameters 18 | and attributes associated with program organisation units (POUs). The block data 19 | structure was employed previously, but as the complexity of POU implementation 20 | increased, the requirements of representation surpassed that which could be 21 | readily accommodated by this generic data structure. 22 | */ 23 | 24 | typedef struct _UNIT { 25 | 26 | BLOCK Block; 27 | 28 | char * Config; 29 | 30 | char * Resource; 31 | 32 | char * POU; 33 | 34 | LL Symbols; 35 | 36 | size_t Size; 37 | 38 | uint8_t Alloc; 39 | } 40 | UNIT; 41 | 42 | 43 | void _unit_initialise(size_t Arg, UNIT *POU, ...); 44 | 45 | int unit_compare(void *A, void *B); 46 | 47 | UNIT * unit_create(char *Config, char *Resource, char *Name); 48 | 49 | void unit_destroy(void *Arg); 50 | 51 | UNIT * unit_new(void); 52 | 53 | 54 | #endif // _UNIT_H 55 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | #define _DEFAULT_SOURCE // Required for vsyslog since glibc 2.19 2 | 3 | #include 4 | #include 5 | #include 6 | #ifndef _MSC_VER 7 | #include 8 | #include 9 | #endif 10 | #include 11 | 12 | 13 | static char * _Level[] = { "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug" }; 14 | 15 | int log_level = LOG_DEBUG; 16 | 17 | 18 | void 19 | log_message(int Priority, const char *Format, ...) { 20 | FILE *pFile; 21 | va_list sArg; 22 | 23 | if(log_level == LOG_NONE) 24 | return; 25 | if(Priority <= log_level) { 26 | //pFile = (log_level <= LOG_ERR) ? stderr : stdout; 27 | pFile = stderr; 28 | va_start(sArg, Format); 29 | #ifndef _MSC_VER 30 | if(/* isatty(fileno(pFile)) */ 1) { 31 | #endif 32 | fprintf(pFile, "%s: ", _Level[Priority]); 33 | vfprintf(pFile, Format, sArg); 34 | fprintf(pFile, "\n"); 35 | fflush(pFile); 36 | #ifndef _MSC_VER 37 | } 38 | else 39 | vsyslog(Priority, Format, sArg); 40 | #endif 41 | va_end(sArg); 42 | } 43 | if(Priority == LOG_EMERG) 44 | exit(1); 45 | } 46 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | int 8 | main(int Count, char **Arg) { 9 | ECHIDNA sContext; 10 | int nResult; 11 | 12 | /* 13 | In passing the command-line arguments to the echidna_initialise function, 14 | all operations of library are initiated and executed based upon these 15 | arguments. If these arguments are _not_ passed to this function, file 16 | parsing, compilation and execution can be controlled programmatically 17 | through the functions exposed in the echidna.h header file. 18 | */ 19 | 20 | memset(&sContext, 0, sizeof(sContext)); 21 | nResult = echidna_initialise(&sContext, Count, Arg); 22 | echidna_destroy(&sContext); 23 | return nResult; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/operator/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= arithmetic.o boolean.o call.o comparison.o inputs.o jump.o logical.o operand.o parameter.o return.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/operator/op_boolean.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | int 13 | operator_boolean(RUNTIME_CONTEXT *Context, SYMBOL *Symbol) { 14 | RUNTIME *pRun; 15 | FRAME *pFrame; 16 | VALUE sValue; 17 | 18 | assert(Context != NULL); 19 | pRun = (RUNTIME *) Context->Parent; 20 | assert(pRun != NULL); 21 | 22 | pFrame = frame_current(Context); 23 | value_copy(&sValue, &pFrame->CR); 24 | value_cast(&sValue, TYPE_BOOL); 25 | 26 | if(sValue.Value.B1) { 27 | assert(Symbol != NULL); 28 | value_assign(&sValue, TYPE_BOOL, (pFrame->BC == BYTECODE_S)); 29 | memcpy(&pRun->Memory[Symbol->Offset], &sValue.Value.Pointer, sValue.Length); 30 | } 31 | 32 | return 0; 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/operator/op_jump.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | int 9 | operator_jump(FRAME *Frame, VALUE *Value) { 10 | uint8_t uValue; 11 | 12 | switch(Frame->BC & BYTECODE_MASK) { 13 | case BYTECODE_JMPC: 14 | case BYTECODE_JMPCN: 15 | 16 | /* 17 | The modifier "C" indicates that the associated instruction shall be performed 18 | only if the value of the currently evaluated result is Boolean 1 (or Boolean 0 19 | if the operator is combined with the "N" modifier). 20 | */ 21 | 22 | uValue = ((Frame->BC & BYTECODE_MASK) == BYTECODE_JMPC); 23 | uValue &= 1; 24 | if((Frame->CR.Type == TYPE_BOOL) && 25 | (Frame->CR.Value.B1 == uValue)) { 26 | case BYTECODE_JMP: 27 | assert(Value->Type == TYPE_LABEL); 28 | Frame->PC = Value->Value.U32; 29 | } 30 | break; 31 | 32 | default: 33 | break; 34 | } 35 | return 0; 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/operator/op_return.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | void 6 | operator_return(FRAME *Frame) { 7 | uint8_t uValue; 8 | 9 | switch(Frame->BC & BYTECODE_MASK) { 10 | case BYTECODE_RETC: 11 | case BYTECODE_RETCN: 12 | 13 | /* 14 | The modifier "C" indicates that the associated instruction shall be performed 15 | only if the value of the currently evaluated result is Boolean 1 (or Boolean 0 16 | if the operator is combined with the "N" modifier). 17 | */ 18 | 19 | uValue = ((Frame->BC & BYTECODE_MASK) == BYTECODE_RETC); 20 | uValue &= 1; 21 | if((Frame->CR.Type == TYPE_BOOL) && 22 | (Frame->CR.Value.B1 == uValue)) { 23 | case BYTECODE_RET: 24 | Frame->PC = (uint32_t) -1; 25 | } 26 | break; 27 | 28 | default: 29 | break; 30 | } 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/port/deps.h: -------------------------------------------------------------------------------- 1 | #ifndef DEPS_H__ 2 | #define DEPS_H__ 3 | 4 | #include 5 | 6 | int strcasecmp(const char* s1, const char* s2); 7 | 8 | struct tm* gmtime_r(const time_t* timer, struct tm* buf); 9 | 10 | time_t timegm(struct tm const* t); 11 | 12 | char* basename(char const* name); 13 | 14 | #endif -------------------------------------------------------------------------------- /src/port/lock.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #include 3 | #else 4 | #include 5 | #endif 6 | #include 7 | 8 | void* lock_init(void) 9 | { 10 | void* pLock; 11 | #ifdef _MSC_VER 12 | pLock = malloc(sizeof(CRITICAL_SECTION)); 13 | if(pLock) InitializeCriticalSection(pLock); 14 | #else 15 | pLock = malloc(sizeof(pthread_rwlock_t)); 16 | if (pLock) 17 | { 18 | if (pthread_rwlock_init((pthread_rwlock_t*)pLock, NULL) != 0) 19 | { 20 | free(pLock); 21 | pLock = NULL; 22 | } 23 | } 24 | #endif 25 | 26 | return pLock; 27 | } 28 | 29 | void lock_exit(void* pLock) 30 | { 31 | if (!pLock) return; 32 | #ifdef _MSC_VER 33 | DeleteCriticalSection(pLock); 34 | #else 35 | pthread_rwlock_destroy((pthread_rwlock_t*)pLock); 36 | #endif 37 | free(pLock); 38 | } 39 | 40 | int lock_rd(void* pLock) 41 | { 42 | int nResult = 0; 43 | if (!pLock) 44 | { 45 | nResult = EACCES; 46 | } 47 | else 48 | { 49 | #ifdef _MSC_VER 50 | EnterCriticalSection(pLock); 51 | #else 52 | nResult = pthread_rwlock_rdlock((pthread_rwlock_t*)pLock); 53 | #endif 54 | } 55 | 56 | return nResult; 57 | } 58 | 59 | int lock_wr(void* pLock) 60 | { 61 | int nResult = 0; 62 | if (!pLock) 63 | { 64 | nResult = EACCES; 65 | } 66 | else 67 | { 68 | #ifdef _MSC_VER 69 | EnterCriticalSection(pLock); 70 | #else 71 | nResult = pthread_rwlock_wrlock((pthread_rwlock_t*)pLock); 72 | if (nResult == EDEADLK) 73 | { 74 | nResult = 0; 75 | } 76 | #endif 77 | } 78 | return nResult; 79 | } 80 | 81 | int lock_unlock(void* pLock) 82 | { 83 | int nResult = 0; 84 | if (!pLock) 85 | { 86 | nResult = EACCES; 87 | } 88 | else 89 | { 90 | #ifdef _MSC_VER 91 | LeaveCriticalSection(pLock); 92 | #else 93 | nResult = pthread_rwlock_unlock((pthread_rwlock_t*)pLock); 94 | #endif 95 | } 96 | return nResult; 97 | } 98 | -------------------------------------------------------------------------------- /src/port/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOCK_H__ 2 | #define _LOCK_H__ 3 | 4 | void* lock_init(void); 5 | void lock_exit(void* pLock); 6 | int lock_rd(void* pLock); 7 | int lock_wr(void* pLock); 8 | int lock_unlock(void* pLock); 9 | 10 | #endif /* _LOCK_H__ */ 11 | 12 | -------------------------------------------------------------------------------- /src/protobuf/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= config.o file.o pou.o symbol.o value.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/runtime/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= bytecode.o call.o context.o error.o exit.o function.o parameter.o task.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/runtime/rt_context.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | void 18 | runtime_context_destroy(void *Arg) { 19 | RUNTIME_CONTEXT *pContext; 20 | size_t uIndex; 21 | 22 | if((pContext = (RUNTIME_CONTEXT *) Arg) == NULL) 23 | return; 24 | 25 | if(pContext->Functions.Function != NULL) { 26 | assert(pContext->Functions.Count > 0); 27 | for(uIndex = 0; uIndex < pContext->Functions.Count; ++uIndex) 28 | runtime_function_destroy(pContext->Functions.Function[uIndex]); 29 | free(pContext->Functions.Function); 30 | pContext->Functions.Count = 0; 31 | } 32 | pContext->Stack.Depth = 0; 33 | 34 | ll_destroy(&pContext->POU, NULL); 35 | if(pContext->Alloc) 36 | free(pContext); 37 | } 38 | 39 | 40 | void 41 | runtime_context_initialise(RUNTIME_CONTEXT *Context, RUNTIME *Run) { 42 | Context->Parent = Run; 43 | Context->Loop = Run->Loop; 44 | Context->Name = NULL; 45 | Context->State = STATE_STOP; 46 | Context->Priority = -1; 47 | Context->Interval = Context->Limit = Context->Single = NULL; 48 | Context->Time = 0.0; 49 | Context->Edge = 0; 50 | ll_initialise(&Context->POU); 51 | stats_initialise(&Context->Stats); 52 | 53 | Context->Functions.Function = NULL; 54 | Context->Functions.Count = 0; 55 | Context->Stack.Depth = 0; 56 | frame_push(Context); 57 | 58 | Context->Alloc = 0; 59 | } 60 | 61 | 62 | RUNTIME_CONTEXT * 63 | runtime_context_new(RUNTIME *Run) { 64 | RUNTIME_CONTEXT *pContext; 65 | 66 | assert(Run != NULL); 67 | if((pContext = calloc(1, sizeof(RUNTIME_CONTEXT))) == NULL) { 68 | log_critical("Failed to allocate memory: %s", strerror(errno)); 69 | return NULL; 70 | } 71 | runtime_context_initialise(pContext, Run); 72 | pContext->Alloc = 1; 73 | return pContext; 74 | } 75 | -------------------------------------------------------------------------------- /src/runtime/rt_error.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | static char * _Error[] = { 5 | "None", 6 | "Internal", 7 | "Internal allocation", 8 | "Internal read", 9 | "Internal write", 10 | "Invalid bytecode", 11 | "Invalid symbol", 12 | "Invalid function", 13 | "Invalid length", 14 | "Divide by zero", 15 | "Modulus by zero", 16 | "Math overflow", 17 | "Operand type", 18 | "Parameter count", 19 | "Parameter mismatch", 20 | "Parameter range", 21 | "Parameter type", 22 | "Parameter unknown", 23 | "Stack overflow", 24 | "Unimplemented", 25 | 26 | NULL 27 | }; 28 | 29 | 30 | const char * 31 | runtime_errortostr(int Error) { 32 | int nCount; 33 | 34 | nCount = sizeof(_Error) / sizeof(_Error[0]); 35 | if((Error < 0) || 36 | (Error >= nCount)) 37 | return NULL; 38 | return _Error[Error]; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/runtime/rt_exit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #ifndef _MSC_VER 3 | #include 4 | #else 5 | #include "deps.h" 6 | #endif 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* 17 | This file implements support for a set of functions (_exit, _exitc and _exitcn) 18 | that can be used to terminate execution of the echidna virtual machine run-time. 19 | These functions are primarily used in association with test operations. 20 | */ 21 | 22 | int 23 | runtime_exit(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 24 | FRAME *pFrame; 25 | RUNTIME *pRun; 26 | RUNTIME_CONTEXT *pContext; 27 | uint8_t uValue; 28 | 29 | pContext = (RUNTIME_CONTEXT *) User; 30 | assert(pContext != NULL); 31 | pRun = (RUNTIME *) pContext->Parent; 32 | assert(pRun != NULL); 33 | 34 | assert(Name != NULL); 35 | if((strcasecmp(Name, "_exitc") == 0) || 36 | (strcasecmp(Name, "_exitcn") == 0)) { 37 | 38 | pFrame = frame_current(pContext); 39 | uValue = (strcasecmp(Name, "_exitc") == 0); 40 | uValue &= 1; 41 | if((pFrame->CR.Type != TYPE_BOOL) || 42 | (pFrame->CR.Value.B1 != uValue)) 43 | return 0; 44 | } 45 | 46 | log_notice("Exit function called, stopping runtime"); 47 | runtime_stop(pRun); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/runtime/rt_parameter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | void 13 | runtime_parameter_destroy(void *Arg) { 14 | RUNTIME_PARAMETER *pParameter; 15 | 16 | if((pParameter = (RUNTIME_PARAMETER *) Arg) == NULL) 17 | return; 18 | value_destroy(&pParameter->Parameter.Value); 19 | value_destroy(&pParameter->Value); 20 | if(pParameter->Parameter.Name != NULL) 21 | free((char *) pParameter->Parameter.Name); 22 | free(pParameter); 23 | } 24 | 25 | 26 | RUNTIME_PARAMETER * 27 | runtime_parameter_new(void) { 28 | RUNTIME_PARAMETER *pParameter; 29 | 30 | errno = 0; 31 | if((pParameter = calloc(1, sizeof(RUNTIME_PARAMETER))) == NULL) { 32 | log_critical("Failed to allocate memory: %s", strerror(errno)); 33 | return NULL; 34 | } 35 | pParameter->Id = pParameter->Internal = -1; 36 | pParameter->Type = TYPE_NONE; 37 | value_initialise(&pParameter->Value); 38 | value_initialise(&pParameter->Parameter.Value); 39 | pParameter->Parameter.Name = NULL; 40 | 41 | return pParameter; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/standard/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 Virtual Machine 2 | 3 | .PHONY: 4 | 5 | CC?= $(CROSS)gcc 6 | 7 | GIT_VERSION:= $(shell git --no-pager describe --tags --always --dirty) 8 | TIMESTAMP:= $(shell date +'%Y%m%d') 9 | 10 | CFLAGS:= -Wall -g -std=c99 -fPIC 11 | DEFINES+= $(foreach VAR,GIT_VERSION TIMESTAMP,-D$(VAR)="$($(VAR))") -D_POSIX_C_SOURCE=200809L 12 | INCLUDES:= -I.. -I../include 13 | 14 | OBJS:= arithmetic.o bistable.o bitstring.o bitwise.o comparison.o counters.o edge.o numeric.o rtc.o select.o string.o time.o timers.o type.o 15 | 16 | all: clean $(OBJS) 17 | 18 | .c.o: 19 | $(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -c $< -o $@ 20 | 21 | clean: 22 | rm -f core *.o *.gcda *.gcno 23 | 24 | -------------------------------------------------------------------------------- /src/standard/std_rtc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifndef _MSC_VER 6 | #include 7 | #include 8 | #else 9 | #include 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | /* 19 | The real-time clock function block is included in Annex F of the IEC 61131-3 20 | version 2 standard, but is not referenced anywhere else in the standard. This 21 | reference is removed entirely in the IEC 61131-3 version 3 standard. Nevertheless, 22 | this function block has been implemented so as to provide the means for 23 | implementation and testing of date and time variable types described in this 24 | standard. 25 | */ 26 | 27 | enum { 28 | FIELD_IN = 0, 29 | FIELD_PDT, 30 | FIELD_Q, 31 | FIELD_CDT, 32 | }; 33 | 34 | 35 | int 36 | _standard_rtc(ECHIDNA *Context, _FUNCTION_BLOCK *Function, char *Instance, void *User) { 37 | VALUE sFields[4]; 38 | struct timespec sTime = { 0 }; 39 | int nResult; 40 | 41 | if((nResult = parameter_read_values(Context, Function, Instance, sFields)) != 0) 42 | return nResult; 43 | 44 | if(sFields[FIELD_IN].Value.B1 & ~sFields[FIELD_Q].Value.B1) { 45 | sTime.tv_sec = sFields[FIELD_PDT].Value.DateTime; 46 | sTime.tv_nsec = 0; 47 | #ifndef _MSC_VER 48 | clock_settime(CLOCK_REALTIME, &sTime); 49 | #else 50 | /* todo C.D. No solution yet for windows port */ 51 | #endif 52 | } 53 | value_assign(&sFields[FIELD_Q], TYPE_BOOL, sFields[FIELD_IN].Value.B1); 54 | 55 | #ifndef _MSC_VER 56 | clock_gettime(CLOCK_REALTIME, &sTime); 57 | #else 58 | /* todo C.D. No solution yet for windows port */ 59 | #endif 60 | value_assign(&sFields[FIELD_CDT], TYPE_DT, sTime.tv_sec); 61 | 62 | return parameter_write_values(Context, Function, Instance, sFields); 63 | } 64 | 65 | 66 | static _FUNCTION_BLOCK _Function = { 67 | 68 | .Name = "rtc", 69 | .Count = 4, 70 | .Fields = (FUNCTION_BLOCK_FIELD[]){ 71 | { "IN", TYPE_INPUT|TYPE_BOOL }, 72 | { "PDT", TYPE_INPUT|TYPE_DT }, 73 | { "Q", TYPE_OUTPUT|TYPE_BOOL }, 74 | { "CDT", TYPE_OUTPUT|TYPE_DT }, 75 | }, 76 | .Execute = _standard_rtc, 77 | }; 78 | 79 | 80 | int 81 | standard_rtc(ECHIDNA *Context) { 82 | return echidna_register(Context, "rtc", TYPE_FUNCTION_BLOCK, &_Function); 83 | } 84 | 85 | -------------------------------------------------------------------------------- /src/standard/std_string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | int 8 | standard_concat(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 9 | return RT_ERR_UNIMPLEMENTED; 10 | } 11 | 12 | 13 | int 14 | standard_delete(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 15 | return RT_ERR_UNIMPLEMENTED; 16 | } 17 | 18 | 19 | int 20 | standard_find(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 21 | return RT_ERR_UNIMPLEMENTED; 22 | } 23 | 24 | 25 | int 26 | standard_insert(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 27 | return RT_ERR_UNIMPLEMENTED; 28 | } 29 | 30 | 31 | int 32 | standard_left(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 33 | return RT_ERR_UNIMPLEMENTED; 34 | } 35 | 36 | 37 | int 38 | standard_len(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 39 | return RT_ERR_UNIMPLEMENTED; 40 | } 41 | 42 | 43 | int 44 | standard_mid(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 45 | return RT_ERR_UNIMPLEMENTED; 46 | } 47 | 48 | 49 | int 50 | standard_replace(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 51 | return RT_ERR_UNIMPLEMENTED; 52 | } 53 | 54 | 55 | int 56 | standard_right(ECHIDNA *Context, const char *Name, LL *Parameters, VALUE *Result, void *User) { 57 | return RT_ERR_UNIMPLEMENTED; 58 | } 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/stats.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | void 7 | stats_initialise(STATS *Stats) { 8 | Stats->Cycle = Stats->Overrun = 0; 9 | Stats->Latency = Stats->Execution = 0.0; 10 | Stats->LatencyStart = 0.0; 11 | Stats->LatencyEnd = 0.0; 12 | Stats->Maximum = 0.0; 13 | Stats->ExecutionStart = 0.0; 14 | /* Stats->ExecutionEnd = 0.0; */ 15 | Stats->Start = ev_time(); 16 | } 17 | -------------------------------------------------------------------------------- /src/strl.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.19 2019/01/25 00:19:25 millert Exp $ */ 2 | /* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */ 3 | 4 | /* 5 | * Copyright (c) 1998, 2015 Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | 24 | size_t 25 | strlcat(char *dst, const char *src, size_t dsize) 26 | { 27 | const char *odst = dst; 28 | const char *osrc = src; 29 | size_t n = dsize; 30 | size_t dlen; 31 | 32 | if(!dst || !src) 33 | return 0; 34 | if(n == 0) 35 | return 0; 36 | while(n-- != 0 && *dst != '\0') 37 | dst++; 38 | dlen = dst - odst; 39 | n = dsize - dlen; 40 | 41 | if(n-- == 0) 42 | return (dlen + strlen(src)); 43 | while(*src != '\0') { 44 | if(n != 0) { 45 | *dst++ = *src; 46 | n--; 47 | } 48 | src++; 49 | } 50 | *dst = '\0'; 51 | 52 | return(dlen + (src - osrc)); 53 | } 54 | 55 | 56 | size_t 57 | strlcpy(char *dst, const char *src, size_t dsize) 58 | { 59 | const char *osrc = src; 60 | size_t nleft = dsize; 61 | 62 | if(!dst || !src) 63 | return 0; 64 | if(nleft == 0) 65 | return 0; 66 | while(--nleft != 0) { 67 | if((*dst++ = *src++) == '\0') 68 | break; 69 | } 70 | 71 | if(nleft == 0) { 72 | *dst = '\0'; 73 | while(*src++); 74 | } 75 | 76 | return(src - osrc - 1); 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /src/unit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | void 16 | _unit_initialise(size_t Arg, UNIT *POU, ...) { 17 | va_list sArg; 18 | char *pName, *pParam; 19 | 20 | block_initialise(&POU->Block); 21 | ll_initialise(&POU->Symbols); 22 | POU->Config = POU->Resource = POU->POU = NULL; 23 | POU->Size = 0; 24 | POU->Alloc = 0; 25 | 26 | if(Arg < 2) 27 | return; 28 | 29 | va_start(sArg, POU); 30 | switch(Arg) { 31 | case 4: 32 | if((pParam = va_arg(sArg, char *)) != NULL) 33 | POU->Config = strdup(pParam); 34 | /* break; */ 35 | case 3: 36 | if((pParam = va_arg(sArg, char *)) != NULL) 37 | POU->Resource = strdup(pParam); 38 | /* break; */ 39 | case 2: 40 | if((pParam = va_arg(sArg, char *)) != NULL) 41 | POU->POU = strdup(pParam); 42 | break; 43 | 44 | default: 45 | break; 46 | } 47 | va_end(sArg); 48 | 49 | if(POU->POU != NULL) { 50 | if((pName = symbol_build_path(POU->Config, POU->Resource, POU->POU)) != NULL) 51 | block_name(&POU->Block, pName); 52 | } 53 | } 54 | 55 | 56 | int 57 | unit_compare(void *A, void *B) { 58 | return block_compare(A, B); 59 | } 60 | 61 | 62 | UNIT * 63 | unit_create(char *Config, char *Resource, char *Name) { 64 | UNIT *pPOU; 65 | 66 | pPOU = unit_new(); 67 | if (pPOU != NULL) 68 | { 69 | unit_initialise(pPOU, Config, Resource, Name); 70 | pPOU->Alloc = 1; 71 | } 72 | return pPOU; 73 | } 74 | 75 | 76 | void 77 | unit_destroy(void *Arg) { 78 | BLOCK *pBlock; 79 | UNIT *pPOU; 80 | 81 | if((pPOU = (UNIT *) Arg) == NULL) 82 | return; 83 | 84 | ll_destroy(&pPOU->Symbols, NULL); 85 | if(pPOU->Config) 86 | free(pPOU->Config); 87 | if(pPOU->Resource) 88 | free(pPOU->Resource); 89 | if(pPOU->POU) 90 | free(pPOU->POU); 91 | pBlock = &pPOU->Block; 92 | if(pBlock->Name) 93 | free(pBlock->Name); 94 | block_destroy(pBlock); 95 | 96 | if(pPOU->Alloc) 97 | free(pPOU); 98 | } 99 | 100 | 101 | UNIT * 102 | unit_new(void) { 103 | UNIT *pPOU; 104 | 105 | errno = 0; 106 | if((pPOU = (UNIT *) calloc(1, sizeof(UNIT))) == NULL) { 107 | log_critical("Failed to allocate memory: %s", strerror(errno)); 108 | return NULL; 109 | } 110 | unit_initialise(pPOU); 111 | pPOU->Alloc = 1; 112 | return pPOU; 113 | } 114 | 115 | 116 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | libsuite.a 2 | munit 3 | core 4 | *.o 5 | run 6 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | LIBS_SUBDIR:= block callback cast echidna grammar ll operator queue sha256 standard/arithmetic standard/bistable standard/bitstring standard/bitwise standard/comparison standard/counters standard/edge standard/numeric standard/rtc standard/select standard/string standard/time standard/timers standard/type stats strl tree unit value 4 | 5 | .PHONY: $(LIBS_SUBDIR) 6 | 7 | CC?= $(CROSS)gcc 8 | AR?= $(CROSS)ar 9 | 10 | SRCDIR:= ../src 11 | 12 | CFLAGS:= -Wall -g -std=c99 13 | DEFINES:= -D_POSIX_C_SOURCE=200809L 14 | INCLUDE_TEMPLATE:= -I! -I!/include 15 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 16 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 17 | LIBS:= $(patsubst %,%/libsuite.a,$(LIBS_SUBDIR)) \ 18 | -L$(SRCDIR) $(foreach VAR,echidna ev gcov jansson m protobuf-c pthread,-l$(VAR)) 19 | 20 | TARGET:= run 21 | OBJS:= main.o munit.o 22 | 23 | all: clean $(TARGET) 24 | 25 | $(TARGET): munit $(OBJS) 26 | for SUBDIR in $(LIBS_SUBDIR); do make -C $$SUBDIR ; done 27 | $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(OBJS) $(LIBS) 28 | test -x ./$@ && ./$@ 29 | 30 | .c.o: 31 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 32 | 33 | munit.o: munit munit/munit.o 34 | 35 | munit: 36 | git clone https://github.com/nemequ/munit.git 37 | 38 | proper: clean 39 | rm -fr munit 40 | 41 | clean: 42 | for SUBDIR in $(LIBS_SUBDIR); do make -C $$SUBDIR $@ ; done 43 | rm -f $(TARGET) core *.o 44 | 45 | -------------------------------------------------------------------------------- /tests/block/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/block/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_block[] = { 7 | 8 | { "append", test_block_append, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "dump", test_block_dump, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "end", test_block_end, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "initialise", test_block_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "name", test_block_name, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "new", test_block_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "pointer", test_block_pointer, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "read", test_block_read, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "size", test_block_size, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "write", test_block_write, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 18 | 19 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /tests/block/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_block_append(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_block_dump(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_block_end(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_block_initialise(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_block_name(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_block_new(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_block_pointer(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_block_read(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_block_size(const MunitParameter Parameters[], void *Fixture); 25 | 26 | MunitResult test_block_write(const MunitParameter Parameters[], void *Fixture); 27 | 28 | 29 | #endif // _TESTS_H 30 | -------------------------------------------------------------------------------- /tests/callback/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= callback.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/callback/callback.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | static void 12 | _test_callback_callback(ECHIDNA *Context, void *Arg, void *User) { 13 | } 14 | 15 | 16 | MunitResult 17 | test_callback_register(const MunitParameter Parameters[], void *Fixture) { 18 | ECHIDNA *pContext; 19 | 20 | pContext = (ECHIDNA *) Fixture; 21 | munit_assert_not_null(pContext); 22 | 23 | munit_assert_int(callback_register(pContext, CALLBACK_NONE), ==, -1); 24 | munit_assert_int(callback_register(pContext, CALLBACK_TASK_START), ==, -1); 25 | munit_assert_int(callback_register(pContext, CALLBACK_TASK_START, NULL), ==, -1); 26 | munit_assert_int(callback_register(pContext, CALLBACK_TASK_START, NULL, _test_callback_callback), ==, 0); 27 | munit_assert_int(callback_register(pContext, CALLBACK_TASK_STOP, NULL, _test_callback_callback), ==, 0); 28 | munit_assert_int(callback_register(pContext, CALLBACK_CYCLE_START, NULL, _test_callback_callback), ==, 0); 29 | munit_assert_int(callback_register(pContext, CALLBACK_CYCLE_FINISH, NULL, _test_callback_callback), ==, 0); 30 | munit_assert_int(callback_register(pContext, CALLBACK_CYCLE_FINISH, NULL, _test_callback_callback, pContext), ==, 0); 31 | 32 | callback_destroy(NULL); 33 | 34 | return MUNIT_OK; 35 | } 36 | -------------------------------------------------------------------------------- /tests/callback/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_callback[] = { 8 | { "register", test_callback_register, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | 10 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /tests/callback/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_callback_register(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/cast/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/cast/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_cast[] = { 7 | { "error", test_cast_error, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | { "none", test_cast_none, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | 10 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /tests/cast/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_cast_error(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_cast_none(const MunitParameter Parameters[], void *Fixture); 11 | 12 | 13 | #endif // _TESTS_H 14 | -------------------------------------------------------------------------------- /tests/echidna/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/echidna/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_echidna[] = { 8 | { "initialise", test_echidna_initialise, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | 10 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /tests/echidna/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | MunitResult 10 | test_echidna_initialise(const MunitParameter Parameters[], void *Fixture) { 11 | return MUNIT_OK; 12 | } 13 | -------------------------------------------------------------------------------- /tests/echidna/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_echidna_initialise(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/grammar/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= comments.o divide.o function.o literals.o modulus.o subrange.o type.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/grammar/comments.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | MunitResult 10 | test_grammar_comments(const MunitParameter Parameters[], void *Fixture) { 11 | ECHIDNA *pContext; 12 | 13 | pContext = (ECHIDNA *) Fixture; 14 | munit_assert_not_null(pContext); 15 | munit_assert_int(test_parse(pContext, "(* (* Nested comment *) *)"), !=, 0); 16 | munit_assert_int(test_parse(pContext, "(* Simple comment *)"), ==, 0); 17 | 18 | return MUNIT_OK; 19 | } 20 | -------------------------------------------------------------------------------- /tests/grammar/divide.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // xxd -i src/divide.txt 16 | 17 | static char _Source[] = { 18 | 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 19 | 0x64, 0x69, 0x76, 0x69, 0x64, 0x65, 0x0a, 0x56, 20 | 0x41, 0x52, 0x20, 0x74, 0x65, 0x73, 0x74, 0x3a, 21 | 0x20, 0x25, 0x73, 0x3b, 0x20, 0x45, 0x4e, 0x44, 22 | 0x5f, 0x56, 0x41, 0x52, 0x0a, 0x0a, 0x4c, 0x44, 23 | 0x20, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x44, 0x49, 24 | 0x56, 0x20, 0x25, 0x73, 0x23, 0x31, 0x0a, 0x44, 25 | 0x49, 0x56, 0x20, 0x25, 0x73, 0x23, 0x30, 0x0a, 26 | 0x53, 0x54, 0x20, 0x74, 0x65, 0x73, 0x74, 0x0a, 27 | 0x0a, 0x45, 0x4e, 0x44, 0x5f, 0x50, 0x52, 0x4f, 28 | 0x47, 0x52, 0x41, 0x4d, 0x0a, 0x00 29 | }; 30 | 31 | 32 | MunitResult 33 | test_grammar_divide(const MunitParameter Parameters[], void *Fixture) { 34 | ECHIDNA *pContext; 35 | PARSE *pParse; 36 | char sLine[LINE_MAX]; 37 | int nIndex; 38 | 39 | char * sType[] = { 40 | "LINT", 41 | "DINT", 42 | "INT", 43 | "SINT", 44 | "ULINT", 45 | "UDINT", 46 | "UINT", 47 | "USINT", 48 | "LWORD", 49 | "DWORD", 50 | "WORD", 51 | "BYTE", 52 | NULL, 53 | }; 54 | 55 | pContext = (ECHIDNA *) Fixture; 56 | munit_assert_not_null(pContext); 57 | 58 | for(nIndex = 0; sType[nIndex] != NULL; ++nIndex) { 59 | snprintf(sLine, sizeof(sLine), _Source, sType[nIndex], sType[nIndex], sType[nIndex]); 60 | fprintf(stderr, "%s", sLine); 61 | munit_assert_int(test_parse(pContext, sLine), !=, 0); 62 | munit_assert_not_null(pParse = &pContext->Parse); 63 | parse_reset(pContext, pParse); 64 | } 65 | 66 | return MUNIT_OK; 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/grammar/modulus.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // xxd -i src/modulus.txt 16 | 17 | static char _Source[] = { 18 | 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 19 | 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x75, 0x73, 0x0a, 20 | 0x56, 0x41, 0x52, 0x20, 0x74, 0x65, 0x73, 0x74, 21 | 0x3a, 0x20, 0x25, 0x73, 0x3b, 0x20, 0x45, 0x4e, 22 | 0x44, 0x5f, 0x56, 0x41, 0x52, 0x0a, 0x0a, 0x4c, 23 | 0x44, 0x20, 0x74, 0x65, 0x73, 0x74, 0x0a, 0x4d, 24 | 0x4f, 0x44, 0x20, 0x25, 0x73, 0x23, 0x31, 0x0a, 25 | 0x4d, 0x4f, 0x44, 0x20, 0x25, 0x73, 0x23, 0x30, 26 | 0x0a, 0x53, 0x54, 0x20, 0x74, 0x65, 0x73, 0x74, 27 | 0x0a, 0x0a, 0x45, 0x4e, 0x44, 0x5f, 0x50, 0x52, 28 | 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x0a, 0x00 29 | }; 30 | 31 | 32 | MunitResult 33 | test_grammar_modulus(const MunitParameter Parameters[], void *Fixture) { 34 | ECHIDNA *pContext; 35 | PARSE *pParse; 36 | char sLine[LINE_MAX]; 37 | int nIndex; 38 | 39 | char * sType[] = { 40 | "LINT", 41 | "DINT", 42 | "INT", 43 | "SINT", 44 | "ULINT", 45 | "UDINT", 46 | "UINT", 47 | "USINT", 48 | "LWORD", 49 | "DWORD", 50 | "WORD", 51 | "BYTE", 52 | NULL, 53 | }; 54 | 55 | pContext = (ECHIDNA *) Fixture; 56 | munit_assert_not_null(pContext); 57 | 58 | for(nIndex = 0; sType[nIndex] != NULL; ++nIndex) { 59 | snprintf(sLine, sizeof(sLine), _Source, sType[nIndex], sType[nIndex], sType[nIndex]); 60 | fprintf(stderr, "%s", sLine); 61 | munit_assert_int(test_parse(pContext, sLine), !=, 0); 62 | munit_assert_not_null(pParse = &pContext->Parse); 63 | parse_reset(pContext, pParse); 64 | } 65 | 66 | return MUNIT_OK; 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /tests/grammar/src/divide.txt: -------------------------------------------------------------------------------- 1 | PROGRAM divide 2 | VAR test: %s; END_VAR 3 | 4 | LD test 5 | DIV %s#1 6 | DIV %s#0 7 | ST test 8 | 9 | END_PROGRAM 10 | 11 | -------------------------------------------------------------------------------- /tests/grammar/src/factorial.txt: -------------------------------------------------------------------------------- 1 | FUNCTION fact : UDINT 2 | VAR_INPUT inp: UDINT; END_VAR 3 | VAR_OUTPUT out: UDINT; END_VAR 4 | VAR local: UDINT; END_VAR 5 | 6 | LD inp 7 | GE 1 8 | JMPC nonzero 9 | LD 1 10 | RET 11 | nonzero: LD inp 12 | SUB 1 13 | ST local 14 | fact local 15 | MUL inp 16 | ST out 17 | RET 18 | 19 | END_FUNCTION 20 | 21 | -------------------------------------------------------------------------------- /tests/grammar/src/modulus.txt: -------------------------------------------------------------------------------- 1 | PROGRAM modulus 2 | VAR test: %s; END_VAR 3 | 4 | LD test 5 | MOD %s#1 6 | MOD %s#0 7 | ST test 8 | 9 | END_PROGRAM 10 | 11 | -------------------------------------------------------------------------------- /tests/grammar/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_grammar[] = { 8 | { "comments", test_grammar_comments, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "divide", test_grammar_divide, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "function", test_grammar_function, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "literals/bitstring", test_grammar_literals_bitstring, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "literals/boolean", test_grammar_literals_boolean, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "literals/datetime", test_grammar_literals_datetime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "literals/integer", test_grammar_literals_integer, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "literals/real", test_grammar_literals_real, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "literals/time", test_grammar_literals_time, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "modulus", test_grammar_modulus, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 18 | { "subrange", test_grammar_subrange, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 19 | { "type", test_grammar_type, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 20 | 21 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /tests/grammar/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_grammar_comments(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_grammar_divide(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_grammar_function(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_grammar_literals_bitstring(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_grammar_literals_boolean(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_grammar_literals_datetime(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_grammar_literals_integer(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_grammar_literals_real(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_grammar_literals_time(const MunitParameter Parameters[], void *Fixture); 25 | 26 | MunitResult test_grammar_modulus(const MunitParameter Parameters[], void *Fixture); 27 | 28 | MunitResult test_grammar_subrange(const MunitParameter Parameters[], void *Fixture); 29 | 30 | MunitResult test_grammar_type(const MunitParameter Parameters[], void *Fixture); 31 | 32 | 33 | #endif // _TESTS_H 34 | -------------------------------------------------------------------------------- /tests/grammar/type.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | 15 | MunitResult 16 | test_grammar_type(const MunitParameter Parameters[], void *Fixture) { 17 | ECHIDNA *pContext; 18 | PARSE *pParse; 19 | int nResult; 20 | 21 | pContext = (ECHIDNA *) Fixture; 22 | munit_assert_not_null(pContext); 23 | munit_assert_not_null(pParse = &pContext->Parse); 24 | 25 | nResult = test_parse(pContext, "TYPE TEST INT; END_TYPE"); 26 | munit_assert_int(nResult, !=, 0); 27 | parse_reset(pContext, pParse); 28 | 29 | return MUNIT_OK; 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/ll/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/ll/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_list[] = { 7 | { "copy", test_ll_copy, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | { "delete", test_ll_delete, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "initialise", test_ll_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "insert_head", test_ll_insert_head, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "insert_tail", test_ll_insert_tail, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "iterate_first", test_ll_iterate_first, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "iterate_last", test_ll_iterate_last, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "merge", test_ll_merge, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "new", test_ll_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 16 | 17 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /tests/ll/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_ll_copy(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_ll_delete(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_ll_initialise(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_ll_insert_head(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_ll_insert_tail(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_ll_iterate_first(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_ll_iterate_last(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_ll_merge(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_ll_new(const MunitParameter Parameters[], void *Fixture); 25 | 26 | 27 | #endif // _TESTS_H 28 | -------------------------------------------------------------------------------- /tests/operator/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= arithmetic.o boolean.o comparison.o logical.o operand.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/operator/src/boolean.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR on: BOOL := true; END_VAR 3 | VAR off: BOOL := false; END_VAR 4 | VAR count: ULINT := 0; END_VAR 5 | 6 | ADD count, 1 7 | ST count 8 | LE 10 9 | JMPCN end 10 | 11 | LD count 12 | MOD 2 13 | EQ 1 14 | S off 15 | R on 16 | RETC 17 | 18 | LD true 19 | R off 20 | S on 21 | RET 22 | 23 | end: _exit 24 | 25 | END_PROGRAM 26 | 27 | CONFIGURATION config1 28 | TASK task1 (PRIORITY := 1); 29 | PROGRAM program1: test; 30 | END_CONFIGURATION 31 | 32 | -------------------------------------------------------------------------------- /tests/operator/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_operator[] = { 8 | 9 | { "arithmetic/add", test_operator_add, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "arithmetic/div", test_operator_div, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "arithmetic/mod", test_operator_mod, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "arithmetic/mul", test_operator_mul, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "arithmetic/sub", test_operator_sub, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "boolean", test_operator_boolean, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "comparison/eq", test_operator_eq, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "comparison/ge", test_operator_ge, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "comparison/gt", test_operator_gt, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 18 | { "comparison/le", test_operator_le, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 19 | { "comparison/lt", test_operator_lt, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 20 | { "comparison/ne", test_operator_ne, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 21 | { "logical/and", test_operator_and, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 22 | { "logical/not", test_operator_not, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 23 | { "logical/or", test_operator_or, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 24 | { "logical/xor", test_operator_xor, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 25 | { "operand/invert", test_operand_invert, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 26 | { "operand/subrange", test_operand_subrange, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 27 | 28 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /tests/operator/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_operand_invert(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_operand_subrange(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_operator_add(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_operator_and(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_operator_boolean(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_operator_div(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_operator_eq(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_operator_ge(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_operator_gt(const MunitParameter Parameters[], void *Fixture); 25 | 26 | MunitResult test_operator_le(const MunitParameter Parameters[], void *Fixture); 27 | 28 | MunitResult test_operator_lt(const MunitParameter Parameters[], void *Fixture); 29 | 30 | MunitResult test_operator_mod(const MunitParameter Parameters[], void *Fixture); 31 | 32 | MunitResult test_operator_mul(const MunitParameter Parameters[], void *Fixture); 33 | 34 | MunitResult test_operator_ne(const MunitParameter Parameters[], void *Fixture); 35 | 36 | MunitResult test_operator_not(const MunitParameter Parameters[], void *Fixture); 37 | 38 | MunitResult test_operator_or(const MunitParameter Parameters[], void *Fixture); 39 | 40 | MunitResult test_operator_sub(const MunitParameter Parameters[], void *Fixture); 41 | 42 | MunitResult test_operator_xor(const MunitParameter Parameters[], void *Fixture); 43 | 44 | 45 | #endif // _TESTS_H 46 | -------------------------------------------------------------------------------- /tests/queue/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= priority.o tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/queue/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_queue[] = { 7 | { "initialise", test_queue_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | { "new", test_queue_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "operations", test_queue_operations, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "priority/equal", test_priority_equal, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "priority/negative", test_priority_negative, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "priority/ordered", test_priority_ordered, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "size", test_queue_size, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | 15 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /tests/queue/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_priority_equal(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_priority_negative(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_priority_ordered(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_queue_initialise(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_queue_new(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_queue_operations(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_queue_size(const MunitParameter Parameters[], void *Fixture); 21 | 22 | 23 | #endif // _TESTS_H 24 | -------------------------------------------------------------------------------- /tests/sha256/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/sha256/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_digest[] = { 7 | { "generate", test_sha256_generate, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | 9 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /tests/sha256/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | static void 10 | _test_sha256_generate(char *Data, size_t Length, char *Digest) { 11 | SHA256 sDigest; 12 | char *pPtr, sBuffer[32]; 13 | int nIndex; 14 | 15 | sha256_initialise(&sDigest); 16 | sha256_update(&sDigest, Data, Length); 17 | sha256_final(&sDigest, sBuffer); 18 | 19 | pPtr = Digest; 20 | for(nIndex = 0; nIndex < sizeof(sBuffer); ++nIndex) 21 | pPtr += sprintf(pPtr, "%02x", (sBuffer[nIndex] & 0xff)); 22 | } 23 | 24 | 25 | MunitResult 26 | test_sha256_generate(const MunitParameter Parameters[], void *Fixture) { 27 | SHA256 sDigest; 28 | char sBuffer[32], sStr[65]; 29 | char *pPtr; 30 | int nIndex; 31 | 32 | // "abc" (24 bits) 33 | _test_sha256_generate("abc", 3, sStr); 34 | munit_assert_string_equal(sStr, "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); 35 | 36 | // "" (0 bits) 37 | _test_sha256_generate("", 0, sStr); 38 | munit_assert_string_equal(sStr, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); 39 | 40 | // "abc..opq" (448 bits) 41 | _test_sha256_generate("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, sStr); 42 | munit_assert_string_equal(sStr, "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); 43 | 44 | // "abc..stu" (896 bits) 45 | _test_sha256_generate("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 112, sStr); 46 | munit_assert_string_equal(sStr, "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1"); 47 | 48 | // "a" x 1000000 (8000000 bits) 49 | sha256_initialise(&sDigest); 50 | for(nIndex = 0; nIndex < 1000000; ++nIndex) 51 | sha256_update(&sDigest, "a", 1); 52 | sha256_final(&sDigest, sBuffer); 53 | pPtr = sStr; 54 | for(nIndex = 0; nIndex < sizeof(sBuffer); ++nIndex) 55 | pPtr += sprintf(pPtr, "%02x", (sBuffer[nIndex] & 0xff)); 56 | munit_assert_string_equal(sStr, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); 57 | 58 | return MUNIT_OK; 59 | } 60 | -------------------------------------------------------------------------------- /tests/sha256/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_sha256_generate(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/standard/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | LIBS_SUBDIR:= arithmetic bistable bitstring bitwise comparison counters edge numeric rtc select string time timers type 4 | .PHONY: $(LIBS_SUBDIR) 5 | 6 | all: clean 7 | for SUBDIR in $(LIBS_SUBDIR); do make -C $$SUBDIR ; done 8 | 9 | clean: 10 | for SUBDIR in $(LIBS_SUBDIR); do make -C $$SUBDIR $@ ; done 11 | 12 | -------------------------------------------------------------------------------- /tests/standard/arithmetic/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= add.o div.o expt.o mod.o mul.o sub.o tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/arithmetic/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_arithmetic[] = { 8 | { "arithmetic/add", test_arithmetic_add, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "arithmetic/div", test_arithmetic_div, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "arithmetic/expt", test_arithmetic_expt, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "arithmetic/mod", test_arithmetic_mod, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "arithmetic/mul", test_arithmetic_mul, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "arithmetic/sub", test_arithmetic_sub, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | 15 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /tests/standard/arithmetic/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | void 11 | _test_arithmetic_modulus(LL *Parameters, VALUE_TYPE Type) { 12 | PARAMETER *pParameter; 13 | int nValue; 14 | 15 | while(Parameters->Head != NULL) 16 | ll_delete(Parameters->Head); 17 | for(nValue = 5; nValue > 1; nValue -= 2) { 18 | munit_assert_not_null(pParameter = parameter_new(NULL)); 19 | value_assign(&pParameter->Value, Type, nValue); 20 | munit_assert_int(ll_insert(Parameters, pParameter), ==, 0); 21 | } 22 | } 23 | 24 | 25 | void 26 | _test_arithmetic_populate(LL *Parameters, VALUE_TYPE Type) { 27 | PARAMETER *pParameter; 28 | double dValue; 29 | int nValue; 30 | 31 | while(Parameters->Head != NULL) 32 | ll_delete(Parameters->Head); 33 | for(nValue = 8; nValue > 1; nValue /= 2) { 34 | munit_assert_not_null(pParameter = parameter_new(NULL)); 35 | dValue = (double) nValue; 36 | switch(Type) { 37 | case TYPE_LREAL: 38 | case TYPE_REAL: 39 | case TYPE_TIME: 40 | value_assign(&pParameter->Value, Type, dValue); 41 | break; 42 | 43 | default: 44 | value_assign(&pParameter->Value, Type, nValue); 45 | break; 46 | } 47 | munit_assert_int(ll_insert(Parameters, pParameter), ==, 0); 48 | } 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /tests/standard/arithmetic/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | void _test_arithmetic_modulus(LL *Parameters, VALUE_TYPE Type); 12 | 13 | void _test_arithmetic_populate(LL *Parameters, VALUE_TYPE Type); 14 | 15 | MunitResult test_arithmetic_add(const MunitParameter Parameters[], void *Fixture); 16 | 17 | MunitResult test_arithmetic_div(const MunitParameter Parameters[], void *Fixture); 18 | 19 | MunitResult test_arithmetic_expt(const MunitParameter Parameters[], void *Fixture); 20 | 21 | MunitResult test_arithmetic_mod(const MunitParameter Parameters[], void *Fixture); 22 | 23 | MunitResult test_arithmetic_mul(const MunitParameter Parameters[], void *Fixture); 24 | 25 | MunitResult test_arithmetic_sub(const MunitParameter Parameters[], void *Fixture); 26 | 27 | 28 | #endif // _TESTS_H 29 | -------------------------------------------------------------------------------- /tests/standard/bistable/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= bistable.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/bistable/src/rs.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: ULINT := 0; END_VAR 4 | VAR fb: RS; END_VAR 5 | 6 | ADD count, 1 7 | ST count 8 | 9 | LD count 10 | MOD 3 11 | EQ 0 12 | ST input 13 | 14 | LD count 15 | MOD 5 16 | EQ 0 17 | ST reset 18 | 19 | CAL fb( 20 | R1 := reset, 21 | S := input 22 | ) 23 | 24 | LD count 25 | EQ 15 26 | RETCN 27 | _exit 28 | 29 | END_PROGRAM 30 | 31 | CONFIGURATION config1 32 | TASK task1 (INTERVAL := t#50ms, PRIORITY := 1); 33 | PROGRAM program1: test; 34 | END_CONFIGURATION 35 | 36 | -------------------------------------------------------------------------------- /tests/standard/bistable/src/sr.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: ULINT := 0; END_VAR 4 | VAR fb: SR; END_VAR 5 | 6 | ADD count, 1 7 | ST count 8 | 9 | LD count 10 | MOD 3 11 | EQ 0 12 | ST input 13 | 14 | LD count 15 | MOD 5 16 | EQ 0 17 | ST reset 18 | 19 | CAL fb( 20 | S1 := input, 21 | R := reset 22 | ) 23 | 24 | LD count 25 | EQ 15 26 | RETCN 27 | _exit 28 | 29 | END_PROGRAM 30 | 31 | CONFIGURATION config1 32 | TASK task1 (INTERVAL := t#50ms, PRIORITY := 1); 33 | PROGRAM program1: test; 34 | END_CONFIGURATION 35 | 36 | -------------------------------------------------------------------------------- /tests/standard/bistable/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_bistable[] = { 8 | 9 | { "bistable/rs", test_bistable_rs, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "bistable/sr", test_bistable_sr, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | 12 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /tests/standard/bistable/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_bistable_rs(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_bistable_sr(const MunitParameter Parameters[], void *Fixture); 11 | 12 | 13 | #endif // _TESTS_H 14 | -------------------------------------------------------------------------------- /tests/standard/bitstring/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= roll.o shift.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/bitstring/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_bitstring[] = { 8 | 9 | { "bitstring/rol", test_bitstring_rol, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "bitstring/ror", test_bitstring_ror, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "bitstring/shl", test_bitstring_shl, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "bitstring/shr", test_bitstring_shr, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | 14 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /tests/standard/bitstring/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_bitstring_rol(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_bitstring_ror(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_bitstring_shl(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_bitstring_shr(const MunitParameter Parameters[], void *Fixture); 15 | 16 | 17 | #endif // _TESTS_H 18 | -------------------------------------------------------------------------------- /tests/standard/bitwise/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/bitwise/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_bitwise[] = { 8 | 9 | { "bitwise/and", test_bitwise_and, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "bitwise/or", test_bitwise_or, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "bitwise/xor", test_bitwise_xor, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | 13 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /tests/standard/bitwise/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_bitwise_and(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_bitwise_or(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_bitwise_xor(const MunitParameter Parameters[], void *Fixture); 13 | 14 | 15 | #endif // _TESTS_H 16 | -------------------------------------------------------------------------------- /tests/standard/comparison/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/comparison/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_comparison[] = { 8 | 9 | { "comparison/eq", test_comparison_eq, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "comparison/ge", test_comparison_ge, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "comparison/gt", test_comparison_gt, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "comparison/le", test_comparison_le, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "comparison/lt", test_comparison_lt, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "comparison/ne", test_comparison_ne, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 15 | 16 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 17 | }; 18 | 19 | -------------------------------------------------------------------------------- /tests/standard/comparison/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_comparison_eq(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_comparison_ge(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_comparison_gt(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_comparison_le(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_comparison_lt(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_comparison_ne(const MunitParameter Parameters[], void *Fixture); 19 | 20 | 21 | #endif // _TESTS_H 22 | -------------------------------------------------------------------------------- /tests/standard/counters/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= ctd.o ctu.o tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/counters/src/ctd.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: %s := 0; END_VAR 4 | VAR maximum: %s := 5; END_VAR 5 | VAR fb: CTD; END_VAR 6 | 7 | ADD count, 1 8 | ST count 9 | 10 | LD count 11 | MOD 2 12 | EQ 0 13 | ST input 14 | 15 | LD count 16 | MOD 15 17 | EQ 1 18 | ST reset 19 | 20 | CAL fb( 21 | CD := input, 22 | LD := reset, 23 | PV := maximum 24 | ) 25 | 26 | LD count 27 | EQ 20 28 | RETCN 29 | _exit 30 | 31 | END_PROGRAM 32 | 33 | CONFIGURATION config1 34 | TASK task1 (INTERVAL := t#10ms, PRIORITY := 1); 35 | PROGRAM program1 WITH task1: test; 36 | END_CONFIGURATION 37 | 38 | -------------------------------------------------------------------------------- /tests/standard/counters/src/ctd_type.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: %s := 0; END_VAR 4 | VAR maximum: %s := 5; END_VAR 5 | VAR fb: CTD_%s; END_VAR 6 | 7 | ADD count, 1 8 | ST count 9 | 10 | LD count 11 | MOD 2 12 | EQ 0 13 | ST input 14 | 15 | LD count 16 | MOD 15 17 | EQ 1 18 | ST reset 19 | 20 | CAL fb( 21 | CD := input, 22 | LD := reset, 23 | PV := maximum 24 | ) 25 | 26 | LD count 27 | EQ 20 28 | RETCN 29 | _exit 30 | 31 | END_PROGRAM 32 | 33 | CONFIGURATION config1 34 | TASK task1 (INTERVAL := t#10ms, PRIORITY := 1); 35 | PROGRAM program1 WITH task1: test; 36 | END_CONFIGURATION 37 | 38 | -------------------------------------------------------------------------------- /tests/standard/counters/src/ctu.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: %s := 0; END_VAR 4 | VAR maximum: %s := 5; END_VAR 5 | VAR fb: CTU; END_VAR 6 | 7 | ADD count, 1 8 | ST count 9 | 10 | LD count 11 | MOD 2 12 | EQ 0 13 | ST input 14 | 15 | LD count 16 | MOD 15 17 | EQ 0 18 | ST reset 19 | 20 | CAL fb( 21 | CU := input, 22 | R := reset, 23 | PV := maximum 24 | ) 25 | 26 | LD count 27 | EQ 20 28 | RETCN 29 | _exit 30 | 31 | END_PROGRAM 32 | 33 | CONFIGURATION config1 34 | TASK task1 (INTERVAL := t#10ms, PRIORITY := 1); 35 | PROGRAM program1 WITH task1: test; 36 | END_CONFIGURATION 37 | 38 | -------------------------------------------------------------------------------- /tests/standard/counters/src/ctu_type.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR input, reset: BOOL := FALSE; END_VAR 3 | VAR count: INT := 0; END_VAR 4 | VAR maximum: %s := 5; END_VAR 5 | VAR fb: CTU_%s; END_VAR 6 | 7 | ADD count, 1 8 | ST count 9 | 10 | LD count 11 | MOD 2 12 | EQ 0 13 | ST input 14 | 15 | LD count 16 | MOD 15 17 | EQ 0 18 | ST reset 19 | 20 | CAL fb( 21 | CU := input, 22 | R := reset, 23 | PV := maximum 24 | ) 25 | 26 | LD count 27 | EQ 20 28 | RETCN 29 | _exit 30 | 31 | END_PROGRAM 32 | 33 | CONFIGURATION config1 34 | TASK task1 (INTERVAL := t#10ms, PRIORITY := 1); 35 | PROGRAM program1 WITH task1: test; 36 | END_CONFIGURATION 37 | 38 | -------------------------------------------------------------------------------- /tests/standard/counters/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_standard_counters[] = { 7 | 8 | { "counters/ctd", test_counters_ctd, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "counters/ctd_type", test_counters_ctdtype, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "counters/ctu", test_counters_ctu, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "counters/ctu_type", test_counters_ctutype, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "counters/ctud", test_counters_ctud, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "counters/ctud_type", test_counters_ctudtype, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | 15 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /tests/standard/counters/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | MunitResult 5 | test_counters_ctud(const MunitParameter Parameters[], void *Fixture) { 6 | return MUNIT_SKIP; 7 | } 8 | 9 | 10 | MunitResult 11 | test_counters_ctudtype(const MunitParameter Parameters[], void *Fixture) { 12 | return MUNIT_SKIP; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests/standard/counters/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_counters_ctd(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_counters_ctdtype(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_counters_ctu(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_counters_ctutype(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_counters_ctud(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_counters_ctudtype(const MunitParameter Parameters[], void *Fixture); 19 | 20 | 21 | #endif // _TESTS_H 22 | -------------------------------------------------------------------------------- /tests/standard/edge/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= edge.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/edge/src/edge.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR i1, i2: BOOL := FALSE; END_VAR 3 | VAR count: ULINT := 0; END_VAR 4 | VAR fedge: F_TRIG; END_VAR 5 | VAR redge: R_TRIG; END_VAR 6 | 7 | ADD count, 1 8 | ST count 9 | 10 | LD count 11 | MOD 3 12 | EQ 0 13 | ST i1 14 | CAL redge( 15 | CLK := i1 16 | ) 17 | 18 | LD count 19 | MOD 5 20 | NE 0 21 | ST i2 22 | CAL fedge( 23 | CLK := i2 24 | ) 25 | 26 | LD fedge.Q 27 | AND redge.Q 28 | RETCN 29 | _exit 30 | 31 | END_PROGRAM 32 | 33 | CONFIGURATION config1 34 | TASK task1 (PRIORITY := 1); 35 | PROGRAM program1: test; 36 | END_CONFIGURATION 37 | 38 | -------------------------------------------------------------------------------- /tests/standard/edge/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_edge[] = { 8 | 9 | { "edge", test_edge, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | 11 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /tests/standard/edge/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_edge(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/standard/numeric/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= abs.o cosine.o exp.o log.o sine.o sqrt.o tangent.o tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/numeric/sqrt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | 16 | MunitResult 17 | test_numeric_sqrt(const MunitParameter Parameters[], void *Fixture) { 18 | ECHIDNA *pContext; 19 | LL sParameters; 20 | PARAMETER *pParameter; 21 | VALUE sResult; 22 | 23 | pContext = (ECHIDNA *) Fixture; 24 | munit_assert_not_null(pContext); 25 | 26 | ll_initialise(&sParameters, parameter_destroy); 27 | munit_assert_int(standard_sqrt(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_COUNT); 28 | munit_assert_not_null(pParameter = parameter_new(NULL)); 29 | value_assign(&pParameter->Value, TYPE_INT); 30 | munit_assert_int(ll_insert(&sParameters, pParameter), ==, 0); 31 | munit_assert_int(standard_sqrt(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 32 | ll_delete(sParameters.Head); 33 | munit_assert_not_null(pParameter = parameter_new(NULL)); 34 | value_assign(&pParameter->Value, ANY_REAL); 35 | munit_assert_int(ll_insert(&sParameters, pParameter), ==, 0); 36 | munit_assert_int(standard_sqrt(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 37 | ll_destroy(&sParameters); 38 | 39 | // TYPE_LREAL 40 | ll_initialise(&sParameters, parameter_destroy); 41 | munit_assert_not_null(pParameter = parameter_new(NULL)); 42 | value_assign(&pParameter->Value, TYPE_LREAL, 625.0); 43 | munit_assert_int(ll_insert(&sParameters, pParameter), ==, 0); 44 | munit_assert_int(standard_sqrt(pContext, NULL, &sParameters, &sResult, NULL), ==, 0); 45 | munit_assert_uint32(sResult.Type, ==, TYPE_LREAL); 46 | munit_assert_double(sResult.Value.Double, ==, 25.0); 47 | ll_destroy(&sParameters); 48 | 49 | // TYPE_REAL 50 | ll_initialise(&sParameters, parameter_destroy); 51 | munit_assert_not_null(pParameter = parameter_new(NULL)); 52 | value_assign(&pParameter->Value, TYPE_REAL, 625.0); 53 | munit_assert_int(ll_insert(&sParameters, pParameter), ==, 0); 54 | munit_assert_int(standard_sqrt(pContext, NULL, &sParameters, &sResult, NULL), ==, 0); 55 | munit_assert_uint32(sResult.Type, ==, TYPE_REAL); 56 | munit_assert_float(sResult.Value.Single, ==, 25.0); 57 | ll_destroy(&sParameters); 58 | 59 | return MUNIT_OK; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /tests/standard/numeric/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_numeric[] = { 8 | 9 | { "numeric/abs", test_numeric_abs, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "numeric/acos", test_numeric_acos, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "numeric/asin", test_numeric_asin, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "numeric/atan", test_numeric_atan, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "numeric/cos", test_numeric_cos, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "numeric/exp", test_numeric_exp, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "numeric/ln", test_numeric_ln, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "numeric/log", test_numeric_log, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "numeric/sin", test_numeric_sin, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 18 | { "numeric/sqrt", test_numeric_sqrt, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 19 | { "numeric/tan", test_numeric_tan, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 20 | 21 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /tests/standard/numeric/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | 16 | 17 | MunitResult 18 | test_numeric_atan(const MunitParameter Parameters[], void *Fixture) { 19 | return MUNIT_SKIP; 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/standard/numeric/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_numeric_abs(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_numeric_acos(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_numeric_asin(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_numeric_atan(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_numeric_cos(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_numeric_exp(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_numeric_sin(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_numeric_sqrt(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_numeric_ln(const MunitParameter Parameters[], void *Fixture); 25 | 26 | MunitResult test_numeric_log(const MunitParameter Parameters[], void *Fixture); 27 | 28 | MunitResult test_numeric_tan(const MunitParameter Parameters[], void *Fixture); 29 | 30 | 31 | #endif // _TESTS_H 32 | -------------------------------------------------------------------------------- /tests/standard/rtc/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= rtc.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/rtc/src/rtc.txt: -------------------------------------------------------------------------------- 1 | PROGRAM test 2 | VAR clock: rtc; END_VAR 3 | VAR now: DATE_AND_TIME := DT#1970-01-01-00:00:00; END_VAR 4 | 5 | CAL clock 6 | 7 | LD clock.CDT 8 | ST now 9 | _exit 10 | 11 | END_PROGRAM 12 | 13 | CONFIGURATION config1 14 | TASK task1 (PRIORITY := 1); 15 | PROGRAM program1: test; 16 | END_CONFIGURATION 17 | 18 | -------------------------------------------------------------------------------- /tests/standard/rtc/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_rtc[] = { 8 | 9 | { "rtc", test_rtc, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | 11 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /tests/standard/rtc/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_rtc(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/standard/select/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= limit.o max.o min.o mux.o select.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/select/mux.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | MunitResult 15 | test_select_mux(const MunitParameter Parameters[], void *Fixture) { 16 | ECHIDNA *pContext; 17 | LL sParameters; 18 | PARAMETER *pK, *pValue; 19 | VALUE sResult; 20 | 21 | pContext = (ECHIDNA *) Fixture; 22 | munit_assert_not_null(pContext); 23 | 24 | ll_initialise(&sParameters, parameter_destroy); 25 | munit_assert_int(standard_mux(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_INTERNAL); 26 | munit_assert_int(standard_mux(pContext, "mux", &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_COUNT); 27 | munit_assert_not_null(pK = parameter_new(NULL)); 28 | value_assign(&pK->Value, TYPE_BOOL); 29 | munit_assert_int(ll_insert(&sParameters, pK), ==, 0); 30 | munit_assert_int(standard_mux(pContext, "mux", &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 31 | value_assign(&pK->Value, TYPE_INT, 2); 32 | munit_assert_not_null(pValue = parameter_new(NULL)); 33 | value_assign(&pValue->Value, TYPE_INT, 1); 34 | munit_assert_int(ll_insert(&sParameters, pValue), ==, 0); 35 | munit_assert_not_null(pValue = parameter_new(NULL)); 36 | value_assign(&pValue->Value, TYPE_INT, 2); 37 | munit_assert_int(ll_insert(&sParameters, pValue), ==, 0); 38 | munit_assert_int(standard_mux(pContext, "mux", &sParameters, &sResult, NULL), ==, 0); 39 | munit_assert_uint32(sResult.Type, ==, TYPE_INT); 40 | munit_assert_int16(sResult.Value.S16, ==, 2); 41 | 42 | munit_assert_int(standard_mux(pContext, "mux_int", &sParameters, &sResult, NULL), ==, ERROR_INVALID_FUNCTION); 43 | munit_assert_int(standard_mux(pContext, "mux_int_bool", &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 44 | munit_assert_int(standard_mux(pContext, "mux_int_int", &sParameters, &sResult, NULL), ==, 0); 45 | munit_assert_uint32(sResult.Type, ==, TYPE_INT); 46 | munit_assert_int16(sResult.Value.S16, ==, 2); 47 | 48 | munit_assert_not_null(pK->Name = strdup("K")); 49 | munit_assert_int(standard_mux(pContext, "mux_bool_int", &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 50 | value_assign(&pK->Value, TYPE_BOOL); 51 | munit_assert_int(standard_mux(pContext, "mux_bool_int", &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 52 | value_assign(&pK->Value, TYPE_INT, 2); 53 | munit_assert_int(standard_mux(pContext, "mux_int_int", &sParameters, &sResult, NULL), ==, 0); 54 | munit_assert_uint32(sResult.Type, ==, TYPE_INT); 55 | munit_assert_int16(sResult.Value.S16, ==, 2); 56 | 57 | ll_destroy(&sParameters); 58 | 59 | return MUNIT_OK; 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/standard/select/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_select[] = { 8 | 9 | { "select/limit", test_select_limit, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "select/max", test_select_max, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "select/min", test_select_min, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "select/mux", test_select_mux, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "select/sel", test_select_select, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | 15 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /tests/standard/select/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_select_limit(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_select_max(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_select_min(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_select_mux(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_select_select(const MunitParameter Parameters[], void *Fixture); 17 | 18 | 19 | #endif // _TESTS_H 20 | -------------------------------------------------------------------------------- /tests/standard/string/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/string/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_string[] = { 8 | 9 | { "string/concat", test_string_concat, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "string/delete", test_string_delete, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "string/find", test_string_find, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "string/insert", test_string_insert, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "string/left", test_string_left, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "string/len", test_string_len, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "string/mid", test_string_mid, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "string/replace", test_string_replace, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "string/right", test_string_right, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 18 | 19 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /tests/standard/string/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | MunitResult 15 | test_string_concat(const MunitParameter Parameters[], void *Fixture) { 16 | munit_assert_int(standard_concat(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 17 | return MUNIT_OK; 18 | } 19 | 20 | 21 | MunitResult 22 | test_string_delete(const MunitParameter Parameters[], void *Fixture) { 23 | munit_assert_int(standard_delete(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 24 | return MUNIT_OK; 25 | } 26 | 27 | 28 | MunitResult 29 | test_string_find(const MunitParameter Parameters[], void *Fixture) { 30 | munit_assert_int(standard_find(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 31 | return MUNIT_OK; 32 | } 33 | 34 | 35 | MunitResult 36 | test_string_insert(const MunitParameter Parameters[], void *Fixture) { 37 | munit_assert_int(standard_insert(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 38 | return MUNIT_OK; 39 | } 40 | 41 | 42 | MunitResult 43 | test_string_left(const MunitParameter Parameters[], void *Fixture) { 44 | munit_assert_int(standard_left(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 45 | return MUNIT_OK; 46 | } 47 | 48 | 49 | MunitResult 50 | test_string_len(const MunitParameter Parameters[], void *Fixture) { 51 | munit_assert_int(standard_len(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 52 | return MUNIT_OK; 53 | } 54 | 55 | 56 | MunitResult 57 | test_string_mid(const MunitParameter Parameters[], void *Fixture) { 58 | munit_assert_int(standard_mid(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 59 | return MUNIT_OK; 60 | } 61 | 62 | 63 | MunitResult 64 | test_string_replace(const MunitParameter Parameters[], void *Fixture) { 65 | munit_assert_int(standard_replace(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 66 | return MUNIT_OK; 67 | } 68 | 69 | 70 | MunitResult 71 | test_string_right(const MunitParameter Parameters[], void *Fixture) { 72 | munit_assert_int(standard_right(NULL, NULL, NULL, NULL, NULL), ==, ERROR_UNIMPLEMENTED); 73 | return MUNIT_OK; 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /tests/standard/string/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_string_concat(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_string_delete(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_string_find(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_string_insert(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_string_left(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_string_len(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_string_mid(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_string_replace(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_string_right(const MunitParameter Parameters[], void *Fixture); 25 | 26 | 27 | #endif // _TESTS_H 28 | -------------------------------------------------------------------------------- /tests/standard/time/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= time.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/time/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_time[] = { 8 | { "time/add_dt_time", test_time_add_dttime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "time/add_time", test_time_add_time, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "time/add_tod_time", test_time_add_todtime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "time/concat_date_tod", test_time_concat_datetod, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "time/divtime", test_time_divtime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "time/multime", test_time_multime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "time/sub_date_date", test_time_sub_datedate, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "time/sub_dt_dt", test_time_sub_dtdt, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "time/sub_dt_time", test_time_sub_dttime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 17 | { "time/sub_time", test_time_sub_time, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 18 | { "time/sub_tod_time", test_time_sub_todtime, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 19 | { "time/sub_tod_tod", test_time_sub_todtod, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 20 | 21 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /tests/standard/time/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | MunitResult test_time_add_dttime(const MunitParameter Parameters[], void *Fixture); 12 | 13 | MunitResult test_time_add_time(const MunitParameter Parameters[], void *Fixture); 14 | 15 | MunitResult test_time_add_todtime(const MunitParameter Parameters[], void *Fixture); 16 | 17 | MunitResult test_time_concat_datetod(const MunitParameter Parameters[], void *Fixture); 18 | 19 | MunitResult test_time_divtime(const MunitParameter Parameters[], void *Fixture); 20 | 21 | MunitResult test_time_multime(const MunitParameter Parameters[], void *Fixture); 22 | 23 | MunitResult test_time_sub_datedate(const MunitParameter Parameters[], void *Fixture); 24 | 25 | MunitResult test_time_sub_dtdt(const MunitParameter Parameters[], void *Fixture); 26 | 27 | MunitResult test_time_sub_dttime(const MunitParameter Parameters[], void *Fixture); 28 | 29 | MunitResult test_time_sub_time(const MunitParameter Parameters[], void *Fixture); 30 | 31 | MunitResult test_time_sub_todtime(const MunitParameter Parameters[], void *Fixture); 32 | 33 | MunitResult test_time_sub_todtod(const MunitParameter Parameters[], void *Fixture); 34 | 35 | 36 | #endif // _TESTS_H 37 | -------------------------------------------------------------------------------- /tests/standard/timers/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= timers.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/timers/src/timers.txt: -------------------------------------------------------------------------------- 1 | program test 2 | var count: uint := 0; end_var 3 | var input: bool; end_var 4 | var fb: %s; end_var 5 | 6 | add count, 1 7 | st count 8 | mod 10 9 | eq 1 10 | jmpcn timer 11 | xor input, true 12 | st input 13 | timer: cal fb( 14 | in := input, 15 | pt := t#250ms 16 | ) 17 | 18 | eq count, 30 19 | _exitc 20 | 21 | end_program 22 | 23 | configuration config1 24 | task task1 (interval := t#50ms, priority := 1); 25 | program program1 with task1: test; 26 | end_configuration 27 | 28 | -------------------------------------------------------------------------------- /tests/standard/timers/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_timers[] = { 8 | 9 | { "timers/tof", test_timers_tof, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "timers/ton", test_timers_ton, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "timers/tp", test_timers_tp, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 12 | 13 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /tests/standard/timers/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_timers_tof(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_timers_ton(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_timers_tp(const MunitParameter Parameters[], void *Fixture); 13 | 14 | 15 | #endif // _TESTS_H 16 | -------------------------------------------------------------------------------- /tests/standard/type/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,../..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= type.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/standard/type/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | 7 | MunitTest suite_standard_type[] = { 8 | { "type/bcd", test_type_bcd, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "type/conversion", test_type_conversion, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "type/trunc", test_type_trunc, suite_setup, suite_teardown, MUNIT_TEST_OPTION_NONE, NULL }, 11 | 12 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /tests/standard/type/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | 11 | MunitResult test_type_bcd(const MunitParameter Parameters[], void *Fixture); 12 | 13 | MunitResult test_type_conversion(const MunitParameter Parameters[], void *Fixture); 14 | 15 | MunitResult test_type_trunc(const MunitParameter Parameters[], void *Fixture); 16 | 17 | 18 | #endif // _TESTS_H 19 | -------------------------------------------------------------------------------- /tests/standard/type/type.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | MunitResult 15 | test_type_bcd(const MunitParameter Parameters[], void *Fixture) { 16 | ECHIDNA *pContext; 17 | 18 | pContext = (ECHIDNA *) Fixture; 19 | munit_assert_not_null(pContext); 20 | 21 | return MUNIT_SKIP; 22 | } 23 | 24 | 25 | MunitResult 26 | test_type_conversion(const MunitParameter Parameters[], void *Fixture) { 27 | ECHIDNA *pContext; 28 | 29 | pContext = (ECHIDNA *) Fixture; 30 | munit_assert_not_null(pContext); 31 | 32 | return MUNIT_SKIP; 33 | } 34 | 35 | 36 | MunitResult 37 | test_type_trunc(const MunitParameter Parameters[], void *Fixture) { 38 | ECHIDNA *pContext; 39 | LL sParameters; 40 | PARAMETER *pParameter; 41 | VALUE sResult; 42 | 43 | pContext = (ECHIDNA *) Fixture; 44 | munit_assert_not_null(pContext); 45 | 46 | ll_initialise(&sParameters, parameter_destroy); 47 | value_initialise(&sResult); 48 | munit_assert_int(standard_trunc(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_COUNT); 49 | munit_assert_not_null(pParameter = parameter_new(NULL)); 50 | value_assign(&pParameter->Value, TYPE_INT); 51 | munit_assert_int(ll_insert(&sParameters, pParameter), ==, 0); 52 | munit_assert_int(standard_trunc(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 53 | value_assign(&pParameter->Value, ANY_REAL); 54 | munit_assert_int(standard_trunc(pContext, NULL, &sParameters, &sResult, NULL), ==, ERROR_PARAMETER_TYPE); 55 | value_assign(&pParameter->Value, TYPE_LREAL, 3.142); 56 | munit_assert_int(standard_trunc(pContext, NULL, &sParameters, &sResult, NULL), ==, 0); 57 | munit_assert_uint32(sResult.Type, ==, TYPE_LREAL); 58 | munit_assert_double(sResult.Value.Double, ==, 3); 59 | value_assign(&pParameter->Value, TYPE_REAL, 3.142); 60 | munit_assert_int(standard_trunc(pContext, NULL, &sParameters, &sResult, NULL), ==, 0); 61 | munit_assert_uint32(sResult.Type, ==, TYPE_REAL); 62 | munit_assert_float(sResult.Value.Single, ==, 3); 63 | ll_destroy(&sParameters); 64 | 65 | return MUNIT_OK; 66 | } 67 | 68 | 69 | -------------------------------------------------------------------------------- /tests/stats/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/stats/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_stats[] = { 7 | { "initialise", test_stats_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | 9 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /tests/stats/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | MunitResult 10 | test_stats_initialise(const MunitParameter Parameters[], void *Fixture) { 11 | STATS sStats; 12 | 13 | stats_initialise(&sStats); 14 | munit_assert_uint64(sStats.Cycle, ==, 0); 15 | munit_assert_uint64(sStats.Overrun, ==, 0); 16 | munit_assert_double(sStats.Execution, ==, 0.0); 17 | munit_assert_double(sStats.ExecutionStart, ==, 0.0); 18 | munit_assert_double(sStats.Latency, ==, 0.0); 19 | munit_assert_double(sStats.LatencyEnd, ==, 0.0); 20 | munit_assert_double(sStats.LatencyStart, ==, 0.0); 21 | munit_assert_double(sStats.Maximum, ==, 0.0); 22 | munit_assert_double(sStats.Start, >=, 0.0); 23 | 24 | return MUNIT_OK; 25 | } 26 | -------------------------------------------------------------------------------- /tests/stats/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_stats_initialise(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/strl/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/strl/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_strl[] = { 7 | { "basic", test_strl_basic, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | 9 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /tests/strl/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | MunitResult 10 | test_strl_basic(const MunitParameter Parameters[], void *Fixture) { 11 | char sBuffer[5]; 12 | 13 | munit_assert_size(strlcpy(sBuffer, "ab", sizeof(sBuffer)), ==, 2); 14 | munit_assert_size(strlcat(sBuffer, "cd", sizeof(sBuffer)), ==, 4); 15 | munit_assert_string_equal(sBuffer, "abcd"); 16 | 17 | munit_assert_size(strlcpy(sBuffer, "abcd", sizeof(sBuffer)), ==, 4); 18 | munit_assert_size(strlcat(sBuffer, "efgh", sizeof(sBuffer)), ==, 8); 19 | munit_assert_string_equal(sBuffer, "abcd"); 20 | 21 | // This is an odd scenario where the destination buffer is already full, _without_ 22 | // a trailing '\0' character. 23 | munit_assert_size(strlcpy(sBuffer, "abcd", sizeof(sBuffer)), ==, 4); 24 | munit_assert_size(strlcat(sBuffer, "efgh", 4), ==, 8); 25 | 26 | sBuffer[0] = '\0'; 27 | munit_assert_size(strlcpy(sBuffer, "abcd", 0), ==, 0); 28 | munit_assert_size(strlcat(sBuffer, "abcd", 0), ==, 0); 29 | 30 | munit_assert_size(strlcpy(NULL, "abc", sizeof(sBuffer)), ==, 0); 31 | munit_assert_size(strlcat(NULL, "abc", sizeof(sBuffer)), ==, 0); 32 | munit_assert_size(strlcpy(sBuffer, NULL, sizeof(sBuffer)), ==, 0); 33 | munit_assert_size(strlcat(sBuffer, NULL, sizeof(sBuffer)), ==, 0); 34 | 35 | return MUNIT_OK; 36 | } 37 | -------------------------------------------------------------------------------- /tests/strl/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_strl_basic(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/stub/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/stub/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest Suite_Stub[] = { 7 | { "template", test_stub_template, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 8 | 9 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 10 | }; 11 | 12 | -------------------------------------------------------------------------------- /tests/stub/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | /* #include */ 7 | 8 | 9 | MunitResult 10 | test_stub_template(const MunitParameter Parameters[], void *Fixture) { 11 | return MUNIT_OK; 12 | } 13 | -------------------------------------------------------------------------------- /tests/stub/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_stub_template(const MunitParameter Parameters[], void *Fixture); 9 | 10 | 11 | #endif // _TESTS_H 12 | -------------------------------------------------------------------------------- /tests/suite.h: -------------------------------------------------------------------------------- 1 | #ifndef _SUITE_H 2 | #define _SUITE_H 3 | 4 | 5 | #include 6 | 7 | #include 8 | 9 | 10 | extern MunitTest suite_block[]; 11 | 12 | extern MunitTest suite_callback[]; 13 | 14 | extern MunitTest suite_cast[]; 15 | 16 | extern MunitTest suite_digest[]; 17 | 18 | extern MunitTest suite_echidna[]; 19 | 20 | extern MunitTest suite_grammar[]; 21 | 22 | extern MunitTest suite_list[]; 23 | 24 | extern MunitTest suite_operator[]; 25 | 26 | extern MunitTest suite_queue[]; 27 | 28 | extern MunitTest suite_standard_arithmetic[]; 29 | 30 | extern MunitTest suite_standard_bistable[]; 31 | 32 | extern MunitTest suite_standard_bitstring[]; 33 | 34 | extern MunitTest suite_standard_bitwise[]; 35 | 36 | extern MunitTest suite_standard_comparison[]; 37 | 38 | extern MunitTest suite_standard_counters[]; 39 | 40 | extern MunitTest suite_standard_edge[]; 41 | 42 | extern MunitTest suite_standard_numeric[]; 43 | 44 | extern MunitTest suite_standard_rtc[]; 45 | 46 | extern MunitTest suite_standard_select[]; 47 | 48 | extern MunitTest suite_standard_string[]; 49 | 50 | extern MunitTest suite_standard_time[]; 51 | 52 | extern MunitTest suite_standard_timers[]; 53 | 54 | extern MunitTest suite_standard_type[]; 55 | 56 | extern MunitTest suite_stats[]; 57 | 58 | extern MunitTest suite_strl[]; 59 | 60 | extern MunitTest suite_tree[]; 61 | 62 | extern MunitTest suite_value[]; 63 | 64 | extern MunitTest suite_unit[]; 65 | 66 | 67 | void * suite_setup(const MunitParameter Parameters[], void *Data); 68 | 69 | void suite_teardown(void *Data); 70 | 71 | int test_parse(ECHIDNA *Context, char *Source); 72 | 73 | 74 | #endif // _SUITE_H 75 | -------------------------------------------------------------------------------- /tests/tree/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/tree/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_tree[] = { 7 | 8 | { "initialise", test_tree_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "iterate", test_tree_iterate, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "new", test_tree_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "operations", test_tree_operations, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "remove", test_tree_remove, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | 14 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /tests/tree/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_tree_initialise(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_tree_iterate(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_tree_new(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_tree_operations(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_tree_remove(const MunitParameter Parameters[], void *Fixture); 17 | 18 | 19 | #endif // _TESTS_H 20 | -------------------------------------------------------------------------------- /tests/unit/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/unit/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_unit[] = { 7 | 8 | { "create", test_unit_create, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "initialise", test_unit_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "new", test_unit_new, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | 12 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /tests/unit/tests.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | 9 | MunitResult 10 | test_unit_create(const MunitParameter Parameters[], void *Fixture) { 11 | BLOCK *pBlock; 12 | UNIT *pUnit; 13 | 14 | pUnit = unit_create("_config", "_resource", "_pou"); 15 | munit_assert_not_null(pUnit); 16 | munit_assert_not_null(pUnit->Config); 17 | munit_assert_string_equal(pUnit->Config, "_config"); 18 | munit_assert_not_null(pUnit->Resource); 19 | munit_assert_string_equal(pUnit->Resource, "_resource"); 20 | munit_assert_not_null(pUnit->POU); 21 | munit_assert_string_equal(pUnit->POU, "_pou"); 22 | munit_assert_size(pUnit->Size, ==, 0); 23 | munit_assert_uint8(pUnit->Alloc, !=, 0); 24 | pBlock = &pUnit->Block; 25 | munit_assert_ptr(pBlock, ==, pUnit); 26 | munit_assert_not_null(block_name(pBlock)); 27 | munit_assert_string_equal(block_name(pBlock), "_config._resource._pou"); 28 | unit_destroy(pUnit); 29 | 30 | return MUNIT_OK; 31 | } 32 | 33 | 34 | MunitResult 35 | test_unit_initialise(const MunitParameter Parameters[], void *Fixture) { 36 | UNIT sUnit; 37 | 38 | unit_initialise(&sUnit, NULL, NULL, NULL); 39 | munit_assert_null(sUnit.Config); 40 | munit_assert_null(sUnit.Resource); 41 | munit_assert_null(sUnit.POU); 42 | munit_assert_size(sUnit.Size, ==, 0); 43 | munit_assert_uint8(sUnit.Alloc, ==, 0); 44 | unit_destroy(&sUnit); 45 | 46 | unit_initialise(&sUnit, NULL, NULL, NULL, NULL); 47 | unit_destroy(NULL); 48 | 49 | return MUNIT_OK; 50 | } 51 | 52 | 53 | MunitResult 54 | test_unit_new(const MunitParameter Parameters[], void *Fixture) { 55 | UNIT *pUnit; 56 | 57 | pUnit = unit_new(); 58 | munit_assert_not_null(pUnit); 59 | munit_assert_null(pUnit->Config); 60 | munit_assert_null(pUnit->Resource); 61 | munit_assert_null(pUnit->POU); 62 | munit_assert_size(pUnit->Size, ==, 0); 63 | munit_assert_uint8(pUnit->Alloc, !=, 0); 64 | unit_destroy(pUnit); 65 | 66 | return MUNIT_OK; 67 | } 68 | -------------------------------------------------------------------------------- /tests/unit/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_unit_create(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_unit_initialise(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_unit_new(const MunitParameter Parameters[], void *Fixture); 13 | 14 | 15 | #endif // _TESTS_H 16 | -------------------------------------------------------------------------------- /tests/value/Makefile: -------------------------------------------------------------------------------- 1 | # echidna - IEC 61131-3 compiler and virtual machine 2 | 3 | CC?= $(CROSS)gcc 4 | AR?= $(CROSS)ar 5 | 6 | SRCDIR:= ../../src 7 | 8 | CFLAGS:= -Wall -g -std=c99 9 | DEFINES:= -D_POSIX_C_SOURCE=200809L 10 | INCLUDE_TEMPLATE:= -I! -I!/include 11 | INCLUDES:= $(subst !,.,$(INCLUDE_TEMPLATE)) \ 12 | $(subst !,..,$(INCLUDE_TEMPLATE)) \ 13 | $(subst !,$(SRCDIR),$(INCLUDE_TEMPLATE)) 14 | 15 | TARGET:= libsuite.a 16 | OBJS:= assign.o cast.o istype.o tests.o suite.o 17 | 18 | all: clean $(TARGET) 19 | 20 | $(TARGET): $(OBJS) 21 | $(AR) rcs $@ $^ 22 | 23 | .c.o: 24 | $(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< 25 | 26 | clean: 27 | rm -f $(TARGET) core *.o 28 | 29 | -------------------------------------------------------------------------------- /tests/value/suite.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | 6 | MunitTest suite_value[] = { 7 | 8 | { "assign", test_value_assign, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 9 | { "cast", test_value_cast, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 10 | { "initialise", test_value_initialise, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 11 | { "istype", test_value_istype, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 12 | { "strtotype", test_value_strtotype, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 13 | { "strtoval", test_value_strtoval, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 14 | { "type", test_value_type, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 15 | { "typetostr", test_value_typetostr, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 16 | { "typetosize", test_value_typetosize, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }, 17 | 18 | { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /tests/value/tests.h: -------------------------------------------------------------------------------- 1 | #ifndef _TESTS_H 2 | #define _TESTS_H 3 | 4 | 5 | #include 6 | 7 | 8 | MunitResult test_value_assign(const MunitParameter Parameters[], void *Fixture); 9 | 10 | MunitResult test_value_cast(const MunitParameter Parameters[], void *Fixture); 11 | 12 | MunitResult test_value_initialise(const MunitParameter Parameters[], void *Fixture); 13 | 14 | MunitResult test_value_istype(const MunitParameter Parameters[], void *Fixture); 15 | 16 | MunitResult test_value_strtotype(const MunitParameter Parameters[], void *Fixture); 17 | 18 | MunitResult test_value_strtoval(const MunitParameter Parameters[], void *Fixture); 19 | 20 | MunitResult test_value_type(const MunitParameter Parameters[], void *Fixture); 21 | 22 | MunitResult test_value_typetostr(const MunitParameter Parameters[], void *Fixture); 23 | 24 | MunitResult test_value_typetosize(const MunitParameter Parameters[], void *Fixture); 25 | 26 | 27 | #endif // _TESTS_H 28 | --------------------------------------------------------------------------------