├── examples ├── rot13_factory │ ├── src │ │ ├── get_input.h │ │ ├── rot13_stage.h │ │ ├── output_stage.h │ │ ├── reacto_factory_config.h │ │ ├── Sconscript.variant │ │ ├── output_stage.c │ │ ├── rot13_stage.c │ │ ├── get_input.c │ │ ├── platform.c │ │ └── main.c │ └── Sconscript ├── msp430_blink │ ├── Sconscript.variant │ ├── Sconscript │ └── main.c ├── msp430_timed_blink │ ├── Sconscript.variant │ ├── Sconscript │ └── main.c ├── msp430_realtime_blink │ ├── Sconscript.variant │ ├── Sconscript │ └── main.c ├── msp430_board.h └── README.md ├── reacto_tests ├── src_host_tests │ ├── main.cpp │ ├── reusables │ │ └── time.c │ └── test_threaded_event_loop.cpp ├── src_tests │ ├── watchdog │ │ ├── hardware_watchdog.cpp │ │ └── test_watchdog.cpp │ ├── test_example.cpp │ ├── reusables │ │ ├── test_log.cpp │ │ ├── log_mock.cpp │ │ ├── test_array.cpp │ │ ├── test_fast_ring_fifo.cpp │ │ ├── test_signal_slot.cpp │ │ └── test_timeout.cpp │ ├── test_queue.cpp │ ├── test_timed_queue.cpp │ └── text_context_and_factory.cpp ├── Sconscript └── Sconscript.variant ├── reacto ├── src │ ├── Sconscript │ ├── reusables │ │ ├── signal_slot.c │ │ ├── array.c │ │ └── timeout.c │ ├── signal_slot_queue.c │ ├── queue_interface.c │ ├── queue.c │ ├── watchdog │ │ └── watchdog.c │ ├── timed_queue.c │ └── main_loop.c ├── Sconscript └── includes │ └── reacto │ ├── realtime │ └── ab_timing.h │ ├── watchdog │ ├── hardware_watchdog.h │ └── watchdog.h │ ├── reusables │ ├── macros.h │ ├── debug.h │ ├── linked_list.hpp │ ├── time.h │ ├── signal_slot.h │ ├── log.h │ ├── timeout.h │ ├── fast_ring_fifo.h │ ├── array.h │ ├── signal_slot.template │ └── linked_list.h │ ├── queue_interface.h │ ├── signal_slot_queue.h │ ├── context.h │ ├── main_loop.h │ ├── context_factory.template │ ├── timed_queue.h │ ├── queue.h │ └── event_loop_types.h ├── .gitignore ├── .codecov.yml ├── dependencies └── cpputest │ ├── setup-cpputest.sh │ ├── Sconscript │ ├── Sconscript.variant │ └── include │ └── generated │ └── CppUTestGeneratedConfig.h ├── .travis.yml ├── LICENSE ├── Sconstruct ├── .ycm_extra_conf.py └── README.md /examples/rot13_factory/src/get_input.h: -------------------------------------------------------------------------------- 1 | #ifndef GET_INPUT_H_ 2 | #define GET_INPUT_H_ 3 | 4 | void get_input_init(); 5 | 6 | #endif /* GET_INPUT_H_ */ 7 | -------------------------------------------------------------------------------- /reacto_tests/src_host_tests/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int ac, char** av) 4 | { 5 | return CommandLineTestRunner::RunAllTests(ac, av); 6 | } 7 | -------------------------------------------------------------------------------- /reacto_tests/src_host_tests/reusables/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | reacto_time_t time_now_variable = 0; 4 | 5 | reacto_time_t time_now() 6 | { 7 | return time_now_variable; 8 | } 9 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/rot13_stage.h: -------------------------------------------------------------------------------- 1 | #ifndef rot13_H_ 2 | #define rot13_H_ 3 | 4 | #include 5 | 6 | #define rot13_stage_buffer_size 2 7 | 8 | int rot13_stage_handler (queue_t * queue); 9 | void rot13_stage_push (char c); 10 | 11 | #endif /* rot13_H_ */ 12 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/output_stage.h: -------------------------------------------------------------------------------- 1 | #ifndef SECOND_STAGE_H_ 2 | #define SECOND_STAGE_H_ 3 | 4 | #include 5 | 6 | #define output_stage_buffer_size 2 7 | 8 | int output_stage_handler (queue_t * queue); 9 | void output_stage_push (char c); 10 | 11 | #endif /* SECOND_STAGE_H_ */ 12 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/reacto_factory_config.h: -------------------------------------------------------------------------------- 1 | #ifndef EXAMPLES_HOST_CONTEXT_REACTO_FACTORY_CONFIG_H_ 2 | #define EXAMPLES_HOST_CONTEXT_REACTO_FACTORY_CONFIG_H_ 3 | 4 | #define REACTO_N_OF_QUEUES 2 5 | #define REACTO_MAX_N_OF_HANDLERS_PER_QUEUE 1 6 | 7 | #endif /* EXAMPLES_HOST_CONTEXT_REACTO_FACTORY_CONFIG_H_ */ 8 | -------------------------------------------------------------------------------- /reacto/src/Sconscript: -------------------------------------------------------------------------------- 1 | #!python 2 | Import('env') 3 | 4 | r = { 5 | 'libs' : [], 6 | 'path' : [], 7 | 'objs' : [] 8 | } 9 | 10 | src = env.FindFiles('./', '*.c') 11 | lib = env.StaticLibrary('reacto', src) 12 | 13 | Depends(env.SourceToObjects(src), env['CXXINCLUDES'] + env['CINCLUDES']) 14 | 15 | r['libs'].extend(lib) 16 | Return('r') 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore eclipse files 2 | .project 3 | .cproject 4 | .settings 5 | 6 | # Ignore build files and folders 7 | build 8 | coverage/ 9 | .coverage.info 10 | .coverage.info.pre 11 | .codecov.ignore 12 | .sconsign.dblite 13 | tests_report 14 | coverage_report 15 | *.pyc 16 | *.pyo 17 | 18 | # Ignore downloaded cpputest 19 | cpputest-3.8.tar.gz 20 | cpputest-3.8 21 | cpputest-tree 22 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "/usr" 4 | - "dependencies/*" 5 | - "*/UtestPlatform.cpp" 6 | - "*/signal_slot_queue.c" 7 | # This file shares the signal_slot.template but doesn't test it 8 | 9 | comment: 10 | layout: "header, diff, tree" 11 | behavior: default 12 | require_changes: false # if true: only post the comment if coverage changes 13 | branches: null 14 | flags: null 15 | paths: null 16 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/watchdog/hardware_watchdog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" void hardware_watchdog_init() 4 | { 5 | mock().actualCall("hardware_watchdog_init"); 6 | } 7 | 8 | extern "C" void hardware_watchdog_kick() 9 | { 10 | mock().actualCall("hardware_watchdog_kick"); 11 | } 12 | 13 | extern "C" void hardware_watchdog_deinit() 14 | { 15 | mock().actualCall("hardware_watchdog_deinit"); 16 | } 17 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/Sconscript.variant: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | import os 4 | 5 | Import('env') 6 | Import('name') 7 | 8 | env = env.Clone() 9 | map_file = Dir('../').path + '/rot13_factory_' + name + '.map' 10 | env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file]) 11 | 12 | sources = env.FindFiles('../', '*.c') 13 | exes = env.Program(['../rot13_factory_' + name, map_file], sources) 14 | exe = {'exe': exes[0], 'map': exes[1]} 15 | Return('exe') 16 | -------------------------------------------------------------------------------- /examples/msp430_blink/Sconscript.variant: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | import os 4 | 5 | Import('env') 6 | Import('name') 7 | 8 | env = env.Clone() 9 | map_file = Dir('../').path + '/msp430_blink_' + name + '.map' 10 | env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file]) 11 | 12 | sources = [File('main.c')] 13 | objects = env.SourceToObjects(sources) 14 | Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES']) 15 | 16 | exes = env.Program(['../msp430_blink_' + name + '.elf', map_file], sources) 17 | exe = {'exe': exes[0], 'map': exes[1]} 18 | Return('exe') 19 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/test_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | /* 5 | * Basic testing guideline: 6 | * 1) Test all functionalities 7 | * 2) Test buffer boundaries 8 | * 3) Test invalid arguments 9 | */ 10 | 11 | 12 | TEST_GROUP(FirstTestGroup) 13 | { 14 | void setup () 15 | { 16 | } 17 | 18 | void teardown () 19 | { 20 | mock().clear(); 21 | } 22 | }; 23 | 24 | TEST(FirstTestGroup, FirstTest) 25 | { 26 | int x = 1; 27 | CHECK_EQUAL(1, x); 28 | } 29 | 30 | -------------------------------------------------------------------------------- /examples/msp430_timed_blink/Sconscript.variant: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | import os 4 | 5 | Import('env') 6 | Import('name') 7 | 8 | env = env.Clone() 9 | map_file = Dir('../').path + '/msp430_timed_blink_' + name + '.map' 10 | env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file]) 11 | 12 | sources = [File('main.c')] 13 | objects = env.SourceToObjects(sources) 14 | Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES']) 15 | 16 | exes = env.Program(['../msp430_timed_blink_' + name + '.elf', map_file], sources) 17 | exe = {'exe': exes[0], 'map': exes[1]} 18 | Return('exe') 19 | -------------------------------------------------------------------------------- /examples/msp430_realtime_blink/Sconscript.variant: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | import os 4 | 5 | Import('env') 6 | Import('name') 7 | 8 | env = env.Clone() 9 | map_file = Dir('../').path + '/msp430_realtime_blink_' + name + '.map' 10 | env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file]) 11 | 12 | sources = [File('main.c')] 13 | objects = env.SourceToObjects(sources) 14 | Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES']) 15 | 16 | exes = env.Program(['../msp430_realtime_blink_' + name + '.elf', map_file], sources) 17 | exe = {'exe': exes[0], 'map': exes[1]} 18 | Return('exe') 19 | -------------------------------------------------------------------------------- /examples/msp430_blink/Sconscript: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | Import('platforms') 4 | 5 | for plat in platforms: 6 | name = plat.Name() 7 | env = plat.Env().Clone() 8 | env.UpdateIncludes() 9 | build_dir = './build/' + name 10 | exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0) 11 | 12 | # Add build results symbols to the platform 13 | plat.BuildListAddDirectory('msp430_blink', Dir(build_dir)) 14 | plat.BuildListAddBinary('msp430_blink', exe['exe']) 15 | # plat['msp430_blink_map_file'] = exe['map'] 16 | -------------------------------------------------------------------------------- /examples/rot13_factory/Sconscript: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | Import('platforms') 4 | 5 | for plat in platforms: 6 | name = plat.Name() 7 | env = plat.Env().Clone() 8 | env.UpdateIncludes() 9 | build_dir = './build/' + name 10 | exe = env.SConscript('./src/Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'src', duplicate=0) 11 | 12 | # Add build results symbols to the platform 13 | plat.BuildListAddDirectory('rot13_factory', Dir(build_dir)) 14 | plat.BuildListAddBinary('rot13_factory', exe['exe']) 15 | # plat['rot13_factory_map_file'] = exe['map'] 16 | -------------------------------------------------------------------------------- /examples/msp430_timed_blink/Sconscript: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | Import('platforms') 4 | 5 | for plat in platforms: 6 | name = plat.Name() 7 | env = plat.Env().Clone() 8 | env.UpdateIncludes() 9 | build_dir = './build/' + name 10 | exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0) 11 | 12 | # Add build results symbols to the platform 13 | plat.BuildListAddDirectory('msp430_timed_blink', Dir(build_dir)) 14 | plat.BuildListAddBinary('msp430_timed_blink', exe['exe']) 15 | # plat['msp430_timed_blink_map_file'] = exe['map'] 16 | -------------------------------------------------------------------------------- /examples/msp430_realtime_blink/Sconscript: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | Import('platforms') 4 | 5 | for plat in platforms: 6 | name = plat.Name() 7 | env = plat.Env().Clone() 8 | env.UpdateIncludes() 9 | build_dir = './build/' + name 10 | exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0) 11 | 12 | # Add build results symbols to the platform 13 | plat.BuildListAddDirectory('msp430_realtime_blink', Dir(build_dir)) 14 | plat.BuildListAddBinary('msp430_realtime_blink', exe['exe']) 15 | # plat['msp430_blink_map_file'] = exe['map'] 16 | -------------------------------------------------------------------------------- /reacto_tests/Sconscript: -------------------------------------------------------------------------------- 1 | Import('platforms') 2 | 3 | for plat in platforms: 4 | name = plat.Name() 5 | env = plat.Env().Clone() 6 | env.UpdateIncludes() 7 | build_dir = './build/' + name 8 | exe = env.SConscript('./Sconscript.variant', exports = ['name','env'], variant_dir = build_dir, src = 'tests', duplicate=0) 9 | 10 | # Add build results symbols to the platform 11 | plat.BuildListAddDirectory('reacto_tests', Dir(build_dir)) 12 | plat.BuildListAddBinary('reacto_tests', exe['exe']) 13 | plat.CoverageAddExclusion(File('./src_host_tests/platform/UtestPlatform.cpp').path) 14 | # plat['reacto_tests_map_file'] = exe['map'] 15 | -------------------------------------------------------------------------------- /dependencies/cpputest/setup-cpputest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Bash script that download and build cpputest inside the project tree, 4 | # where project's Makefile will look for it. 5 | if [ -z "$1" ]; then 6 | echo "Usage $0 " 7 | exit -1 8 | fi 9 | 10 | if [ -e $1 ]; then 11 | if [ ! -d $1 ]; then 12 | echo "Path $1 exists and is not a folder." 13 | exit -1 14 | fi 15 | fi 16 | 17 | rm -rf $1 18 | 19 | if [ ! -e './cpputest-3.8.tar.gz' ]; then 20 | wget https://github.com/cpputest/cpputest/releases/download/v3.8/cpputest-3.8.tar.gz 21 | fi 22 | tar -xf cpputest-3.8.tar.gz 23 | mv cpputest-3.8 $1 24 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/output_stage.c: -------------------------------------------------------------------------------- 1 | #include "reacto_factory_config.h" 2 | #include 3 | #include 4 | #include "output_stage.h" 5 | 6 | #include 7 | 8 | struct stage_data 9 | { 10 | char c; 11 | }; 12 | 13 | static struct stage_data stage_buffer[output_stage_buffer_size]; 14 | 15 | int output_stage_handler (queue_t * queue) 16 | { 17 | struct stage_data ev; 18 | queue_peek(queue, stage_buffer, &ev); 19 | putchar(ev.c); 20 | return 0; 21 | } 22 | 23 | void output_stage_push (char c) 24 | { 25 | struct stage_data ev; 26 | ev.c = c; 27 | queue_push(reacto_context_queue(1), stage_buffer, ev); 28 | } 29 | -------------------------------------------------------------------------------- /reacto_tests/Sconscript.variant: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | Import('env') 4 | Import('name') 5 | 6 | env = env.Clone() 7 | map_file = Dir('../').path + '/reacto_' + name + '.map' 8 | env.Append(LINKFLAGS = ['-Xlinker', '-Map=' + map_file]) 9 | 10 | sources = env.FindFiles('./src_tests', '*.c') 11 | sources.extend (env.FindFiles('./src_tests', '*.cpp')) 12 | sources.extend (env.FindFiles('./src_' + name, '*.c')) 13 | sources.extend (env.FindFiles('./src_' + name, '*.cpp')) 14 | objects = env.SourceToObjects(sources) 15 | Depends(objects, env['CXXINCLUDES'] + env['CINCLUDES']) 16 | 17 | exes = env.Program(['../reacto_' + name, map_file], sources) 18 | exe = {'exe': exes[0], 'map': exes[1]} 19 | Return('exe') 20 | -------------------------------------------------------------------------------- /reacto/Sconscript: -------------------------------------------------------------------------------- 1 | Import('platforms') 2 | 3 | for plat in platforms: 4 | name = plat.Name() 5 | plat.Env().Append(CPPPATH = [Dir('./includes')]) 6 | if 'tests' in name: 7 | plat.Env().Append(CPPPATH = [Dir('./src')]) 8 | 9 | env = plat.Env().Clone() 10 | env.UpdateIncludes() 11 | build_dir = './build/' + name 12 | mods = env.SConscript('./src/Sconscript', exports = 'env', variant_dir=build_dir, duplicate=0) 13 | 14 | # Add libs and includes to parent env. 15 | plat.Env().Append(LIBS = mods['libs']) 16 | plat.Env().Append(LIBPATH = mods['path']) 17 | plat.BuildListAddDirectory('reacto', Dir(build_dir)) 18 | plat.BuildListAddLibrary('reacto', mods['libs'][0]) 19 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/test_log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" 5 | { 6 | #include 7 | } 8 | 9 | TEST_GROUP(Log) 10 | { 11 | void setup () 12 | { 13 | } 14 | 15 | void teardown () 16 | { 17 | mock().checkExpectations(); 18 | mock().clear(); 19 | } 20 | }; 21 | 22 | TEST(Log, periodic) 23 | { 24 | mock().expectOneCall("_log_file_line") 25 | .withParameter("msg", "Error: oops!") 26 | .withParameter("file", __FILE__) 27 | .withParameter("line", __LINE__ + 2); 28 | /* Do not remove this line, nor add any extra line before log_error */ 29 | log_error("oops!"); 30 | } 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | language: cpp 4 | 5 | addons: 6 | apt: 7 | packages: 8 | - lcov 9 | - binutils-msp430 10 | - gcc-msp430 11 | - msp430-libc 12 | 13 | script: 14 | - scons -Q reacto_tests/build/reacto_host_tests 15 | - ./reacto_tests/build/reacto_host_tests -v 16 | - scons -Q examples/msp430_blink/build/msp430_blink_msp430.elf 17 | - scons -Q examples/msp430_timed_blink/build/msp430_timed_blink_msp430.elf 18 | - scons -Q examples/msp430_realtime_blink/build/msp430_realtime_blink_msp430.elf 19 | - scons -Q examples/rot13_factory/build/rot13_factory_host 20 | 21 | after_success: 22 | - scons -Q .coverage.info 23 | - scons -Q .codecov.ignore 24 | - bash <(curl -s https://codecov.io/bash) "$(< .codecov.ignore)" 25 | -------------------------------------------------------------------------------- /reacto/includes/reacto/realtime/ab_timing.h: -------------------------------------------------------------------------------- 1 | #ifndef REACTO_REALTIME_AB_TIMING_H_ 2 | #define REACTO_REALTIME_AB_TIMING_H_ 3 | 4 | #include 5 | #include 6 | 7 | struct ab_timing_private 8 | { 9 | timeout_t t; 10 | }; 11 | 12 | typedef struct ab_timing_private ab_timing_t; 13 | 14 | static inline void ab_timing_start(ab_timing_t * obj) 15 | { 16 | debug_ptr(obj); 17 | timeout_init(&obj->t); 18 | } 19 | 20 | static inline void ab_timing_copy(ab_timing_t * to, ab_timing_t * from) 21 | { 22 | debug_ptr(to); 23 | debug_ptr(from); 24 | timeout_copy(&to->t, &from->t); 25 | } 26 | 27 | static inline bool ab_timing_check_criteria_failed(ab_timing_t * obj, reacto_time_t time_criteria) 28 | { 29 | debug_ptr(obj, false); 30 | return timeout_check(&obj->t, time_criteria); 31 | } 32 | 33 | 34 | 35 | #endif /* REACTO_REALTIME_AB_TIMING_H_ */ 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Felipe Lavratti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/rot13_stage.c: -------------------------------------------------------------------------------- 1 | #include "reacto_factory_config.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rot13_stage.h" 7 | #include "output_stage.h" 8 | 9 | struct stage_data 10 | { 11 | char c; 12 | }; 13 | 14 | static struct stage_data stage_buffer[rot13_stage_buffer_size]; 15 | 16 | static char * upper_array = "ABCDEFGHIJKLMNOPQRSTUVXYZ"; 17 | static char * lower_array = "abcdefghijklmnopqrstuvxyz"; 18 | 19 | static char rot13 (char c) 20 | { 21 | if (c >= 'a' && c <= 'z') 22 | return lower_array[(c - 'a' + 13) % (int)ARRAY_SIZE(lower_array)]; 23 | 24 | if (c >= 'A' && c <= 'Z') 25 | return upper_array[(c - 'A' + 13) % (int)ARRAY_SIZE(upper_array)]; 26 | 27 | return c; 28 | } 29 | 30 | int rot13_stage_handler (queue_t * queue) 31 | { 32 | struct stage_data ev; 33 | queue_peek(queue, stage_buffer, &ev); 34 | output_stage_push (rot13(ev.c)); 35 | return 0; 36 | } 37 | 38 | void rot13_stage_push (char c) 39 | { 40 | struct stage_data ev; 41 | ev.c = c; 42 | queue_push(reacto_context_queue(0), stage_buffer, ev); 43 | } 44 | -------------------------------------------------------------------------------- /examples/msp430_board.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef interrupt 4 | #define interrupt(...) void 5 | #endif 6 | 7 | #define LED0 BIT0 8 | #define LED1 BIT6 9 | #define BUTTON BIT3 10 | 11 | static void board_init(void) 12 | { 13 | __disable_interrupt(); 14 | WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer 15 | BCSCTL1 = CALBC1_1MHZ; // Set range 16 | DCOCTL = CALDCO_1MHZ; // SMCLK = DCO = 1MHz 17 | CCTL0 = CCIE; 18 | TACTL = TASSEL_2 + MC_1; // Set the timer A to SMCLCK, Continuous 19 | TACCR0 = 1000; 20 | // Clear the timer and enable timer interrupt 21 | 22 | P1DIR |= (LED0 + LED1); // Set P1.0 to output direction 23 | // P1.3 must stay at input 24 | P1OUT |= (LED0 + LED1); 25 | P1IE |= BUTTON; // P1.3 interrupt enabled 26 | P1IFG &= ~BUTTON; // P1.3 IFG cleared 27 | } 28 | 29 | volatile static reacto_time_t time_ms_cnt; 30 | 31 | interrupt(TIMER0_A0_VECTOR) timer_isr (void) 32 | { 33 | time_ms_cnt++; 34 | } 35 | 36 | /* Examples uses the time.h module, it is necessary to define 37 | the platform dependent functions */ 38 | reacto_time_t time_now () 39 | { 40 | return time_ms_cnt; 41 | } 42 | 43 | void time_sleep (reacto_time_t delay) 44 | { 45 | volatile const reacto_time_t now = time_ms_cnt; 46 | while ((time_ms_cnt - now) < delay); 47 | } 48 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/get_input.c: -------------------------------------------------------------------------------- 1 | #include "reacto_factory_config.h" 2 | #include 3 | #include 4 | #include "rot13_stage.h" 5 | 6 | #include 7 | #include 8 | 9 | static timed_event_t ev; 10 | 11 | static char poll_input() 12 | { 13 | fd_set rfds; 14 | struct timeval tv; 15 | int retval; 16 | 17 | /* Watch stdin (fd 0) to see when it has input. */ 18 | FD_ZERO(&rfds); 19 | FD_SET(0, &rfds); 20 | 21 | /* Wait up to 0 seconds. */ 22 | tv.tv_sec = 0; 23 | tv.tv_usec = 0; 24 | 25 | retval = select(1, &rfds, NULL, NULL, &tv); 26 | /* Don't rely on the value of tv now! */ 27 | 28 | if (retval == -1) 29 | perror("select()"); 30 | 31 | if (!retval) 32 | return 0; 33 | 34 | /* should not block */ 35 | int c = getchar (); 36 | if (c < 0) 37 | return 0; 38 | 39 | return (char)c; 40 | } 41 | 42 | static void get_input_periodic_handler (timed_event_t * ev) 43 | { 44 | char c; 45 | c = poll_input(); 46 | 47 | if (c) 48 | rot13_stage_push(c); 49 | 50 | /* Relink to get called cyclicly */ 51 | timed_queue_link(reacto_context_timed_queue(), ev); 52 | } 53 | 54 | void get_input_init() 55 | { 56 | timed_event_init(&ev, 5, get_input_periodic_handler); 57 | timed_queue_link(reacto_context_timed_queue(), &ev); 58 | setvbuf(stdin, NULL, _IONBF, 0); //turn off buffering 59 | } 60 | -------------------------------------------------------------------------------- /reacto/includes/reacto/watchdog/hardware_watchdog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_WATCHDOG_HARDWARE_WATCHDOG_H_ 25 | #define REACTO_WATCHDOG_HARDWARE_WATCHDOG_H_ 26 | 27 | void hardware_watchdog_init(); 28 | void hardware_watchdog_kick(); 29 | void hardware_watchdog_deinit(); 30 | 31 | #endif /* REACTO_WATCHDOG_HARDWARE_WATCHDOG_H_ */ 32 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## rot13_factory 4 | 5 | This is a rot13 algorithm example using the Factory (reacto/factory.h) sub-system where the initialization and allocation of 6 | every object related to the Main Loop is abstracted. 7 | It is an example supposed to run in the host machine, where an executable will be created. 8 | 9 | The example architecture implements a datapath where the stdin is read by periodic polling, using the Timed Queue deferred job scheduler. The handler then pushes the character read to the rot13 queue, where the rot13 handler will tranform the data and then 10 | pushe to the output queue, where te subsequent handler will output the processed character to the stdout. 11 | 12 | A sleep handler is installed in the Main Loop to let the program sleep whenever there's nothing to process, avoiding a busy loop that will occupy 100% of the CPU, or energy, if it was running in an embedded system. 13 | 14 | ## msp430 examples 15 | 16 | The examples starting with msp430 are meant to run in a launchpad board. These examples doesn't use the Factory sub-system, instead, ccore elements are initialized individually and manually. 17 | 18 | ### Building and running MSP430 examples 19 | 20 | 1. You need to install the compiler: 21 | 22 | ```sh 23 | sudo apt-get install binutils-msp430 gcc-msp430 msp430-libc mspdebug 24 | ``` 25 | 26 | 2. Change the target MCU on the mcp430.sconscript file, variable `mcu_flag` in `_SetupEnv` method of the class. 27 | 28 | 3. Connect the Launchpad board to your usb port, and run: 29 | 30 | ```sh 31 | scons -Q msp430_blink_deploy 32 | ``` 33 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/platform.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | void _log_file_line (const char * file, int line, const char * msg, ...) 12 | { 13 | /* 14 | * We want to use CppUTest Mock system in this function, 15 | * this way tests will fail if any code under tests print 16 | * an error message. 17 | */ 18 | va_list ap; 19 | va_start(ap, msg); 20 | 21 | printf("%s:%d ", file, line); 22 | vprintf(msg, ap); 23 | printf("\n"); 24 | 25 | va_end(ap); 26 | } 27 | 28 | 29 | void log_message (const char * msg, ...) 30 | { 31 | va_list ap; 32 | va_start(ap, msg); 33 | vprintf(msg, ap); 34 | printf("\n"); 35 | va_end(ap); 36 | } 37 | 38 | uint32_t time_now() 39 | { 40 | struct timeval tv; 41 | 42 | int r = gettimeofday(&tv, NULL); 43 | 44 | if (r != 0) //LCOV_EXCL_LINE 45 | { //LCOV_EXCL_LINE 46 | log_error("Unable to get time of day: %s", strerror(errno)); //LCOV_EXCL_LINE 47 | return 0; //LCOV_EXCL_LINE 48 | } //LCOV_EXCL_LINE 49 | 50 | uint32_t msec = (uint32_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000); 51 | return msec; 52 | } 53 | 54 | void time_sleep (uint32_t ms) 55 | { 56 | usleep(ms * 1000); 57 | } 58 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_MACROS_H_ 25 | #define REACTO_REUSABLES_MACROS_H_ 26 | 27 | #define container_of(ptr, type, member) ({ \ 28 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 29 | (type *)( (char *)__mptr - offsetof(type,member) );}) 30 | 31 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 32 | 33 | #endif /* REACTO_REUSABLES_MACROS_H_ */ 34 | -------------------------------------------------------------------------------- /reacto/src/reusables/signal_slot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | 26 | /* Setup macros to the template */ 27 | #define signal_prefix signal_ 28 | #define slot_prefix slot_ 29 | #define parameters_declaration(...) __VA_ARGS__ 30 | #define parameters_list(...) __VA_ARGS__ 31 | #define handler_parameters_list(...) __VA_ARGS__ 32 | 33 | /* Now we include the template, that was lots of fun, right? */ 34 | #include 35 | -------------------------------------------------------------------------------- /reacto/src/signal_slot_queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | 26 | /* Setup macros to the template */ 27 | #define signal_prefix signal_queue_ 28 | #define slot_prefix slot_queue_ 29 | #define parameters_declaration(...) __VA_ARGS__, queue_t * the_queue 30 | #define parameters_list(...) __VA_ARGS__, the_queue 31 | #define handler_parameters_list(...) the_queue 32 | 33 | /* Now we include the template, that was lots of fun, right? */ 34 | #include 35 | -------------------------------------------------------------------------------- /reacto/includes/reacto/queue_interface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_QUEUE_INTERFACE_H_ 25 | #define REACTO_QUEUE_INTERFACE_H_ 26 | 27 | #include 28 | #include "reusables/time.h" 29 | #include "event_loop_types.h" 30 | 31 | bool queue_interface_emit(queue_i * itf); 32 | size_t queue_interface_count(queue_i * itf); 33 | void queue_interface_pop(queue_i * itf); 34 | size_t queue_interface_hash(queue_i * itf); 35 | reacto_time_t queue_interface_sleep_tout(queue_i * itf); 36 | 37 | #endif /* REACTO_QUEUE_INTERFACE_H_ */ 38 | -------------------------------------------------------------------------------- /reacto/src/reusables/array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | 26 | void array_init(array_t * obj, size_t max_length) 27 | { 28 | debug_ptr(obj); 29 | 30 | obj->max = max_length; 31 | obj->top = 0; 32 | } 33 | 34 | void array_deinit(array_t * obj) 35 | { 36 | debug_ptr(obj); 37 | 38 | obj->max = 0; 39 | obj->top = 0; 40 | } 41 | 42 | void array_clear(array_t * obj) 43 | { 44 | debug_ptr(obj); 45 | obj->top = 0; 46 | } 47 | 48 | size_t array_length(array_t * obj) 49 | { 50 | debug_ptr(obj, 0); 51 | return obj->top; 52 | } 53 | 54 | bool array_full(array_t * obj) 55 | { 56 | debug_ptr(obj, true); 57 | return obj->top == obj->max; 58 | } 59 | -------------------------------------------------------------------------------- /reacto/includes/reacto/signal_slot_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_SIGNAL_SLOT_QUEUE_H_ 25 | #define REACTO_SIGNAL_SLOT_QUEUE_H_ 26 | 27 | #include 28 | #include 29 | #include "event_loop_types.h" 30 | 31 | void signal_queue_init(signal_queue_t *); 32 | void signal_queue_deinit(signal_queue_t *); 33 | bool signal_queue_is_connected(signal_queue_t *, slot_queue_t *); 34 | void signal_queue_emit(signal_queue_t *, queue_t * queue); 35 | 36 | void slot_queue_init(slot_queue_t *, slot_queue_handler_t handler); 37 | void slot_queue_deinit(slot_queue_t *); 38 | void slot_queue_connect(slot_queue_t *, signal_queue_t *); 39 | int slot_queue_disconnect(slot_queue_t *, signal_queue_t *); 40 | 41 | 42 | #endif /* REACTO_SIGNAL_SLOT_QUEUE_H_ */ 43 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef REACTO_REUSABLES_DEBUG_H_ 26 | #define REACTO_REUSABLES_DEBUG_H_ 27 | 28 | #ifdef REACTO_ENABLE_DEBUG 29 | 30 | #include "log.h" 31 | 32 | #define debug_if(__expr) if (__expr) 33 | #define debug(_code_under_debug) _code_under_debug 34 | #define debug_ptr(p, ...) do {if (!(p)) {log_error("Invalid Pointer"); return __VA_ARGS__;}} while(0) 35 | #define debug_assert(p, ...) do {if (!(p)) {log_error("Assertion failed: " #p); return __VA_ARGS__;}} while(0) 36 | 37 | #else /* REACTO_ENABLE_DEBUG */ 38 | 39 | #define debug_if(__expr) if (0) 40 | #define debug(_code_under_debug) 41 | #define debug_ptr(p, ...) 42 | #define debug_assert(p, ...) 43 | 44 | #endif /* REACTO_ENABLE_DEBUG */ 45 | 46 | 47 | #endif /* REACTO_REUSABLES_DEBUG_H_ */ 48 | -------------------------------------------------------------------------------- /dependencies/cpputest/Sconscript: -------------------------------------------------------------------------------- 1 | Import('platforms') 2 | 3 | # Important headers of cpputest 4 | new_macros = File('./cpputest-tree/include/CppUTest/MemoryLeakDetectorNewMacros.h') 5 | malloc_macros = File('./cpputest-tree/include/CppUTest/MemoryLeakDetectorMallocMacros.h') 6 | cpputest_include = Dir('./cpputest-tree/include') 7 | 8 | # Enviroment variables that will be incremented platform wise 9 | cpputest_exports = { 10 | 'CPPDEFINES': ['HAVE_CONFIG_H'], 11 | # Scons has no support for gcc -include command line option, 12 | # we have to do some workaround. 13 | 'CXXFLAGS' : [ 14 | # '-include', 15 | # new_macros, 16 | # '-include', 17 | # malloc_macros 18 | ], 19 | 'CFLAGS' : [ 20 | # '-include', 21 | # malloc_macros 22 | ], 23 | 'CPPPATH' : [ cpputest_include, Dir('./include') ], 24 | # This is a ugly workaround becouse scons doesn't detect dependency on C*FLAGS 25 | # every single build will have to add CPPINCLUDES dependency to their's .o 26 | 'CXXINCLUDES' : [new_macros], 27 | 'CINCLUDES' : [malloc_macros], 28 | } 29 | 30 | # Download and extract cpputest-3.8.tar.gz to cpputest-tree 31 | Command(target = [new_macros, malloc_macros], 32 | source = File('./setup-cpputest.sh'), 33 | action = './${SOURCE} ' + Dir('./cpputest-tree').path ) 34 | 35 | for plat in platforms: 36 | name = plat.Name() 37 | # Modify imported environment to be used by further builds 38 | plat.Env().Prepend(**cpputest_exports) 39 | env = plat.Env().Clone() 40 | env.UpdateIncludes() 41 | 42 | # Call script to build cpputest 43 | config = {'cpputest_extensions_enabled' : plat.CppUTestExtensionsEnabled()} 44 | mods = env.SConscript('./Sconscript.variant', exports = ['env', 'name', 'config'], variant_dir='./build/' + name, duplicate=0) 45 | 46 | # Add libs to platform env 47 | plat.Env().Append(LIBS = mods['libs']) 48 | plat.Env().Append(LIBPATH = mods['path']) 49 | -------------------------------------------------------------------------------- /reacto/includes/reacto/context.h: -------------------------------------------------------------------------------- 1 | #ifndef REACTO_CONTEXT_H_ 2 | #define REACTO_CONTEXT_H_ 3 | 4 | #ifndef REACTO_N_OF_QUEUES 5 | #error "You have to define REACTO_N_OF_QUEUES with the number of queues you want to be allocated." 6 | #endif 7 | 8 | #ifndef REACTO_MAX_N_OF_HANDLERS_PER_QUEUE 9 | #error "You have to define REACTO_MAX_N_OF_HANDLERS_PER_QUEUE with the maximum number of handlers per queue allowed." 10 | #endif 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | struct reacto_queues_context 20 | { 21 | slot_queue_handler_t queue_handlers[REACTO_N_OF_QUEUES][REACTO_MAX_N_OF_HANDLERS_PER_QUEUE]; 22 | size_t queue_buffer_sizes[REACTO_N_OF_QUEUES]; 23 | }; 24 | 25 | struct reacto_timed_queue_context 26 | { 27 | bool high_priority; 28 | }; 29 | 30 | struct reacto_main_loop_context 31 | { 32 | const main_loop_strategy strategy; 33 | }; 34 | 35 | struct reacto_context_private 36 | { 37 | slot_queue_t slots [REACTO_N_OF_QUEUES][REACTO_MAX_N_OF_HANDLERS_PER_QUEUE]; 38 | queue_t queues [REACTO_N_OF_QUEUES]; 39 | timed_queue_t timed_queue; 40 | main_loop_t loop; 41 | 42 | bool has_loop; 43 | bool has_tq; 44 | size_t total_queues; 45 | }; 46 | 47 | extern struct reacto_context_private reacto_context_private_data; 48 | 49 | static inline main_loop_t * reacto_context_main_loop() 50 | { 51 | if (!reacto_context_private_data.has_loop) 52 | return NULL; 53 | 54 | return &reacto_context_private_data.loop; 55 | } 56 | 57 | static inline timed_queue_t * reacto_context_timed_queue() 58 | { 59 | if (!reacto_context_private_data.has_tq) 60 | return NULL; 61 | 62 | return &reacto_context_private_data.timed_queue; 63 | } 64 | 65 | static inline queue_t * reacto_context_queue(size_t n) 66 | { 67 | if (n >= reacto_context_private_data.total_queues) 68 | return NULL; 69 | 70 | return &reacto_context_private_data.queues[n]; 71 | } 72 | 73 | 74 | #endif /* REACTO_CONTEXT_H_ */ 75 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/linked_list.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_LINKED_LIST_HPP_ 25 | #define REACTO_REUSABLES_LINKED_LIST_HPP_ 26 | 27 | #ifdef __cplusplus 28 | #include 29 | #include 30 | 31 | #define __ll_auto_type(___zcxzzarg) auto 32 | #define __ll_typeof(___zarg) std::remove_reference::type 33 | 34 | template 35 | size_t __ll_offsetof(const M P::*member) 36 | { 37 | return (size_t) &( reinterpret_cast(0)->*member); 38 | } 39 | 40 | template 41 | P* __ll_container_of_impl(M* ptr, const M P::*member) 42 | { 43 | return (P*)( (char*)ptr - __ll_offsetof(member)); 44 | } 45 | 46 | #define __ll_container_of(ptr, type, member) \ 47 | __ll_container_of_impl (ptr, &type::member) 48 | #endif 49 | 50 | #include "linked_list.h" 51 | 52 | #endif /* REACTO_REUSABLES_LINKED_LIST_HPP_ */ 53 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_TIME_H_ 25 | #define REACTO_REUSABLES_TIME_H_ 26 | 27 | #include 28 | 29 | /* reacto_time_t is the type used to measure time. 30 | * - it must be unsigned 31 | * - it must be big enough to store the amount of time required 32 | * by the application considering the platform provided time 33 | * unit. 34 | * REACTO_TIME_TYPE macro can be used to change the time unit in 35 | * built time. Be aware you can cause ABI mismatch if you build 36 | * the react.o library with a different setting than the one 37 | * used in the application. 38 | */ 39 | #ifndef REACTO_TIME_TYPE 40 | typedef unsigned long reacto_time_t; 41 | #else 42 | typedef REACTO_TIME_TYPE reacto_time_t; 43 | #endif 44 | 45 | /* 46 | * Get current platform time in platform time unit 47 | */ 48 | reacto_time_t time_now(void); 49 | 50 | #endif /* REACTO_REUSABLES_TIME_H_ */ 51 | -------------------------------------------------------------------------------- /reacto/src/queue_interface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | 27 | bool queue_interface_emit(queue_i * itf) 28 | { 29 | debug_ptr(itf, false); 30 | debug_ptr(itf->emitter, false); 31 | return itf->emitter(itf); 32 | } 33 | 34 | size_t queue_interface_count(queue_i * itf) 35 | { 36 | debug_ptr(itf, false); 37 | debug_ptr(itf->count, false); 38 | return itf->count(itf); 39 | } 40 | 41 | reacto_time_t queue_interface_sleep_tout(queue_i * itf) 42 | { 43 | debug_ptr(itf, false); 44 | debug_ptr(itf->count, false); 45 | return itf->sleep(itf); 46 | } 47 | 48 | size_t queue_interface_hash(queue_i * itf) 49 | { 50 | debug_ptr(itf, false); 51 | debug_ptr(itf->count, false); 52 | return itf->hash(itf); 53 | } 54 | 55 | void queue_interface_pop(queue_i * itf) 56 | { 57 | debug_ptr(itf); 58 | debug_ptr(itf->pop); 59 | itf->pop(itf); 60 | } 61 | -------------------------------------------------------------------------------- /examples/rot13_factory/src/main.c: -------------------------------------------------------------------------------- 1 | /* reacto_factory_config.h is a local header that will configure 2 | * static allocations made by the context_factory.template module. 3 | * It is always necessary to include reacto_factory_config.h before 4 | * reacto/factory.h */ 5 | #include "reacto_factory_config.h" 6 | #include 7 | 8 | #include "get_input.h" 9 | #include "rot13_stage.h" 10 | #include "output_stage.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | static struct reacto_queues_context queues_context = { 19 | 20 | /* Installing the queue handlers */ 21 | .queue_handlers = { 22 | /* Queues handlers for the first queue */ 23 | [0] = { 24 | rot13_stage_handler 25 | }, 26 | /* Queue handlers for the second queue */ 27 | [1] = { 28 | output_stage_handler 29 | }, 30 | }, 31 | .queue_buffer_sizes = { 32 | [0] = rot13_stage_buffer_size, 33 | [1] = output_stage_buffer_size 34 | }, 35 | }; 36 | 37 | static const struct reacto_timed_queue_context timed_queue_context = 38 | { 39 | .high_priority = true, 40 | }; 41 | 42 | static void sleep_handler (main_loop_t * loop) 43 | { 44 | reacto_time_t sleep = main_loop_sleep_timeout(loop); 45 | usleep((uint32_t)sleep * 1000); 46 | } 47 | 48 | 49 | static void exit_handler(int s) 50 | { 51 | /* Exit nicely */ 52 | s = s+1; 53 | main_loop_quit(reacto_context_main_loop()); 54 | } 55 | 56 | int main() 57 | { 58 | int r = reacto_context_factory(main_loop_strategy_priority_queue, 59 | &timed_queue_context, 60 | &queues_context); 61 | if (r < 0) 62 | { 63 | printf ("reacto_context_factory failed with %d.", r); 64 | exit(EXIT_FAILURE); 65 | } 66 | 67 | signal (SIGINT, exit_handler); 68 | 69 | get_input_init(); 70 | main_loop_set_sleep_handler(reacto_context_main_loop(), sleep_handler); 71 | main_loop_run(reacto_context_main_loop()); 72 | printf("\nBye bye.\n"); 73 | exit(EXIT_SUCCESS); 74 | } 75 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/log_mock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /* Bypass cpputest memory leak detection */ 7 | #ifdef realloc 8 | #undef realloc 9 | #endif 10 | 11 | static size_t get_buffer (size_t n, char ** const ret_buf) 12 | { 13 | static char * buf = NULL; 14 | static size_t size = 0; 15 | 16 | if (n > size) 17 | { 18 | size = n * 2; 19 | buf = (char *)realloc(buf, size); 20 | } 21 | 22 | if (ret_buf) //LCOV_EXCL_LINE 23 | *ret_buf = buf; 24 | return size; 25 | } 26 | 27 | static const char * format(const char * format, va_list ap) 28 | { 29 | char * buf; 30 | 31 | va_list ap2; 32 | va_copy(ap2, ap); 33 | 34 | int n = vsnprintf(NULL, 0, format, ap); 35 | if (n < 0) //LCOV_EXCL_LINE 36 | FAIL("Error on vsnprintf"); //LCOV_EXCL_LINE 37 | 38 | size_t size = get_buffer((size_t)n, &buf); 39 | 40 | vsnprintf(buf, size, format, ap2); 41 | va_end(ap2); 42 | return buf; 43 | } 44 | 45 | extern "C" 46 | void _log_file_line (const char * file, int line, const char * msg, ...) 47 | { 48 | /* 49 | * We want to use CppUTest Mock system in this function, 50 | * this way tests will fail if any code under tests print 51 | * an error message. 52 | */ 53 | va_list ap; 54 | va_start(ap, msg); 55 | 56 | mock().actualCall("_log_file_line") 57 | .withStringParameter("msg", format(msg, ap)) 58 | .withStringParameter("file", file) 59 | .withIntParameter("line", line); 60 | 61 | va_end(ap); 62 | } 63 | 64 | 65 | extern "C" 66 | void log_message (const char * msg, ...) 67 | { 68 | /* 69 | * We want to use CppUTest Mock system in this function, 70 | * this way tests will fail if any code under tests print 71 | * an error message. 72 | */ 73 | va_list ap; 74 | va_start(ap, msg); 75 | 76 | mock().actualCall("log_message") 77 | .withStringParameter("msg", format(msg, ap)); 78 | 79 | va_end(ap); 80 | } 81 | -------------------------------------------------------------------------------- /reacto/includes/reacto/main_loop.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_MAIN_LOOP_H_ 25 | #define REACTO_MAIN_LOOP_H_ 26 | 27 | #include 28 | #include "reusables/signal_slot.h" 29 | #include "reusables/time.h" 30 | #include "event_loop_types.h" 31 | 32 | /* First queues get prioritized */ 33 | extern const main_loop_strategy main_loop_strategy_priority_queue; 34 | /* Queues get approximately the same importance */ 35 | extern const main_loop_strategy main_loop_strategy_fare; 36 | 37 | void main_loop_init(main_loop_t * obj, main_loop_strategy strategy); 38 | void main_loop_deinit(main_loop_t * obj); 39 | 40 | void main_loop_add_queue(main_loop_t * obj, queue_i * queue, int position); 41 | int main_loop_remove_queue(main_loop_t * obj, queue_i * queue); 42 | 43 | void main_loop_run(main_loop_t * obj); 44 | void main_loop_quit(main_loop_t * obj); 45 | 46 | /* 47 | * Return a milliseconds value with the maximum allowed 48 | * sleep duration. 49 | * You must wake-up yourself on the occurrence of event. 50 | */ 51 | reacto_time_t main_loop_sleep_timeout (main_loop_t * obj); 52 | 53 | void main_loop_set_sleep_handler (main_loop_t * obj, void (*handler)(main_loop_t *)); 54 | 55 | #endif /* REACTO_MAIN_LOOP_H_ */ 56 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/signal_slot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_SIGNAL_SLOT_H_ 25 | #define REACTO_REUSABLES_SIGNAL_SLOT_H_ 26 | 27 | #include "linked_list.h" 28 | #include 29 | 30 | struct slot_private; 31 | typedef struct slot_private slot_t; 32 | 33 | struct signal_private; 34 | typedef struct signal_private signal_t; 35 | 36 | /* 37 | * Rules of the Handler: 38 | * Handlers will be called in the order they were inserted. 39 | * If a handler returns anything but 0, the call loop will stop and no other 40 | * connected handler will be called. 41 | */ 42 | typedef int (*slot_handler_t) (slot_t *); 43 | 44 | void signal_init(signal_t *); 45 | void signal_deinit(signal_t *); 46 | bool signal_is_connected(signal_t *, slot_t *); 47 | void signal_emit(signal_t *); 48 | 49 | void slot_init(slot_t *, slot_handler_t handler); 50 | void slot_deinit(slot_t *); 51 | void slot_connect(slot_t *, signal_t *); 52 | int slot_disconnect(slot_t *, signal_t *); 53 | 54 | struct signal_private 55 | { 56 | struct slot_private * root; 57 | }; 58 | 59 | struct slot_private 60 | { 61 | signal_t * connection; 62 | slot_handler_t handler; 63 | linked_list_t ll; 64 | }; 65 | 66 | #endif /* REACTO_REUSABLES_SIGNAL_SLOT_H_ */ 67 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_LOG_H_ 25 | #define REACTO_REUSABLES_LOG_H_ 26 | 27 | #ifndef REACTO_DISABLE_LOGGING 28 | 29 | __attribute__ ((format (printf, 3, 4))) void _log_file_line (const char * file, int line, const char * msg, ...); 30 | __attribute__ ((format (printf, 1, 2))) void log_message (const char * msg, ...); 31 | 32 | #ifdef REACTO_SHORT_LOGS 33 | #define log_error(...) log_message("[E]" __VA_ARGS__) 34 | #define log_warning(...) log_message("[W]" __VA_ARGS__) 35 | #else /* REACTO_SHORT_LOGS */ 36 | #define log_error(...) _log_file_line(__FILE__, __LINE__, "Error: " __VA_ARGS__) 37 | #define log_warning(...) _log_file_line(__FILE__, __LINE__, "Warning: " __VA_ARGS__) 38 | #endif /* REACTO_SHORT_LOGS */ 39 | 40 | #else /* REACTO_DISABLE_LOGGING */ 41 | 42 | __attribute__ ((format (printf, 1, 2))) static inline void log_error(const char * msg, ...) {msg = msg+1;}; 43 | __attribute__ ((format (printf, 1, 2))) static inline void log_warning(const char * msg, ...) {msg = msg+1;}; 44 | __attribute__ ((format (printf, 1, 2))) static inline void log_message(const char * msg, ...) {msg = msg+1;}; 45 | 46 | #endif /* REACTO_DISABLE_LOGGING */ 47 | 48 | #endif /* REACTO_REUSABLES_LOG_H_ */ 49 | -------------------------------------------------------------------------------- /reacto/includes/reacto/context_factory.template: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __cplusplus 4 | struct reacto_context_private reacto_context_private_data = {}; 5 | #else 6 | struct reacto_context_private reacto_context_private_data = { 7 | .has_loop = false, 8 | .has_tq = false, 9 | .total_queues = 0 10 | }; 11 | #endif 12 | 13 | static inline int reacto_context_factory (const main_loop_strategy strategy, 14 | const struct reacto_timed_queue_context * tq_ctx, 15 | const struct reacto_queues_context *q_ctx) 16 | { 17 | debug_ptr(strategy, -100); 18 | 19 | struct reacto_context_private * const ctx = &reacto_context_private_data; 20 | const int n_of_queues = REACTO_N_OF_QUEUES; 21 | const int n_of_handlers = REACTO_MAX_N_OF_HANDLERS_PER_QUEUE; 22 | int r; 23 | int q, h; 24 | main_loop_t * const loop = &ctx->loop; 25 | 26 | main_loop_init(loop, strategy); 27 | 28 | ctx->has_loop = true; 29 | 30 | ctx->total_queues = 0; 31 | 32 | if (q_ctx) 33 | { 34 | for (q = 0; q < n_of_queues; q++) 35 | { 36 | queue_t * const queue = &ctx->queues[q]; 37 | const size_t queue_size = q_ctx->queue_buffer_sizes[q]; 38 | const int queue_pos = q; 39 | 40 | r = queue_init(queue, queue_size); 41 | ctx->total_queues ++; 42 | 43 | if (r < 0) 44 | return -1; 45 | 46 | main_loop_add_queue(loop, 47 | queue_interface(queue), 48 | queue_pos); 49 | 50 | for (h = 0; h < n_of_handlers; h++) 51 | { 52 | slot_queue_t * const slot = &ctx->slots[q][h]; 53 | slot_queue_handler_t const handler = q_ctx->queue_handlers[q][h]; 54 | 55 | if (!handler) 56 | continue; 57 | 58 | slot_queue_init(slot, handler); 59 | 60 | slot_queue_connect(slot, queue_signal(queue)); 61 | } 62 | } 63 | } 64 | 65 | ctx->has_tq = false; 66 | if (tq_ctx) 67 | { 68 | timed_queue_t * const timed_queue = &ctx->timed_queue; 69 | int priority = tq_ctx->high_priority ? 0 : (int)ctx->total_queues; 70 | 71 | timed_queue_init(timed_queue); 72 | ctx->has_tq = true; 73 | 74 | main_loop_add_queue(loop, 75 | timed_queue_interface(timed_queue), 76 | priority); 77 | } 78 | 79 | return 0; 80 | } -------------------------------------------------------------------------------- /reacto/src/reusables/timeout.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | 28 | void timeout_init(timeout_t * cobj) 29 | { 30 | *cobj = time_now(); 31 | } 32 | 33 | void timeout_copy(timeout_t * to, timeout_t * from) 34 | { 35 | *to = *from; 36 | } 37 | 38 | bool timeout_check_elapsed(reacto_time_t now, reacto_time_t before, reacto_time_t desired_wait) 39 | { 40 | return (now - before) >= desired_wait; 41 | } 42 | 43 | reacto_time_t timeout_remaining(reacto_time_t now, reacto_time_t before, reacto_time_t desired_wait) 44 | { 45 | if (timeout_check_elapsed(now, before, desired_wait - 1)) 46 | return 0; 47 | 48 | return desired_wait - (now - before); 49 | } 50 | 51 | bool timeout_check_reached(reacto_time_t timestamp, reacto_time_t now) 52 | { 53 | const reacto_time_t max = (reacto_time_t)-1; 54 | const reacto_time_t stupid_big_number = (max/2) + 1; 55 | reacto_time_t before = timestamp - stupid_big_number; 56 | return timeout_check_elapsed(now, before, stupid_big_number); 57 | } 58 | 59 | bool timeout_check(timeout_t * cobj, reacto_time_t tout) 60 | { 61 | return timeout_check_elapsed(time_now(), *cobj, tout); 62 | } 63 | 64 | bool timeout_check_and_reinit(timeout_t * cobj, reacto_time_t period) 65 | { 66 | if (!timeout_check_elapsed(time_now(), *cobj, period)) 67 | { 68 | return false; 69 | } 70 | else 71 | { 72 | *cobj += period; 73 | return true; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /reacto/includes/reacto/watchdog/watchdog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_WATCHDOG_WATCHDOG_H_ 25 | #define REACTO_WATCHDOG_WATCHDOG_H_ 26 | 27 | /* 28 | * This is a Software Watchdog Module 29 | * User code declare and initialize watchdog objects 30 | * that will be checked when feeding the hardware watchdog. 31 | * If any software watchdog expires, no hardware feeding will occur. 32 | */ 33 | 34 | #include "../reusables/linked_list.h" 35 | #include "../reusables/timeout.h" 36 | 37 | struct _watchdog_private 38 | { 39 | const char * name; 40 | reacto_time_t period; 41 | timeout_t timeout; 42 | linked_list_t list_head; 43 | }; 44 | 45 | typedef struct _watchdog_private watchdog_t; 46 | 47 | /* Initialize a soft watchdog object. 48 | * period: the amount of time to the watchdog expire 49 | * name: the name of the watchdog, must be a string literal or global. 50 | */ 51 | int watchdog_init(watchdog_t *, reacto_time_t period, const char * name); 52 | void watchdog_deinit(watchdog_t *); 53 | 54 | /* ISR safe */ 55 | void watchdog_enter (watchdog_t * obj); 56 | 57 | /* ISR safe */ 58 | void watchdog_exit (watchdog_t * obj); 59 | 60 | /* ISR safe */ 61 | void watchdog_kick (watchdog_t * obj); 62 | 63 | /* 64 | * Call this periodically, 65 | * this function will kick the hardware watchdog 66 | * only if every active soft watchdog has not expired. 67 | * 68 | * Configure hardware watchdog timeout to match the 69 | * frequency this function is called. 70 | * 71 | * ISR safe 72 | */ 73 | void watchdog_periodic (); 74 | 75 | #endif /* REACTO_WATCHDOG_WATCHDOG_H_ */ 76 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/timeout.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_TIMEOUT_H_ 25 | #define REACTO_REUSABLES_TIMEOUT_H_ 26 | 27 | #include 28 | #include 29 | #include "time.h" 30 | 31 | typedef reacto_time_t timeout_t; 32 | 33 | void timeout_init(timeout_t *); 34 | void timeout_copy(timeout_t * to, timeout_t * from); 35 | 36 | /* Return true if tout has elapsed */ 37 | bool timeout_check(timeout_t *, reacto_time_t tout); 38 | 39 | /* Return true if tout has elapsed and reinit cobj, so it can be used after to create periodically execution */ 40 | bool timeout_check_and_reinit(timeout_t * cobj, reacto_time_t period); 41 | 42 | /* Sleep until the next timeout (use only to spend time while waiting for a timeout, 43 | do not count on time precision of this function) */ 44 | void timeout_sleep(timeout_t *cobj, reacto_time_t period); 45 | 46 | /* This is a elapsed time checker that protects against wrap around. 47 | Now must always be (physically) bigger than before.*/ 48 | bool timeout_check_elapsed(reacto_time_t now, reacto_time_t before, reacto_time_t desired_wait); 49 | 50 | /* Return the remaining time to timeout expiration.*/ 51 | reacto_time_t timeout_remaining(reacto_time_t now, reacto_time_t before, reacto_time_t desired_wait); 52 | 53 | /* This is a reached time checker that protects against wrap around. 54 | It checks if now has reached timestamp. Timestamp must always be bigger than 55 | now when first stored. */ 56 | bool timeout_check_reached(reacto_time_t timestamp, reacto_time_t now); 57 | 58 | #endif /* REACTO_REUSABLES_TIMEOUT_H_ */ 59 | -------------------------------------------------------------------------------- /reacto/includes/reacto/timed_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_TIMED_QUEUE_H_ 25 | #define REACTO_TIMED_QUEUE_H_ 26 | 27 | #include 28 | #include 29 | #include "reusables/linked_list.h" 30 | #include "reusables/time.h" 31 | #include "event_loop_types.h" 32 | 33 | /* 34 | * This is the Timed Queue, to be used with the Main Loop. 35 | * You can schedule deferred handlers to be called in the configured timestamp. 36 | */ 37 | 38 | typedef void (*timed_event_handler_t)(timed_event_t *); 39 | 40 | struct timed_event_private 41 | { 42 | reacto_time_t link_timestamp; 43 | reacto_time_t timeout; 44 | timed_event_handler_t handler; 45 | linked_list_t ll; 46 | }; 47 | void timed_event_init(timed_event_t * ev, reacto_time_t timeout, timed_event_handler_t handler); 48 | 49 | void timed_queue_init(timed_queue_t * obj); 50 | void timed_queue_deinit(timed_queue_t * obj); 51 | 52 | /* 53 | * Whenever you link a timed_event_t to the queue, you must keep it in valid scope until 54 | * the handler is called, zero copy here, it is only linked. 55 | * NOT ISR SAFE 56 | * The configured timeout in the event starts counting after linking. 57 | * It is safe to re link without unlinking. 58 | */ 59 | void timed_queue_link(timed_queue_t * obj, timed_event_t * ev); 60 | /* 61 | * Same as last, but now you can change event timeout. 62 | */ 63 | void timed_queue_link_update_timeout(timed_queue_t * obj, timed_event_t * ev, reacto_time_t timeout); 64 | /* 65 | * Unlinking an event prevent the handler from being called. 66 | * When a handler is called, the event is automatically unlinked. 67 | */ 68 | void timed_queue_unlink(timed_queue_t * obj, timed_event_t * ev); 69 | 70 | queue_i * timed_queue_interface (timed_queue_t * obj); 71 | 72 | #endif /* REACTO_TIMED_QUEUE_H_ */ 73 | -------------------------------------------------------------------------------- /examples/msp430_blink/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../msp430_board.h" 7 | 8 | typedef enum button 9 | { 10 | button_invalid, 11 | button_0 12 | } button_event_t; 13 | 14 | struct button_stream 15 | { 16 | slot_queue_t slot; 17 | queue_t queue; 18 | button_event_t buffer [8]; 19 | }; 20 | 21 | typedef enum led 22 | { 23 | led_invalid, 24 | led_0 25 | } led_event_t; 26 | 27 | struct led_stream 28 | { 29 | slot_queue_t slot; 30 | queue_t queue; 31 | led_event_t buffer [8]; 32 | }; 33 | 34 | static main_loop_t loop; 35 | static struct button_stream button_stream; 36 | static struct led_stream led_stream; 37 | 38 | static int button_stream_handler (queue_t * queue); 39 | static int led_stream_handler (queue_t * queue); 40 | 41 | static void button_stream_init() 42 | { 43 | queue_init(&button_stream.queue, 8); 44 | slot_queue_init(&button_stream.slot, button_stream_handler); 45 | slot_queue_connect(&button_stream.slot, queue_signal(&button_stream.queue)); 46 | main_loop_add_queue(&loop, queue_interface(&button_stream.queue), 0); 47 | } 48 | 49 | static void led_stream_init() 50 | { 51 | queue_init(&led_stream.queue, 8); 52 | slot_queue_init(&led_stream.slot, led_stream_handler); 53 | slot_queue_connect(&led_stream.slot, queue_signal(&led_stream.queue)); 54 | main_loop_add_queue(&loop, queue_interface(&led_stream.queue), 0); 55 | } 56 | 57 | int main (void) 58 | { 59 | board_init(); 60 | 61 | main_loop_init (&loop, main_loop_strategy_fare); 62 | button_stream_init(); 63 | led_stream_init(); 64 | 65 | __enable_interrupt(); // enable all interrupts 66 | main_loop_run (&loop); 67 | /* this will not return until main_loop_quit() is called */ 68 | P1OUT = 0; 69 | return 0; 70 | } 71 | 72 | /* 73 | * Now the handlers in order of data flow 74 | */ 75 | 76 | /* First the PUSH BUTTON Interrupt Handler */ 77 | interrupt(PORT1_VECTOR) on_button_pressed(void) 78 | { 79 | /* Interrupt stuff */ 80 | P1IFG &= ~BUTTON; // P1.3 IFG cleared 81 | P1IES ^= BUTTON; // toggle the interrupt edge, 82 | if (P1IN & BUTTON) return; // Ignore one edge 83 | 84 | /* Push event to the queue */ 85 | queue_push (&button_stream.queue, button_stream.buffer, button_0); 86 | } 87 | 88 | /* Second the button stream handler */ 89 | static int button_stream_handler (queue_t * queue) 90 | { 91 | button_event_t event = button_invalid; 92 | queue_peek (&button_stream.queue, button_stream.buffer, &event); 93 | 94 | if (event == button_0) 95 | queue_push (&led_stream.queue, led_stream.buffer, led_0); 96 | 97 | return 0; 98 | } 99 | 100 | /* Third the led stream handler */ 101 | static int led_stream_handler (queue_t * queue) 102 | { 103 | led_event_t event = led_invalid; 104 | queue_peek (&led_stream.queue, led_stream.buffer, &event); 105 | 106 | if (event == led_0) 107 | P1OUT ^= (LED0 + LED1); // P1.0 = toggle 108 | 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/test_array.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | extern "C" 6 | { 7 | #include 8 | } 9 | 10 | TEST_GROUP(Array) 11 | { 12 | array_t cut; 13 | int buffer[5 + 1]; 14 | 15 | void setup () 16 | { 17 | buffer[5] = 0; 18 | array_init(&cut, 5); 19 | } 20 | 21 | void teardown () 22 | { 23 | array_deinit(&cut); 24 | mock().clear(); 25 | } 26 | 27 | static bool compare (int element, int seed) 28 | { 29 | return element == seed; 30 | } 31 | 32 | static void freefunc (int element) 33 | { 34 | mock().actualCall("freefunc") 35 | .withIntParameter("element", element); 36 | } 37 | }; 38 | 39 | TEST(Array, init) 40 | { 41 | CHECK_EQUAL(5, cut.max); 42 | CHECK_EQUAL(0, cut.top); 43 | } 44 | 45 | TEST(Array, insert_remove_free_find) 46 | { 47 | array_insert(&cut, buffer, 10); 48 | CHECK_EQUAL(10, buffer[0]); 49 | array_insert(&cut, buffer, 11); 50 | CHECK_EQUAL(11, buffer[1]); 51 | array_insert(&cut, buffer, 12); 52 | CHECK_EQUAL(12, buffer[2]); 53 | array_insert(&cut, buffer, 13); 54 | CHECK_EQUAL(13, buffer[3]); 55 | 56 | CHECK_EQUAL(4, cut.top); 57 | CHECK_EQUAL(false, array_full(&cut)); 58 | 59 | array_insert(&cut, buffer, 14); 60 | CHECK_EQUAL(14, buffer[4]); 61 | CHECK_EQUAL(cut.max, cut.top); 62 | CHECK_EQUAL(true, array_full(&cut)); 63 | 64 | /* Extra insert should trigger an warning */ 65 | mock().expectOneCall("_log_file_line") 66 | .withParameter("msg", "Warning: Trying to insert in a full array, data loss happened.") 67 | .ignoreOtherParameters(); 68 | array_insert(&cut, buffer, 14); 69 | CHECK_EQUAL(14, buffer[4]); 70 | CHECK_EQUAL(0, buffer[5]); 71 | 72 | /* Now we remove one from the middle */ 73 | array_remove(&cut, buffer, 3); 74 | CHECK_EQUAL(10, buffer[0]); 75 | CHECK_EQUAL(11, buffer[1]); 76 | CHECK_EQUAL(12, buffer[2]); 77 | CHECK_EQUAL(14, buffer[3]); 78 | CHECK_EQUAL(0, buffer[5]); 79 | CHECK_EQUAL(4, cut.top); 80 | 81 | /* And then we remove an invalid position, nothing should happen */ 82 | array_remove(&cut, buffer, 312); 83 | CHECK_EQUAL(10, buffer[0]); 84 | CHECK_EQUAL(11, buffer[1]); 85 | CHECK_EQUAL(12, buffer[2]); 86 | CHECK_EQUAL(14, buffer[3]); 87 | CHECK_EQUAL(0, buffer[5]); 88 | CHECK_EQUAL(4, cut.top); 89 | 90 | /* Now we remove another with freefunc */ 91 | mock().expectOneCall("freefunc") 92 | .withParameter("element", 11); 93 | 94 | array_free(&cut, buffer, 1, freefunc); 95 | CHECK_EQUAL(10, buffer[0]); 96 | CHECK_EQUAL(12, buffer[1]); 97 | CHECK_EQUAL(14, buffer[2]); 98 | CHECK_EQUAL(0, buffer[5]); 99 | CHECK_EQUAL(3, cut.top); 100 | 101 | /* Lets do a little of searching */ 102 | int pos = array_find(&cut, buffer, compare, 14); 103 | CHECK_EQUAL(2, pos); 104 | pos = array_find(&cut, buffer, compare, 23141241); 105 | CHECK_EQUAL(-1, pos); 106 | 107 | /* bye bye array! */ 108 | array_clear(&cut); 109 | CHECK_EQUAL(5, cut.max); 110 | CHECK_EQUAL(0, cut.top); 111 | } 112 | -------------------------------------------------------------------------------- /reacto/includes/reacto/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_QUEUE_H_ 25 | #define REACTO_QUEUE_H_ 26 | 27 | #include 28 | #include "reusables/macros.h" 29 | #include "event_loop_types.h" 30 | #include "signal_slot_queue.h" 31 | 32 | 33 | #ifdef __cplusplus 34 | #define __queue_auto_type(___zcxzzarg) auto 35 | #else 36 | #define __queue_auto_type(___zcxzzarg) typeof(___zcxzzarg) 37 | #endif 38 | 39 | 40 | /* 41 | * Number of slots must be a power of two, otherwise it will be down sized 42 | * to its approximate power of two. 43 | * The fast_ring_fifo algorithm used by this queue cannot fill the whole 44 | * buffer, it becomes full with number_of_slots - 1. If you need a queue 45 | * of two slots, make it 4, if you need 3, make it 8, and so on. 46 | * `event_queue_init` returns -1 if error or the accepted number_of_slots. 47 | */ 48 | int queue_init(queue_t * obj, size_t number_of_slots); 49 | void queue_deinit(queue_t * obj); 50 | 51 | /* 52 | * ISR safe, use this function to add data to the queue. 53 | */ 54 | #define queue_push(queue, buffer, data) \ 55 | ({ \ 56 | fast_ring_fifo_t * _fifo = &((queue)->fifo); \ 57 | int _success = -1; \ 58 | if (!fast_ring_fifo_full (_fifo)) {\ 59 | buffer[fast_ring_fifo_write_index(_fifo)] = data; \ 60 | fast_ring_fifo_write_increment(_fifo); \ 61 | _success = 0; \ 62 | } \ 63 | _success; \ 64 | }) 65 | 66 | /* 67 | * Use this function to get data from the queue in the slot handler. 68 | */ 69 | #define queue_peek(queue, buffer, destination) \ 70 | ({ \ 71 | fast_ring_fifo_t * _fifo = &((queue)->fifo); \ 72 | int _success = -1; \ 73 | if (!fast_ring_fifo_empty (_fifo)) {\ 74 | *(destination) = buffer[fast_ring_fifo_read_index(_fifo)]; \ 75 | _success = 0; \ 76 | } \ 77 | _success; \ 78 | }) 79 | 80 | #define queue_full(queue) \ 81 | ({ \ 82 | fast_ring_fifo_t * _fifo = &((queue)->fifo); \ 83 | bool _full = false; \ 84 | if (fast_ring_fifo_full (_fifo)) {\ 85 | _full = true; \ 86 | } \ 87 | _full; \ 88 | }) 89 | 90 | signal_queue_t * queue_signal(queue_t * obj); 91 | queue_i * queue_interface (queue_t * obj); 92 | 93 | 94 | #endif /* REACTO_QUEUE_H_ */ 95 | -------------------------------------------------------------------------------- /dependencies/cpputest/Sconscript.variant: -------------------------------------------------------------------------------- 1 | #!python 2 | Import('env') 3 | Import('config') 4 | Import('name') 5 | 6 | # Source files have to be manually added in this case, since cpputest-tree doesn't exists 7 | # until donwloaded and extracted. 8 | 9 | src_str = """./cpputest-tree/src/CppUTest/CommandLineArguments.cpp 10 | ./cpputest-tree/src/CppUTest/CommandLineTestRunner.cpp 11 | ./cpputest-tree/src/CppUTest/JUnitTestOutput.cpp 12 | ./cpputest-tree/src/CppUTest/MemoryLeakDetector.cpp 13 | ./cpputest-tree/src/CppUTest/MemoryLeakWarningPlugin.cpp 14 | ./cpputest-tree/src/CppUTest/SimpleMutex.cpp 15 | ./cpputest-tree/src/CppUTest/SimpleString.cpp 16 | ./cpputest-tree/src/CppUTest/TeamCityTestOutput.cpp 17 | ./cpputest-tree/src/CppUTest/TestFailure.cpp 18 | ./cpputest-tree/src/CppUTest/TestFilter.cpp 19 | ./cpputest-tree/src/CppUTest/TestHarness_c.cpp 20 | ./cpputest-tree/src/CppUTest/TestMemoryAllocator.cpp 21 | ./cpputest-tree/src/CppUTest/TestOutput.cpp 22 | ./cpputest-tree/src/CppUTest/TestPlugin.cpp 23 | ./cpputest-tree/src/CppUTest/TestRegistry.cpp 24 | ./cpputest-tree/src/CppUTest/TestResult.cpp 25 | ./cpputest-tree/src/CppUTest/TestTestingFixture.cpp 26 | ./cpputest-tree/src/CppUTest/Utest.cpp""" 27 | 28 | src_ext_str = """./cpputest-tree/src/CppUTestExt/CodeMemoryReportFormatter.cpp 29 | ./cpputest-tree/src/CppUTestExt/MemoryReportAllocator.cpp 30 | ./cpputest-tree/src/CppUTestExt/MemoryReportFormatter.cpp 31 | ./cpputest-tree/src/CppUTestExt/MemoryReporterPlugin.cpp 32 | ./cpputest-tree/src/CppUTestExt/MockActualCall.cpp 33 | ./cpputest-tree/src/CppUTestExt/MockExpectedCall.cpp 34 | ./cpputest-tree/src/CppUTestExt/MockExpectedCallsList.cpp 35 | ./cpputest-tree/src/CppUTestExt/MockFailure.cpp 36 | ./cpputest-tree/src/CppUTestExt/MockNamedValue.cpp 37 | ./cpputest-tree/src/CppUTestExt/MockSupport.cpp 38 | ./cpputest-tree/src/CppUTestExt/MockSupportPlugin.cpp 39 | ./cpputest-tree/src/CppUTestExt/MockSupport_c.cpp 40 | ./cpputest-tree/src/CppUTestExt/OrderedTest.cpp 41 | ./cpputest-tree/src/CppUTestExt/CodeMemoryReportFormatter.cpp 42 | ./cpputest-tree/src/CppUTestExt/MemoryReportAllocator.cpp 43 | ./cpputest-tree/src/CppUTestExt/MemoryReportFormatter.cpp 44 | ./cpputest-tree/src/CppUTestExt/MemoryReporterPlugin.cpp 45 | ./cpputest-tree/src/CppUTestExt/MockActualCall.cpp 46 | ./cpputest-tree/src/CppUTestExt/MockExpectedCall.cpp 47 | ./cpputest-tree/src/CppUTestExt/MockExpectedCallsList.cpp 48 | ./cpputest-tree/src/CppUTestExt/MockFailure.cpp 49 | ./cpputest-tree/src/CppUTestExt/MockNamedValue.cpp 50 | ./cpputest-tree/src/CppUTestExt/MockSupport.cpp 51 | ./cpputest-tree/src/CppUTestExt/MockSupportPlugin.cpp 52 | ./cpputest-tree/src/CppUTestExt/MockSupport_c.cpp 53 | ./cpputest-tree/src/CppUTestExt/OrderedTest.cpp""" 54 | #./cpputest-tree/src/CppUTestExt/IEEE754ExceptionsPlugin.cpp 55 | #./cpputest-tree/src/CppUTestExt/IEEE754ExceptionsPlugin.cpp 56 | 57 | src = env.MultiLineStringToFiles(src_str) 58 | objs = env.SourceToObjects(src) 59 | src_ext = env.MultiLineStringToFiles(src_ext_str) 60 | objs_ext = env.SourceToObjects(src_ext) 61 | #Depends(src + objs + src_ext + objs_ext, env['CXXINCLUDES'] + env['CINCLUDES']) 62 | 63 | r = { 'libs' : [], 'path' : [] } 64 | lib_cpputest = env.StaticLibrary('cpputest', src) 65 | r['libs'].append(lib_cpputest) 66 | 67 | if config['cpputest_extensions_enabled']: 68 | lib_cpputestext = env.StaticLibrary('cpputestext', src_ext) 69 | r['libs'].append(lib_cpputestext) 70 | 71 | r['path'].append(Dir('./')) 72 | Return('r') 73 | -------------------------------------------------------------------------------- /reacto/includes/reacto/event_loop_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_EVENT_LOOP_TYPES_H_ 25 | #define REACTO_EVENT_LOOP_TYPES_H_ 26 | 27 | #ifndef __GNUC__ 28 | #error "Reacto need GNU Extensions enabled" 29 | #endif 30 | 31 | #include "reusables/fast_ring_fifo.h" 32 | #include "reusables/linked_list.h" 33 | #include "reusables/signal_slot.h" 34 | #include "reusables/time.h" 35 | 36 | struct main_loop_private; 37 | typedef struct main_loop_private main_loop_t; 38 | 39 | struct queue_private; 40 | typedef struct queue_private queue_t; 41 | 42 | struct queue_interface_private; 43 | typedef struct queue_interface_private queue_i; 44 | 45 | struct timed_queue_private; 46 | typedef struct timed_queue_private timed_queue_t; 47 | typedef struct timed_event_private timed_event_t; 48 | 49 | struct slot_queue_private; 50 | typedef struct slot_queue_private slot_queue_t; 51 | 52 | struct signal_queue_private; 53 | typedef struct signal_queue_private signal_queue_t; 54 | 55 | typedef bool (*main_loop_strategy)(queue_i * queue); 56 | typedef int (*slot_queue_handler_t)(queue_t * queue); 57 | 58 | struct slot_queue_private 59 | { 60 | signal_queue_t * connection; 61 | slot_queue_handler_t handler; 62 | linked_list_t ll; 63 | }; 64 | 65 | struct signal_queue_private 66 | { 67 | slot_queue_t * root; 68 | }; 69 | 70 | struct queue_interface_private 71 | { 72 | main_loop_t * loop; 73 | linked_list_t ll; 74 | bool (*emitter)(queue_i *); 75 | size_t (*count)(queue_i *); 76 | reacto_time_t (*sleep)(queue_i *); 77 | size_t (*hash)(queue_i *); 78 | void (*pop)(queue_i *); 79 | }; 80 | 81 | struct queue_private 82 | { 83 | signal_queue_t signal; 84 | fast_ring_fifo_t fifo; 85 | struct queue_interface_private itf; 86 | }; 87 | 88 | struct timed_queue_private 89 | { 90 | struct queue_private queue; 91 | timed_event_t * root; 92 | size_t cnt_cache; 93 | struct queue_interface_private itf; 94 | }; 95 | 96 | struct main_loop_private 97 | { 98 | queue_i * root; 99 | main_loop_strategy strategy; 100 | void (*sleep)(main_loop_t *); 101 | bool looping; 102 | }; 103 | 104 | #endif /* REACTO_EVENT_LOOP_TYPES_H_ */ 105 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/test_queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | extern "C" 8 | { 9 | #include 10 | #include 11 | } 12 | 13 | struct my_event 14 | { 15 | int data; 16 | }; 17 | 18 | struct my_event data_queue[256]; 19 | 20 | TEST_GROUP(Queue) 21 | { 22 | queue_t cut; 23 | 24 | void setup () 25 | { 26 | memset((void *)data_queue, 0xFF, sizeof(data_queue)); 27 | int n = queue_init(&cut, 256); 28 | CHECK_EQUAL((int)(sizeof(data_queue) / sizeof(data_queue[0])), n); 29 | } 30 | 31 | void teardown () 32 | { 33 | queue_deinit(&cut); 34 | mock().clear(); 35 | } 36 | }; 37 | 38 | TEST(Queue, enque) 39 | { 40 | struct my_event event; 41 | event.data = 10; 42 | 43 | int result = queue_push (&cut, data_queue, event); 44 | CHECK_EQUAL(0, result); 45 | 46 | struct my_event poped; 47 | result = queue_peek (&cut, data_queue, &poped); 48 | fast_ring_fifo_read_increment(&cut.fifo); 49 | CHECK_EQUAL(0, result); 50 | 51 | MEMCMP_EQUAL(&event, &poped, sizeof(event)); 52 | } 53 | 54 | 55 | TEST(Queue, enque_full) 56 | { 57 | struct my_event event; 58 | 59 | int result = 0; 60 | int i = 0; 61 | 62 | while (result == 0) 63 | { 64 | event.data = i++; 65 | result = queue_push (&cut, data_queue, event); 66 | } 67 | CHECK_EQUAL(256, fast_ring_fifo_count(&cut.fifo)); 68 | 69 | for (i = 0; i < 256; i++) 70 | CHECK_EQUAL(i, data_queue[i].data); 71 | 72 | i = 0; 73 | result = 0; 74 | while (result == 0) 75 | { 76 | struct my_event poped; 77 | result = queue_peek (&cut, data_queue, &poped); 78 | fast_ring_fifo_read_increment(&cut.fifo); 79 | if (result == 0) 80 | CHECK_EQUAL(i, poped.data); 81 | i++; 82 | } 83 | } 84 | 85 | TEST(Queue, inval) 86 | { 87 | queue_t queue; 88 | 89 | mock().strictOrder(); 90 | 91 | mock().expectOneCall("_log_file_line") 92 | .withParameter("msg", "Error: Invalid Pointer") 93 | .ignoreOtherParameters(); 94 | mock().expectOneCall("_log_file_line") 95 | .withParameter("msg", "Error: Unable to initialize Fast Ring FIFO, size is too small") 96 | .ignoreOtherParameters(); 97 | 98 | queue_init(0, 0); 99 | queue_init(&queue, 0); 100 | } 101 | 102 | TEST(Queue, remove_on_deinit) 103 | { 104 | main_loop_t loop; 105 | queue_t queue; 106 | 107 | queue_init(&queue, 2); 108 | main_loop_init(&loop, main_loop_strategy_priority_queue); 109 | main_loop_add_queue(&loop, &queue.itf, 0); 110 | CHECK_EQUAL(&queue.itf, loop.root); 111 | CHECK_EQUAL(&loop, queue.itf.loop); 112 | queue_deinit(&queue); 113 | CHECK_EQUAL(0, loop.root); 114 | CHECK_EQUAL(0, queue.itf.loop); 115 | } 116 | 117 | TEST(Queue, remove_on_deinit2) 118 | { 119 | main_loop_t loop; 120 | queue_t queue; 121 | 122 | queue_init(&queue, 2); 123 | main_loop_init(&loop, main_loop_strategy_priority_queue); 124 | main_loop_add_queue(&loop, &queue.itf, 0); 125 | CHECK_EQUAL(&queue.itf, loop.root); 126 | CHECK_EQUAL(&loop, queue.itf.loop); 127 | main_loop_deinit(&loop); 128 | CHECK_EQUAL(0, loop.root); 129 | CHECK_EQUAL(0, queue.itf.loop); 130 | } 131 | 132 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/fast_ring_fifo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_FAST_RING_FIFO_H_ 25 | #define REACTO_REUSABLES_FAST_RING_FIFO_H_ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | typedef struct s_fast_ring_fifo_private { 32 | size_t mask; 33 | size_t wrIdx; 34 | size_t rdIdx; 35 | } fast_ring_fifo_t; 36 | 37 | /* 38 | * num_of_slots must be base of two, i.e. 2, 4, 8, 16, 32, 64, ... 39 | */ 40 | static inline int fast_ring_fifo_init(fast_ring_fifo_t * obj, size_t num_of_slots) 41 | { 42 | size_t pre_mask = (SIZE_MAX >> 1) + 1; 43 | 44 | while (pre_mask) 45 | { 46 | if (num_of_slots & pre_mask) { 47 | break; 48 | } 49 | 50 | pre_mask >>= 1; 51 | } 52 | 53 | if (pre_mask <= 1) { 54 | obj->mask = 0; 55 | return -1; 56 | } 57 | 58 | obj->mask = pre_mask - 1; 59 | obj->rdIdx = 0; 60 | obj->wrIdx = 0; 61 | 62 | return (int)pre_mask; 63 | } 64 | 65 | static inline size_t fast_ring_fifo_num_of_slots(fast_ring_fifo_t * obj) 66 | { 67 | return obj->mask + 1; 68 | } 69 | 70 | static inline size_t fast_ring_fifo_write_index(fast_ring_fifo_t * obj) 71 | { 72 | return obj->mask & obj->wrIdx; 73 | } 74 | 75 | static inline size_t fast_ring_fifo_read_index(fast_ring_fifo_t * obj) 76 | { 77 | return obj->mask & obj->rdIdx; 78 | } 79 | 80 | static inline void fast_ring_fifo_write_increment(fast_ring_fifo_t * obj) 81 | { 82 | obj->wrIdx++; 83 | } 84 | 85 | static inline void fast_ring_fifo_read_increment(fast_ring_fifo_t * obj) 86 | { 87 | obj->rdIdx++; 88 | } 89 | 90 | static inline void fast_ring_fifo_read_reset(fast_ring_fifo_t * obj) 91 | { 92 | obj->rdIdx = 0; 93 | obj->wrIdx = 0; 94 | } 95 | 96 | static inline bool fast_ring_fifo_empty(fast_ring_fifo_t * obj) 97 | { 98 | return obj->rdIdx == obj->wrIdx; 99 | } 100 | 101 | static inline size_t fast_ring_fifo_count(fast_ring_fifo_t * obj) 102 | { 103 | return obj->wrIdx - obj->rdIdx; 104 | } 105 | 106 | static inline bool fast_ring_fifo_full(fast_ring_fifo_t * obj) 107 | { 108 | return fast_ring_fifo_count (obj) == fast_ring_fifo_num_of_slots (obj); 109 | } 110 | 111 | #endif /* REACTO_REUSABLES_FAST_RING_FIFO_H_ */ 112 | -------------------------------------------------------------------------------- /reacto/src/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | static bool emitter(queue_i * itf) 33 | { 34 | queue_t * obj = container_of(itf, typeof(*obj), itf); 35 | signal_queue_emit(&obj->signal, obj); 36 | return false; 37 | } 38 | 39 | static size_t count(queue_i * itf) 40 | { 41 | queue_t * obj = container_of(itf, typeof(*obj), itf); 42 | return fast_ring_fifo_count(&obj->fifo); 43 | } 44 | 45 | static reacto_time_t sleep(queue_i * itf) 46 | { 47 | queue_t * obj = container_of(itf, typeof(*obj), itf); 48 | return fast_ring_fifo_count(&obj->fifo) == 0 ? (reacto_time_t)-1 : 0; 49 | } 50 | 51 | static size_t hash(queue_i * itf) 52 | { 53 | queue_t * obj = container_of(itf, typeof(*obj), itf); 54 | return fast_ring_fifo_read_index(&obj->fifo); 55 | } 56 | 57 | static void pop(queue_i * itf) 58 | { 59 | queue_t * obj = container_of(itf, typeof(*obj), itf); 60 | fast_ring_fifo_read_increment(&obj->fifo); 61 | } 62 | 63 | int queue_init(queue_t * obj, size_t number_of_slots) 64 | { 65 | int r; 66 | debug_ptr(obj, -1); 67 | 68 | obj->itf.loop = NULL; 69 | obj->itf.emitter = emitter; 70 | obj->itf.count = count; 71 | obj->itf.sleep = sleep; 72 | obj->itf.hash = hash; 73 | obj->itf.pop = pop; 74 | linked_list_init(&obj->itf, ll); 75 | signal_queue_init(&obj->signal); 76 | 77 | r = fast_ring_fifo_init(&obj->fifo, number_of_slots); 78 | 79 | if (r == -1) 80 | { 81 | log_error("Unable to initialize Fast Ring FIFO, size is too small"); 82 | return -1; 83 | } 84 | 85 | return r; 86 | } 87 | 88 | void queue_deinit(queue_t * obj) 89 | { 90 | debug_ptr(obj); 91 | 92 | if (obj->itf.loop) 93 | main_loop_remove_queue(obj->itf.loop, &obj->itf); 94 | 95 | fast_ring_fifo_init(&obj->fifo, 0); 96 | signal_queue_deinit(&obj->signal); 97 | obj->itf.loop = NULL; 98 | } 99 | 100 | signal_queue_t * queue_signal(queue_t * obj) 101 | { 102 | debug_ptr(obj, NULL); 103 | return &obj->signal; 104 | } 105 | 106 | queue_i * queue_interface (queue_t * obj) 107 | { 108 | debug_ptr(obj, NULL); 109 | return &obj->itf; 110 | } 111 | -------------------------------------------------------------------------------- /reacto/src/watchdog/watchdog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | static watchdog_t * root = NULL; 31 | 32 | static void insert_entry (watchdog_t * obj) 33 | { 34 | if (root) 35 | linked_list_insert_after( 36 | linked_list_last(root, list_head), 37 | obj, 38 | list_head); 39 | else 40 | root = obj; 41 | } 42 | 43 | static void remove_entry (watchdog_t * obj) 44 | { 45 | root = linked_list_remove(obj, list_head); 46 | } 47 | 48 | static void check_initialize_hardware () 49 | { 50 | /* Only initialize hardware once */ 51 | if (linked_list_next(root, list_head) == NULL) 52 | hardware_watchdog_init(); 53 | } 54 | 55 | static void check_deinitialize_hardware () 56 | { 57 | /* Only deinitialize hardware once */ 58 | if (!root) 59 | hardware_watchdog_deinit(); 60 | } 61 | 62 | static bool is_active (watchdog_t * obj) 63 | { 64 | return !!obj->timeout; 65 | } 66 | 67 | static bool is_expired (watchdog_t * obj) 68 | { 69 | return timeout_check(&obj->timeout, obj->period); 70 | } 71 | 72 | int watchdog_init(watchdog_t * obj, reacto_time_t period, const char * name) 73 | { 74 | debug_ptr(obj, -1); 75 | 76 | obj->name = name; 77 | obj->period = period; 78 | obj->timeout = (timeout_t) 0; 79 | linked_list_init(obj, list_head); 80 | 81 | insert_entry(obj); 82 | check_initialize_hardware(); 83 | 84 | return 0; 85 | } 86 | 87 | void watchdog_deinit (watchdog_t * obj) 88 | { 89 | debug_ptr(obj); 90 | 91 | watchdog_exit(obj); 92 | remove_entry (obj); 93 | check_deinitialize_hardware(); 94 | } 95 | 96 | void watchdog_enter (watchdog_t * obj) 97 | { 98 | debug_ptr(obj); 99 | 100 | if (obj->timeout) 101 | return; 102 | 103 | timeout_init(&obj->timeout); 104 | } 105 | 106 | void watchdog_exit (watchdog_t * obj) 107 | { 108 | debug_ptr(obj); 109 | obj->timeout = (timeout_t) 0; 110 | } 111 | 112 | void watchdog_kick (watchdog_t * obj) 113 | { 114 | debug_ptr(obj); 115 | timeout_init(&obj->timeout); 116 | } 117 | 118 | void watchdog_periodic () 119 | { 120 | watchdog_t * entry = root; 121 | 122 | while (entry) 123 | { 124 | if (is_active(entry)) 125 | { 126 | if (is_expired(entry)) 127 | { 128 | log_message ("Watchdog %s expired.", entry->name); 129 | return; 130 | } 131 | } 132 | entry = linked_list_next(entry, list_head); 133 | } 134 | 135 | hardware_watchdog_kick(); 136 | } 137 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/test_fast_ring_fifo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern "C" 5 | { 6 | #include 7 | } 8 | 9 | TEST_GROUP(fast_ring_fifo) 10 | { 11 | void setup() 12 | { 13 | } 14 | 15 | void teardown() 16 | { 17 | } 18 | }; 19 | 20 | 21 | TEST(fast_ring_fifo, sizes) 22 | { 23 | fast_ring_fifo_t cut; 24 | long long int sz = fast_ring_fifo_init(&cut, 0); 25 | CHECK_EQUAL(-1, sz); 26 | 27 | sz = fast_ring_fifo_init(&cut, 1); 28 | CHECK_EQUAL(-1, sz); 29 | 30 | sz = fast_ring_fifo_init(&cut, 2); 31 | CHECK_EQUAL(2, sz); 32 | 33 | sz = fast_ring_fifo_init(&cut, 3); 34 | CHECK_EQUAL(2, sz); 35 | 36 | sz = fast_ring_fifo_init(&cut, 4); 37 | CHECK_EQUAL(4, sz); 38 | 39 | sz = fast_ring_fifo_init(&cut, 7); 40 | CHECK_EQUAL(4, sz); 41 | 42 | sz = fast_ring_fifo_init(&cut, 8); 43 | CHECK_EQUAL(8, sz); 44 | 45 | sz = fast_ring_fifo_init(&cut, 9); 46 | CHECK_EQUAL(8, sz); 47 | 48 | sz = fast_ring_fifo_init(&cut, 15); 49 | CHECK_EQUAL(8, sz); 50 | 51 | sz = fast_ring_fifo_init(&cut, 16); 52 | CHECK_EQUAL(16, sz); 53 | 54 | sz = fast_ring_fifo_init(&cut, 17); 55 | CHECK_EQUAL(16, sz); 56 | 57 | sz = fast_ring_fifo_init(&cut, 31); 58 | CHECK_EQUAL(16, sz); 59 | 60 | sz = fast_ring_fifo_init(&cut, 32); 61 | CHECK_EQUAL(32, sz); 62 | 63 | sz = fast_ring_fifo_init(&cut, 255); 64 | CHECK_EQUAL(128, sz); 65 | 66 | sz = fast_ring_fifo_init(&cut, 256); 67 | CHECK_EQUAL(256, sz); 68 | 69 | sz = fast_ring_fifo_init(&cut, 0x200); 70 | CHECK_EQUAL(0x200, sz); 71 | 72 | sz = fast_ring_fifo_init(&cut, 0x400); 73 | CHECK_EQUAL(0x400, sz); 74 | 75 | sz = fast_ring_fifo_init(&cut, 0x800); 76 | CHECK_EQUAL(0x800, sz); 77 | 78 | sz = fast_ring_fifo_init(&cut, 0x80000000); 79 | CHECK_EQUAL((unsigned)0x80000000, (unsigned)sz); 80 | } 81 | 82 | TEST(fast_ring_fifo, boundaries) 83 | { 84 | fast_ring_fifo_t cut; 85 | int buffer[1026]; 86 | buffer[0] = INT_MAX; 87 | buffer[1025] = INT_MAX; 88 | int * const buf = buffer + 1; 89 | int c; 90 | 91 | int sz = fast_ring_fifo_init(&cut, 1024); 92 | CHECK_EQUAL(1024, sz); 93 | 94 | c = 0; 95 | while (!fast_ring_fifo_full(&cut)) 96 | { 97 | buf[fast_ring_fifo_write_index(&cut)] = c++; 98 | fast_ring_fifo_write_increment(&cut); 99 | } 100 | 101 | CHECK_EQUAL(INT_MAX, buffer[0]); 102 | CHECK_EQUAL(INT_MAX, buffer[1025]); 103 | 104 | } 105 | 106 | TEST(fast_ring_fifo, read_write) 107 | { 108 | fast_ring_fifo_t cut; 109 | 110 | char reference_buffer[] = "abcdefghijklmn"; 111 | char buffer[16]; 112 | 113 | int sz = fast_ring_fifo_init(&cut, 16); 114 | CHECK_EQUAL(16, sz); 115 | 116 | int i = 0; 117 | 118 | while (!fast_ring_fifo_full(&cut)) 119 | { 120 | buffer[fast_ring_fifo_write_index(&cut)] = reference_buffer[i++]; 121 | fast_ring_fifo_write_increment(&cut); 122 | } 123 | 124 | STRCMP_EQUAL(reference_buffer, buffer); 125 | CHECK_EQUAL(16, fast_ring_fifo_count(&cut)); 126 | 127 | 128 | i = 0; 129 | 130 | while(!fast_ring_fifo_empty(&cut)) 131 | { 132 | int n = i++; 133 | CHECK_EQUAL(reference_buffer[n], buffer[fast_ring_fifo_read_index(&cut)]); 134 | fast_ring_fifo_read_increment(&cut); 135 | } 136 | 137 | int n = 3; 138 | while (n--) 139 | { 140 | i = 0; 141 | 142 | while (!fast_ring_fifo_full(&cut)) 143 | { 144 | buffer[fast_ring_fifo_write_index(&cut)] = reference_buffer[i++]; 145 | fast_ring_fifo_write_increment(&cut); 146 | } 147 | 148 | CHECK_EQUAL(16, fast_ring_fifo_count(&cut)); 149 | 150 | i = 0; 151 | 152 | while(!fast_ring_fifo_empty(&cut)) 153 | { 154 | int m = i++; 155 | CHECK_EQUAL(reference_buffer[m], buffer[fast_ring_fifo_read_index(&cut)]); 156 | fast_ring_fifo_read_increment(&cut); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_ARRAY_H_ 25 | #define REACTO_REUSABLES_ARRAY_H_ 26 | 27 | #include "debug.h" 28 | #include "log.h" 29 | #include 30 | #include 31 | #include 32 | 33 | #ifdef __cplusplus 34 | #define __arr_auto_type(___zcxzzarg) auto 35 | #else 36 | #define __arr_auto_type(___zcxzzarg) typeof(___zcxzzarg) 37 | #endif 38 | 39 | struct array_private 40 | { 41 | size_t max; 42 | size_t top; 43 | }; 44 | 45 | typedef struct array_private array_t; 46 | 47 | void array_init(array_t * obj, size_t max_length); 48 | void array_deinit(array_t * obj); 49 | 50 | void array_clear(array_t * obj); 51 | size_t array_length(array_t * obj); 52 | bool array_full(array_t * obj); 53 | 54 | 55 | static inline size_t _array_insert_prepare(array_t * obj) 56 | { 57 | debug_ptr(obj, 0); 58 | 59 | if (array_full(obj)) 60 | { 61 | log_warning("Trying to insert in a full array, data loss happened."); 62 | obj->top--; 63 | } 64 | 65 | return obj->top; 66 | } 67 | 68 | static inline void _array_insert_end(array_t * obj) 69 | { 70 | debug_ptr(obj); 71 | obj->top ++; 72 | } 73 | 74 | #define array_insert(obj, buffer, data) \ 75 | ({ \ 76 | array_t * _o = (obj); \ 77 | buffer[_array_insert_prepare(_o)] = data; \ 78 | _array_insert_end(_o); \ 79 | }) 80 | 81 | static inline size_t _array_remove_prepare(array_t * obj, size_t pos) 82 | { 83 | debug_ptr(obj, 0); 84 | 85 | if (pos >= obj->top) 86 | return 0; 87 | 88 | return obj->top - 1 - pos; 89 | } 90 | 91 | static inline void _array_remove_end(array_t * obj) 92 | { 93 | debug_ptr(obj); 94 | obj->top --; 95 | } 96 | 97 | #define array_remove(obj, buffer, pos) \ 98 | ({ \ 99 | array_t * _o = (obj); \ 100 | size_t _p = (pos); \ 101 | __arr_auto_type (buffer) _b = (buffer); \ 102 | size_t n = _array_remove_prepare(_o, _p); \ 103 | for (size_t i = 0; i < n; i++) \ 104 | _b[_p + i] = _b[_p + i + 1]; \ 105 | if (n) _array_remove_end(_o); \ 106 | }) 107 | 108 | #define array_free(obj, buffer, pos, freefunc) \ 109 | ({ \ 110 | array_t * _o = (obj); \ 111 | size_t _p = (pos); \ 112 | __arr_auto_type (buffer) _b = (buffer); \ 113 | __arr_auto_type (freefunc) _f = (freefunc); \ 114 | _f(_b[_p]); \ 115 | for (size_t i = 0; i < _array_remove_prepare(_o, _p); i++) \ 116 | _b[_p + i] = _b[_p + i + 1]; \ 117 | _array_remove_end(_o); \ 118 | }) 119 | 120 | #define array_find(obj, buffer, comparefunc, seed) \ 121 | ({ \ 122 | int _r = -1; \ 123 | array_t * _o = (obj); \ 124 | __arr_auto_type (buffer) _b = (buffer); \ 125 | __arr_auto_type (seed) _s = (seed); \ 126 | __arr_auto_type (comparefunc) _f = (comparefunc); \ 127 | for (size_t i = 0; i < array_length(_o); i++) \ 128 | if (_f(_b[i], _s)) { _r = (int)i; break; } \ 129 | _r; \ 130 | }) 131 | 132 | 133 | #endif /* REACTO_REUSABLES_ARRAY_H_ */ 134 | -------------------------------------------------------------------------------- /reacto_tests/src_host_tests/test_threaded_event_loop.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a test that shows how the Event Loop can be used. 3 | * 4 | * It is composed of a "main" thread where main_loop_run is called 5 | * repeatedly, and a thread that generates events and pushes it into the 6 | * event queue. 7 | * 8 | * One `event_loop` is created. 9 | * One `event_queue` for the data type is created. 10 | * After, a `slot_eq` is created and initialized to call our handler and then 11 | * connected to the queue's signal. 12 | * 13 | * Now initialization is done and the producer thread is spawned and tests run. 14 | * 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | extern "C" 25 | { 26 | #include 27 | #include 28 | #include 29 | } 30 | 31 | static const int test_duration = 100; 32 | 33 | TEST_GROUP(ThreadedEventLoop) {}; 34 | 35 | /* A container for all the example data */ 36 | struct s_cut 37 | { 38 | slot_queue_t slot; 39 | queue_t queue; 40 | main_loop_t loop; 41 | int buffer[4]; 42 | }; 43 | 44 | /* Helper macro */ 45 | #define container_of(ptr, type, member) ({ \ 46 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 47 | (type *)( (char *)__mptr - offsetof(type,member) );}) 48 | 49 | /* 50 | * This is the event handler, it is called every time there's an event 51 | * to be processed. 52 | */ 53 | static int event_handler (queue_t * queue) 54 | { 55 | /* Retrieve queue's containing struct */ 56 | struct s_cut * cut = container_of(queue, struct s_cut, queue); 57 | 58 | /* Get the event data from the queue */ 59 | int event_data; 60 | queue_peek(queue, cut->buffer, &event_data); 61 | 62 | /* Consume event */ 63 | mock().actualCall("event_handler") 64 | .withIntParameter("event_data", event_data); 65 | 66 | /* Let the caller knows it should keep calling connected handlers */ 67 | return 0; 68 | } 69 | 70 | /* Initialize all objects of the example */ 71 | static void cut_init (struct s_cut *cut) 72 | { 73 | /* Creates the loop object */ 74 | main_loop_init(&cut->loop, main_loop_strategy_priority_queue); 75 | 76 | /* Creates a queue and add it to the loop */ 77 | queue_init(&cut->queue, 4); 78 | main_loop_add_queue(&cut->loop, queue_interface(&cut->queue), 0); 79 | 80 | /* Creates the slot with the handler and connect it to 81 | * the queue's signal */ 82 | slot_queue_init(&cut->slot, event_handler); 83 | slot_queue_connect(&cut->slot, queue_signal(&cut->queue)); 84 | } 85 | 86 | void * thread_handler (void * opaque_cut) 87 | { 88 | struct s_cut *cut = (struct s_cut *)opaque_cut; 89 | const int n = test_duration; 90 | 91 | for (int i = 0; i < n; i++) 92 | { 93 | if (!queue_full(&cut->queue)) 94 | { 95 | /* Acquire event data */ 96 | int event_data = i; 97 | 98 | /* Push it to the queue */ 99 | queue_push(&cut->queue, cut->buffer, event_data); 100 | } 101 | else 102 | { 103 | /* If the queue is full, we try it again later */ 104 | pthread_yield(); 105 | i--; 106 | } 107 | } 108 | 109 | main_loop_quit(&cut->loop); 110 | return NULL; 111 | } 112 | 113 | TEST(ThreadedEventLoop, threaded) 114 | { 115 | static struct s_cut cut; 116 | pthread_t thread; 117 | 118 | mock().strictOrder(); 119 | 120 | /* We add a mock expectation before, since CppUTest's mock is 121 | * not thread safe. */ 122 | for (int i = 0; i < test_duration; i++) 123 | mock().expectOneCall("event_handler") 124 | .withParameter("event_data", i); 125 | 126 | 127 | /* First we initialize our CUT */ 128 | cut_init(&cut); 129 | 130 | /* Second, we spawn a thread to generate events. 131 | * Only one thread per queue allowed, the queue is single consumer 132 | * single producer safe. */ 133 | pthread_create(&thread, NULL, thread_handler, &cut); 134 | 135 | 136 | main_loop_run(&cut.loop); 137 | pthread_join(thread, NULL); 138 | 139 | mock().clear(); 140 | } 141 | -------------------------------------------------------------------------------- /examples/msp430_realtime_blink/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a blink example where the events 3 | * are expected to be processed within 10ms. 4 | * If it takes more than 10ms, the led1 toggles. 5 | * Every time you push the button, led0 toggles. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "../msp430_board.h" 15 | 16 | enum button 17 | { 18 | button_invalid, 19 | button_0 20 | }; 21 | 22 | typedef struct 23 | { 24 | enum button b; 25 | ab_timing_t ab; 26 | } button_event_t; 27 | 28 | enum led 29 | { 30 | led_invalid, 31 | led_0, 32 | led_1 33 | }; 34 | 35 | typedef struct 36 | { 37 | enum led l; 38 | ab_timing_t ab; 39 | } led_event_t; 40 | 41 | static slot_queue_t button_slot; 42 | static queue_t button_queue; 43 | static button_event_t button_buffer [8]; 44 | 45 | static slot_queue_t led_slot; 46 | static queue_t led_queue; 47 | static led_event_t led_buffer [8]; 48 | 49 | static main_loop_t loop; 50 | 51 | static int button_stream_handler (queue_t * queue); 52 | static int led_stream_handler (queue_t * queue); 53 | void time_sleep (reacto_time_t delay); 54 | 55 | static void button_stream_init() 56 | { 57 | queue_init(&button_queue, 8); 58 | slot_queue_init(&button_slot, button_stream_handler); 59 | slot_queue_connect(&button_slot, queue_signal(&button_queue)); 60 | main_loop_add_queue(&loop, queue_interface(&button_queue), 0); 61 | } 62 | 63 | static void led_stream_init() 64 | { 65 | queue_init(&led_queue, 8); 66 | slot_queue_init(&led_slot, led_stream_handler); 67 | slot_queue_connect(&led_slot, queue_signal(&led_queue)); 68 | main_loop_add_queue(&loop, queue_interface(&led_queue), 0); 69 | } 70 | 71 | 72 | int main (void) 73 | { 74 | board_init(); 75 | 76 | main_loop_init (&loop, main_loop_strategy_fare); 77 | button_stream_init(); 78 | led_stream_init(); 79 | 80 | __enable_interrupt(); // enable all interrupts 81 | main_loop_run (&loop); 82 | /* this will not return until main_loop_quit() is called */ 83 | P1OUT = 0; 84 | return 0; 85 | } 86 | 87 | /* 88 | * Now the handlers in order of data flow 89 | */ 90 | 91 | /* First the PUSH BUTTON Interrupt Handler */ 92 | interrupt(PORT1_VECTOR) on_button_pressed(void) 93 | { 94 | button_event_t ev; 95 | 96 | /* Interrupt stuff */ 97 | P1IFG &= ~BUTTON; // P1.3 IFG cleared 98 | P1IES ^= BUTTON; // toggle the interrupt edge, 99 | if (P1IN & BUTTON) return; // Ignore one edge 100 | 101 | ev.b = button_0; 102 | /* New event arrived, we will start the realtime monitor for this event */ 103 | ab_timing_start(&ev.ab); 104 | 105 | /* Push event to the queue */ 106 | queue_push (&button_queue, button_buffer, ev); 107 | } 108 | 109 | /* Second the button stream handler */ 110 | static int button_stream_handler (queue_t * queue) 111 | { 112 | static int i = 0; 113 | button_event_t ev_in; 114 | led_event_t ev_out; 115 | queue_peek (&button_queue, button_buffer, &ev_in); 116 | 117 | /* Lets simulate random latency */ 118 | time_sleep(time_now() % 10); 119 | 120 | if (ev_in.b == button_0) 121 | { 122 | ev_out.l = led_0; 123 | /* We copy the ab_timing object to the new event */ 124 | ab_timing_copy(&ev_out.ab, &ev_in.ab); 125 | queue_push (&led_queue, led_buffer, ev_out); 126 | } 127 | return 0; 128 | } 129 | 130 | /* Third the led stream handler */ 131 | static int led_stream_handler (queue_t * queue) 132 | { 133 | led_event_t event; 134 | queue_peek (&led_queue, led_buffer, &event); 135 | 136 | if (event.l == led_0) 137 | P1OUT ^= LED0; // P1.0 = toggle 138 | 139 | if (event.l == led_1) 140 | P1OUT ^= LED0; // P1.0 = toggle 141 | 142 | /* Now we check if the constrain is met, if not we have to 143 | * take an action, preferably to push an error event to a 144 | * queue. 145 | */ 146 | if (ab_timing_check_criteria_failed(&event.ab, 10)) 147 | { 148 | /* failed, the whole processing took more than the allowed 1 ms 149 | * lets toggle the other LED to indicate that. */ 150 | P1OUT ^= LED1; // P1.0 = toggle 151 | } 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/test_signal_slot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | extern "C" 7 | { 8 | #include 9 | } 10 | 11 | extern "C" 12 | int handler (slot_t * slot) 13 | { 14 | mock().actualCall("handler") 15 | .withPointerParameter("slot", slot); 16 | 17 | return mock().returnValue().getIntValue(); 18 | } 19 | 20 | TEST_GROUP(SignalSlotDemo) 21 | { 22 | signal_t signal; 23 | slot_t slot; 24 | 25 | void setup () 26 | { 27 | signal_init(&signal); 28 | slot_init(&slot, handler); 29 | } 30 | 31 | void teardown () 32 | { 33 | slot_deinit(&slot); 34 | signal_deinit(&signal); 35 | 36 | mock().checkExpectations(); 37 | mock().clear(); 38 | } 39 | }; 40 | 41 | TEST(SignalSlotDemo, init_deinit) 42 | { 43 | slot_deinit(&slot); 44 | signal_deinit(&signal); 45 | signal_init(&signal); 46 | slot_init(&slot, handler); 47 | } 48 | 49 | TEST(SignalSlotDemo, emit_invalid_handler) 50 | { 51 | mock().expectNoCall("handler"); 52 | 53 | slot_connect(&slot, &signal); 54 | slot.handler = 0; 55 | 56 | signal_emit(&signal); 57 | signal_emit(&signal); 58 | signal_emit(&signal); 59 | signal_emit(&signal); 60 | signal_emit(&signal); 61 | signal_emit(&signal); 62 | signal_emit(&signal); 63 | signal_emit(&signal); 64 | signal_emit(&signal); 65 | signal_emit(&signal); 66 | slot_disconnect(&slot, &signal); 67 | } 68 | 69 | TEST(SignalSlotDemo, emit_a_lot) 70 | { 71 | mock().expectNCalls(10, "handler") 72 | .withParameter("slot", &slot) 73 | .andReturnValue(0); 74 | 75 | slot_connect(&slot, &signal); 76 | signal_emit(&signal); 77 | signal_emit(&signal); 78 | signal_emit(&signal); 79 | signal_emit(&signal); 80 | signal_emit(&signal); 81 | signal_emit(&signal); 82 | signal_emit(&signal); 83 | signal_emit(&signal); 84 | signal_emit(&signal); 85 | signal_emit(&signal); 86 | slot_disconnect(&slot, &signal); 87 | } 88 | 89 | TEST(SignalSlotDemo, emit_to_lots) 90 | { 91 | slot_t slots[10]; 92 | 93 | mock().strictOrder(); 94 | 95 | for (int i = 0; i < 10; i++) 96 | { 97 | slot_init(&slots[i], handler); 98 | slot_connect(&slots[i], &signal); 99 | 100 | mock().expectOneCall("handler") 101 | .withParameter("slot", &slots[i]) 102 | .andReturnValue(0); 103 | } 104 | 105 | signal_emit(&signal); 106 | 107 | 108 | CHECK_EQUAL(10, linked_list_count(signal.root, ll)); 109 | signal_deinit(&signal); 110 | CHECK_EQUAL(0, linked_list_count(signal.root, ll)); 111 | 112 | for (int i = 0; i < 10; i++) 113 | { 114 | CHECK_EQUAL(0, slots[i].connection); 115 | CHECK_EQUAL(1, linked_list_count(&slots[i], ll)); 116 | slot_deinit(&slots[i]); 117 | } 118 | } 119 | 120 | TEST(SignalSlotDemo, handler_return_1) 121 | { 122 | slot_t slots[10]; 123 | 124 | mock().strictOrder(); 125 | 126 | for (int i = 0; i < 10; i++) 127 | { 128 | slot_init(&slots[i], handler); 129 | slot_connect(&slots[i], &signal); 130 | 131 | if (i <= 5) 132 | { 133 | mock().expectOneCall("handler") 134 | .withParameter("slot", &slots[i]) 135 | .andReturnValue( i == 5 ? 1 : 0); 136 | } 137 | } 138 | 139 | signal_emit(&signal); 140 | 141 | for (int i = 0; i < 10; i++) 142 | { 143 | slot_deinit(&slots[i]); 144 | } 145 | } 146 | 147 | TEST(SignalSlotDemo, disconnect_from_deinit) 148 | { 149 | mock().expectNCalls(1, "handler") 150 | .withParameter("slot", &slot); 151 | 152 | slot_connect(&slot, &signal); 153 | signal_emit(&signal); 154 | 155 | slot_deinit(&slot); 156 | CHECK_EQUAL(0, slot.connection); 157 | CHECK_EQUAL(0, slot.handler); 158 | CHECK_EQUAL(0, linked_list_count(signal.root, ll)); 159 | 160 | signal_emit(&signal); 161 | } 162 | 163 | TEST(SignalSlotDemo, bad_disconnect) 164 | { 165 | mock().expectOneCall("_log_file_line") 166 | .withParameter("msg", "Error: Provided signal is not connected to slot, cannot disconnect.") 167 | .ignoreOtherParameters(); 168 | 169 | 170 | slot_disconnect(&slot, &signal); 171 | } 172 | 173 | TEST(SignalSlotDemo, inits) 174 | { 175 | CHECK_EQUAL(0, slot.connection); 176 | CHECK_EQUAL((void*) handler, (void*) slot.handler); 177 | CHECK_EQUAL(0, linked_list_count(signal.root, ll)); 178 | } 179 | 180 | TEST(SignalSlotDemo, connect) 181 | { 182 | slot_connect(&slot, &signal); 183 | slot_connect(&slot, &signal); 184 | slot_connect(&slot, &signal); 185 | slot_connect(&slot, &signal); 186 | CHECK_EQUAL(&signal, slot.connection); 187 | CHECK_EQUAL(signal.root, &slot); 188 | CHECK_EQUAL(1, linked_list_count(signal.root, ll)); 189 | CHECK_EQUAL(1, linked_list_count(&slot, ll)); 190 | } 191 | 192 | -------------------------------------------------------------------------------- /examples/msp430_timed_blink/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a blink example showing deferred jobs. 3 | * 4 | * A single push will toggle led0. 5 | * A double push will toggle led1. 6 | * 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "../msp430_board.h" 18 | 19 | 20 | typedef enum button 21 | { 22 | button_invalid, 23 | button_0 24 | } button_event_t; 25 | 26 | struct button_stream 27 | { 28 | slot_queue_t slot; 29 | queue_t queue; 30 | button_event_t buffer [8]; 31 | }; 32 | 33 | struct time_stream 34 | { 35 | timed_queue_t queue; 36 | timed_event_t event; 37 | }; 38 | 39 | typedef enum led 40 | { 41 | led_invalid, 42 | led_0, 43 | led_1, 44 | } led_event_t; 45 | 46 | struct led_stream 47 | { 48 | slot_queue_t slot; 49 | queue_t queue; 50 | led_event_t buffer [8]; 51 | }; 52 | 53 | static main_loop_t loop; 54 | static struct button_stream button_stream; 55 | static struct led_stream led_stream; 56 | static struct time_stream time_stream; 57 | static uint8_t button_accumulator; 58 | 59 | static int button_stream_handler (queue_t * queue); 60 | static void delayed_handler (timed_event_t * ev); 61 | static int led_stream_handler (queue_t * queue); 62 | static void single_pressed(); 63 | static void double_pressed(); 64 | 65 | static void button_stream_init() 66 | { 67 | queue_init(&button_stream.queue, 8); 68 | slot_queue_init(&button_stream.slot, button_stream_handler); 69 | slot_queue_connect(&button_stream.slot, queue_signal(&button_stream.queue)); 70 | main_loop_add_queue(&loop, queue_interface(&button_stream.queue), 0); 71 | } 72 | 73 | static void led_stream_init() 74 | { 75 | queue_init(&led_stream.queue, 8); 76 | slot_queue_init(&led_stream.slot, led_stream_handler); 77 | slot_queue_connect(&led_stream.slot, queue_signal(&led_stream.queue)); 78 | main_loop_add_queue(&loop, queue_interface(&led_stream.queue), 0); 79 | } 80 | 81 | static void time_stream_init() 82 | { 83 | timed_queue_init(&time_stream.queue); 84 | main_loop_add_queue(&loop, timed_queue_interface(&time_stream.queue), 0); 85 | timed_event_init(&time_stream.event, 250, delayed_handler); 86 | } 87 | 88 | int main (void) 89 | { 90 | board_init(); 91 | 92 | main_loop_init (&loop, main_loop_strategy_fare); 93 | button_stream_init(); 94 | led_stream_init(); 95 | time_stream_init(); 96 | button_accumulator = 0; 97 | 98 | __enable_interrupt(); // enable all interrupts 99 | 100 | main_loop_run (&loop); 101 | /* this will not return until main_loop_quit() is called */ 102 | P1OUT = 0; 103 | return 0; 104 | } 105 | 106 | /* 107 | * Now the handlers in order of data flow 108 | */ 109 | 110 | /* First the PUSH BUTTON Interrupt Handler */ 111 | interrupt(PORT1_VECTOR) on_button_pressed(void) 112 | { 113 | /* Interrupt stuff */ 114 | P1IFG &= ~BUTTON; // P1.3 IFG cleared 115 | P1IES ^= BUTTON; // toggle the interrupt edge, 116 | if (P1IN & BUTTON) return; // Ignore one edge 117 | 118 | /* Push event to the queue */ 119 | queue_push (&button_stream.queue, button_stream.buffer, button_0); 120 | } 121 | 122 | /* Second the button stream handler */ 123 | static int button_stream_handler (queue_t * queue) 124 | { 125 | button_event_t event = button_invalid; 126 | queue_peek (&button_stream.queue, button_stream.buffer, &event); 127 | 128 | if (button_accumulator == 0) 129 | { 130 | /* First press, increment the accumulator and schedule timeout on */ 131 | button_accumulator += 1; 132 | timed_queue_link(&time_stream.queue, &time_stream.event); 133 | } 134 | else 135 | { 136 | /* It is a second press, unschedule the timeout and deal with double press 137 | * here */ 138 | button_accumulator = 0; 139 | timed_queue_unlink(&time_stream.queue, &time_stream.event); 140 | double_pressed(event); 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | /* Third the timed event handler */ 147 | static void delayed_handler (timed_event_t * ev) 148 | { 149 | /* Handler got called, we have a timeout. 150 | * it only happens in single press */ 151 | button_accumulator = 0; 152 | single_pressed(); 153 | } 154 | 155 | static void single_pressed() 156 | { 157 | /* Push to the queue a led_1 event */ 158 | queue_push (&led_stream.queue, led_stream.buffer, led_0); 159 | } 160 | 161 | static void double_pressed() 162 | { 163 | /* Push to the queue a led_1 event */ 164 | queue_push (&led_stream.queue, led_stream.buffer, led_1); 165 | } 166 | 167 | /* 4th the led stream handler */ 168 | static int led_stream_handler (queue_t * queue) 169 | { 170 | led_event_t event = led_invalid; 171 | queue_peek (&led_stream.queue, led_stream.buffer, &event); 172 | 173 | if (event == led_0) 174 | P1OUT ^= (LED0); // P1.0 = toggle 175 | 176 | else if (event == led_1) 177 | P1OUT ^= (LED1); // P1.0 = toggle 178 | 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /reacto/src/timed_queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | static void unlink(timed_queue_t * obj, timed_event_t * ev) 35 | { 36 | obj->root = linked_list_remove(ev, ll); 37 | linked_list_init(ev, ll); 38 | obj->cnt_cache--; 39 | } 40 | 41 | static bool emitter(queue_i * itf) 42 | { 43 | timed_queue_t * obj = container_of(itf, typeof(*obj), itf); 44 | timed_event_t * ev = obj->root; 45 | 46 | if (!timeout_check_elapsed(time_now(), ev->link_timestamp, ev->timeout)) 47 | return true; /* Skip this queue */ 48 | 49 | unlink(obj, ev); 50 | ev->handler(ev); 51 | return false; 52 | } 53 | 54 | static size_t count(queue_i * itf) 55 | { 56 | timed_queue_t * obj = container_of(itf, typeof(*obj), itf); 57 | return obj->cnt_cache; 58 | } 59 | 60 | static reacto_time_t sleep(queue_i * itf) 61 | { 62 | timed_queue_t * obj = container_of(itf, typeof(*obj), itf); 63 | if (obj->cnt_cache == 0) 64 | return (reacto_time_t)-1; 65 | 66 | return timeout_remaining(time_now(), 67 | obj->root->link_timestamp, 68 | obj->root->timeout); 69 | } 70 | 71 | static size_t hash(queue_i * obj) 72 | { 73 | obj = obj + 1; 74 | return 0; 75 | } 76 | 77 | static void pop(queue_i * obj) 78 | { 79 | obj = obj + 1; 80 | } 81 | 82 | void timed_queue_init(timed_queue_t * obj) 83 | { 84 | debug_ptr(obj); 85 | 86 | obj->itf.loop = NULL; 87 | obj->itf.emitter = emitter; 88 | obj->itf.pop = pop; 89 | obj->itf.count = count; 90 | obj->itf.hash = hash; 91 | obj->itf.sleep = sleep; 92 | linked_list_init(&obj->itf, ll); 93 | obj->root = NULL; 94 | obj->cnt_cache = 0; 95 | } 96 | 97 | static void _free (timed_event_t * ev) 98 | { 99 | linked_list_init(ev, ll); 100 | } 101 | 102 | void timed_queue_deinit(timed_queue_t * obj) 103 | { 104 | debug_ptr(obj); 105 | 106 | if (obj->itf.loop) 107 | main_loop_remove_queue(obj->itf.loop, &obj->itf); 108 | 109 | obj->itf.loop = 0; 110 | linked_list_free(obj->root, ll, _free); 111 | obj->root = NULL; 112 | obj->cnt_cache = 0; 113 | } 114 | 115 | void timed_event_init(timed_event_t * ev, reacto_time_t timeout, timed_event_handler_t handler) 116 | { 117 | debug_ptr(ev); 118 | debug_ptr(handler); 119 | ev->link_timestamp = 0; 120 | ev->timeout = timeout; 121 | ev->handler = handler; 122 | linked_list_init(ev, ll); 123 | } 124 | 125 | static bool comp (reacto_time_t seed, timed_event_t * ev) 126 | { 127 | return (ev->link_timestamp + ev->timeout) > seed ? true : false; 128 | } 129 | 130 | void timed_queue_unlink(timed_queue_t * obj, timed_event_t * ev) 131 | { 132 | debug_ptr(obj); 133 | debug_ptr(ev); 134 | 135 | if (ev->ll.next == 0 && ev->ll.prev == 0 && obj->root != ev) 136 | return; 137 | 138 | unlink(obj, ev); 139 | } 140 | 141 | void timed_queue_link(timed_queue_t * obj, timed_event_t * ev) 142 | { 143 | debug_ptr(obj); 144 | debug_ptr(ev); 145 | 146 | timed_queue_unlink(obj, ev); 147 | 148 | ev->link_timestamp = time_now(); 149 | 150 | 151 | if (!obj->root) 152 | { 153 | obj->root = ev; 154 | } 155 | else 156 | { 157 | timed_event_t * after = linked_list_find(obj->root, ll, comp, ev->link_timestamp + ev->timeout); 158 | 159 | if (after) 160 | { 161 | linked_list_insert_before(after, ev, ll); 162 | obj->root = linked_list_first(ev, ll); 163 | } 164 | else 165 | { 166 | linked_list_insert_after(linked_list_last(obj->root, ll), ev, ll); 167 | } 168 | } 169 | 170 | obj->cnt_cache++; 171 | } 172 | 173 | 174 | void timed_queue_link_update_timeout(timed_queue_t * obj, timed_event_t * ev, reacto_time_t timeout) 175 | { 176 | debug_ptr(obj); 177 | debug_ptr(ev); 178 | 179 | ev->timeout = timeout; 180 | timed_queue_link(obj, ev); 181 | } 182 | 183 | queue_i * timed_queue_interface (timed_queue_t * obj) 184 | { 185 | debug_ptr(obj, NULL); 186 | return &obj->itf; 187 | } 188 | -------------------------------------------------------------------------------- /Sconstruct: -------------------------------------------------------------------------------- 1 | #!python 2 | 3 | # Overview of the build system 4 | # - All global configurations goes in this file, 5 | # - Each platforms created contains configurations and environment 6 | # - Each project is called passing platforms. 7 | # - For each platform one build will run, always in the 'build' folder. 8 | # - Projects are expected to append data to platform enviroments when 9 | # necessary, such as includes, defines, libraries, etc. 10 | 11 | 12 | # 13 | # First we add our custom Functions to a default enviroment and configure it 14 | import os 15 | import fnmatch 16 | default_env = Environment() 17 | 18 | # Enable color terminal if available 19 | if 'TERM' in os.environ.keys(): 20 | default_env['ENV']['TERM'] = os.environ['TERM'] 21 | 22 | # Add a FindFiles function to help Programs to search for code 23 | def FindFiles(self, path, glob): 24 | matches = [] 25 | matches.extend(Glob(path + '/' + glob)) 26 | matches.extend(Glob(path + '/*/' + glob)) 27 | matches.extend(Glob(path + '/*/*/' + glob)) 28 | matches.extend(Glob(path + '/*/*/*/' + glob)) 29 | matches.extend(Glob(path + '/*/*/*/*/' + glob)) 30 | matches.extend(Glob(path + '/*/*/*/*/*/' + glob)) 31 | return matches 32 | default_env.AddMethod(FindFiles) 33 | 34 | # Transform a multiline string into a list of Files 35 | def MultiLineStringToFiles(self, multiline_string): 36 | r = [] 37 | for f in multiline_string.split('\n'): 38 | if len(f) > 0: 39 | r.append(File('./' + f)) 40 | return r 41 | default_env.AddMethod(MultiLineStringToFiles) 42 | 43 | # Transform a list of C source into Objects 44 | def SourceToObjects(self, source_list): 45 | r = [] 46 | for s in source_list: 47 | s_path = s.path 48 | o_path = s_path.replace('.CPP', '.o').replace('.C', '.o').replace('.cpp', '.o').replace('.c', '.o') 49 | o = File('#' + o_path) 50 | r.append(o) 51 | return r 52 | default_env.AddMethod(SourceToObjects) 53 | 54 | # Transform a list of Objects into GCDA and GDNO 55 | def ObjectsToGcov(self, source_list): 56 | r = [] 57 | for s in source_list: 58 | s_path = s.path 59 | da_path = s_path.replace('.o', '.gcda') 60 | da = File('#' + da_path) 61 | no_path = s_path.replace('.o', '.gcno') 62 | no = File('#' + no_path) 63 | r.append(da) 64 | r.append(no) 65 | return r 66 | default_env.AddMethod(ObjectsToGcov) 67 | 68 | # Create -include flags 69 | def UpdateIncludes(self): 70 | env = { 71 | 'CXXFLAGS': sum([['-include', i] for i in self['CXXINCLUDES']], []), 72 | 'CFLAGS' : sum([['-include', i] for i in self['CINCLUDES']], []) 73 | } 74 | self.Prepend(**env) 75 | default_env.AddMethod(UpdateIncludes) 76 | 77 | def EnablePlatformsFor(build_name, available_platforms): 78 | r = [] 79 | for plat in available_platforms: 80 | if build_name in plat.BuildList(): 81 | r.append(plat); 82 | return r 83 | 84 | def FindAvailablePlatforms(): 85 | r = [] 86 | for f in Glob('build_platforms/*.sconscript'): 87 | plat = SConscript(f, exports = 'default_env') 88 | r.append(plat) 89 | return r; 90 | 91 | available_platforms = FindAvailablePlatforms() 92 | 93 | # Build CppUTest libraries for each platforms 94 | platforms = EnablePlatformsFor('cpputest', available_platforms) 95 | cpputest = SConscript('dependencies/cpputest/Sconscript', exports ='platforms') 96 | 97 | # Enable GNU Coverage for the next builds 98 | for plat in available_platforms: 99 | if plat.ProfileEnabled(): 100 | plat.Env().Append( 101 | CFLAGS = ['-fprofile-arcs', '-ftest-coverage'], 102 | CXXFLAGS = ['-fprofile-arcs', '-ftest-coverage'], 103 | LIBS = ['gcov'] 104 | ) 105 | 106 | # Build reacto as library 107 | platforms = EnablePlatformsFor('reacto', available_platforms) 108 | SConscript('reacto/Sconscript', exports ='platforms') 109 | 110 | # Build reacto_tests executable 111 | platforms = EnablePlatformsFor('reacto_tests', available_platforms) 112 | SConscript('reacto_tests/Sconscript', exports ='platforms') 113 | 114 | # Build examples 115 | platforms = EnablePlatformsFor('rot13_factory', available_platforms) 116 | SConscript('examples/rot13_factory/Sconscript', exports ='platforms') 117 | 118 | # Build examples 119 | platforms = EnablePlatformsFor('msp430_blink', available_platforms) 120 | SConscript('examples/msp430_blink/Sconscript', exports ='platforms') 121 | 122 | # Build examples 123 | platforms = EnablePlatformsFor('msp430_timed_blink', available_platforms) 124 | SConscript('examples/msp430_timed_blink/Sconscript', exports ='platforms') 125 | 126 | # Build examples 127 | platforms = EnablePlatformsFor('msp430_realtime_blink', available_platforms) 128 | SConscript('examples/msp430_realtime_blink/Sconscript', exports ='platforms') 129 | 130 | # Create extra targets for each platform 131 | for p in available_platforms: 132 | p.PostBuildTargets() 133 | 134 | # Creating root target for each platform 135 | for plat in available_platforms: 136 | t = Command (target=plat.Name(), source='', action='@echo Built default targets for $TARGET') 137 | for target in plat.TargetNameList(): 138 | if isinstance(target, plat.Default): 139 | Depends(t, str(target)) 140 | 141 | # printing targets 142 | def PrintHelp(target, source, env): 143 | print 144 | print "Usage:" 145 | print " scons -Q " 146 | print 147 | print "Available targets ([d]efault targets for platform)" 148 | for plat in available_platforms: 149 | print '\t' + plat.Name() + ':' 150 | for target in plat.TargetNameList(): 151 | if isinstance(target, plat.Default): 152 | d = '[d] ' 153 | else: 154 | d = ' ' 155 | print '\t\t' + d + str(target) 156 | 157 | none = Command ('none', '', PrintHelp) 158 | Default(none) 159 | -------------------------------------------------------------------------------- /reacto/src/main_loop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | static void _free (queue_i * queue) 31 | { 32 | queue->loop = NULL; 33 | linked_list_init(queue, ll); 34 | } 35 | 36 | void main_loop_init(main_loop_t * obj, main_loop_strategy strategy) 37 | { 38 | debug_ptr(obj); 39 | debug_ptr(strategy); 40 | obj->root = NULL; 41 | obj->strategy = strategy; 42 | obj->looping = true; 43 | obj->sleep = NULL; 44 | } 45 | 46 | void main_loop_deinit(main_loop_t * obj) 47 | { 48 | debug_ptr(obj); 49 | 50 | if (obj->root) 51 | linked_list_free(obj->root, ll, _free); 52 | 53 | obj->root = NULL; 54 | obj->strategy = NULL; 55 | obj->sleep = NULL; 56 | } 57 | 58 | void main_loop_set_sleep_handler (main_loop_t * obj, void (*handler)(main_loop_t *)) 59 | { 60 | debug_ptr(obj); 61 | obj->sleep = handler; 62 | } 63 | 64 | void main_loop_add_queue(main_loop_t * obj, queue_i * queue, int position) 65 | { 66 | debug_ptr(obj); 67 | debug_ptr(queue); 68 | queue_i * reference_queue; 69 | bool insert_after = false; 70 | 71 | if (!obj->root) 72 | { 73 | obj->root = queue; 74 | queue->loop = obj; 75 | return; 76 | } 77 | 78 | reference_queue = obj->root; 79 | 80 | while(position-- > 0) 81 | { 82 | queue_i * next = linked_list_next(reference_queue, ll); 83 | if (!next) { 84 | /* List ended before position, insert last */ 85 | insert_after = true; 86 | break; 87 | } 88 | reference_queue = next; 89 | } 90 | 91 | if (insert_after) 92 | { 93 | linked_list_insert_after(reference_queue, queue, ll); 94 | } 95 | else 96 | { 97 | linked_list_insert_before(reference_queue, queue, ll); 98 | obj->root = linked_list_first(queue, ll); 99 | } 100 | queue->loop = obj; 101 | } 102 | 103 | int main_loop_remove_queue(main_loop_t * obj, queue_i * queue) 104 | { 105 | debug_ptr(obj, -1); 106 | debug_ptr(queue, -1); 107 | 108 | if (queue->loop != obj) { 109 | log_error ("Provided queue hasn't been added to the main_loop, cannot remove it."); 110 | return -2; 111 | } 112 | 113 | obj->root = linked_list_remove(queue, ll); 114 | return 0; 115 | } 116 | 117 | void main_loop_run(main_loop_t * obj) 118 | { 119 | debug_ptr(obj); 120 | debug_ptr(obj->strategy); 121 | 122 | do 123 | { 124 | bool go_to_sleep = obj->strategy(obj->root); 125 | if (go_to_sleep && obj->sleep) 126 | obj->sleep(obj); 127 | } 128 | while (obj->looping); 129 | } 130 | 131 | void main_loop_quit(main_loop_t * obj) 132 | { 133 | debug_ptr(obj); 134 | obj->looping = false; 135 | } 136 | 137 | reacto_time_t main_loop_sleep_timeout (main_loop_t * obj) 138 | { 139 | debug_ptr(obj, false); 140 | queue_i * queue = obj->root; 141 | reacto_time_t tout = (reacto_time_t)-1; 142 | 143 | while (queue) 144 | { 145 | reacto_time_t n = queue_interface_sleep_tout(queue); 146 | if (n < tout) 147 | tout = n; 148 | 149 | queue = linked_list_next(queue, ll); 150 | } 151 | 152 | return tout; 153 | } 154 | 155 | static bool priority_queue_and_fare (queue_i * queue, bool priority_enabled) 156 | { 157 | while (queue) 158 | { 159 | size_t cnt; 160 | while ((cnt = queue_interface_count(queue)) != 0) 161 | { 162 | size_t hash = queue_interface_hash(queue); 163 | bool skip_queue = queue_interface_emit(queue); 164 | 165 | if (skip_queue) 166 | break; 167 | 168 | /* If the queue data has not been popped out, we discard it here 169 | * If a handler pop out data, others handlers will loose access to 170 | * it. */ 171 | if (hash == queue_interface_hash(queue)) 172 | queue_interface_pop(queue); 173 | 174 | /* Queues are not empty yet */ 175 | if (priority_enabled) 176 | return false; 177 | } 178 | queue = linked_list_next(queue, ll); 179 | } 180 | 181 | /* Maybe queues are empty */ 182 | return true; 183 | } 184 | 185 | static bool priority_queue(queue_i * queue) 186 | { 187 | return priority_queue_and_fare (queue, true); 188 | } 189 | 190 | static bool fare(queue_i * queue) 191 | { 192 | return priority_queue_and_fare (queue, false); 193 | } 194 | 195 | const main_loop_strategy main_loop_strategy_priority_queue = priority_queue; 196 | const main_loop_strategy main_loop_strategy_fare = fare; 197 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/watchdog/test_watchdog.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | extern "C" 7 | { 8 | #include 9 | #include 10 | 11 | extern reacto_time_t time_now_variable; 12 | } 13 | 14 | TEST_GROUP(Watchdog) 15 | { 16 | void setup () 17 | { 18 | root = (watchdog_t *)0; 19 | } 20 | 21 | void teardown () 22 | { 23 | mock().clear(); 24 | } 25 | }; 26 | 27 | TEST(Watchdog, repeted_enter) 28 | { 29 | watchdog_t cut, cut2; 30 | mock().expectOneCall("hardware_watchdog_init"); 31 | int r = watchdog_init(&cut, 1, "cut"); 32 | CHECK_EQUAL (0, r); 33 | mock().checkExpectations(); 34 | 35 | r = watchdog_init(&cut2, 1, "cut"); 36 | CHECK_EQUAL (0, r); 37 | 38 | watchdog_enter(&cut); 39 | timeout_t t = cut.timeout; 40 | 41 | watchdog_enter(&cut); 42 | CHECK_EQUAL(t, cut.timeout); 43 | 44 | time_now_variable ++; 45 | 46 | watchdog_kick(&cut); 47 | CHECK_FALSE(t == cut.timeout); 48 | 49 | watchdog_exit(&cut); 50 | CHECK_EQUAL(0, cut.timeout); 51 | 52 | watchdog_deinit(&cut); 53 | 54 | mock().expectOneCall("hardware_watchdog_deinit"); 55 | watchdog_deinit(&cut2); 56 | mock().checkExpectations(); 57 | } 58 | TEST(Watchdog, hw_init_deinit) 59 | { 60 | watchdog_t cut, cut2; 61 | mock().expectOneCall("hardware_watchdog_init"); 62 | int r = watchdog_init(&cut, 1, "cut"); 63 | CHECK_EQUAL (0, r); 64 | mock().checkExpectations(); 65 | 66 | r = watchdog_init(&cut2, 1, "cut"); 67 | CHECK_EQUAL (0, r); 68 | 69 | watchdog_deinit(&cut); 70 | 71 | mock().expectOneCall("hardware_watchdog_deinit"); 72 | watchdog_deinit(&cut2); 73 | mock().checkExpectations(); 74 | } 75 | 76 | TEST(Watchdog, init_inval_arg) 77 | { 78 | mock().expectOneCall("_log_file_line") 79 | .withParameter("msg", "Error: Invalid Pointer") 80 | .ignoreOtherParameters(); 81 | int r = watchdog_init(NULL, 0, "cut"); 82 | CHECK_EQUAL (-1, r); 83 | } 84 | 85 | TEST(Watchdog, list_size) 86 | { 87 | mock().expectOneCall("hardware_watchdog_init"); 88 | mock().expectOneCall("hardware_watchdog_deinit"); 89 | 90 | CHECK_EQUAL(0, linked_list_count(root, list_head)); 91 | 92 | watchdog_t cut, cut2; 93 | watchdog_init(&cut, 1, "cut"); 94 | CHECK_EQUAL(1, linked_list_count(root, list_head)); 95 | 96 | watchdog_init(&cut2, 1, "cut"); 97 | CHECK_EQUAL(2, linked_list_count(root, list_head)); 98 | 99 | watchdog_deinit(&cut); 100 | CHECK_EQUAL(1, linked_list_count(root, list_head)); 101 | 102 | watchdog_init(&cut, 1, "cut"); 103 | CHECK_EQUAL(2, linked_list_count(root, list_head)); 104 | 105 | watchdog_deinit(&cut); 106 | CHECK_EQUAL(1, linked_list_count(root, list_head)); 107 | 108 | watchdog_deinit(&cut2); 109 | CHECK_EQUAL(0, linked_list_count(root, list_head)); 110 | } 111 | 112 | TEST(Watchdog, list_root) 113 | { 114 | mock().expectOneCall("hardware_watchdog_init"); 115 | mock().expectOneCall("hardware_watchdog_deinit"); 116 | 117 | watchdog_t cut, cut2; 118 | watchdog_init(&cut, 1, "cut"); 119 | CHECK_EQUAL(&cut, root); 120 | 121 | watchdog_init(&cut2, 1, "cut"); 122 | 123 | watchdog_deinit(&cut); 124 | CHECK_EQUAL(&cut2, root) 125 | 126 | watchdog_init(&cut, 1, "cut"); 127 | 128 | watchdog_deinit(&cut2); 129 | CHECK_EQUAL(&cut, root) 130 | 131 | watchdog_deinit(&cut); 132 | CHECK_EQUAL(0, root) 133 | } 134 | 135 | TEST(Watchdog, expire) 136 | { 137 | mock().expectOneCall("hardware_watchdog_init"); 138 | mock().expectOneCall("hardware_watchdog_deinit"); 139 | 140 | mock().expectNCalls(4, "hardware_watchdog_kick"); 141 | 142 | mock().expectOneCall("log_message") 143 | .withParameter("msg", "Watchdog cut expired."); 144 | 145 | watchdog_t cut, cut2; 146 | timeout_t tout; 147 | 148 | watchdog_init(&cut, 10, "cut"); 149 | watchdog_init(&cut2, 100, "cut2"); 150 | 151 | watchdog_enter(&cut); 152 | watchdog_enter(&cut2); 153 | timeout_init(&tout); /* Tout init, this is the base time */ 154 | 155 | time_now_variable += 2; /* Wait 2ms after tout init */ 156 | watchdog_periodic(); /* 1st kick */ 157 | 158 | time_now_variable += 2; /* Wait 4ms after tout init */ 159 | watchdog_periodic(); /* 2nd kick */ 160 | 161 | time_now_variable += 2; /* Wait 6ms after tout init */ 162 | watchdog_periodic(); /* 3rd kick */ 163 | 164 | time_now_variable += 2; /* Wait 8ms after tout init */ 165 | watchdog_periodic(); /* 4rd kick */ 166 | 167 | time_now_variable += 3; /* Wait 11ms after tout init */ 168 | watchdog_periodic(); /* No kick expected here */ 169 | 170 | watchdog_deinit(&cut); 171 | watchdog_deinit(&cut2); 172 | } 173 | 174 | TEST(Watchdog, enter_exit) 175 | { 176 | mock().expectOneCall("hardware_watchdog_init"); 177 | mock().expectOneCall("hardware_watchdog_deinit"); 178 | 179 | mock().expectNCalls(5, "hardware_watchdog_kick"); 180 | 181 | watchdog_t cut, cut2; 182 | timeout_t tout; 183 | 184 | watchdog_init(&cut, 10, "cut"); 185 | watchdog_init(&cut2, 100, "cut2"); 186 | 187 | watchdog_enter(&cut); 188 | watchdog_enter(&cut2); 189 | timeout_init(&tout); /* Tout init, this is the base time */ 190 | 191 | time_now_variable += 2; /* Wait 2ms after tout init */ 192 | watchdog_periodic(); /* 1st kick */ 193 | 194 | time_now_variable += 2; /* Wait 4ms after tout init */ 195 | watchdog_periodic(); /* 2nd kick */ 196 | 197 | time_now_variable += 2; /* Wait 6ms after tout init */ 198 | watchdog_periodic(); /* 3rd kick */ 199 | 200 | time_now_variable += 2; /* Wait 8ms after tout init */ 201 | watchdog_periodic(); /* 4th kick */ 202 | 203 | watchdog_exit(&cut); /* Cut exited before expiring */ 204 | 205 | time_now_variable += 3; /* Wait 11ms after tout init */ 206 | watchdog_periodic(); /* 5th kick */ 207 | 208 | watchdog_deinit(&cut); 209 | watchdog_deinit(&cut2); 210 | } 211 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/reusables/test_timeout.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" 4 | { 5 | #include 6 | #include 7 | 8 | extern reacto_time_t time_now_variable; 9 | } 10 | 11 | TEST_GROUP(timeout) 12 | { 13 | void setup() 14 | { 15 | } 16 | 17 | void teardown() 18 | { 19 | } 20 | }; 21 | 22 | TEST(timeout, init_copy) 23 | { 24 | timeout_t tout, tout2; 25 | timeout_init(&tout); 26 | timeout_copy(&tout2, &tout); 27 | CHECK_EQUAL(tout, tout2); 28 | } 29 | 30 | TEST(timeout, test) 31 | { 32 | timeout_t tout; 33 | timeout_init(&tout); 34 | 35 | CHECK_FALSE(timeout_check(&tout, 100)); 36 | time_now_variable += 1; 37 | CHECK_FALSE(timeout_check(&tout, 100)); 38 | time_now_variable += 9; 39 | CHECK_FALSE(timeout_check(&tout, 100)); 40 | time_now_variable += 40; 41 | CHECK_FALSE(timeout_check(&tout, 100)); 42 | time_now_variable += 49; 43 | CHECK_FALSE(timeout_check(&tout, 100)); 44 | time_now_variable += 1; 45 | CHECK_TRUE(timeout_check(&tout, 100)); 46 | } 47 | 48 | TEST(timeout, periodically_test) 49 | { 50 | timeout_t tout; 51 | timeout_init(&tout); 52 | 53 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 54 | time_now_variable += 1; 55 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 56 | time_now_variable += 9; 57 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 58 | time_now_variable += 40; 59 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 60 | time_now_variable += 49; 61 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 62 | time_now_variable += 1; 63 | CHECK_TRUE(timeout_check_and_reinit(&tout, 100)); 64 | 65 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 66 | time_now_variable += 1; 67 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 68 | time_now_variable += 9; 69 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 70 | time_now_variable += 40; 71 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 72 | time_now_variable += 49; 73 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 74 | time_now_variable += 1; 75 | CHECK_TRUE(timeout_check_and_reinit(&tout, 100)); 76 | 77 | CHECK_FALSE(timeout_check_and_reinit(&tout, 100)); 78 | } 79 | 80 | TEST(timeout, remaining_test) 81 | { 82 | timeout_t tout; 83 | timeout_init(&tout); 84 | reacto_time_t now = time_now(); 85 | CHECK_EQUAL(100, timeout_remaining(time_now(), now, 100)); 86 | 87 | time_now_variable += 1; 88 | CHECK_EQUAL(99, timeout_remaining(time_now(), now, 100)); 89 | time_now_variable += 10; 90 | CHECK_EQUAL(89, timeout_remaining(time_now(), now, 100)); 91 | time_now_variable += 88; 92 | CHECK_EQUAL(0, timeout_remaining(time_now(), now, 100)); 93 | 94 | } 95 | 96 | TEST(timeout, comparator_test) 97 | { 98 | const reacto_time_t max = (reacto_time_t)-1; 99 | 100 | /* Comparator margin */ 101 | CHECK_FALSE(timeout_check_elapsed(10, 0, 11)); 102 | CHECK_TRUE (timeout_check_elapsed(10, 0, 10)); 103 | 104 | /* Considering timer wrap */ 105 | CHECK_FALSE(timeout_check_elapsed(max - 1, max - 1, 3)); 106 | CHECK_FALSE(timeout_check_elapsed(max, max - 1, 3)); 107 | CHECK_FALSE(timeout_check_elapsed(max + 1, max - 1, 3)); 108 | CHECK_TRUE (timeout_check_elapsed(max + 2, max - 1, 3)); 109 | CHECK_TRUE (timeout_check_elapsed(max + 3, max - 1, 3)); 110 | CHECK_TRUE (timeout_check_elapsed(max + 4, max - 1, 3)); 111 | CHECK_TRUE (timeout_check_elapsed(max + 5, max - 1, 3)); 112 | CHECK_TRUE (timeout_check_elapsed(max + 6, max - 1, 3)); 113 | 114 | CHECK_FALSE(timeout_check_elapsed(max - 1, max - 1, 1)); 115 | CHECK_TRUE (timeout_check_elapsed(max, max - 1, 1)); 116 | CHECK_TRUE (timeout_check_elapsed(max + 1, max - 1, 1)); 117 | CHECK_TRUE (timeout_check_elapsed(max + 2, max - 1, 1)); 118 | CHECK_TRUE (timeout_check_elapsed(max + 3, max - 1, 1)); 119 | CHECK_TRUE (timeout_check_elapsed(max + 4, max - 1, 1)); 120 | CHECK_TRUE (timeout_check_elapsed(max + 5, max - 1, 1)); 121 | CHECK_TRUE (timeout_check_elapsed(max + 6, max - 1, 1)); 122 | 123 | CHECK_FALSE(timeout_check_elapsed(max - 1, max + 1, max)); 124 | CHECK_TRUE (timeout_check_elapsed(max, max + 1, max)); 125 | 126 | CHECK_FALSE(timeout_check_elapsed(0xE, 0x10, max)); 127 | CHECK_TRUE (timeout_check_elapsed(0xF, 0x10, max)); 128 | 129 | /* Tests pass because the subtraction made in check_elapsed 130 | * removes the wrap effect. 131 | * It only works if "now" is bigger than "before", considering 132 | * we are dealing with time, now is bigger than before, always. 133 | */ 134 | 135 | /* Elapsed 0 always return true! */ 136 | CHECK_TRUE (timeout_check_elapsed(max - 2, max - 1, 0)); 137 | CHECK_TRUE (timeout_check_elapsed(max - 1, max - 1, 0)); 138 | 139 | /* Ok, what if I wanted to test now against a number in the future? 140 | * Simple! Transform later in before with a stupid big number and 141 | * check against it! */ 142 | reacto_time_t stupid_big_number = (max/2) + 1; 143 | reacto_time_t later = 0x00000010; 144 | reacto_time_t before = later - stupid_big_number; 145 | 146 | CHECK_FALSE(timeout_check_elapsed(max - 255, before, stupid_big_number)); 147 | CHECK_FALSE(timeout_check_elapsed(max, before, stupid_big_number)); 148 | CHECK_FALSE(timeout_check_elapsed(max + 1, before, stupid_big_number)); 149 | CHECK_FALSE(timeout_check_elapsed(0x0F, before, stupid_big_number)); 150 | CHECK_TRUE (timeout_check_elapsed(0x10, before, stupid_big_number)); 151 | CHECK_TRUE (timeout_check_elapsed(0x11, before, stupid_big_number)); 152 | 153 | /* As we are good programmers, we wrapped the algorithm in a new function */ 154 | CHECK_FALSE(timeout_check_reached(0x10, max - 255)); 155 | CHECK_FALSE(timeout_check_reached(0x10, max)); 156 | CHECK_FALSE(timeout_check_reached(0x10, max + 1)); 157 | CHECK_FALSE(timeout_check_reached(0x10, 0x0F)); 158 | CHECK_TRUE (timeout_check_reached(0x10, 0x10)); 159 | CHECK_TRUE (timeout_check_reached(0x10, 0x11)); 160 | 161 | /* Wrap around whooooooooooooooooooooooooooooooo? */ 162 | } 163 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # This file is NOT licensed under the GPLv3, which is the license for the rest 2 | # of YouCompleteMe. 3 | # 4 | # Here's the license text for this file: 5 | # 6 | # This is free and unencumbered software released into the public domain. 7 | # 8 | # Anyone is free to copy, modify, publish, use, compile, sell, or 9 | # distribute this software, either in source code form or as a compiled 10 | # binary, for any purpose, commercial or non-commercial, and by any 11 | # means. 12 | # 13 | # In jurisdictions that recognize copyright laws, the author or authors 14 | # of this software dedicate any and all copyright interest in the 15 | # software to the public domain. We make this dedication for the benefit 16 | # of the public at large and to the detriment of our heirs and 17 | # successors. We intend this dedication to be an overt act of 18 | # relinquishment in perpetuity of all present and future rights to this 19 | # software under copyright law. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27 | # OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # For more information, please refer to 30 | 31 | # These are the compilation flags that will be used in case there's no 32 | # compilation database set (by default, one is not set). 33 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 34 | module_name = "ycm_flags" 35 | modyle_path = ".ycm_flags.py.host_tests" 36 | # try: 37 | import sys 38 | if sys.version_info[0] < 3: 39 | from imp import load_source 40 | ycm_flags = load_source(module_name, modyle_path) 41 | flags = ycm_flags.flags 42 | else: 43 | if sys.version_info[1] < 5: 44 | import importlib.util 45 | spec = importlib.util.spec_from_file_location(module_name, modyle_path) 46 | ycm_flags = importlib.util.module_from_spec(spec) 47 | spec.loader.exec_module(ycm_flags) 48 | flags = ycm_flags.flags 49 | else: 50 | from importlib.machinery import SourceFileLoader 51 | ycm_flags = SourceFileLoader(modyle_name, modyle_path).load_module() 52 | flags = ycm_flags.flags 53 | 54 | # except: 55 | # flags = [ 56 | # '-Wall', 57 | # #'-Wextra', 58 | # '-Werror', 59 | # #'-Wc++98-compat', 60 | # '-Wno-long-long', 61 | # '-Wno-variadic-macros', 62 | # '-fexceptions', 63 | # # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which 64 | # # language to use when compiling headers. So it will guess. Badly. So C++ 65 | # # headers will be compiled as C headers. You don't want that so ALWAYS specify 66 | # # a "-std=". 67 | # # For a C project, you would set this to something like 'c99' instead of 68 | # # 'c++11'. 69 | # '-std=c++11', 70 | # # ...and the same thing goes for the magic -x option which specifies the 71 | # # language that the files to be compiled are written in. This is mostly 72 | # # relevant for c++ headers. 73 | # # For a C project, you would set this to 'c' instead of 'c++'. 74 | # '-x', 75 | # 'c++', 76 | # # You can add the specified directory to the search path for 77 | # # system include files. 78 | # #'-isystem', 79 | # #'/usr/include/c++/5', 80 | # # You can add the specified directory to the search path for 81 | # # include files. 82 | # #'-I', 83 | # #'/usr/include/gmock', 84 | # ] 85 | 86 | print flags 87 | 88 | import os 89 | import ycm_core 90 | 91 | 92 | # Set this to the absolute path to the folder (NOT the file!) containing the 93 | # compile_commands.json file to use that instead of 'flags'. See here for 94 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 95 | # 96 | # You can get CMake to generate this file for you by adding: 97 | # set( CMAKE_EXPORT_COMPILE_COMMANDS 1 ) 98 | # to your CMakeLists.txt file. 99 | # 100 | # Most projects will NOT need to set this to anything; you can just change the 101 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 102 | compilation_database_folder = '' 103 | 104 | if os.path.exists( compilation_database_folder ): 105 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 106 | else: 107 | database = None 108 | 109 | SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] 110 | 111 | def DirectoryOfThisScript(): 112 | return os.path.dirname( os.path.abspath( __file__ ) ) 113 | 114 | 115 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 116 | if not working_directory: 117 | return list( flags ) 118 | new_flags = [] 119 | make_next_absolute = False 120 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 121 | for flag in flags: 122 | new_flag = flag 123 | 124 | if make_next_absolute: 125 | make_next_absolute = False 126 | if not flag.startswith( '/' ): 127 | new_flag = os.path.join( working_directory, flag ) 128 | 129 | for path_flag in path_flags: 130 | if flag == path_flag: 131 | make_next_absolute = True 132 | break 133 | 134 | if flag.startswith( path_flag ): 135 | path = flag[ len( path_flag ): ] 136 | new_flag = path_flag + os.path.join( working_directory, path ) 137 | break 138 | 139 | if new_flag: 140 | new_flags.append( new_flag ) 141 | return new_flags 142 | 143 | 144 | def IsHeaderFile( filename ): 145 | extension = os.path.splitext( filename )[ 1 ] 146 | return extension in [ '.h', '.hxx', '.hpp', '.hh' ] 147 | 148 | 149 | def GetCompilationInfoForFile( filename ): 150 | # The compilation_commands.json file generated by CMake does not have entries 151 | # for header files. So we do our best by asking the db for flags for a 152 | # corresponding source file, if any. If one exists, the flags for that file 153 | # should be good enough. 154 | if IsHeaderFile( filename ): 155 | basename = os.path.splitext( filename )[ 0 ] 156 | for extension in SOURCE_EXTENSIONS: 157 | replacement_file = basename + extension 158 | if os.path.exists( replacement_file ): 159 | compilation_info = database.GetCompilationInfoForFile( 160 | replacement_file ) 161 | if compilation_info.compiler_flags_: 162 | return compilation_info 163 | return None 164 | return database.GetCompilationInfoForFile( filename ) 165 | 166 | 167 | def FlagsForFile( filename, **kwargs ): 168 | if database: 169 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 170 | # python list, but a "list-like" StringVec object 171 | compilation_info = GetCompilationInfoForFile( filename ) 172 | if not compilation_info: 173 | return None 174 | 175 | final_flags = MakeRelativePathsInFlagsAbsolute( 176 | compilation_info.compiler_flags_, 177 | compilation_info.compiler_working_dir_ ) 178 | 179 | # NOTE: This is just for YouCompleteMe; it's highly likely that your project 180 | # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR 181 | # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT. 182 | try: 183 | final_flags.remove( '-stdlib=libc++' ) 184 | except ValueError: 185 | pass 186 | else: 187 | relative_to = DirectoryOfThisScript() 188 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 189 | 190 | return { 191 | 'flags': final_flags, 192 | 'do_cache': True 193 | } 194 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/test_timed_queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | extern "C" 9 | { 10 | #include 11 | #include 12 | #include 13 | extern reacto_time_t time_now_variable; 14 | } 15 | 16 | 17 | TEST_GROUP(TimedQueue) 18 | { 19 | timed_queue_t cut; 20 | 21 | void setup () 22 | { 23 | time_now_variable = 0; 24 | timed_queue_init(&cut); 25 | } 26 | 27 | void teardown () 28 | { 29 | timed_queue_deinit(&cut); 30 | mock().clear(); 31 | } 32 | }; 33 | 34 | TEST(TimedQueue, inval) 35 | { 36 | mock().strictOrder(); 37 | 38 | mock().expectOneCall("_log_file_line") 39 | .withParameter("msg", "Error: Invalid Pointer") 40 | .ignoreOtherParameters(); 41 | 42 | timed_queue_init(0); 43 | } 44 | 45 | void handler (timed_event_t * ev) 46 | { 47 | CHECK_TRUE(ev); 48 | 49 | mock().actualCall("handler") 50 | .withIntParameter("timestamp", (int)ev->link_timestamp + (int)ev->timeout); 51 | 52 | CHECK_EQUAL(0, ev->ll.next); 53 | CHECK_EQUAL(0, ev->ll.prev); 54 | } 55 | 56 | 57 | TEST(TimedQueue, link_relink_update) 58 | { 59 | timed_queue_t queue; 60 | timed_event_t ev1, ev2; 61 | 62 | timed_queue_init(&queue); 63 | timed_event_init(&ev1, 1000, handler); 64 | timed_event_init(&ev2, 500, handler); 65 | 66 | CHECK_EQUAL((reacto_time_t)-1, sleep(&queue.itf)); 67 | 68 | timed_queue_link(&queue, &ev1); 69 | timed_queue_link(&queue, &ev2); 70 | 71 | CHECK_EQUAL(500, sleep(&queue.itf)); 72 | 73 | timed_queue_link_update_timeout(&queue, &ev2, 2000); 74 | CHECK_EQUAL(&ev1, queue.root); 75 | CHECK_EQUAL(0, ev1.ll.prev); 76 | CHECK_EQUAL(0, ev2.ll.next); 77 | CHECK_EQUAL(&ev2.ll, ev1.ll.next); 78 | CHECK_EQUAL(&ev1.ll, ev2.ll.prev); 79 | } 80 | 81 | TEST(TimedQueue, link_unlink) 82 | { 83 | timed_queue_t queue; 84 | timed_event_t ev1, ev2; 85 | 86 | timed_queue_init(&queue); 87 | timed_event_init(&ev2, 500, handler); 88 | timed_event_init(&ev1, 1000, handler); 89 | CHECK_EQUAL(0, queue.root); 90 | CHECK_EQUAL(0, ev1.ll.prev); 91 | CHECK_EQUAL(0, ev2.ll.prev); 92 | CHECK_EQUAL(0, ev1.ll.next); 93 | CHECK_EQUAL(0, ev2.ll.next); 94 | 95 | timed_queue_link(&queue, &ev1); 96 | timed_queue_link(&queue, &ev2); 97 | CHECK_EQUAL(&ev2, queue.root); 98 | CHECK_EQUAL(0, ev2.ll.prev); 99 | CHECK_EQUAL(0, ev1.ll.next); 100 | CHECK_EQUAL(&ev1.ll, ev2.ll.next); 101 | CHECK_EQUAL(&ev2.ll, ev1.ll.prev); 102 | 103 | timed_queue_unlink(&queue, &ev1); 104 | timed_queue_unlink(&queue, &ev2); 105 | CHECK_EQUAL(0, queue.root); 106 | CHECK_EQUAL(0, ev1.ll.prev); 107 | CHECK_EQUAL(0, ev2.ll.prev); 108 | CHECK_EQUAL(0, ev1.ll.next); 109 | CHECK_EQUAL(0, ev2.ll.next); 110 | } 111 | 112 | TEST(TimedQueue, link_unlink_on_deinit) 113 | { 114 | timed_queue_t queue; 115 | timed_event_t ev1, ev2; 116 | 117 | timed_queue_init(&queue); 118 | timed_event_init(&ev2, 500, handler); 119 | timed_event_init(&ev1, 1000, handler); 120 | CHECK_EQUAL(0, queue.root); 121 | CHECK_EQUAL(0, ev1.ll.prev); 122 | CHECK_EQUAL(0, ev2.ll.prev); 123 | CHECK_EQUAL(0, ev1.ll.next); 124 | CHECK_EQUAL(0, ev2.ll.next); 125 | 126 | timed_queue_link(&queue, &ev1); 127 | timed_queue_link(&queue, &ev2); 128 | CHECK_EQUAL(&ev2, queue.root); 129 | CHECK_EQUAL(0, ev2.ll.prev); 130 | CHECK_EQUAL(0, ev1.ll.next); 131 | CHECK_EQUAL(&ev1.ll, ev2.ll.next); 132 | CHECK_EQUAL(&ev2.ll, ev1.ll.prev); 133 | 134 | timed_queue_deinit(&queue); 135 | CHECK_EQUAL(0, queue.root); 136 | CHECK_EQUAL(0, ev1.ll.prev); 137 | CHECK_EQUAL(0, ev2.ll.prev); 138 | CHECK_EQUAL(0, ev1.ll.next); 139 | CHECK_EQUAL(0, ev2.ll.next); 140 | } 141 | 142 | TEST(TimedQueue, link_order_2) 143 | { 144 | timed_event_t evs[5]; 145 | main_loop_t loop; 146 | 147 | time_now_variable = 0; 148 | 149 | CHECK_EQUAL((reacto_time_t)-1, sleep(&cut.itf)); 150 | 151 | 152 | for (reacto_time_t i = 0; i < 5; i++) { 153 | timed_event_init(&evs[i], (i+1) * 100, handler); 154 | timed_queue_link(&cut, &evs[i]); 155 | } 156 | 157 | CHECK_EQUAL(5, cut.cnt_cache); 158 | 159 | main_loop_init(&loop, main_loop_strategy_fare); 160 | loop.looping = false; 161 | main_loop_add_queue(&loop, timed_queue_interface(&cut), 0); 162 | 163 | time_now_variable = 0; 164 | main_loop_run(&loop); 165 | mock().checkExpectations(); 166 | 167 | CHECK_EQUAL(100, sleep(&cut.itf)); 168 | 169 | time_now_variable = 99; 170 | main_loop_run(&loop); 171 | mock().checkExpectations(); 172 | 173 | CHECK_EQUAL(0, sleep(&cut.itf)); 174 | 175 | time_now_variable = 100; 176 | mock().expectOneCall("handler") 177 | .withParameter("timestamp", 100); 178 | main_loop_run(&loop); 179 | mock().checkExpectations(); 180 | CHECK_EQUAL(4, cut.cnt_cache); 181 | 182 | CHECK_EQUAL(100, sleep(&cut.itf)); 183 | 184 | time_now_variable = 199; 185 | main_loop_run(&loop); 186 | mock().checkExpectations(); 187 | 188 | CHECK_EQUAL(0, sleep(&cut.itf)); 189 | 190 | time_now_variable = 299; 191 | mock().expectOneCall("handler") 192 | .withParameter("timestamp", 200); 193 | main_loop_run(&loop); 194 | mock().checkExpectations(); 195 | CHECK_EQUAL(3, cut.cnt_cache); 196 | 197 | CHECK_EQUAL(0, sleep(&cut.itf)); 198 | 199 | time_now_variable = 300; 200 | mock().expectOneCall("handler") 201 | .withParameter("timestamp", 300); 202 | main_loop_run(&loop); 203 | mock().checkExpectations(); 204 | CHECK_EQUAL(2, cut.cnt_cache); 205 | 206 | CHECK_EQUAL(100, sleep(&cut.itf)); 207 | 208 | time_now_variable = 500; 209 | mock().expectOneCall("handler") 210 | .withParameter("timestamp", 400); 211 | mock().expectOneCall("handler") 212 | .withParameter("timestamp", 500); 213 | main_loop_run(&loop); 214 | mock().checkExpectations(); 215 | CHECK_EQUAL(0, cut.cnt_cache); 216 | 217 | CHECK_EQUAL((reacto_time_t)-1, sleep(&cut.itf)); 218 | 219 | timed_queue_deinit(&cut); 220 | } 221 | 222 | 223 | TEST(TimedQueue, link_order) 224 | { 225 | timed_event_t evs[100]; 226 | main_loop_t loop; 227 | 228 | for (reacto_time_t i = 0; i < 100; i++) { 229 | timed_event_init(&evs[i], 1000000 - (i * 100), handler); 230 | timed_queue_link(&cut, &evs[i]); 231 | } 232 | 233 | CHECK_EQUAL(100, cut.cnt_cache); 234 | 235 | mock().strictOrder(); 236 | 237 | for (int i = 99; i >= 0; i--) { 238 | mock().expectOneCall("handler") 239 | .withParameter("timestamp", 1000000 - (i * 100)); 240 | } 241 | 242 | main_loop_init(&loop, main_loop_strategy_fare); 243 | loop.looping = false; 244 | main_loop_add_queue(&loop, timed_queue_interface(&cut), 0); 245 | 246 | time_now_variable = 10000000; 247 | main_loop_run(&loop); 248 | timed_queue_deinit(&cut); 249 | mock().checkExpectations(); 250 | } 251 | 252 | TEST(TimedQueue, remove_on_deinit) 253 | { 254 | main_loop_t loop; 255 | timed_queue_t queue; 256 | 257 | timed_queue_init(&queue); 258 | main_loop_init(&loop, main_loop_strategy_priority_queue); 259 | main_loop_add_queue(&loop, &queue.itf, 0); 260 | CHECK_EQUAL(&queue.itf, loop.root); 261 | CHECK_EQUAL(&loop, queue.itf.loop); 262 | timed_queue_deinit(&queue); 263 | CHECK_EQUAL(0, loop.root); 264 | CHECK_EQUAL(0, queue.itf.loop); 265 | } 266 | 267 | TEST(TimedQueue, remove_on_deinit2) 268 | { 269 | main_loop_t loop; 270 | timed_queue_t queue; 271 | 272 | timed_queue_init(&queue); 273 | main_loop_init(&loop, main_loop_strategy_priority_queue); 274 | main_loop_add_queue(&loop, &queue.itf, 0); 275 | CHECK_EQUAL(&queue.itf, loop.root); 276 | CHECK_EQUAL(&loop, queue.itf.loop); 277 | main_loop_deinit(&loop); 278 | CHECK_EQUAL(0, loop.root); 279 | CHECK_EQUAL(0, queue.itf.loop); 280 | } 281 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis](https://img.shields.io/travis/flplv/reacto.svg?style=flat-square)](https://travis-ci.org/flplv/reacto) 2 | [![Codecov](https://img.shields.io/codecov/c/github/flplv/reacto.svg?style=flat-square)](https://codecov.io/gh/flplv/reacto) 3 | [![GitHub release](https://img.shields.io/github/release/flplv/reacto.svg?style=flat-square)](https://github.com/flplv/reacto/releases) 4 | 5 | # react.o 6 | Portable framework for developing reactive embedded systems in C 7 | - Project web page: [http://flplv.github.io/reacto/](http://flplv.github.io/reacto/) 8 | 9 | # Links 10 | 11 | - Change Log: [https://github.com/flplv/reacto/releases](https://github.com/flplv/reacto/releases) 12 | - Project Planning: [https://github.com/flplv/reacto/wiki/0.-Planning](https://github.com/flplv/reacto/wiki/0.-Planning) 13 | - Project Wiki: [https://github.com/flplv/reacto/wiki](https://github.com/flplv/reacto/wiki) 14 | 15 | # Table of Content 16 | 17 | 18 | - [react.o](#reacto) 19 | - [Links](#links) 20 | - [Table of Content](#table-of-content) 21 | - [Project Structure](#project-structure) 22 | - [How to Build](#how-to-build) 23 | - [The build system](#the-build-system) 24 | - [Cross Building](#cross-building) 25 | - [Method 1: Copying code to the embedded project](#method-1-copying-code-to-the-embedded-project) 26 | - [Method 2: Add support to your platform in **react.o** build scripts](#method-2-add-support-to-your-platform-in-reacto-build-scripts) 27 | - [Continuous Integration and Coverage Report Page](#continuous-integration-and-coverage-report-page) 28 | 29 | 30 | 31 | # Project Structure 32 | 33 | ```md 34 | . 35 | ├── **build_platforms** 36 | │ In this folder you will find the platforms definitions in 37 | │ Python/SCons. Each platform extends the class 38 | │ `PlatformBaseClass`. To add a new platform support, this is 39 | │ the only place you have to edit. 40 | │ 41 | ├── **dependencies** 42 | │ │ Only for dependency project, no application code here, 43 | │ │ projects in this folder will not be considered on coverage 44 | │ │ reports. 45 | │ │ All projects inside this folder will be built into static 46 | │ │ libraries for each related platform. 47 | │ │ 48 | │   └── **cpputest** 49 | │ │ CppUTest is the test framework we are using, build scripts 50 | │ │ will download and build it here. CppuTest's libraries are 51 | │ │ created for each platform that tests will run. 52 | │ │ All projects built for tests include headers and libraries from 53 | │ │ here. 54 | │ │ 55 | │      ├── *include/generated/CppUTestGeneratedConfig.h* 56 | │ │ This file configures the CppUTest build, it is shared between 57 | │ │ all platform builds. 58 | │ │ 59 | │      └── *setup-cpputest.sh* 60 | │ This is the script responsible to download and decompress 61 | │ CppUTest source. 62 | │ 63 | ├── **reacto** 64 | │ │ Finally the application code. No tests allowed here, nor 65 | │ │ platform dependent code, only application. Every dependency to 66 | │ │ external world must be abstracted in order to have a testable 67 | │ │ project. 68 | │ │ This project will generate a library that will be linked against 69 | │ │ tests builds and final builds. 70 | │ │ 71 | │   ├── *src* 72 | │ │ │ Here goes the source code of the application. 73 | │ │ │ 74 | │   │ ├── *reusables* 75 | │ │ │ Every project has reusable modules, such as checks, logs, 76 | │ │ │ FIFOs, etc. This is no different. 77 | │ │ │ 78 | │   │ └── *watchdog* 79 | │ │ This is an extended example of a Software Watchdog Class created 80 | │ │ to provide diversified and safe watchdogs along the firwmare. 81 | │ │ A hardware watchdog will reboot by the expiration of any soft 82 | │ │ one. 83 | │ │ 84 | │ └── *includes* 85 | │ The include tree, has the same folders as the source tree. Files 86 | │ are thought to be public, include this folder in your project. 87 | │ 88 | ├── **reacto_tests** 89 | │ │ Finally our application tests. This project will create 90 | │ │ executables for each platform where tests will run. 91 | │ │ There are test code supposed to run on a platform but not on the 92 | │ │ others, this is why you have a source folder for each platform 93 | │ │ and one that will have tests that run on every platforms. 94 | │ │ Each sub folder of *reacto_tests* is equivalent of the *src* 95 | │ │ folder of the application. It means that, if you are testing a 96 | │ │ pattern, the test code will be at *platform_X/patterns/*. 97 | │ │ 98 | │   ├── *platform_host_tests* 99 | │ │ Test code that will run only on development platform, your 100 | │ │ computer. 101 | │ │ 102 | │   └── *tests* 103 | │ Test code that will run only on every platform. 104 | │ 105 | └── *README.md* 106 | This README :) 107 | ``` 108 | 109 | # How to Build 110 | 111 | **1. Install Dependencies** 112 | 113 | - GCC (The compiler) 114 | - scons (The build generator used) 115 | - wget (To download dependency source code) 116 | - lcov (To generate code coverage reports) 117 | 118 | In ubuntu: 119 | ```sh 120 | sudo apt-get install build-essential scons wget lcov 121 | ``` 122 | 123 | **2. Build and run Tests** 124 | 125 | Inside the project root, this line will build the test executable `reacto_host_tests` in the folder `./reacto_tests/build`: 126 | 127 | ```sh 128 | scons -Q ./reacto_tests/build/reacto_host_tests 129 | ``` 130 | 131 | You can run tests with: 132 | 133 | ```sh 134 | ./reacto_tests/build/reacto_host_tests 135 | ``` 136 | 137 | **3. Generate and open code coverage** 138 | 139 | To generate code coverage and open in firefox: 140 | ```sh 141 | scons -Q coverage 142 | firefox ./coverage/index.html 143 | ``` 144 | 145 | If you need to know what targets are available to build: 146 | 147 | ```sh 148 | scons -Q 149 | ``` 150 | # The build system 151 | 152 | ## Cross Building 153 | 154 | There are many ways to cross build **react.o**, one way is copying the code 155 | to your project, and the other is to add a new platform to **react.o**'s build system. 156 | 157 | ### Method 1: Copying code to the embedded project 158 | 159 | 1. Copy folder `reacto/include` and `recto/src` to your project 160 | 2. Add the `include` folder to the compiler search path (`-I include`) 161 | 3. Now enable the GNU extensions with the gcc (or equivalent) flag `-std=gnu11` 162 | 163 | You should now be able to build the your application successfully. 164 | 165 | ### Method 2: Add support to your platform in **react.o** build scripts 166 | 167 | **react.o** uses Scons, a Python based build system, and created an expansible 168 | build system where you can add one more platform considerably easy. 169 | 170 | Platforms are defined in the folder `build_platforms`, 171 | there you can find a few platform configured: 172 | 173 | - `msp430.sconscript` defines a platform for the MSP430 chip, it is used to build the examples. 174 | - `host_tests.sconscript` is a platform used during development, it build and run all **react.o**'s tests. 175 | 176 | To create another platform, it is recommended to copy one of the available and setup: 177 | 178 | - The python class name; 179 | - The platform name returned in the `Name()` method; 180 | - Define your own targets and return it in `TargetNameList()`; 181 | - Set what projects will be built with your platform in the list returned by `BuildList()`; 182 | - Choose `ProfileEnabled` and `CppUTestExtensionsEnabled` status; 183 | - Create your `PostBuildTargets()` Commands 184 | - Clone and setup your enviroment in `_SetupEnv()`, and finally; 185 | - Use the new class when creating an instance at the end of the file. 186 | 187 | # Continuous Integration and Coverage Report Page 188 | 189 | *To be described* 190 | -------------------------------------------------------------------------------- /dependencies/cpputest/include/generated/CppUTestGeneratedConfig.h: -------------------------------------------------------------------------------- 1 | #ifndef _GENERATED_CPPUTESTGENERATEDCONFIG_H 2 | #define _GENERATED_CPPUTESTGENERATEDCONFIG_H 1 3 | 4 | /* generated/CppUTestGeneratedConfig.h. Generated automatically at end of configure. */ 5 | /* config.h. Generated from config.h.in by configure. */ 6 | /* config.h.in. Generated from configure.ac by autoheader. */ 7 | 8 | /* Define to 1 if you have the header file. */ 9 | #ifndef CPPUTEST_HAVE_DLFCN_H 10 | #define CPPUTEST_HAVE_DLFCN_H 1 11 | #endif 12 | 13 | #define CPPUTEST_STD_CPP_LIB_DISABLED 14 | 15 | /* Define to 1 if you have the `fork' function. */ 16 | #ifndef CPPUTEST_HAVE_FORK 17 | #define CPPUTEST_HAVE_FORK 0 18 | #endif 19 | 20 | /* Define to 1 if you have the `gettimeofday' function. */ 21 | //#ifndef CPPUTEST_HAVE_GETTIMEOFDAY 22 | //#define CPPUTEST_HAVE_GETTIMEOFDAY 0 23 | //#endif 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #ifndef CPPUTEST_HAVE_INTTYPES_H 27 | #define CPPUTEST_HAVE_INTTYPES_H 1 28 | #endif 29 | 30 | /* Define to 1 if the system has the type 'long long int'. */ 31 | //#ifndef CPPUTEST_HAVE_LONG_LONG_INT 32 | //#define CPPUTEST_HAVE_LONG_LONG_INT 0 33 | //#endif 34 | 35 | /* Define to 1 if you have the header file. */ 36 | #ifndef CPPUTEST_HAVE_MEMORY_H 37 | #define CPPUTEST_HAVE_MEMORY_H 1 38 | #endif 39 | 40 | /* Define to 1 if you have the `memset' function. */ 41 | #ifndef CPPUTEST_HAVE_MEMSET 42 | #define CPPUTEST_HAVE_MEMSET 1 43 | #endif 44 | 45 | /* Define if you have POSIX threads libraries and header files. */ 46 | /* #undef HAVE_PTHREAD */ 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #ifndef CPPUTEST_HAVE_STDDEF_H 50 | #define CPPUTEST_HAVE_STDDEF_H 1 51 | #endif 52 | 53 | /* Define to 1 if you have the header file. */ 54 | #ifndef CPPUTEST_HAVE_STDINT_H 55 | #define CPPUTEST_HAVE_STDINT_H 1 56 | #endif 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #ifndef CPPUTEST_HAVE_STDLIB_H 60 | #define CPPUTEST_HAVE_STDLIB_H 1 61 | #endif 62 | 63 | /* Define to 1 if you have the header file. */ 64 | #ifndef CPPUTEST_HAVE_STRINGS_H 65 | #define CPPUTEST_HAVE_STRINGS_H 1 66 | #endif 67 | 68 | /* Define to 1 if you have the header file. */ 69 | #ifndef CPPUTEST_HAVE_STRING_H 70 | #define CPPUTEST_HAVE_STRING_H 1 71 | #endif 72 | 73 | /* Define to 1 if you have the `strstr' function. */ 74 | #ifndef CPPUTEST_HAVE_STRSTR 75 | #define CPPUTEST_HAVE_STRSTR 1 76 | #endif 77 | 78 | /* Define to 1 if you have the header file. */ 79 | #ifndef CPPUTEST_HAVE_SYS_STAT_H 80 | #define CPPUTEST_HAVE_SYS_STAT_H 1 81 | #endif 82 | 83 | /* Define to 1 if you have the header file. */ 84 | #ifndef CPPUTEST_HAVE_SYS_TIME_H 85 | #define CPPUTEST_HAVE_SYS_TIME_H 1 86 | #endif 87 | 88 | /* Define to 1 if you have the header file. */ 89 | #ifndef CPPUTEST_HAVE_SYS_TYPES_H 90 | #define CPPUTEST_HAVE_SYS_TYPES_H 1 91 | #endif 92 | 93 | /* Define to 1 if you have the header file. */ 94 | #ifndef CPPUTEST_HAVE_UNISTD_H 95 | #define CPPUTEST_HAVE_UNISTD_H 1 96 | #endif 97 | 98 | /* Define to 1 if the system has the type 'unsigned long long int'. */ 99 | //#ifndef CPPUTEST_HAVE_UNSIGNED_LONG_LONG_INT 100 | //#define CPPUTEST_HAVE_UNSIGNED_LONG_LONG_INT 0 101 | //#endif 102 | 103 | /* Define to 1 if you have the `vfork' function. */ 104 | //#ifndef CPPUTEST_HAVE_VFORK 105 | //#define CPPUTEST_HAVE_VFORK 0 106 | //#endif 107 | 108 | /* Define to 1 if you have the header file. */ 109 | ///* #undef HAVE_VFORK_H */ 110 | // 111 | ///* Define to 1 if `fork' works. */ 112 | //#ifndef CPPUTEST_HAVE_WORKING_FORK 113 | //#define CPPUTEST_HAVE_WORKING_FORK 0 114 | //#endif 115 | // 116 | ///* Define to 1 if `vfork' works. */ 117 | //#ifndef CPPUTEST_HAVE_WORKING_VFORK 118 | //#define CPPUTEST_HAVE_WORKING_VFORK 0 119 | //#endif 120 | 121 | /* Include the GTest-related tests in the build */ 122 | /* #undef INCLUDE_GTEST_TESTS */ 123 | 124 | /* disable long long */ 125 | /* #undef LONG_LONG_DISABLED */ 126 | 127 | /* Define to the sub-directory where libtool stores uninstalled libraries. */ 128 | #ifndef CPPUTEST_LT_OBJDIR 129 | #define CPPUTEST_LT_OBJDIR ".libs/" 130 | #endif 131 | 132 | /* memory leak detection disabled */ 133 | //#ifndef CPPUTEST_MEM_LEAK_DETECTION_DISABLED 134 | //#define CPPUTEST_MEM_LEAK_DETECTION_DISABLED 1 135 | //#endif 136 | 137 | /* Name of package */ 138 | #ifndef CPPUTEST_PACKAGE 139 | #define CPPUTEST_PACKAGE "cpputest" 140 | #endif 141 | 142 | /* Define to the address where bug reports for this package should be sent. */ 143 | #ifndef CPPUTEST_PACKAGE_BUGREPORT 144 | #define CPPUTEST_PACKAGE_BUGREPORT "https://github.com/cpputest/cpputest" 145 | #endif 146 | 147 | /* Define to the full name of this package. */ 148 | #ifndef CPPUTEST_PACKAGE_NAME 149 | #define CPPUTEST_PACKAGE_NAME "CppUTest" 150 | #endif 151 | 152 | /* Define to the full name and version of this package. */ 153 | #ifndef CPPUTEST_PACKAGE_STRING 154 | #define CPPUTEST_PACKAGE_STRING "CppUTest 3.8" 155 | #endif 156 | 157 | /* Define to the one symbol short name of this package. */ 158 | #ifndef CPPUTEST_PACKAGE_TARNAME 159 | #define CPPUTEST_PACKAGE_TARNAME "cpputest" 160 | #endif 161 | 162 | /* Define to the home page for this package. */ 163 | #ifndef CPPUTEST_PACKAGE_URL 164 | #define CPPUTEST_PACKAGE_URL "" 165 | #endif 166 | 167 | /* Define to the version of this package. */ 168 | #ifndef CPPUTEST_PACKAGE_VERSION 169 | #define CPPUTEST_PACKAGE_VERSION "3.8" 170 | #endif 171 | 172 | /* Define to necessary symbol if this constant uses a non-standard name on 173 | your system. */ 174 | /* #undef PTHREAD_CREATE_JOINABLE */ 175 | 176 | /* Define to 1 if you have the ANSI C header files. */ 177 | #ifndef CPPUTEST_STDC_HEADERS 178 | #define CPPUTEST_STDC_HEADERS 1 179 | #endif 180 | 181 | /* Standard C++ library disabled */ 182 | /* #undef STD_CPP_LIB_DISABLED */ 183 | 184 | /* Standard C library disabled */ 185 | /* #undef STD_C_LIB_DISABLED */ 186 | 187 | /* Version number of package */ 188 | #ifndef CPPUTEST_VERSION 189 | #define CPPUTEST_VERSION "3.8" 190 | #endif 191 | 192 | /* Define for Solaris 2.5.1 so the uint32_t typedef from , 193 | , or is not used. If the typedef were allowed, the 194 | #define below would cause a syntax error. */ 195 | /* #undef _UINT32_T */ 196 | 197 | /* Define for Solaris 2.5.1 so the uint64_t typedef from , 198 | , or is not used. If the typedef were allowed, the 199 | #define below would cause a syntax error. */ 200 | /* #undef _UINT64_T */ 201 | 202 | /* Define for Solaris 2.5.1 so the uint8_t typedef from , 203 | , or is not used. If the typedef were allowed, the 204 | #define below would cause a syntax error. */ 205 | /* #undef _UINT8_T */ 206 | 207 | /* Define to `__inline__' or `__inline' if that's what the C compiler 208 | calls it, or to nothing if 'inline' is not supported under any name. */ 209 | #ifndef __cplusplus 210 | /* #undef inline */ 211 | #endif 212 | 213 | /* Define to the type of a signed integer type of width exactly 16 bits if 214 | such a type exists and the standard includes do not define it. */ 215 | /* #undef int16_t */ 216 | 217 | /* Define to the type of a signed integer type of width exactly 32 bits if 218 | such a type exists and the standard includes do not define it. */ 219 | /* #undef int32_t */ 220 | 221 | /* Define to the type of a signed integer type of width exactly 64 bits if 222 | such a type exists and the standard includes do not define it. */ 223 | /* #undef int64_t */ 224 | 225 | /* Define to the type of a signed integer type of width exactly 8 bits if such 226 | a type exists and the standard includes do not define it. */ 227 | /* #undef int8_t */ 228 | 229 | /* Define to `int' if does not define. */ 230 | /* #undef pid_t */ 231 | 232 | /* Define to `unsigned int' if does not define. */ 233 | /* #undef size_t */ 234 | 235 | /* Define to the type of an unsigned integer type of width exactly 16 bits if 236 | such a type exists and the standard includes do not define it. */ 237 | /* #undef uint16_t */ 238 | 239 | /* Define to the type of an unsigned integer type of width exactly 32 bits if 240 | such a type exists and the standard includes do not define it. */ 241 | /* #undef uint32_t */ 242 | 243 | /* Define to the type of an unsigned integer type of width exactly 64 bits if 244 | such a type exists and the standard includes do not define it. */ 245 | /* #undef uint64_t */ 246 | 247 | /* Define to the type of an unsigned integer type of width exactly 8 bits if 248 | such a type exists and the standard includes do not define it. */ 249 | /* #undef uint8_t */ 250 | 251 | /* Define as `fork' if `vfork' does not work. */ 252 | /* #undef vfork */ 253 | 254 | /* once: _GENERATED_CPPUTESTGENERATEDCONFIG_H */ 255 | #endif 256 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/signal_slot.template: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /* 26 | * 27 | * The Customized Signal Slot Class Body Generator 28 | * 29 | * 30 | * This code generates functions with the customized signatures for a signal 31 | * slot event emitting system. Besides being a generic template, it keeps type 32 | * safety, there's absolutely no opaque data, commonly used to generalize 33 | * signatures and bypas type checking on build time. 34 | * 35 | * Our approach create names and signatures from configuration macros. Because 36 | * that, you have to define four macros that will be used by this file and then 37 | * `#include` this file to your .c code. 38 | * 39 | * Below an example of explained .c file to generate a signal slot module where 40 | * the handler takes an `int` and a `char *` as argument and the modudle is 41 | * called "signal_slot_test": 42 | * 43 | * First, we setup the prefixes used to form function and types names. It has 44 | * to finish with `_`. 45 | * 46 | * #define signal_prefix signal_test_ 47 | * #define slot_prefix slot_test_ 48 | * 49 | * Next the parameters of the handler function that is called when a signal is 50 | * emmited. It is necessary three macros: 51 | * `parameters_declaration`: used to create a list of arguments for internal 52 | * functions, __VA_ARGS__ cannot be removed. 53 | * `parameters_list`: used to create a list of arguments passed to internal 54 | * functions, __VA_ARGS__ cannot be removed. 55 | * `handler_parameters_list`: used only to create arguments passed to user 56 | * handler. Here you can remove __VA_ARGS__, if you keep it you will 57 | * have a pointer to the slot as an argument. 58 | * 59 | * ps: add `_` in front of the argument names to avoid conflicts. 60 | * 61 | * #define parameters_declaration(...) __VA_ARGS__, int _a, char * _b 62 | * #define parameters_list(...) __VA_ARGS__, _a, _b 63 | * #define handler_parameters_list(...) __VA_ARGS__, _a, _b 64 | * 65 | * It's done, now we include this file in the `signal_slot_test.c` at the end: 66 | * 67 | * #include "signalslot.template" 68 | * 69 | * Do not export those macros in a header, since they have no namespacing and 70 | * will cause conflict, this is a point of improvment, since it makes impossible 71 | * to generate code for the header as well. 72 | * 73 | * The header has to be written manually, this is the appropriate header used 74 | * to export the generated code in this example: 75 | * 76 | * #include "linked_list.h" 77 | * #include 78 | * 79 | * struct slot_test_private; 80 | * typedef struct slot_test_private slot_test_t; 81 | * 82 | * struct signal_test_private; 83 | * typedef struct signal_test_private signal_test_t; 84 | * 85 | * typedef void (*slot_test_handler_t) (slot_test_t * slot, int, char *); 86 | * 87 | * void signal_test_init(signal_test_t *, slot_demo_handler_t handler); 88 | * void signal_test_deinit(signal_test_t *); 89 | * bool signal_test_is_connected(signal_test_t *, slot_test_t *); 90 | * void signal_test_emit(signal_test_t *, int n, char * buf); 91 | * 92 | * void slot_test_init(slot_test_t *); 93 | * void slot_test_deinit(slot_test_t *); 94 | * void slot_test_connect(slot_test_t *, signal_test_t *); 95 | * void slot_test_disconnect(slot_test_t *, signal_test_t *); 96 | * 97 | * struct signal_test_private 98 | * { 99 | * struct slot_test_private * root; 100 | * }; 101 | * 102 | * struct slot_test_private 103 | * { 104 | * signal_test_t * connection; 105 | * slot_test_handler_t handler; 106 | * linked_list_t ll; 107 | * }; 108 | * 109 | * ps: We avoided calling this file .c to keep it away from being built directly 110 | * by a build system that build everything that has the .c extension. 111 | */ 112 | 113 | #include 114 | #include 115 | #include 116 | #include 117 | 118 | #define macro_cat(a, ...) a ## __VA_ARGS__ 119 | #define function(m, f) macro_cat(m, f) 120 | #define type_name(m) macro_cat(m, t) 121 | #define handler_declaration(m) macro_cat(m, handler_t) 122 | 123 | 124 | static void function(slot_prefix, free_from_signal)(type_name(slot_prefix) * obj) 125 | { 126 | obj->connection = NULL; 127 | linked_list_init(obj, ll); 128 | } 129 | 130 | void function(signal_prefix, init)(type_name(signal_prefix) * obj) 131 | { 132 | debug_ptr(obj); 133 | obj->root = NULL; 134 | } 135 | 136 | void function(signal_prefix, deinit)(type_name(signal_prefix) * obj) 137 | { 138 | debug_ptr(obj); 139 | 140 | if (obj->root) 141 | linked_list_free(obj->root, ll, function(slot_prefix, free_from_signal)); 142 | 143 | obj->root = 0; 144 | } 145 | 146 | 147 | static int function(slot_prefix, call)(parameters_declaration(type_name(slot_prefix) * obj)) 148 | { 149 | debug_ptr(obj, -1); 150 | 151 | if (!obj->handler) 152 | return 0; 153 | 154 | return obj->handler(handler_parameters_list(obj)); 155 | } 156 | 157 | /* 158 | * Rules of the Handler: 159 | * Handlers will be called in the order they were inserted. 160 | * If a handler returns anything but 0, the call loop will stop and no other 161 | * connected handler will be called. 162 | */ 163 | void function(signal_prefix, emit)(parameters_declaration(type_name(signal_prefix) * obj)) 164 | { 165 | type_name(slot_prefix) * slot_to_be_called = NULL; 166 | 167 | debug_ptr(obj); 168 | 169 | if (!obj->root) 170 | return; 171 | 172 | slot_to_be_called = obj->root; 173 | 174 | do 175 | { 176 | int r = function(slot_prefix, call)(parameters_list(slot_to_be_called)); 177 | if (r != 0) break; 178 | } 179 | while ((slot_to_be_called = linked_list_next(slot_to_be_called, ll))); 180 | } 181 | 182 | bool function(signal_prefix, is_connected)(type_name(signal_prefix) *obj, type_name(slot_prefix) *slot) 183 | { 184 | type_name(slot_prefix) * registered_slot = NULL; 185 | 186 | debug_ptr(obj, false); 187 | debug_ptr(slot, false); 188 | 189 | if (!obj->root) 190 | return false; 191 | 192 | registered_slot = obj->root; 193 | 194 | do 195 | { 196 | if (slot == registered_slot) return true; 197 | } 198 | while ((registered_slot = linked_list_next(registered_slot, ll))); 199 | 200 | return false; 201 | } 202 | 203 | static void function(signal_prefix, connect)(type_name(signal_prefix) *obj, type_name(slot_prefix) *slot) 204 | { 205 | if (function(signal_prefix, is_connected)(obj, slot)) 206 | return; 207 | 208 | if (!obj->root) 209 | obj->root = slot; 210 | else 211 | linked_list_insert_after(linked_list_last(obj->root, ll), slot, ll); 212 | } 213 | 214 | static void function(signal_prefix, disconnect)(type_name(signal_prefix) *obj, type_name(slot_prefix) *slot) 215 | { 216 | obj->root = linked_list_remove(slot, ll); 217 | } 218 | 219 | void function(slot_prefix, init)(type_name(slot_prefix) * obj, handler_declaration(slot_prefix) handler) 220 | { 221 | debug_ptr(obj); 222 | linked_list_init(obj, ll); 223 | obj->connection = NULL; 224 | obj->handler = handler; 225 | } 226 | 227 | void function(slot_prefix, deinit)(type_name(slot_prefix) * obj) 228 | { 229 | debug_ptr(obj); 230 | if (obj->connection) 231 | function(signal_prefix, disconnect)(obj->connection, obj); 232 | obj->connection = NULL; 233 | obj->handler = NULL; 234 | linked_list_init(obj, ll); 235 | } 236 | 237 | void function(slot_prefix, connect)(type_name(slot_prefix) *obj, type_name(signal_prefix)* signal) 238 | { 239 | debug_ptr(obj); 240 | debug_ptr(signal); 241 | function(signal_prefix, connect)(signal, obj); 242 | obj->connection = signal; 243 | } 244 | 245 | int function(slot_prefix, disconnect)(type_name(slot_prefix) *obj, type_name(signal_prefix)* signal) 246 | { 247 | debug_ptr(obj, -1); 248 | debug_ptr(signal, -1); 249 | 250 | if (obj->connection != signal) { 251 | log_error ("Provided signal is not connected to slot, cannot disconnect."); 252 | return -2; 253 | } 254 | 255 | function(signal_prefix, disconnect)(signal, obj); 256 | obj->connection = NULL; 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /reacto_tests/src_tests/text_context_and_factory.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | extern "C" 9 | { 10 | #define REACTO_N_OF_QUEUES 5 11 | #define REACTO_MAX_N_OF_HANDLERS_PER_QUEUE 5 12 | #include 13 | #include 14 | } 15 | 16 | 17 | static struct reacto_queues_context queues_context; 18 | static struct reacto_timed_queue_context timed_queue_context; 19 | 20 | static int h (queue_t * q) 21 | { 22 | mock().actualCall("h").withPointerParameter("q", q); 23 | return 0; 24 | } 25 | 26 | TEST_GROUP(Context) 27 | { 28 | void setup () 29 | { 30 | typeof(queues_context.queue_buffer_sizes) sizes = { 31 | 2, 4, 8, 16, 32 32 | }; 33 | 34 | typeof(queues_context.queue_handlers) handlers = { 35 | { h, h, h, h, h }, 36 | { h, h, h, h, h }, 37 | { h, h, h, h, h }, 38 | { h, h, h, h, h }, 39 | { h, h, h, h, h }, 40 | }; 41 | 42 | memcpy(queues_context.queue_buffer_sizes, sizes, sizeof(sizes)); 43 | memcpy(queues_context.queue_handlers, handlers, sizeof(handlers)); 44 | timed_queue_context.high_priority = false; 45 | 46 | memset(&reacto_context_private_data, 0x00, sizeof(reacto_context_private_data)); 47 | } 48 | 49 | void teardown () 50 | { 51 | mock().clear(); 52 | } 53 | }; 54 | 55 | TEST(Context, no_queues) 56 | { 57 | int r = reacto_context_factory(main_loop_strategy_fare, 58 | 0, 59 | 0); 60 | 61 | CHECK_EQUAL(0 , r); 62 | CHECK_EQUAL(0, reacto_context_queue(0)); 63 | CHECK_EQUAL(0, reacto_context_timed_queue()); 64 | CHECK_TRUE (0 == reacto_context_main_loop()->root); 65 | } 66 | 67 | TEST(Context, no_handlers) 68 | { 69 | typeof(queues_context.queue_handlers) handlers = { 70 | { 0, 0, 0, 0, 0 }, 71 | { 0, 0, 0, 0, 0 }, 72 | { 0, 0, 0, 0, 0 }, 73 | { 0, 0, 0, 0, 0 }, 74 | { 0, 0, 0, 0, 0 }, 75 | }; 76 | memcpy(queues_context.queue_handlers, handlers, sizeof(handlers)); 77 | 78 | int r = reacto_context_factory(main_loop_strategy_fare, 79 | 0, 80 | &queues_context); 81 | 82 | CHECK_EQUAL(0 , r); 83 | CHECK_FALSE(0 == reacto_context_main_loop()->root); 84 | } 85 | 86 | TEST(Context, handlers) 87 | { 88 | int r = reacto_context_factory(main_loop_strategy_fare, 89 | &timed_queue_context, 90 | &queues_context); 91 | 92 | CHECK_EQUAL(0 , r); 93 | 94 | mock().expectNCalls(5, "h") 95 | .withPointerParameter("q", &reacto_context_private_data.queues[0]); 96 | mock().expectNCalls(5, "h") 97 | .withPointerParameter("q", &reacto_context_private_data.queues[1]); 98 | mock().expectNCalls(5, "h") 99 | .withPointerParameter("q", &reacto_context_private_data.queues[2]); 100 | mock().expectNCalls(5, "h") 101 | .withPointerParameter("q", &reacto_context_private_data.queues[3]); 102 | mock().expectNCalls(5, "h") 103 | .withPointerParameter("q", &reacto_context_private_data.queues[4]); 104 | 105 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[0].fifo); 106 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[1].fifo); 107 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[2].fifo); 108 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[3].fifo); 109 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[4].fifo); 110 | 111 | auto loop = reacto_context_main_loop(); 112 | loop->looping = false; 113 | main_loop_run(loop); 114 | } 115 | 116 | TEST(Context, incomplete_handlers) 117 | { 118 | typeof(queues_context.queue_handlers) handlers = { 119 | { h, h, 0, 0, 0 }, 120 | { h, h, 0, 0, 0 }, 121 | { h, h, 0, 0, 0 }, 122 | { h, h, 0, 0, 0 }, 123 | { h, h, 0, 0, 0 }, 124 | }; 125 | 126 | memcpy(queues_context.queue_handlers, handlers, sizeof(handlers)); 127 | 128 | int r = reacto_context_factory(main_loop_strategy_fare, 129 | &timed_queue_context, 130 | &queues_context); 131 | 132 | CHECK_EQUAL(0 , r); 133 | 134 | mock().expectNCalls(2, "h") 135 | .withPointerParameter("q", &reacto_context_private_data.queues[0]); 136 | mock().expectNCalls(2, "h") 137 | .withPointerParameter("q", &reacto_context_private_data.queues[1]); 138 | mock().expectNCalls(2, "h") 139 | .withPointerParameter("q", &reacto_context_private_data.queues[2]); 140 | mock().expectNCalls(2, "h") 141 | .withPointerParameter("q", &reacto_context_private_data.queues[3]); 142 | mock().expectNCalls(2, "h") 143 | .withPointerParameter("q", &reacto_context_private_data.queues[4]); 144 | 145 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[0].fifo); 146 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[1].fifo); 147 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[2].fifo); 148 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[3].fifo); 149 | fast_ring_fifo_write_increment(&reacto_context_private_data.queues[4].fifo); 150 | 151 | auto loop = reacto_context_main_loop(); 152 | loop->looping = false; 153 | main_loop_run(loop); 154 | } 155 | 156 | TEST(Context, timed_prio) 157 | { 158 | timed_queue_context.high_priority = true; 159 | 160 | int r = reacto_context_factory(main_loop_strategy_fare, 161 | &timed_queue_context, 162 | &queues_context); 163 | auto loop = reacto_context_main_loop(); 164 | 165 | CHECK_EQUAL(0 , r); 166 | 167 | CHECK_EQUAL(&reacto_context_private_data.timed_queue.itf, loop->root); 168 | CHECK_EQUAL(&reacto_context_private_data.queues[0].itf, linked_list_next(loop->root, ll)); 169 | CHECK_EQUAL(&reacto_context_private_data.queues[4].itf, linked_list_last(loop->root, ll)); 170 | } 171 | 172 | TEST(Context, timed_not_prio) 173 | { 174 | timed_queue_context.high_priority = false; 175 | 176 | int r = reacto_context_factory(main_loop_strategy_fare, 177 | &timed_queue_context, 178 | &queues_context); 179 | auto loop = reacto_context_main_loop(); 180 | 181 | CHECK_EQUAL(0 , r); 182 | 183 | CHECK_EQUAL(&reacto_context_private_data.queues[0].itf, loop->root); 184 | CHECK_EQUAL(&reacto_context_private_data.queues[1].itf, linked_list_next(loop->root, ll)); 185 | CHECK_EQUAL(&reacto_context_private_data.timed_queue.itf, linked_list_last(loop->root, ll)); 186 | } 187 | 188 | TEST(Context, fifos_order) 189 | { 190 | int r = reacto_context_factory(main_loop_strategy_fare, 191 | &timed_queue_context, 192 | &queues_context); 193 | 194 | CHECK_EQUAL(0 , r); 195 | CHECK_EQUAL(2 , fast_ring_fifo_num_of_slots(&reacto_context_private_data.queues[0].fifo)); 196 | CHECK_EQUAL(4 , fast_ring_fifo_num_of_slots(&reacto_context_private_data.queues[1].fifo)); 197 | CHECK_EQUAL(8 , fast_ring_fifo_num_of_slots(&reacto_context_private_data.queues[2].fifo)); 198 | CHECK_EQUAL(16, fast_ring_fifo_num_of_slots(&reacto_context_private_data.queues[3].fifo)); 199 | CHECK_EQUAL(32, fast_ring_fifo_num_of_slots(&reacto_context_private_data.queues[4].fifo)); 200 | } 201 | 202 | TEST(Context, bad_queue) 203 | { 204 | mock().expectOneCall("_log_file_line").ignoreOtherParameters(); 205 | 206 | queues_context.queue_buffer_sizes[0] = 0; 207 | 208 | int r = reacto_context_factory(main_loop_strategy_fare, 209 | &timed_queue_context, 210 | &queues_context); 211 | 212 | CHECK_EQUAL(-1 , r); 213 | } 214 | 215 | TEST(Context, getters) 216 | { 217 | CHECK_EQUAL(0, reacto_context_main_loop()); 218 | CHECK_EQUAL(0, reacto_context_timed_queue()); 219 | CHECK_EQUAL(0, reacto_context_queue(0)); 220 | CHECK_EQUAL(0, reacto_context_queue(1)); 221 | CHECK_EQUAL(0, reacto_context_queue(2)); 222 | CHECK_EQUAL(0, reacto_context_queue(3)); 223 | CHECK_EQUAL(0, reacto_context_queue(4)); 224 | CHECK_EQUAL(0, reacto_context_queue(127981)); 225 | 226 | int r = reacto_context_factory(main_loop_strategy_fare, 227 | &timed_queue_context, 228 | &queues_context); 229 | CHECK_EQUAL(0 , r); 230 | 231 | CHECK_EQUAL(&reacto_context_private_data.loop, reacto_context_main_loop()); 232 | CHECK_EQUAL(&reacto_context_private_data.timed_queue, reacto_context_timed_queue()); 233 | CHECK_EQUAL(&reacto_context_private_data.queues[0], reacto_context_queue(0)); 234 | CHECK_EQUAL(&reacto_context_private_data.queues[1], reacto_context_queue(1)); 235 | CHECK_EQUAL(&reacto_context_private_data.queues[2], reacto_context_queue(2)); 236 | CHECK_EQUAL(&reacto_context_private_data.queues[3], reacto_context_queue(3)); 237 | CHECK_EQUAL(&reacto_context_private_data.queues[4], reacto_context_queue(4)); 238 | } 239 | -------------------------------------------------------------------------------- /reacto/includes/reacto/reusables/linked_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2016 Felipe Lavratti 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 10 | * of the Software, and to permit persons to whom the Software is furnished to do 11 | * so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef REACTO_REUSABLES_LINKED_LIST_H_ 25 | #define REACTO_REUSABLES_LINKED_LIST_H_ 26 | 27 | #include 28 | 29 | #ifndef __cplusplus 30 | #define __ll_auto_type typeof 31 | #define __ll_typeof typeof 32 | 33 | #define __ll_container_of(ptr, type, member) ({ \ 34 | const __ll_auto_type( ((type *)0)->member ) *__mptr = (ptr); \ 35 | (type *)( (char *)__mptr - offsetof(type, member) );}) 36 | #else 37 | #ifndef __ll_container_of 38 | #error "You need to include linked_list.hpp to use this module in C++" 39 | #endif 40 | #endif // __cplusplus 41 | 42 | struct s_linked_list_head 43 | { 44 | struct s_linked_list_head * next; 45 | struct s_linked_list_head * prev; 46 | }; 47 | 48 | typedef struct s_linked_list_head linked_list_t; 49 | 50 | 51 | /** 52 | * Initialize a linked_list_t within structure 53 | * @param 54 | */ 55 | #define linked_list_init(structure, field) \ 56 | ({ \ 57 | __ll_auto_type(structure) ___str = structure; \ 58 | if (___str) {\ 59 | ___str->field.next = (linked_list_t *)0;\ 60 | ___str->field.prev = (linked_list_t *)0;\ 61 | } \ 62 | }) 63 | 64 | /** 65 | * Get the number of nodes of the list. 66 | * 67 | * @param ptr_to_current 68 | * @return Pointer to the last node of the list, including ptr_to_current. 69 | */ 70 | #define linked_list_count(ptr_to_current, field) \ 71 | ({ \ 72 | int ___ret = 0; \ 73 | __ll_auto_type(ptr_to_current) ___cur = linked_list_first(ptr_to_current, field); linked_list_t * ___head;\ 74 | if (___cur) ___ret++; \ 75 | if (___ret) \ 76 | { \ 77 | ___head = &___cur->field; \ 78 | if (___head->next) { while (___head->next){ ___head = ___head->next; ___ret++;}} \ 79 | } \ 80 | ___ret; \ 81 | }) 82 | 83 | 84 | /** 85 | * Get the next node. 86 | * @param ptr_to_current 87 | * @return Pointer to the next node. 88 | */ 89 | #define linked_list_next(ptr_to_current, field) \ 90 | ({ \ 91 | __ll_auto_type(ptr_to_current) ___ret = ptr_to_current; linked_list_t * ___head;\ 92 | if (___ret) \ 93 | { \ 94 | ___head = ___ret->field.next; \ 95 | if (___head) { ___ret = __ll_container_of(___head, __ll_typeof(*(ptr_to_current)), field); }\ 96 | else {___ret = 0; } \ 97 | } \ 98 | ___ret; \ 99 | }) 100 | 101 | /** 102 | * Get the previous node. 103 | * @param ptr_to_current 104 | * @return Pointer to the previous node. 105 | */ 106 | #define linked_list_previous(ptr_to_current, field) \ 107 | ({ \ 108 | __ll_auto_type(ptr_to_current) ___ret = ptr_to_current; linked_list_t * ___head;\ 109 | if (___ret) \ 110 | { \ 111 | ___head = ___ret->field.prev; \ 112 | if (___head) { ___ret = __ll_container_of(___head, __ll_typeof(*(ptr_to_current)), field); }\ 113 | else {___ret = 0; } \ 114 | } \ 115 | ___ret; \ 116 | }) 117 | 118 | /** 119 | * Get the last node of the list, including ptr_to_current. 120 | * 121 | * @param ptr_to_current 122 | * @return Pointer to the last node of the list, including ptr_to_current. 123 | */ 124 | #define linked_list_last(ptr_to_current, field) \ 125 | ({ \ 126 | __ll_auto_type(ptr_to_current) ___ret = ptr_to_current; linked_list_t * ___head;\ 127 | if (___ret) \ 128 | { \ 129 | ___head = &___ret->field; \ 130 | if (___head->next) { while (___head->next) ___head = ___head->next;} \ 131 | if (___head) { ___ret = __ll_container_of(___head, __ll_typeof(*(ptr_to_current)), field); } \ 132 | else {___ret = 0; } \ 133 | } \ 134 | ___ret; \ 135 | }) 136 | 137 | /** 138 | * Get the first node of the list, including ptr_to_current. 139 | * 140 | * @param ptr_to_current 141 | * @return Pointer to the first node of the list, including ptr_to_current. 142 | */ 143 | #define linked_list_first(ptr_to_current, field) \ 144 | ({ \ 145 | __ll_auto_type(ptr_to_current) ___ret2 = ptr_to_current; linked_list_t * ___head;\ 146 | if (___ret2) \ 147 | { \ 148 | ___head = &___ret2->field; \ 149 | if (___head->prev) { while (___head->prev) ___head = ___head->prev;} \ 150 | if (___head) { ___ret2 = __ll_container_of(___head, __ll_typeof(*(ptr_to_current)), field); } \ 151 | else {___ret2 = 0; } \ 152 | } \ 153 | ___ret2; \ 154 | }) 155 | 156 | /** 157 | * Insert new node between current and current's next. 158 | * 159 | * @param ptr_to_current 160 | * @param ptr_to_new 161 | */ 162 | #define linked_list_insert_after(ptr_to_current, ptr_to_new, field) \ 163 | ({ \ 164 | __ll_auto_type(ptr_to_current) ___curr = ptr_to_current; \ 165 | __ll_auto_type(ptr_to_new) ___new = ptr_to_new; \ 166 | if (___curr && ___new) \ 167 | { \ 168 | ___new->field.next = ___curr->field.next; \ 169 | ___new->field.prev = &___curr->field; \ 170 | if (___curr->field.next) ___curr->field.next->prev = &___new->field; \ 171 | ___curr->field.next = &___new->field; \ 172 | } \ 173 | }) 174 | 175 | /** 176 | * Insert new node between current and current's previous. 177 | * 178 | * @param ptr_to_current 179 | * @param ptr_to_new 180 | */ 181 | #define linked_list_insert_before(ptr_to_current, ptr_to_new, field) \ 182 | ({ \ 183 | __ll_auto_type(ptr_to_current) ___curr = ptr_to_current; \ 184 | __ll_auto_type(ptr_to_new) ___new = ptr_to_new; \ 185 | if (___curr && ___new) \ 186 | { \ 187 | ___new->field.prev = ___curr->field.prev; \ 188 | ___new->field.next = &___curr->field; \ 189 | if(___curr->field.prev) ___curr->field.prev->next = &___new->field; \ 190 | ___curr->field.prev = &___new->field; \ 191 | } \ 192 | }) 193 | 194 | /** 195 | * Remove the current node and return it. 196 | * 197 | * @param current 198 | * @return Return the new or old beginning of the list. 199 | */ 200 | #define linked_list_remove(ptr_to_current, field) \ 201 | ({ \ 202 | __ll_auto_type(ptr_to_current) ___cur = ptr_to_current; \ 203 | __ll_auto_type(ptr_to_current) ___ret = (__ll_typeof(ptr_to_current))0; \ 204 | linked_list_t * ___head_next = (linked_list_t*)0; \ 205 | linked_list_t * ___head_prev = (linked_list_t*)0; \ 206 | if (___cur) \ 207 | { \ 208 | ___head_next = ___cur->field.next; \ 209 | ___head_prev = ___cur->field.prev; \ 210 | if (___head_prev) ___head_prev->next = ___head_next; \ 211 | if (___head_next) ___head_next->prev = ___head_prev; \ 212 | linked_list_init(___cur, field); \ 213 | if (___head_prev) ___ret = linked_list_first(__ll_container_of(___head_prev, __ll_typeof(*(ptr_to_current)), field), field); \ 214 | else if(___head_next) ___ret = linked_list_first(__ll_container_of(___head_next, __ll_typeof(*(ptr_to_current)), field), field); \ 215 | } \ 216 | ___ret; \ 217 | }) 218 | 219 | /** 220 | * Free all list members, 221 | * but instead calling free itself, this function calls 222 | * user free function passed on free_callback. 223 | * 224 | * @param ptr_to_current 225 | * 226 | * @warning 227 | * Any pointer to the a list node will be invalid. 228 | */ 229 | #define linked_list_free(ptr_to_current, field, free_callback) \ 230 | ({ \ 231 | __ll_auto_type(ptr_to_current) ___item = linked_list_first(ptr_to_current, field); \ 232 | __ll_typeof(___item) ___item_to_delete; \ 233 | while (___item) \ 234 | { \ 235 | ___item_to_delete = ___item; \ 236 | ___item = linked_list_next(___item_to_delete, field); \ 237 | free_callback(___item_to_delete); \ 238 | } \ 239 | }) 240 | 241 | /** 242 | */ 243 | #define linked_list_find(ptr_to_current, field, comparator_func, comparator_seed) \ 244 | ({ \ 245 | __ll_auto_type(ptr_to_current) ___item = ptr_to_current; \ 246 | while (___item) \ 247 | { \ 248 | if (comparator_func(comparator_seed, ___item) == true) break; \ 249 | ___item = linked_list_next(___item, field); \ 250 | } \ 251 | ___item; \ 252 | }) 253 | 254 | #endif /* REACTO_REUSABLES_LINKED_LIST_H_ */ 255 | --------------------------------------------------------------------------------