diff --git a/examples/chapter09_08a/build.bat b/examples/chapter09_08a/build.bat index 7d8f3b968..a53396a57 100644 --- a/examples/chapter09_08a/build.bat +++ b/examples/chapter09_08a/build.bat @@ -54,6 +54,9 @@ @echo.Compile : mcal_cpu.cpp to bin/mcal_cpu.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_cpu.cpp -o bin/mcal_cpu.o +@echo.Compile : mcal_eep.cpp to bin/mcal_eep.o +@%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_eep.cpp -o bin/mcal_eep.o + @echo.Compile : mcal_gpt.cpp to bin/mcal_gpt.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_gpt.cpp -o bin/mcal_gpt.o @@ -78,15 +81,15 @@ @echo.Compile : mcal_pwm.cpp to bin/mcal_pwm.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_pwm.cpp -o bin/mcal_pwm.o +@echo.Compile : mcal_spi.cpp to bin/mcal_spi.o +@%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_spi.cpp -o bin/mcal_spi.o + @echo.Compile : mcal_wdg.cpp to bin/mcal_wdg.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/mcal/avr/mcal_wdg.cpp -o bin/mcal_wdg.o @echo.Compile : os.cpp to bin/os.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/os/os.cpp -o bin/os.o -@echo.Compile : os.cpp to bin/os_task_control_block.o -@%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/os/os_task_control_block.cpp -o bin/os_task_control_block.o - @echo.Compile : sys_idle.cpp to bin/sys_idle.o @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c src/sys/idle/sys_idle.cpp -o bin/sys_idle.o @@ -109,7 +112,7 @@ @%TOOL_PATH%\%TOOL_PREFIX%-g++ -x c++ %CFLAGS% %CPPFLAGS% %CINCLUDES% -c target/micros/avr/startup/int_vect.cpp -o bin/int_vect.o @echo.Link : objects to bin/chapter09_08a.elf -@%TOOL_PATH%\%TOOL_PREFIX%-g++ -x none -mrelax -nostartfiles %CFLAGS% %CPPFLAGS% %CINCLUDES% -Wl,--gc-sections -Wl,-Ttarget/micros/avr/make/avr.ld,-Map,bin/chapter09_08a.map bin/app_led.o bin/mcal.o bin/mcal_gcc_cxx_completion.o bin/mcal_cpu.o bin/mcal_gpt.o bin/mcal_led.o bin/mcal_led_rgb.o bin/mcal_led_sys_start_interface.o bin/mcal_irq.o bin/mcal_osc.o bin/mcal_port.o bin/mcal_pwm.o bin/mcal_wdg.o bin/os.o bin/os_task_control_block.o bin/sys_idle.o bin/sys_mon.o bin/sys_start.o bin/crt0.o bin/crt0_init_ram.o bin/crt1.o bin/int_vect.o -o bin/chapter09_08a.elf +@%TOOL_PATH%\%TOOL_PREFIX%-g++ -x none -mrelax -nostartfiles %CFLAGS% %CPPFLAGS% %CINCLUDES% -Wl,--gc-sections -Wl,-Ttarget/micros/avr/make/avr.ld,-Map,bin/chapter09_08a.map bin/app_led.o bin/mcal.o bin/mcal_gcc_cxx_completion.o bin/mcal_cpu.o bin/mcal_eep.o bin/mcal_gpt.o bin/mcal_led.o bin/mcal_led_rgb.o bin/mcal_led_sys_start_interface.o bin/mcal_irq.o bin/mcal_osc.o bin/mcal_port.o bin/mcal_pwm.o bin/mcal_spi.o bin/mcal_wdg.o bin/os.o bin/sys_idle.o bin/sys_mon.o bin/sys_start.o bin/crt0.o bin/crt0_init_ram.o bin/crt1.o bin/int_vect.o -o bin/chapter09_08a.elf @echo. @echo.Extract : executable hex file : from bin/chapter09_08a.elf diff --git a/examples/chapter09_08a/build.sh b/examples/chapter09_08a/build.sh index b280d4950..44870cec8 100755 --- a/examples/chapter09_08a/build.sh +++ b/examples/chapter09_08a/build.sh @@ -12,7 +12,7 @@ # # If command # /usr/bin/avr-g++ -# installed, e.g. via command apt-get install gcc-avr avr-libc +# installed, e.g. via command sudo apt-get install gcc-avr avr-libc # then: # ./build.sh # @@ -73,6 +73,9 @@ $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/mcal echo "Compile : mcal_cpu.cpp to bin/mcal_cpu.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_cpu.cpp -o bin/mcal_cpu.o +echo "Compile : mcal_eep.cpp to bin/mcal_eep.o" +$TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_eep.cpp -o bin/mcal_eep.o + echo "Compile : mcal_led.cpp to bin/mcal_led.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_led.cpp -o bin/mcal_led.o @@ -97,15 +100,15 @@ $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/ echo "Compile : mcal_pwm.cpp to bin/mcal_pwm.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_pwm.cpp -o bin/mcal_pwm.o +echo "Compile : mcal_spi.cpp to bin/mcal_spi.o" +$TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_spi.cpp -o bin/mcal_spi.o + echo "Compile : mcal_wdg.cpp to bin/mcal_wdg.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/mcal/avr/mcal_wdg.cpp -o bin/mcal_wdg.o echo "Compile : os.cpp to bin/os.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/os/os.cpp -o bin/os.o -echo "Compile : os.cpp to bin/os_task_control_block.o". -$TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/os/os_task_control_block.cpp -o bin/os_task_control_block.o - echo "Compile : sys_idle.cpp to bin/sys_idle.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c src/sys/idle/sys_idle.cpp -o bin/sys_idle.o @@ -128,7 +131,7 @@ echo "Compile : int_vect.cpp to bin/int_vect.o" $TOOL_PATH/$TOOL_PREFIX-g++ -x c++ $CFLAGS $CPPFLAGS $CINCLUDES -c target/micros/avr/startup/int_vect.cpp -o bin/int_vect.o echo "Link : objects to bin/chapter09_08a.elf" -$TOOL_PATH/$TOOL_PREFIX-g++ -x none -mrelax -nostartfiles $CFLAGS $CPPFLAGS $CINCLUDES -Wl,--gc-sections -Wl,-Ttarget/micros/avr/make/avr.ld,-Map,bin/chapter09_08a.map bin/app_led.o bin/mcal.o bin/mcal_gcc_cxx_completion.o bin/mcal_cpu.o bin/mcal_gpt.o bin/mcal_irq.o bin/mcal_led.o bin/mcal_led_rgb.o bin/mcal_led_sys_start_interface.o bin/mcal_osc.o bin/mcal_port.o bin/mcal_pwm.o bin/mcal_wdg.o bin/os.o bin/os_task_control_block.o bin/sys_idle.o bin/sys_mon.o bin/sys_start.o bin/crt0.o bin/crt0_init_ram.o bin/crt1.o bin/int_vect.o -o bin/chapter09_08a.elf +$TOOL_PATH/$TOOL_PREFIX-g++ -x none -mrelax -nostartfiles $CFLAGS $CPPFLAGS $CINCLUDES -Wl,--gc-sections -Wl,-Ttarget/micros/avr/make/avr.ld,-Map,bin/chapter09_08a.map bin/app_led.o bin/mcal.o bin/mcal_gcc_cxx_completion.o bin/mcal_cpu.o bin/mcal_eep.o bin/mcal_gpt.o bin/mcal_irq.o bin/mcal_led.o bin/mcal_led_rgb.o bin/mcal_led_sys_start_interface.o bin/mcal_osc.o bin/mcal_port.o bin/mcal_pwm.o bin/mcal_spi.o bin/mcal_wdg.o bin/os.o bin/sys_idle.o bin/sys_mon.o bin/sys_start.o bin/crt0.o bin/crt0_init_ram.o bin/crt1.o bin/int_vect.o -o bin/chapter09_08a.elf echo echo "Extract : executable hex file : from bin/chapter09_08a.elf" diff --git a/examples/chapter09_08a/chapter09_08a.cppproj b/examples/chapter09_08a/chapter09_08a.cppproj index 0ddc5d723..e480ff747 100644 --- a/examples/chapter09_08a/chapter09_08a.cppproj +++ b/examples/chapter09_08a/chapter09_08a.cppproj @@ -148,6 +148,8 @@ + + @@ -174,12 +176,21 @@ compile + + compile + compile compile + + compile + + + compile + compile @@ -237,6 +248,12 @@ compile + + compile + + + compile + compile @@ -267,12 +284,18 @@ compile + + compile + compile compile + + compile + compile @@ -297,6 +320,24 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile @@ -306,9 +347,6 @@ compile - - compile - compile @@ -366,24 +404,42 @@ compile - + compile - + + compile + + compile compile + + compile + + + compile + compile + + compile + compile + + compile + compile + + compile + compile @@ -399,6 +455,9 @@ compile + + compile + compile @@ -458,6 +517,9 @@ compile + + compile + compile @@ -515,6 +577,9 @@ compile + + compile + compile @@ -530,6 +595,9 @@ compile + + compile + compile diff --git a/examples/chapter09_08a/chapter09_08a.vcxproj b/examples/chapter09_08a/chapter09_08a.vcxproj index 8c179aeac..17a5ef22b 100644 --- a/examples/chapter09_08a/chapter09_08a.vcxproj +++ b/examples/chapter09_08a/chapter09_08a.vcxproj @@ -106,6 +106,10 @@ true true + + true + true + true true @@ -138,6 +142,10 @@ true true + + true + true + true true @@ -147,6 +155,8 @@ true true + + @@ -154,10 +164,13 @@ + + + + - @@ -179,10 +192,18 @@ + + true + true + true true + + true + true + true true @@ -227,14 +248,26 @@ true true + + true + true + + + true + true + true true + + + + @@ -244,9 +277,12 @@ + + - + + @@ -255,6 +291,12 @@ + + + + + + @@ -313,6 +355,8 @@ + + true diff --git a/examples/chapter09_08a/chapter09_08a.vcxproj.filters b/examples/chapter09_08a/chapter09_08a.vcxproj.filters index 270792a69..2a0f60b9f 100644 --- a/examples/chapter09_08a/chapter09_08a.vcxproj.filters +++ b/examples/chapter09_08a/chapter09_08a.vcxproj.filters @@ -64,6 +64,12 @@ {a0535197-0c3a-4d51-b990-93cef869c23a} + + {7c8b3a64-0d36-4a18-833c-e53da967214d} + + + {b5e41e8f-8ae5-4e62-9577-1349fe2fa44a} + @@ -75,9 +81,6 @@ src\os - - src\os - src\sys\idle @@ -90,30 +93,6 @@ src\app\led - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - src\util\STL\impl @@ -126,6 +105,21 @@ src\util\STD_LIBC + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + src\mcal\avr @@ -141,23 +135,56 @@ src\mcal\avr - + src\mcal\avr - + src\mcal\avr - - src\mcal\avr + + src\mcal\win32 - - src\mcal\avr + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 src\mcal\win32 - - src\mcal\avr + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 @@ -176,33 +203,9 @@ src\util\STL_C++XX_stdfloat - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - src - - src\mcal\win32 - src\util\memory @@ -215,21 +218,6 @@ src\util\memory - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - - - src\mcal\win32 - src\util\STL\impl @@ -296,6 +284,51 @@ src\util\utility + + src\mcal_led + + + src\mcal_led + + + src\mcal_led + + + src\mcal_led + + + src\mcal_led + + + src\mcal_led + + + src\mcal + + + src\mcal + + + src\util\STL + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + + + src\mcal\avr + src\mcal\avr @@ -320,53 +353,98 @@ src\mcal\avr - + src\mcal\avr - + src\mcal\avr - + src\mcal\avr - - src\mcal\avr + + src\mcal - - src\mcal_led + + src\mcal - - src\mcal_led + + src\mcal\win32 - - src\mcal_led + + src\mcal\win32 - - src\mcal_led + + src\mcal\win32 - - src\mcal_led + + src\mcal\win32 - - src\mcal_led + + src\mcal\win32 src\mcal\win32 - - src\mcal\avr + + src\mcal\win32 + + + src\mcal\win32 src\mcal\win32 - - src\mcal + + src\mcal\win32 - - src\mcal + + src\mcal\win32 - - src\util\STL + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal\win32 + + + src\mcal_pwm + + + src\mcal_pwm + + + src\mcal_pwm + + + src\mcal_pwm + + + src\mcal_spi + + + src\mcal_spi @@ -493,6 +571,8 @@ src\util\STL + + diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_benchmark.h b/examples/chapter09_08a/src/mcal/avr/mcal_benchmark.h new file mode 100644 index 000000000..d57ed58ce --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_benchmark.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2014 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_BENCHMARK_2014_04_16_H + #define MCAL_BENCHMARK_2014_04_16_H + + #include + #include + + #include + + namespace mcal + { + namespace benchmark + { + using benchmark_port_type = mcal::port::port_pin; + } + } + +#endif // MCAL_BENCHMARK_2014_04_16_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_eep.cpp b/examples/chapter09_08a/src/mcal/avr/mcal_eep.cpp new file mode 100644 index 000000000..1a36498c9 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_eep.cpp @@ -0,0 +1,105 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2018 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include + +namespace local +{ + auto mcal_eep_is_busy() -> bool; + + auto mcal_eep_is_busy() -> bool + { + return (mcal::reg::reg_access_static::bit_get()); + } +} // namespace local + +auto mcal::eep::init(const config_type*) -> void +{ +} + +auto mcal::eep::write(const address_type addr, const std::uint8_t data) -> void +{ + while(local::mcal_eep_is_busy()) + { + mcal::cpu::nop(); + } + + // Write the address register. + mcal::reg::reg_access_dynamic::reg_set(mcal::reg::eear, addr); + + // Write the data register. + mcal::reg::reg_access_dynamic::reg_set(mcal::reg::eedr, data); + + // Set eecr.eempe (bit 2). + mcal::reg::reg_access_static::bit_set(); + + // Set eecr.eepe (bit 1). + mcal::reg::reg_access_static::bit_set(); +} + +auto mcal::eep::read(const address_type addr) -> std::uint8_t +{ + while(local::mcal_eep_is_busy()) + { + mcal::cpu::nop(); + } + + // Write the address register. + mcal::reg::reg_access_dynamic::reg_set(mcal::reg::eear, addr); + + // Set eecr.eere (bit 0). + mcal::reg::reg_access_static::bit_set(); + + // Read one data byte. + const std::uint8_t data = + mcal::reg::reg_access_static::reg_get(); + + return data; +} + +/* +#define EERE 0 +#define EEPE 1 +#define EEMPE 2 +#define EERIE 3 +#define EEPM0 4 +#define EEPM1 5 +*/ + +/* +while(EECR & (1 << EEPE)); +EEAR = uiAddress; +EEDR = ucData; +EECR |= 1 << EEMPE; +EECR |= 1 << EEPE; +*/ + +/* + while (EECR & (1 << EEPE)); + EEAR = uiAddress; + EECR |= (1 << EERE); + return EEDR; +*/ diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_eep.h b/examples/chapter09_08a/src/mcal/avr/mcal_eep.h new file mode 100644 index 000000000..aa875539a --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_eep.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2018 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_EEP_2018_12_15_H + #define MCAL_EEP_2018_12_15_H + + #include + + namespace mcal + { + namespace eep + { + using config_type = void; + using address_type = std::uint_fast16_t; + + auto init(const config_type*) -> void; + + auto write(const address_type addr, const std::uint8_t data)-> void; + auto read (const address_type addr) -> std::uint8_t; + } + } + +#endif // MCAL_EEP_2018_12_15_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_gpt.cpp b/examples/chapter09_08a/src/mcal/avr/mcal_gpt.cpp index db5d8dd8d..1c715a12b 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_gpt.cpp +++ b/examples/chapter09_08a/src/mcal/avr/mcal_gpt.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,75 +8,101 @@ #include #include +#include + namespace { // The one (and only one) system tick. - volatile mcal::gpt::value_type mcal_gpt_system_tick; + volatile auto mcal_gpt_system_tick = mcal::gpt::value_type { }; - bool& gpt_is_initialized() __attribute__((used, noinline)); + auto gpt_is_initialized() -> bool& ATTRIBUTE(used, noinline); - bool& gpt_is_initialized() + auto gpt_is_initialized() -> bool& { - static bool is_init = bool(); + static auto is_init = bool { }; return is_init; } } extern "C" -void __vector_16() __attribute__((signal, used, externally_visible)); +auto __vector_16() -> void ATTRIBUTE(signal, used, externally_visible); -void __vector_16() +auto __vector_16() -> void { - // Increment the 32-bit system tick with 0x80, representing 128 microseconds. - const mcal::gpt::value_type new_tick = mcal_gpt_system_tick + static_cast(0x80U); + // Increment the 32-bit system tick with 0x100, representing 256 [(1/2) us]. + // This is basically the roll-over of the 8-bit timer0 at 2MHz each 128us. + + const auto new_tick = + static_cast + ( + mcal_gpt_system_tick + static_cast(UINT16_C(0x100)) + ); mcal_gpt_system_tick = new_tick; } -void mcal::gpt::init(const config_type*) +auto mcal::gpt::init(const config_type*) -> void { - if(gpt_is_initialized() == false) + if(!gpt_is_initialized()) { // Clear the timer0 overflow flag. - mcal::reg::reg_access_static::reg_set(); + mcal::reg::reg_access_static(UINT8_C(0x01))>::reg_set(); // Enable the timer0 overflow interrupt. - mcal::reg::reg_access_static::reg_set(); + mcal::reg::reg_access_static(UINT8_C(0x01))>::reg_set(); // Set the timer0 clock source to f_osc/8 = 2MHz and begin counting. - mcal::reg::reg_access_static::reg_set(); + mcal::reg::reg_access_static(UINT8_C(0x02))>::reg_set(); // Set the is-initialized indication flag. gpt_is_initialized() = true; } } -mcal::gpt::value_type mcal::gpt::secure::get_time_elapsed() +auto mcal::gpt::secure::get_time_elapsed() -> mcal::gpt::value_type { if(gpt_is_initialized()) { // Return the system tick using a multiple read to ensure data consistency. - typedef std::uint8_t timer_address_type; - typedef std::uint8_t timer_register_type; + using timer_address_type = std::uint8_t; + using timer_register_type = std::uint8_t; // Do the first read of the timer0 counter and the system tick. - const timer_register_type tim0_cnt_1 = mcal::reg::reg_access_static::reg_get(); - const mcal::gpt::value_type sys_tick_1 = mcal_gpt_system_tick; + const auto t0_cnt_1 = mcal::reg::reg_access_static::reg_get(); + const auto sys_tick_1 = mcal_gpt_system_tick; // Do the second read of the timer0 counter. - const timer_register_type tim0_cnt_2 = mcal::reg::reg_access_static::reg_get(); + const auto t0_cnt_2 = mcal::reg::reg_access_static::reg_get(); - // Perform the consistency check. - const mcal::gpt::value_type consistent_microsecond_tick = - ((tim0_cnt_2 >= tim0_cnt_1) ? mcal::gpt::value_type(sys_tick_1 | std::uint8_t(tim0_cnt_1 >> 1U)) - : mcal::gpt::value_type(mcal_gpt_system_tick | std::uint8_t(tim0_cnt_2 >> 1U))); + const auto t0_tick_is_consistent = (t0_cnt_2 >= t0_cnt_1); - return consistent_microsecond_tick; + // Perform the consistency check. + const auto consistent_half_microsecond_tick = + static_cast + ( + t0_tick_is_consistent ? static_cast(sys_tick_1 | t0_cnt_1) + : static_cast(mcal_gpt_system_tick | t0_cnt_2) + ); + + // Scale the timer0 tick to 1MHz and perform a rounding correction. + return + static_cast + ( + static_cast + ( + static_cast + ( + static_cast(consistent_half_microsecond_tick) + + static_cast(UINT8_C(1)) + ) + / static_cast(UINT8_C(2)) + ) + ); } else { - return mcal::gpt::value_type(0U); + return static_cast(UINT8_C(0)); } } diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_gpt.h b/examples/chapter09_08a/src/mcal/avr/mcal_gpt.h index d94491117..ce3a093e4 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_gpt.h +++ b/examples/chapter09_08a/src/mcal/avr/mcal_gpt.h @@ -1,45 +1,29 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef MCAL_GPT_2011_10_20_H_ - #define MCAL_GPT_2011_10_20_H_ +#ifndef MCAL_GPT_2011_10_20_H + #define MCAL_GPT_2011_10_20_H - #include #include - #include - - // Forward declaration of the util::timer template class. - namespace util - { - template - class timer; - } - namespace mcal { namespace gpt { - typedef void config_type; - typedef std::uint64_t value_type; + using config_type = void; + using value_type = std::uint64_t; - void init(const config_type*); + auto init(const config_type*) -> void; struct secure final { - private: - static value_type get_time_elapsed(); - - friend std::chrono::high_resolution_clock::time_point std::chrono::high_resolution_clock::now() noexcept; - - template - friend class util::timer; + static auto get_time_elapsed() -> value_type; }; } } -#endif // MCAL_GPT_2011_10_20_H_ +#endif // MCAL_GPT_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_led.cpp b/examples/chapter09_08a/src/mcal/avr/mcal_led.cpp index e378682d5..c9971f653 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_led.cpp +++ b/examples/chapter09_08a/src/mcal/avr/mcal_led.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2020. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_led.h b/examples/chapter09_08a/src/mcal/avr/mcal_led.h index 7dc79b163..c91fe8413 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_led.h +++ b/examples/chapter09_08a/src/mcal/avr/mcal_led.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2020. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef MCAL_LED_2010_09_14_H_ - #define MCAL_LED_2010_09_14_H_ +#ifndef MCAL_LED_2010_09_14_H + #define MCAL_LED_2010_09_14_H #include @@ -18,4 +18,4 @@ } } -#endif // MCAL_LED_2010_09_14_H_ +#endif // MCAL_LED_2010_09_14_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_port.h b/examples/chapter09_08a/src/mcal/avr/mcal_port.h index fbe2a2bd2..6676e1eb3 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_port.h +++ b/examples/chapter09_08a/src/mcal/avr/mcal_port.h @@ -10,6 +10,15 @@ #include + #include + + auto mcal_port_pin_expander_set_direction_output(const uint8_t bpos) -> void; + auto mcal_port_pin_expander_set_direction_input (const uint8_t bpos) -> void; + auto mcal_port_pin_expander_set_pin_high (const uint8_t bpos) -> void; + auto mcal_port_pin_expander_set_pin_low (const uint8_t bpos) -> void; + auto mcal_port_pin_expander_read_input_value (const uint8_t bpos) -> bool; + auto mcal_port_pin_expander_toggle_pin (const uint8_t bpos) -> void; + namespace mcal { namespace port @@ -97,6 +106,18 @@ bpos_value>::bit_not(); } }; + + template + class port_pin_expander + { + public: + static auto set_direction_output() -> void { mcal_port_pin_expander_set_direction_output(bpos); } + static auto set_direction_input () -> void { mcal_port_pin_expander_set_direction_input (bpos); } + static auto set_pin_high () -> void { mcal_port_pin_expander_set_pin_high (bpos); } + static auto set_pin_low () -> void { mcal_port_pin_expander_set_pin_low (bpos); } + static auto read_input_value () -> bool { return mcal_port_pin_expander_read_input_value (bpos); } + static auto toggle_pin () -> void { mcal_port_pin_expander_toggle_pin (bpos); } + }; } } diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_pwm.cpp b/examples/chapter09_08a/src/mcal/avr/mcal_pwm.cpp index d49165912..0e08f3ef1 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_pwm.cpp +++ b/examples/chapter09_08a/src/mcal/avr/mcal_pwm.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,6 +7,6 @@ #include -void mcal::pwm::init(const mcal::pwm::config_type*) +auto mcal::pwm::init(const mcal::pwm::config_type*) -> void { } diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_pwm.h b/examples/chapter09_08a/src/mcal/avr/mcal_pwm.h index 1fe9536e3..1ced6476a 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_pwm.h +++ b/examples/chapter09_08a/src/mcal/avr/mcal_pwm.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -14,7 +14,7 @@ { using config_type = void; - void init(const config_type*); + auto init(const config_type*) -> void; } } diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_ser.h b/examples/chapter09_08a/src/mcal/avr/mcal_ser.h new file mode 100644 index 000000000..bdcb95ad9 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_ser.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SER_2011_10_20_H + #define MCAL_SER_2011_10_20_H + + namespace mcal + { + namespace ser + { + using config_type = void; + + inline auto init(const config_type*) -> void { } + } + } + +#endif // MCAL_SER_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_spi.cpp b/examples/chapter09_08a/src/mcal/avr/mcal_spi.cpp new file mode 100644 index 000000000..cf6952d71 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_spi.cpp @@ -0,0 +1,12 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2012 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +auto mcal::spi::init(const config_type*) -> void +{ +} diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_spi.h b/examples/chapter09_08a/src/mcal/avr/mcal_spi.h new file mode 100644 index 000000000..81790dbd3 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/avr/mcal_spi.h @@ -0,0 +1,19 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2012 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SPI_2012_05_24_H + #define MCAL_SPI_2012_05_24_H + + namespace mcal { namespace spi { + + using config_type = void; + + auto init(const config_type*) -> void; + + } } + +#endif // MCAL_SPI_2012_05_24_H diff --git a/examples/chapter09_08a/src/mcal/avr/mcal_wdg.h b/examples/chapter09_08a/src/mcal/avr/mcal_wdg.h index 8e8141310..94949ac58 100644 --- a/examples/chapter09_08a/src/mcal/avr/mcal_wdg.h +++ b/examples/chapter09_08a/src/mcal/avr/mcal_wdg.h @@ -8,10 +8,6 @@ #ifndef MCAL_WDT_2010_04_10_H #define MCAL_WDT_2010_04_10_H - extern "C" void __my_startup() __attribute__((section(".startup"), used, noinline)); - - namespace sys { namespace idle { auto task_func() -> void; } } - namespace mcal { namespace wdg @@ -22,11 +18,7 @@ struct secure final { - private: static auto trigger() -> void; - - friend auto ::sys::idle::task_func() -> void; - friend auto ::__my_startup() -> void; }; } } diff --git a/examples/chapter09_08a/src/mcal/mcal.cpp b/examples/chapter09_08a/src/mcal/mcal.cpp index 06c77cb46..985f7f0d9 100644 --- a/examples/chapter09_08a/src/mcal/mcal.cpp +++ b/examples/chapter09_08a/src/mcal/mcal.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2019. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,7 +7,7 @@ #include -void mcal::init() +auto mcal::init() -> void { // Initialize the microcontroller abstraction layer. @@ -20,6 +20,10 @@ void mcal::init() mcal::irq::init(nullptr); mcal::gpt::init(nullptr); + mcal::ser::init(nullptr); + mcal::spi::init(nullptr); + mcal::pwm::init(nullptr); + mcal::eep::init(nullptr); mcal::cpu::post_init(); } diff --git a/examples/chapter09_08a/src/mcal/mcal.h b/examples/chapter09_08a/src/mcal/mcal.h index 7676cfed7..ba0967737 100644 --- a/examples/chapter09_08a/src/mcal/mcal.h +++ b/examples/chapter09_08a/src/mcal/mcal.h @@ -1,27 +1,35 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2018. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef MCAL_2011_10_20_H_ - #define MCAL_2011_10_20_H_ +#ifndef MCAL_2011_10_20_H + #define MCAL_2011_10_20_H #include + #include #include #include - #include + #include + #include + #include + #include + #include #include - static_assert( (std::numeric_limits::digits >= 32) - && (std::numeric_limits::is_integer == true) - && (std::numeric_limits::is_signed == false), - "The gpt value type must be an unsigned integer type having at least 32 bits"); + #include + #include + + static_assert( (std::numeric_limits::digits >= static_cast(INT8_C(64))) + && std::numeric_limits::is_integer + && (!std::numeric_limits::is_signed), + "The gpt value type must be an unsigned integer type having at least 64 bits."); namespace mcal { - void init(); - } + auto init() -> void; + } // namespace mcal -#endif // MCAL_2011_10_20_H_ +#endif // MCAL_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/mcal_gcc_cxx_completion_with_stdlib.cpp b/examples/chapter09_08a/src/mcal/mcal_gcc_cxx_completion_with_stdlib.cpp new file mode 100644 index 000000000..f46214b34 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/mcal_gcc_cxx_completion_with_stdlib.cpp @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2021. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +extern "C" +{ + // Patched functions. + void __cxa_pure_virtual (); + char* __cxa_demangle (const char*, char*, size_t*, int*); + + void __cxa_pure_virtual () { } + char* __cxa_demangle (const char*, char*, size_t*, int*) { return nullptr; } +} + +extern "C" +{ + // Patched labels. + void* __dso_handle; +} diff --git a/examples/chapter09_08a/src/mcal/mcal_gpt_arm_sys_tick.h b/examples/chapter09_08a/src/mcal/mcal_gpt_arm_sys_tick.h new file mode 100644 index 000000000..65620803d --- /dev/null +++ b/examples/chapter09_08a/src/mcal/mcal_gpt_arm_sys_tick.h @@ -0,0 +1,181 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2022 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_GPT_ARM_SYS_TICK_2022_11_30_H + #define MCAL_GPT_ARM_SYS_TICK_2022_11_30_H + + #include + #include + #include + + #if defined(__GNUC__) + extern "C" auto __sys_tick_handler() -> void __attribute__((used, noinline)); + #endif + + namespace mcal { namespace gpt { + + template + class arm_sys_tick_base + { + protected: + using register_address_type = RegisterAddressType; + using register_value_type = RegisterValueType; + using value_type = ValueType; + + static constexpr auto scs_base = static_cast(UINT32_C(0xE000E000)); + static constexpr auto sys_tick_mhz = SysTickMHz; + static constexpr auto sys_tick_base = static_cast(scs_base + static_cast(UINT8_C(0x10))); + static constexpr auto sys_tick_ctrl = static_cast(sys_tick_base + static_cast(UINT8_C(0x00))); + static constexpr auto sys_tick_load = static_cast(sys_tick_base + static_cast(UINT8_C(0x04))); + static constexpr auto sys_tick_val = static_cast(sys_tick_base + static_cast(UINT8_C(0x08))); + static constexpr auto sys_tick_cal = static_cast(sys_tick_base + static_cast(UINT8_C(0x0C))); + + template(UINT8_C(0))> + struct reg_access_static + { + static auto reg_get() noexcept -> register_value_type { volatile register_value_type* pa = reinterpret_cast(address); return *pa; } + static auto reg_set() noexcept -> void { volatile register_value_type* pa = reinterpret_cast(address); *pa = value; } + static auto reg_or () noexcept -> void { volatile register_value_type* pa = reinterpret_cast(address); *pa = *pa | value; } + }; + }; + + template + class arm_sys_tick : private arm_sys_tick_base + { + private: + using base_class_type = arm_sys_tick_base; + + using register_address_type = typename base_class_type::register_address_type; + using register_value_type = typename base_class_type::register_value_type; + + static_assert(std::numeric_limits::digits == static_cast(INT8_C(32)), + "Error: Wrong width of register address type"); + + static_assert(std::numeric_limits::digits == static_cast(INT8_C(32)), + "Error: Wrong width of register value type"); + + public: + using value_type = typename base_class_type::value_type; + + static constexpr auto sys_tick_mhz() noexcept -> std::uint32_t { return SysTickMHz; } + + static auto init() noexcept -> void + { + if(!my_is_init) + { + my_is_init = true; + + // Set up an interrupt on the ARM(R) sys-tick. + + base_class_type::template reg_access_static(UINT8_C(0))>::reg_set(); + + // Set the sys-tick reload register. + base_class_type::template reg_access_static(UINT32_C(0x00FFFFFF))>::reg_set(); + + // Initialize the sys-tick counter value. + base_class_type::template reg_access_static(UINT8_C(0))>::reg_set(); + + // Set the sys-tick clock source to be the processor clock. + base_class_type::template reg_access_static(UINT8_C(4))>::reg_or(); + + // Enable the sys-tick interrupt. + base_class_type::template reg_access_static(UINT8_C(2))>::reg_or(); + + // Enable the sys-tick timer. + base_class_type::template reg_access_static(UINT8_C(1))>::reg_or(); + } + } + + static auto get_time_elapsed() noexcept -> value_type + { + return + static_cast + ( + my_is_init ? get_consistent_microsecond_tick() : static_cast(UINT8_C(0)) + ); + } + + private: + static volatile value_type my_sys_tick_value; + static bool my_is_init; + + static auto get_consistent_microsecond_tick() noexcept -> value_type + { + // Return the system tick using a multiple read to ensure data consistency. + + // Do the first read of the sys-tick counter and the sys-tick + // value. Also handle reverse counting for the sys-tick counter, + // since this timer counts down. + + const auto sys_tick_counter_1 = + static_cast + ( + static_cast + ( + static_cast(UINT32_C(0x00FFFFFF)) + - static_cast(base_class_type::template reg_access_static::reg_get()) + ) + ); + + const value_type sys_tick_value { my_sys_tick_value }; + + // Do the second read of the sys-tick counter and the sys-tick + // value. Also handle reverse counting for the sys-tick counter, + // since this timer counts down. + + const auto sys_tick_counter_2 = + static_cast + ( + static_cast + ( + static_cast(UINT32_C(0x00FFFFFF)) + - static_cast(base_class_type::template reg_access_static::reg_get()) + ) + ); + + // Perform the consistency check. + + const std::uint64_t + sys_tick_consistent_value + { + static_cast + ( + ((sys_tick_counter_2 >= sys_tick_counter_1) + ? static_cast(static_cast( sys_tick_value) | sys_tick_counter_1) + : static_cast(static_cast(my_sys_tick_value) | sys_tick_counter_2)) + ) + }; + + // Perform scaling and include a rounding correction. + return + static_cast + ( + static_cast + ( + sys_tick_consistent_value + + static_cast(base_class_type::sys_tick_mhz / static_cast(UINT8_C(2))) + ) + / base_class_type::sys_tick_mhz + ); + } + + #if defined(__GNUC__) + friend auto ::__sys_tick_handler() -> void; + #endif + }; + + template bool arm_sys_tick::my_is_init; + template volatile typename arm_sys_tick::value_type arm_sys_tick::my_sys_tick_value; + + } } + +#endif // MCAL_GPT_ARM_SYS_TICK_2022_11_30_H diff --git a/examples/chapter09_08a/src/mcal/mcal_helper.h b/examples/chapter09_08a/src/mcal/mcal_helper.h new file mode 100644 index 000000000..44b4b9d50 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/mcal_helper.h @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_HELPER_2020_05_21_H + #define MCAL_HELPER_2020_05_21_H + + #include + #include + + #include + #include + + namespace mcal { namespace helper { + + template + auto nop_maker() -> typename std::enable_if<(1U < nop_count) && (nop_count <= 12U), void>::type + { + nop_maker(); + + mcal::cpu::nop(); + } + + template + auto nop_maker() -> typename std::enable_if<(nop_count == 1U), void>::type + { + mcal::cpu::nop(); + } + + template + auto nop_maker() -> typename std::enable_if<(nop_count == 0U), void>::type + { + } + + template + auto nop_maker() -> typename std::enable_if<(12U < nop_count), void>::type + { + for(std::uint_fast16_t i = 0U; i < nop_count; ++i) + { + mcal::cpu::nop(); + } + } + + template + auto disable_all_interrupts(const bool = has_disable_enable_interrupts, + const typename std::enable_if::type* = nullptr) noexcept -> void + { + mcal::irq::disable_all(); + } + + template + auto enable_all_interrupts(const bool = has_disable_enable_interrupts, + const typename std::enable_if::type* = nullptr) noexcept -> void + { + mcal::irq::enable_all(); + } + + template + auto disable_all_interrupts(const bool = has_disable_enable_interrupts, + const typename std::enable_if<(!has_disable_enable_interrupts)>::type* = nullptr) noexcept -> void { } + + template + auto enable_all_interrupts(const bool = has_disable_enable_interrupts, + const typename std::enable_if<(!has_disable_enable_interrupts)>::type* = nullptr) noexcept -> void { } + + } } // namespace mcal::helper + +#endif // MCAL_HELPER_2020_05_21_H diff --git a/examples/chapter09_08a/src/mcal/mcal_reg_access_dynamic.h b/examples/chapter09_08a/src/mcal/mcal_reg_access_dynamic.h index dd121cff7..3bc3cf54b 100644 --- a/examples/chapter09_08a/src/mcal/mcal_reg_access_dynamic.h +++ b/examples/chapter09_08a/src/mcal/mcal_reg_access_dynamic.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2025. +// Copyright Christopher Kormanyos 2013 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/examples/chapter09_08a/src/mcal/mcal_reg_access_static.h b/examples/chapter09_08a/src/mcal/mcal_reg_access_static.h index a444f183f..564c3dc2f 100644 --- a/examples/chapter09_08a/src/mcal/mcal_reg_access_static.h +++ b/examples/chapter09_08a/src/mcal/mcal_reg_access_static.h @@ -1,5 +1,5 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2025. +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_benchmark.h b/examples/chapter09_08a/src/mcal/win32/mcal_benchmark.h new file mode 100644 index 000000000..4795ccb6d --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_benchmark.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2014 - 2023. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_BENCHMARK_2014_04_16_H + #define MCAL_BENCHMARK_2014_04_16_H + + #include + + namespace mcal + { + namespace benchmark + { + using benchmark_port_type = mcal::port::port_pin; + } // namespace benchmark + } // namespace mcal + +#endif // MCAL_BENCHMARK_2014_04_16_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_cpu.h b/examples/chapter09_08a/src/mcal/win32/mcal_cpu.h index 9b180093b..62dfd643b 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_cpu.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_cpu.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,14 +13,18 @@ #include #include - namespace mcal { namespace cpu { + namespace mcal + { + namespace cpu + { - auto init() -> void; + auto init() -> void; - inline auto post_init() -> void { } + inline auto post_init() -> void { } - inline auto nop() -> void { } + inline auto nop() -> void { } - } } // namespace mcal::cpu + } // namespace cpu + } // namespace mcal #endif // MCAL_CPU_2009_02_14_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_eep.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_eep.cpp new file mode 100644 index 000000000..2c7c06b8b --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_eep.cpp @@ -0,0 +1,14 @@ +#include + +auto mcal::eep::write(const address_type addr, const std::uint8_t data) -> void // NOLINT(bugprone-easily-swappable-parameters) +{ + static_cast(addr); + static_cast(data); +} + +auto mcal::eep::read(const address_type addr) -> std::uint8_t +{ + static_cast(addr); + + return static_cast(UINT8_C(0)); +} diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_eep.h b/examples/chapter09_08a/src/mcal/win32/mcal_eep.h new file mode 100644 index 000000000..3e7d03690 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_eep.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2022. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_EEP_2018_12_15_H + #define MCAL_EEP_2018_12_15_H + + #include + + namespace mcal + { + namespace eep + { + using config_type = void; + using address_type = std::uint64_t; + + inline auto init(const config_type*) -> void { } + + auto write(const address_type addr, const std::uint8_t data) -> void; + auto read (const address_type addr) -> std::uint8_t; + } // namespace eep + } // namespace mcal + +#endif // MCAL_EEP_2018_12_15_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_gpt.h b/examples/chapter09_08a/src/mcal/win32/mcal_gpt.h index 676143e52..e1a6ee00e 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_gpt.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_gpt.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,18 +8,8 @@ #ifndef MCAL_GPT_2011_10_20_H #define MCAL_GPT_2011_10_20_H - #include #include - #include - - // Forward declaration of the util::timer template class. - namespace util - { - template - class timer; - } - namespace mcal { namespace gpt @@ -29,16 +19,11 @@ inline auto init(const config_type*) noexcept -> void { } - class secure final + struct secure final { static auto get_time_elapsed() -> value_type; - - friend std::chrono::high_resolution_clock::time_point std::chrono::high_resolution_clock::now() UTIL_NOEXCEPT; - - template - friend class util::timer; }; - } - } + } // namespace gpt + } // namespace mcal #endif // MCAL_GPT_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_irq.h b/examples/chapter09_08a/src/mcal/win32/mcal_irq.h index ba9ca8fd9..0eee5f010 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_irq.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_irq.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,9 +16,9 @@ auto init(const config_type*) -> void; - inline auto enable_all () -> void { } - inline auto disable_all() -> void { } - } - } + inline auto enable_all () noexcept -> void { } + inline auto disable_all() noexcept -> void { } + } // namespace irq + } // namespace mcal #endif // MCAL_IRQ_2010_04_10_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_led.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_led.cpp index 540486992..ec071272a 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_led.cpp +++ b/examples/chapter09_08a/src/mcal/win32/mcal_led.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2020. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_led.h b/examples/chapter09_08a/src/mcal/win32/mcal_led.h index eb3311015..1897eb522 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_led.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_led.h @@ -15,7 +15,7 @@ namespace led { auto led0() -> led_base&; - } - } + } // namespace led + } // namespace mcal #endif // MCAL_LED_2010_09_14_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_osc.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_osc.cpp new file mode 100644 index 000000000..79036e733 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_osc.cpp @@ -0,0 +1,13 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +auto mcal::osc::init(const config_type*) -> void // NOLINT(readability-named-parameter,hicpp-named-parameter) +{ + // Subroutine is empty on purpose. +} diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_osc.h b/examples/chapter09_08a/src/mcal/win32/mcal_osc.h new file mode 100644 index 000000000..603503bab --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_osc.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_OSC_2011_10_20_H + #define MCAL_OSC_2011_10_20_H + + namespace mcal + { + namespace osc + { + using config_type = void; + + auto init(const config_type*) -> void; + } // namespace osc + } // namespace mcal + +#endif // MCAL_OSC_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_port.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_port.cpp new file mode 100644 index 000000000..7d5c0e23a --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_port.cpp @@ -0,0 +1,13 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2018. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +auto mcal::port::init(const config_type*) -> void // NOLINT(readability-named-parameter,hicpp-named-parameter) +{ + // Subroutine is empty on purpose. +} diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_port.h b/examples/chapter09_08a/src/mcal/win32/mcal_port.h index 43447f387..bae7087fd 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_port.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_port.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,14 +19,14 @@ class port_pin { public: - static auto set_direction_output()noexcept -> void { } - static auto set_direction_input ()noexcept -> void { } - static auto set_pin_high ()noexcept -> void { } - static auto set_pin_low ()noexcept -> void { } - static auto read_input_value ()noexcept -> bool { return false; } - static auto toggle_pin ()noexcept -> void { } + static constexpr auto set_direction_output() noexcept -> void { } + static constexpr auto set_direction_input () noexcept -> void { } + static constexpr auto set_pin_high () noexcept -> void { } + static constexpr auto set_pin_low () noexcept -> void { } + static constexpr auto read_input_value () noexcept -> bool { return false; } + static constexpr auto toggle_pin () noexcept -> void { } }; - } - } + } // namespace port + } // namespace mcal #endif // MCAL_PORT_2012_06_27_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_pwm.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_pwm.cpp new file mode 100644 index 000000000..ed11d307b --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_pwm.cpp @@ -0,0 +1,20 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +auto mcal::pwm::pwm0() noexcept -> mcal::pwm::pwm_base& +{ + static mcal::pwm::pwm_console pwm; + + static const volatile bool init_is_ok = pwm.init(); + + static_cast(init_is_ok); + + return pwm; +} diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_pwm.h b/examples/chapter09_08a/src/mcal/win32/mcal_pwm.h new file mode 100644 index 000000000..40f66189f --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_pwm.h @@ -0,0 +1,25 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_PWM_2010_09_14_H + #define MCAL_PWM_2010_09_14_H + + #include + + namespace mcal + { + namespace pwm + { + using config_type = void; + + inline auto init(const config_type*) -> void { } + + auto pwm0() noexcept -> mcal::pwm::pwm_base&; + } // namespace pwm + } // namespace mcal + +#endif // MCAL_PWM_2010_09_14_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_ser.h b/examples/chapter09_08a/src/mcal/win32/mcal_ser.h new file mode 100644 index 000000000..599e71bd5 --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_ser.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SER_2011_10_20_H + #define MCAL_SER_2011_10_20_H + + namespace mcal + { + namespace ser + { + using config_type = void; + + inline auto init(const config_type*) -> void { } + } // namespace ser + } // namespace mcal + +#endif // MCAL_SER_2011_10_20_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_spi.cpp b/examples/chapter09_08a/src/mcal/win32/mcal_spi.cpp new file mode 100644 index 000000000..b0f02b30b --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_spi.cpp @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2012 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#include + +auto mcal::spi::init(const mcal::spi::config_type*) -> void // NOLINT(readability-named-parameter,hicpp-named-parameter) +{ + // Subroutine is empty on purpose. +} + +auto mcal::spi::spi0() -> util::communication_base& +{ + static mcal::spi::spi_software_dummy com0; + + return com0; +} diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_spi.h b/examples/chapter09_08a/src/mcal/win32/mcal_spi.h new file mode 100644 index 000000000..c0f26e71b --- /dev/null +++ b/examples/chapter09_08a/src/mcal/win32/mcal_spi.h @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2012 - 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SPI_2012_05_24_H + #define MCAL_SPI_2012_05_24_H + + #include + + namespace mcal + { + namespace spi + { + + using config_type = void; + + auto init(const config_type*) -> void; + + auto spi0() -> util::communication_base&; + + } // namespace spi + } // namespace mcal + +#endif // MCAL_SPI_2012_05_24_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_wdg.h b/examples/chapter09_08a/src/mcal/win32/mcal_wdg.h index f0810a9a4..a26e36a84 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_wdg.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_wdg.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2023. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,15 +8,6 @@ #ifndef MCAL_WDG_2010_04_10_H #define MCAL_WDG_2010_04_10_H - // Forward declaration of the util::timer template class. - namespace util - { - template - class timer; - } - - namespace sys { namespace idle { void task_func(); } } - namespace mcal { namespace wdg @@ -25,16 +16,11 @@ auto init(const config_type*) -> void; - class secure final + struct secure final { static auto trigger() -> void; - - friend auto ::sys::idle::task_func() -> void; - - template - friend class util::timer; }; - } - } + } // namespace wdg + } // namespace mcal #endif // MCAL_WDG_2010_04_10_H diff --git a/examples/chapter09_08a/src/mcal/win32/mcal_wdg_watchdog.h b/examples/chapter09_08a/src/mcal/win32/mcal_wdg_watchdog.h index 5e5d34767..f6310da5d 100644 --- a/examples/chapter09_08a/src/mcal/win32/mcal_wdg_watchdog.h +++ b/examples/chapter09_08a/src/mcal/win32/mcal_wdg_watchdog.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2023. +// Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,15 +8,16 @@ #ifndef MCAL_WDG_WATCHDOG_2013_12_11_H #define MCAL_WDG_WATCHDOG_2013_12_11_H + #include + + #include + #include + #include #include #include #include - #include - #include - #include - #if defined(_MSC_VER) #define MCAL_WDG_NORETURN #else @@ -69,8 +70,8 @@ timer_type my_timer { my_period }; const std::thread my_thread; - static watchdog my_watchdog; - static std::atomic_flag my_lock; + static watchdog my_watchdog; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + static std::atomic_flag my_lock; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) auto get_watchdog_timeout() const -> bool { @@ -90,7 +91,7 @@ MCAL_WDG_NORETURN static auto thread_function() -> void { - std::this_thread::sleep_for(std::chrono::milliseconds(10U)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(UINT8_C(10)))); bool timeout_has_occurred = false; @@ -100,7 +101,7 @@ { print_timeout_message(); - std::this_thread::sleep_for(std::chrono::milliseconds(500U)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(UINT16_C(500)))); } else { @@ -109,20 +110,20 @@ timeout_has_occurred = true; } - std::this_thread::sleep_for(std::chrono::milliseconds(20U)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(UINT8_C(20)))); } } } - friend class ::mcal::wdg::secure; + friend struct ::mcal::wdg::secure; }; template - watchdog watchdog::my_watchdog(thread_function); + watchdog watchdog::my_watchdog(thread_function); // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,cert-err58-cpp) template - std::atomic_flag watchdog::my_lock = ATOMIC_FLAG_INIT; - } - } + std::atomic_flag watchdog::my_lock = ATOMIC_FLAG_INIT; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + } // namespace wdg + } // namespace mcal #endif // MCAL_WDG_WATCHDOG_2013_12_11_H diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_base.h b/examples/chapter09_08a/src/mcal_led/mcal_led_base.h index e9d099b72..3d24f22f2 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_base.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2023. +// Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,12 +12,14 @@ namespace mcal { namespace led { - class led_base : private util::noncopyable + class led_base : private util::noncopyable // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: + virtual ~led_base() = default; + virtual auto toggle() -> void = 0; - virtual auto state_is_on() const -> bool = 0; + virtual auto state_is_on() const noexcept -> bool = 0; protected: constexpr led_base() = default; diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_boolean_state_base.h b/examples/chapter09_08a/src/mcal_led/mcal_led_boolean_state_base.h index e74ed23b2..f0faf337c 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_boolean_state_base.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_boolean_state_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2020 - 2023. +// Copyright Christopher Kormanyos 2020 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -12,23 +12,29 @@ namespace mcal { namespace led { - class led_boolean_state_base : public mcal::led::led_base + class led_boolean_state_base : public mcal::led::led_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { + public: + ~led_boolean_state_base() override = default; + + auto state_is_on() const noexcept -> bool override { return is_on; } + protected: constexpr led_boolean_state_base() = default; auto toggle() -> void override { // Toggle the LED state. - is_on = (!is_on); + set_is_on(!is_on); } - auto state_is_on() const -> bool override { return is_on; } + auto set_is_on(const bool val) noexcept -> void { is_on = val; } private: bool is_on { }; }; - } } // namespace mcal::led + } // namespace led + } // namespace mcal #endif // MCAL_LED_BOOLEAN_STATE_BASE_2020_08_07_H diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_console.h b/examples/chapter09_08a/src/mcal_led/mcal_led_console.h index 92516cd2e..8c15b5bba 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_console.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_console.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2023. +// Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,37 +8,54 @@ #ifndef MCAL_LED_CONSOLE_2020_04_23_H #define MCAL_LED_CONSOLE_2020_04_23_H + #include + + #include #include #include - - #include + #include namespace mcal { namespace led { - class led_console final : public mcal::led::led_boolean_state_base + class led_console final : public mcal::led::led_boolean_state_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: - explicit constexpr led_console(const std::uint_fast8_t i) - : my_index(i) { } + explicit constexpr led_console(const std::uint_fast8_t idx = std::uint_fast8_t { UINT8_C(0) }) noexcept + : my_index(idx) { } + + ~led_console() override = default; auto toggle() -> void override { using base_class_type = mcal::led::led_boolean_state_base; - // Print the LED state. - std::cout << "LED" - << static_cast(my_index) - << " is " - << (base_class_type::state_is_on() ? "on" : "off") - << std::endl; - base_class_type::toggle(); + + // Print the LED state to the console. + std::stringstream strm { }; + + strm << "LED" + << static_cast(my_index) + << " is " + << (base_class_type::state_is_on() ? "on" : "off"); + + while(console_sync().test_and_set(std::memory_order_acquire)) { } + std::cout << strm.str() << std::endl; + console_sync().clear(std::memory_order_release); } private: - const std::uint_fast8_t my_index; + const std::uint_fast8_t my_index { }; + + static auto console_sync() noexcept -> std::atomic_flag& + { + static std::atomic_flag console_lock { }; + + return console_lock; + } }; - } } // namespace mcal::led + } // namespace led + } // namespace mcal #endif // MCAL_LED_CONSOLE_2020_04_23_H diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_dummy.h b/examples/chapter09_08a/src/mcal_led/mcal_led_dummy.h new file mode 100644 index 000000000..ea451ac5b --- /dev/null +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_dummy.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_LED_DUMMY_2025_02_22_H + #define MCAL_LED_DUMMY_2025_02_22_H + + #include + #include + + namespace mcal { namespace led { + + class led_dummy : public mcal::led::led_boolean_state_base + { + public: + led_dummy() noexcept + { + } + + ~led_dummy() override = default; + + auto toggle() noexcept -> void override + { + using base_class_type = mcal::led::led_boolean_state_base; + + base_class_type::toggle(); + } + }; + + } // namespace led + } // namespace mcal + +#endif // MCAL_LED_DUMMY_2025_02_22_H diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_port.h b/examples/chapter09_08a/src/mcal_led/mcal_led_port.h index f0d383ef7..4157ec58c 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_port.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_port.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2023. +// Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,13 +17,15 @@ class led_port : public mcal::led::led_boolean_state_base { public: - led_port() + led_port() noexcept { port_type::set_pin_low(); port_type::set_direction_output(); } - auto toggle() -> void override + ~led_port() override = default; + + auto toggle() noexcept -> void override { using base_class_type = led_boolean_state_base; diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_port_inverted.h b/examples/chapter09_08a/src/mcal_led/mcal_led_port_inverted.h index 847661fad..95daaf686 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_port_inverted.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_port_inverted.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2020 - 2023. +// Copyright Christopher Kormanyos 2020 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,13 +17,15 @@ class led_port_inverted : public mcal::led::led_boolean_state_base { public: - led_port_inverted() + led_port_inverted() noexcept { port_type::set_pin_high(); port_type::set_direction_output(); } - auto toggle() -> void override + ~led_port_inverted() override = default; + + auto toggle() noexcept -> void override { using base_class_type = led_boolean_state_base; diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_pwm.h b/examples/chapter09_08a/src/mcal_led/mcal_led_pwm.h new file mode 100644 index 000000000..711699092 --- /dev/null +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_pwm.h @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2013 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_LED_PWM_2020_04_23_H + #define MCAL_LED_PWM_2020_04_23_H + + #include + #include + + namespace mcal { namespace led { + + class led_pwm : public mcal::led::led_base + { + public: + explicit led_pwm(mcal::pwm::pwm_base& pwm) : my_pwm(pwm) + { + my_pwm.set_duty(mcal::pwm::pwm_base::duty_type { UINT8_C(0) }); + } + + ~led_pwm() override = default; + + auto state_is_on() const noexcept -> bool override { return (my_pwm.get_duty() > static_cast(UINT8_C(0))); } + + auto toggle() -> void override + { + // Toggle the duty cycle. + const auto new_duty = + static_cast + ( + state_is_on() ? UINT16_C(0) : UINT16_C(1000) + ); + + my_pwm.set_duty(new_duty); + } + + private: + mcal::pwm::pwm_base& my_pwm; + }; + + } // namespace led + } // namespace mcal + +#endif // MCAL_LED_PWM_2020_04_23_H diff --git a/examples/chapter09_08a/src/mcal_led/mcal_led_rgb_base.h b/examples/chapter09_08a/src/mcal_led/mcal_led_rgb_base.h index 6277b28b8..35655b33e 100644 --- a/examples/chapter09_08a/src/mcal_led/mcal_led_rgb_base.h +++ b/examples/chapter09_08a/src/mcal_led/mcal_led_rgb_base.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2017 - 2023. +// Copyright Christopher Kormanyos 2017 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,16 +8,18 @@ #ifndef MCAL_LED_RGB_BASE_2023_07_12_H #define MCAL_LED_RGB_BASE_2023_07_12_H - #include - #include + #include + namespace mcal { namespace led { class led_rgb_base : public mcal::led::led_boolean_state_base { public: - auto toggle() -> void override + ~led_rgb_base() override = default; + + auto toggle() noexcept -> void override { using base_class_type = mcal::led::led_boolean_state_base; @@ -48,7 +50,7 @@ ); } - constexpr auto get_color() const noexcept -> std::uint32_t + auto get_color() const noexcept -> std::uint32_t { return static_cast @@ -59,9 +61,9 @@ ); } - constexpr auto get_hue_r() const noexcept -> std::uint_fast8_t { return my_hue_r; } - constexpr auto get_hue_g() const noexcept -> std::uint_fast8_t { return my_hue_g; } - constexpr auto get_hue_b() const noexcept -> std::uint_fast8_t { return my_hue_b; } + auto get_hue_r() const noexcept -> std::uint_fast8_t { return my_hue_r; } + auto get_hue_g() const noexcept -> std::uint_fast8_t { return my_hue_g; } + auto get_hue_b() const noexcept -> std::uint_fast8_t { return my_hue_b; } protected: constexpr led_rgb_base() = default; @@ -94,6 +96,7 @@ } }; - } } // namespace mcal::led + } // namespace led + } // namespace mcal #endif // MCAL_LED_RGB_BASE_2023_07_12_H diff --git a/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_base.h b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_base.h new file mode 100644 index 000000000..66f27f3a8 --- /dev/null +++ b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_base.h @@ -0,0 +1,41 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_PWM_BASE_2020_04_12_H + #define MCAL_PWM_BASE_2020_04_12_H + + #include + + #include + + namespace mcal { namespace pwm { + + class pwm_base : private util::noncopyable // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + { + public: + using duty_type = std::uint16_t; + + virtual ~pwm_base() noexcept = default; + + virtual auto init() noexcept -> bool = 0; + + virtual auto set_duty(const duty_type duty_cycle) -> void { my_duty_cycle = duty_cycle; } + + auto get_duty() const noexcept -> duty_type { return my_duty_cycle; } + + protected: + explicit pwm_base(const duty_type initial_duty = static_cast(UINT8_C(0))) noexcept + : my_duty_cycle(initial_duty) { } + + private: + duty_type my_duty_cycle { }; // NOLINT(readability-identifier-naming) + }; + + } // namespace pwm + } // namespace mcal + +#endif // MCAL_PWM_BASE_2020_04_12_H diff --git a/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_console.h b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_console.h new file mode 100644 index 000000000..9d19e3dc1 --- /dev/null +++ b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_console.h @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_PWM_CONSOLE_2020_04_12_H + #define MCAL_PWM_CONSOLE_2020_04_12_H + + #include + + #include + #include + #include + + namespace mcal { namespace pwm { + + class pwm_console : public mcal::pwm::pwm_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + { + private: + using base_class_type = mcal::pwm::pwm_base; + + public: + pwm_console() = default; + + auto init() noexcept -> bool override { return true; } + + auto set_duty(const std::uint16_t duty_cycle) noexcept -> void override + { + base_class_type::set_duty(duty_cycle); + + const auto duty_cycle_as_percent = + static_cast + ( + static_cast(base_class_type::get_duty()) / 10.0F + ); + + std::stringstream strm; + + strm << "duty cycle: " + << std::fixed + << std::setprecision(1) + << duty_cycle_as_percent + << "%"; + + std::cout << strm.str() + (std::string(2U, ' ') + "\r"); + } + + ~pwm_console() override = default; + }; + + } // namespace pwm + } // namespace mcal + +#endif // MCAL_PWM_CONSOLE_2020_04_12_H diff --git a/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_dummy.h b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_dummy.h new file mode 100644 index 000000000..2a37fa113 --- /dev/null +++ b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_dummy.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_PWM_DUMMY_2020_04_29_H + #define MCAL_PWM_DUMMY_2020_04_29_H + + #include + + namespace mcal { namespace pwm { + + class pwm_dummy : public mcal::pwm::pwm_base + { + private: + using base_class_type = mcal::pwm::pwm_base; + + public: + pwm_dummy() = default; + + auto init() noexcept -> bool override { return true; } + + auto set_duty(const std::uint16_t duty_cycle) noexcept -> void override + { + base_class_type::set_duty(duty_cycle); + } + + ~pwm_dummy() override = default; + }; + + } // namespace pwm + } // namespace mcal + +#endif // MCAL_PWM_DUMMY_2020_04_29_H diff --git a/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_port.h b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_port.h new file mode 100644 index 000000000..7b454062e --- /dev/null +++ b/examples/chapter09_08a/src/mcal_pwm/mcal_pwm_port.h @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_PWM_PORT_2023_08_23_H + #define MCAL_PWM_PORT_2023_08_23_H + + #include + + #include + + namespace mcal { namespace pwm { + + // A software PWM template for a port-pin having the standard + // port interface for ref_app. The default resolution is 100 ticks. + + template + class pwm_port : public pwm_base + { + private: + using base_class_type = pwm_base; + using port_pin_type = PortPinType; + + public: + using base_class_type::duty_type; + + explicit pwm_port(const duty_type initial_duty = static_cast(UINT8_C(0))) + : base_class_type(initial_duty), + my_duty_shadow(initial_duty) + { + port_pin_type::set_pin_low(); + port_pin_type::set_direction_output(); + } + + ~pwm_port() noexcept override = default; + + auto init() noexcept -> bool override + { + return true; + } + + static constexpr auto get_resolution() noexcept -> duty_type { return duty_type { UINT16_C(1000) }; } + + auto set_duty(const duty_type duty_cycle) noexcept -> void override + { + my_duty_shadow = (std::min)(duty_cycle, get_resolution()); + } + + auto service() noexcept -> void + { + // Increment the cycle counter. + ++my_cycle_counter; + + ((my_cycle_counter <= base_class_type::get_duty()) ? port_pin_type::set_pin_high() : port_pin_type::set_pin_low()); + + if(my_cycle_counter == get_resolution()) + { + // Latch the duty cycle from the shadow register. + // This is done at the end of the running cycle. + base_class_type::set_duty(my_duty_shadow); + + // Reset the cycle counter for a new PWM period. + my_cycle_counter = static_cast(UINT8_C(0)); + } + } + + private: + duty_type my_cycle_counter { }; + duty_type my_duty_shadow { }; + }; + + } // namespace pwm + } // namespace mcal + +#endif // MCAL_PWM_PORT_2023_08_23_H diff --git a/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_dummy.h b/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_dummy.h new file mode 100644 index 000000000..2deb3e08d --- /dev/null +++ b/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_dummy.h @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2022. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SPI_SOFTWARE_DUMMY_2020_04_10_H + #define MCAL_SPI_SOFTWARE_DUMMY_2020_04_10_H + + #include + + namespace mcal { namespace spi { + + class spi_software_dummy : public util::communication_buffer_depth_one_byte // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + { + private: + using base_class_type = util::communication_buffer_depth_one_byte; + + public: + // This class implements a dummy SPI with no real functionality. + + spi_software_dummy() = default; + + ~spi_software_dummy() override = default; + + auto send(const std::uint8_t byte_to_send) noexcept -> bool override + { + static_cast(byte_to_send); + + base_class_type::recv_buffer = 0U; + + return true; + } + + auto select() -> void override { } + auto deselect() -> void override { } + }; + + } // namespace spi + } // namespace mcal + +#endif // MCAL_SPI_SOFTWARE_DUMMY_2020_04_10_H diff --git a/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_port_driver.h b/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_port_driver.h new file mode 100644 index 000000000..74bc0c60f --- /dev/null +++ b/examples/chapter09_08a/src/mcal_spi/mcal_spi_software_port_driver.h @@ -0,0 +1,145 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2022. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef MCAL_SPI_SOFTWARE_PORT_DRIVER_2020_04_09_H + #define MCAL_SPI_SOFTWARE_PORT_DRIVER_2020_04_09_H + + #include + #include + #include + + #include + + namespace mcal { namespace spi { + + template + class spi_software_port_driver : public util::communication_buffer_depth_one_byte + { + private: + // Consider: + // https://en.wikipedia.org/wiki/Serial_Peripheral_Interface + + // Timing applies to both the master and the slave device. + + // CPOL=0: + // The clock idles to 0 and each cycle consists + // of a pulse of 1. The leading edge is a rising edge + // and the trailing edge is a falling edge. + + // CPHA=0: + // Data out changes on the trailing edge of the + // preceding clock cycle, while data in is captured + // on (or shortly after) the leading edge of the + // clock cycle. + + using base_class_type = util::communication_buffer_depth_one_byte; + + public: + spi_software_port_driver() + { + port_pin_csn__type::set_pin_high(); + port_pin_sck__type::set_pin_low(); + port_pin_mosi_type::set_pin_low(); + + port_pin_csn__type::set_direction_output(); + port_pin_sck__type::set_direction_output(); + port_pin_mosi_type::set_direction_output(); + port_pin_miso_type::set_direction_input(); + } + + ~spi_software_port_driver() override = default; + + auto send(const std::uint8_t byte_to_send) noexcept -> bool override + { + base_class_type::recv_buffer = 0U; + + for(std::uint_fast8_t bit_mask = UINT8_C(0x80); bit_mask != UINT8_C(0); bit_mask = std::uint_fast8_t(bit_mask >> 1U)) + { + ((std::uint_fast8_t(byte_to_send & bit_mask) != UINT8_C(0)) ? port_pin_mosi_type::set_pin_high() + : port_pin_mosi_type::set_pin_low()); + + mcal::helper::disable_all_interrupts(); + + port_pin_sck__type::set_pin_high(); + mcal::helper::nop_maker(); + + port_pin_sck__type::set_pin_low (); + mcal::helper::nop_maker(); + + if(port_pin_miso_type::read_input_value()) + { + base_class_type::recv_buffer = + base_class_type::buffer_type(base_class_type::recv_buffer | bit_mask); + } + + mcal::helper::enable_all_interrupts(); + } + + return true; + } + + auto select() -> void override { port_pin_csn__type::set_pin_low(); } + auto deselect() -> void override { port_pin_csn__type::set_pin_high(); } + }; + + template + class spi_software_port_driver : public util::communication_buffer_depth_one_byte + { + public: + spi_software_port_driver() + { + port_pin_csn__type::set_pin_high(); + port_pin_sck__type::set_pin_low(); + port_pin_mosi_type::set_pin_low(); + + port_pin_csn__type::set_direction_output(); + port_pin_sck__type::set_direction_output(); + port_pin_mosi_type::set_direction_output(); + } + + ~spi_software_port_driver() override = default; + + auto send(const std::uint8_t byte_to_send) noexcept -> bool override + { + for(std::uint_fast8_t bit_mask = UINT8_C(0x80); + bit_mask != UINT8_C(0); + bit_mask = std::uint_fast8_t(bit_mask >> 1U)) + { + ((std::uint_fast8_t(byte_to_send & bit_mask) != UINT8_C(0)) ? port_pin_mosi_type::set_pin_high() + : port_pin_mosi_type::set_pin_low()); + + mcal::helper::disable_all_interrupts(); + + port_pin_sck__type::set_pin_high(); + port_pin_sck__type::set_pin_low(); + + mcal::helper::enable_all_interrupts(); + } + + return true; + } + + auto select() -> void override { port_pin_csn__type::set_pin_low(); } + auto deselect() -> void override { port_pin_csn__type::set_pin_high(); } + }; + + } // namespace spi + } // namespace mcal + +#endif // MCAL_SPI_SOFTWARE_PORT_DRIVER_2020_04_09_H diff --git a/examples/chapter09_08a/src/os/os.cpp b/examples/chapter09_08a/src/os/os.cpp index 591e0ac8a..a1bd651a5 100644 --- a/examples/chapter09_08a/src/os/os.cpp +++ b/examples/chapter09_08a/src/os/os.cpp @@ -1,37 +1,44 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2025. +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // #include -#include #include #include #include #include -#include -namespace +namespace local { - using task_list_type = std::array; + using task_list_type = std::array; using task_index_type = std::uint_fast8_t; - // The one (and only one) operating system task list. - task_list_type os_task_list(OS_TASK_LIST); + auto os_task_list() -> task_list_type&; // The index of the running task. - task_index_type os_task_index { }; + task_index_type os_task_index; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +} // namespace local + +// The one (and only one) operating system task list. +auto local::os_task_list() -> local::task_list_type& +{ + static task_list_type my_task_list(OS_TASK_LIST); + + return my_task_list; } -auto os::start_os() -> void +OS_NORETURN auto os::start_os() -> void { + auto& task_list = local::os_task_list(); + // Initialize each task once (and only once) before the task scheduling begins. - auto const it_init_func = std::for_each(os_task_list.cbegin(), - os_task_list.cend(), + const auto it_init_func = std::for_each(task_list.cbegin(), + task_list.cend(), [](const task_control_block& the_tcb) { the_tcb.initialize(); @@ -44,31 +51,31 @@ auto os::start_os() -> void // Enter the endless loop of the multitasking scheduler... // ...and never return. - while(mcal::led::sys_start_interface::my_exit_pc_api_flag() == false) + for(;;) { // Find the next ready task using a priority-based search algorithm. // Use a constant time-point based on the timer mark of now. // In this way, each task in the loop will be checked for being // ready using the same time-point. - const os::tick_type timepoint_of_ckeck_ready { os::timer_type::get_mark() }; + const os::tick_type timepoint_of_ckeck_ready = os::timer_type::get_mark(); - os_task_index = static_cast(0U); + local::os_task_index = static_cast(0U); - const auto it_ready_task = - std::find_if(os_task_list.begin(), - os_task_list.end(), - [&timepoint_of_ckeck_ready](task_control_block& tcb) -> bool + const auto it_ready_task = // NOLINT(llvm-qualified-auto,readability-qualified-auto) + std::find_if(task_list.begin(), + task_list.end(), + [&timepoint_of_ckeck_ready](task_control_block& tcb) // NOLINT(modernize-use-trailing-return-type) { - const bool task_is_ready = tcb.execute(timepoint_of_ckeck_ready); + const auto task_is_ready = tcb.execute(timepoint_of_ckeck_ready); - ++os_task_index; + ++local::os_task_index; return task_is_ready; }); // If no ready-task was found, then service the idle task. - if(it_ready_task == os_task_list.end()) + if(it_ready_task == task_list.end()) { OS_IDLE_TASK_FUNC(); } @@ -77,12 +84,16 @@ auto os::start_os() -> void auto os::set_event(const task_id_type task_id, const event_type& event_to_set) -> bool { - if(task_id < task_id_end) + bool result_set_is_ok { }; + + auto& task_list = local::os_task_list(); + + if(task_id < task_id_type::task_id_end) { // Get the iterator of the control block corresponding to // the task id that has been supplied to this subroutine. - const auto it_task_id = ( os_task_list.begin() - + task_list_type::size_type(task_id)); + const auto it_task_id = ( task_list.begin() // NOLINT(llvm-qualified-auto,readability-qualified-auto) + + static_cast(task_id)); // Set the event of the corresponding task. mcal::irq::disable_all(); @@ -91,25 +102,25 @@ auto os::set_event(const task_id_type task_id, const event_type& event_to_set) - mcal::irq::enable_all(); - return true; - } - else - { - return false; + result_set_is_ok = true; } + + return result_set_is_ok; } auto os::get_event(event_type& event_to_get) -> void { + const auto& task_list = local::os_task_list(); + // Get the iterator of the control block of the running task. - const auto it_running_task = (os_task_list.cbegin() + os_task_index); + const auto it_running_task = (task_list.cbegin() + local::os_task_index); // NOLINT(llvm-qualified-auto,readability-qualified-auto) - if(it_running_task != os_task_list.cend()) + if(it_running_task != task_list.cend()) { // Get the event of the running task. mcal::irq::disable_all(); - const volatile event_type the_event { it_running_task->my_event }; + const volatile event_type the_event = it_running_task->my_event; mcal::irq::enable_all(); @@ -117,23 +128,25 @@ auto os::get_event(event_type& event_to_get) -> void } else { - event_to_get = event_type(); + event_to_get = event_type { }; } } auto os::clear_event(const event_type& event_to_clear) -> void { + auto& task_list = local::os_task_list(); + // Get the iterator of the control block of the running task. - const auto it_running_task = (os_task_list.begin() + os_task_index); + const auto it_running_task = (task_list.begin() + local::os_task_index); // NOLINT(llvm-qualified-auto,readability-qualified-auto) - if(it_running_task != os_task_list.end()) + if(it_running_task != task_list.end()) { - const volatile event_type event_clear_mask { static_cast(~event_to_clear) }; + volatile const auto event_clear_mask = static_cast(~event_to_clear); // Clear the event of the running task. mcal::irq::disable_all(); - it_running_task->my_event &= event_clear_mask; + it_running_task->my_event = static_cast(it_running_task->my_event & event_clear_mask); mcal::irq::enable_all(); } diff --git a/examples/chapter09_08a/src/os/os.h b/examples/chapter09_08a/src/os/os.h index 50821168b..8adc64573 100644 --- a/examples/chapter09_08a/src/os/os.h +++ b/examples/chapter09_08a/src/os/os.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2025. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -11,12 +11,21 @@ #include #include + #include + #include + + #if defined(_MSC_VER) + #define OS_NORETURN + #else + #define OS_NORETURN [[noreturn]] + #endif + namespace os { - auto start_os() -> void; - auto set_event(const task_id_type task_id, const event_type& event_to_set) -> bool; - auto get_event(event_type& event_to_get) -> void; + OS_NORETURN auto start_os() -> void; + auto set_event (const task_id_type task_id, const event_type& event_to_set) -> bool; + auto get_event (event_type& event_to_get) -> void; auto clear_event(const event_type& event_to_clear) -> void; - } + } // namespace os #endif // OS_2011_10_20_H diff --git a/examples/chapter09_08a/src/os/os_cfg.h b/examples/chapter09_08a/src/os/os_cfg.h index d7c75e463..baa4cf046 100644 --- a/examples/chapter09_08a/src/os/os_cfg.h +++ b/examples/chapter09_08a/src/os/os_cfg.h @@ -8,34 +8,57 @@ #ifndef OS_CFG_2011_10_20_H #define OS_CFG_2011_10_20_H + #include + #include #include #include - #include - // Declare the task initialization and the task function of the idle process. - namespace sys { namespace idle { auto task_init() -> void; auto task_func() -> void; } } + namespace sys { namespace idle { + + auto task_init() noexcept -> void; auto task_func() -> void; + + } // namespace idle + } // namespace sys // Define symbols for the task initialization and the task function of the idle process. #define OS_IDLE_TASK_INIT() sys::idle::task_init() #define OS_IDLE_TASK_FUNC() sys::idle::task_func() // Declare all of the task initializations and the task functions. - namespace app { namespace led { auto task_init() -> void; auto task_func() -> void; } } - namespace sys { namespace mon { auto task_init() -> void; auto task_func() -> void; } } + namespace app { namespace led { + + auto task_init() -> void; auto task_func() -> void; + + } // namespace led + } // namespace app + + namespace app { namespace benchmark { + + auto task_init() -> void; auto task_func() -> void; + + } // namespace benchmark + } // namespace app + + namespace sys { namespace mon { + + auto task_init() -> void; auto task_func() -> void; + + } // namespace mon + } // namespace sys namespace os { // Enumerate the task IDs. Note that the order in this list must // be identical with the order of the tasks in the task list below. - typedef enum enum_task_id + + enum class task_id_type // NOLINT(performance-enum-size) { task_id_app_led, task_id_sys_mon, task_id_end - } - task_id_type; + }; // Configure the operating system types. using function_type = void(*)(); @@ -44,43 +67,39 @@ using tick_type = timer_type::tick_type; using event_type = std::uint_fast16_t; - static_assert(std::numeric_limits::digits >= 32, + static_assert(std::numeric_limits::digits >= static_cast(INT8_C(32)), "The operating system timer_type must be at least 32-bits wide."); - static_assert(std::numeric_limits::digits >= 16, + static_assert(std::numeric_limits::digits >= static_cast(INT8_C(16)), "The operating system event_type must be at least 16-bits wide."); - } + } // namespace os // Configure the operating system tasks. // Use small prime numbers (representing microseconds) for task offsets. - // Use Wolfram's Alpha or Mathematica(R): Table[Prime[n], {n, 50, 4000, 50}] + // Use Wolfram's Alpha or Mathematica(R): Table[Prime[n], {n, 25, 1000, 25}] // to obtain: - // 229, 541, 863, 1223, 1583, 1987, 2357, 2741, 3181, 3571, - // 3989, 4409, 4831, 5279, 5693, 6133, 6571, 6997, 7499, 7919, - // 8387, 8831, 9283, 9733, 10177, 10657, 11149, 11657, 12109, 12553, - // 13007, 13499, 13967, 14519, 14947, 15401, 15881, 16381, 16903, 17389, - // 17891, 18313, 18899, 19423, 19891, 20357, 20897, 21383, 21841, 22307, - // 22817, 23321, 23827, 24281, 24877, 25391, 25913, 26399, 26891, 27449, - // 27947, 28499, 28933, 29443, 30059, 30559, 31091, 31601, 32159, 32609, - // 33113, 33613, 34157, 34649, 35159, 35759, 36277, 36781, 37309, 37813 - - #define OS_TASK_COUNT static_cast(os::task_id_end) - - #define OS_TASK_LIST \ - { \ - { \ - os::task_control_block(app::led::task_init, \ - app::led::task_func, \ - os::timer_type::microseconds(UINT32_C( 4000)), \ - os::timer_type::microseconds(UINT32_C( 229))), \ - os::task_control_block(sys::mon::task_init, \ - sys::mon::task_func, \ - os::timer_type::microseconds(UINT32_C( 20000)), \ - os::timer_type::microseconds(UINT32_C( 541))), \ - } \ + // 97, 229, 379, 541, 691, 863, 1039, 1223, 1427, 1583, 1777, + // 1987, 2153, 2357, 2557, 2741, 2953, 3181, 3371, 3571, 3769, 3989, + // 4201, 4409, 4637, 4831, 5039, 5279, 5483, 5693, 5881, 6133, 6337, + // 6571, 6793, 6997, 7237, 7499, 7687, 7919 + + constexpr auto OS_TASK_COUNT = static_cast(os::task_id_type::task_id_end); + + #define OS_TASK_LIST \ + { \ + { \ + os::task_control_block(app::led::task_init, \ + app::led::task_func, \ + os::timer_type::microseconds(UINT32_C( 7000)), \ + os::timer_type::microseconds(UINT32_C( 0))), \ + os::task_control_block(sys::mon::task_init, \ + sys::mon::task_func, \ + os::timer_type::microseconds(UINT32_C( 27000)), \ + os::timer_type::microseconds(UINT32_C( 541))), \ + } \ } - static_assert(OS_TASK_COUNT > std::size_t(0U), "the task count must exceed zero"); + static_assert(OS_TASK_COUNT > static_cast(UINT8_C(0)), "the task count must exceed zero"); #endif // OS_CFG_2011_10_20_H diff --git a/examples/chapter09_08a/src/os/os_task_control_block.h b/examples/chapter09_08a/src/os/os_task_control_block.h index 318d29c13..d0a60bd2b 100644 --- a/examples/chapter09_08a/src/os/os_task_control_block.h +++ b/examples/chapter09_08a/src/os/os_task_control_block.h @@ -1,5 +1,5 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2025. +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,50 +19,67 @@ class task_control_block final { public: - explicit task_control_block(const function_type init, - const function_type func, - const tick_type cycle, - const tick_type offset) - : my_init (init), - my_func (func), - my_cycle(cycle), - my_timer(offset) { } - - task_control_block(const task_control_block& other_tcb) : my_init (other_tcb.my_init), - my_func (other_tcb.my_func), - my_cycle(other_tcb.my_cycle), - my_timer(other_tcb.my_timer), - my_event(other_tcb.my_event) { } - - task_control_block(task_control_block&& other_tcb) : my_init (other_tcb.my_init), - my_func (other_tcb.my_func), - my_cycle(other_tcb.my_cycle), - my_timer(other_tcb.my_timer), - my_event(other_tcb.my_event) { } - - ~task_control_block() { } + task_control_block(const function_type init, // NOLINT(bugprone-easily-swappable-parameters) + const function_type func, // NOLINT(bugprone-easily-swappable-parameters) + const tick_type cycle, // NOLINT(bugprone-easily-swappable-parameters) + const tick_type offset) // NOLINT(bugprone-easily-swappable-parameters) + : my_init { init }, + my_func { func }, + my_cycle { cycle }, + my_timer { offset } { } + + task_control_block(const task_control_block& other_tcb) = default; + + task_control_block(task_control_block&& other_tcb) noexcept = default; task_control_block() = delete; - auto operator=(const task_control_block&) -> task_control_block& = default; - auto operator=(task_control_block&&) -> task_control_block& = default; + ~task_control_block() = default; + + auto operator=(const task_control_block&) -> task_control_block& = delete; + auto operator=(task_control_block&&) noexcept -> task_control_block& = delete; private: - const function_type my_init; - const function_type my_func; - const tick_type my_cycle; + const function_type my_init; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + const function_type my_func; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + const tick_type my_cycle; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) timer_type my_timer; event_type my_event { }; auto initialize() const -> void { my_init(); } - auto execute(const tick_type& timepoint_of_ckeck_ready) -> bool; + auto execute(const tick_type& timepoint_of_ckeck_ready) -> bool + { + // Check for a task event. + const auto task_does_have_event = (my_event != static_cast(UINT8_C(0))); + + if(task_does_have_event) + { + // Call the task function because of an event. + my_func(); + } + + // Check for a task timeout. + const bool task_does_have_timeout = ( (my_cycle != static_cast(UINT8_C(0))) + && my_timer.timeout_of_specific_timepoint(timepoint_of_ckeck_ready)); + + if(task_does_have_timeout) + { + // Increment the task's interval timer with the task cycle. + my_timer.start_interval(my_cycle); + + // Call the task function because of a timer timeout. + my_func(); + } + + return (task_does_have_event || task_does_have_timeout); + } - friend auto start_os() -> void; - friend auto set_event(const task_id_type, const event_type&) -> bool; + friend auto start_os () -> void; + friend auto set_event (const task_id_type, const event_type&) -> bool; friend auto get_event (event_type&) -> void; friend auto clear_event(const event_type&) -> void; }; - } + } // namespace os #endif // OS_TASK_CONTROL_BLOCK_2013_07_30_H diff --git a/examples/chapter09_08a/src/sys/idle/sys_idle.cpp b/examples/chapter09_08a/src/sys/idle/sys_idle.cpp index 2efb4c037..a8b049f30 100644 --- a/examples/chapter09_08a/src/sys/idle/sys_idle.cpp +++ b/examples/chapter09_08a/src/sys/idle/sys_idle.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2013. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -7,14 +7,13 @@ #include -namespace sys -{ - namespace idle - { - auto task_init() -> void; - auto task_func() -> void; - } -} +namespace sys { namespace idle { + +auto task_init() -> void; +auto task_func() -> void; + +} // namespace idle +} // namespace sys auto sys::idle::task_init() -> void { } diff --git a/examples/chapter09_08a/src/sys/mon/sys_mon.cpp b/examples/chapter09_08a/src/sys/mon/sys_mon.cpp index f52bcfd9d..6b03045e1 100644 --- a/examples/chapter09_08a/src/sys/mon/sys_mon.cpp +++ b/examples/chapter09_08a/src/sys/mon/sys_mon.cpp @@ -1,24 +1,25 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2013. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -namespace sys -{ - namespace mon - { - auto task_init() -> void; - auto task_func() -> void; - } -} +namespace sys { namespace mon { + +auto task_init() -> void; +auto task_func() -> void; + +} // namespace mon +} // namespace sys auto sys::mon::task_init() -> void { + // Subroutine is empty on purpose. } auto sys::mon::task_func() -> void { + // Subroutine is empty on purpose. } diff --git a/examples/chapter09_08a/src/util/memory/util_factory.h b/examples/chapter09_08a/src/util/memory/util_factory.h index 84b50257b..782475ea5 100644 --- a/examples/chapter09_08a/src/util/memory/util_factory.h +++ b/examples/chapter09_08a/src/util/memory/util_factory.h @@ -1,72 +1,81 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2020. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_FACTORY_2012_02_19_H_ - #define UTIL_FACTORY_2012_02_19_H_ +#ifndef UTIL_FACTORY_2012_02_19_H + #define UTIL_FACTORY_2012_02_19_H + #include + #include #include - #include - namespace util { - class factory_product : private util::noncopyable + class factory_product { public: virtual ~factory_product() { } - virtual void init() = 0; + virtual auto init() -> void = 0; protected: factory_product() { } }; template> + typename AllocatorType = std::allocator> class factory { public: - typedef T value_type; - typedef T* pointer_type; - typedef alloc allocator_type; + using value_type = T; + using pointer_type = T*; + using allocator_type = AllocatorType; - static pointer_type make() + static auto make() -> pointer_type { pointer_type p = new(allocate()) value_type(); + static_cast(p)->init(); + return p; } template - static pointer_type make(parameters... params) + static auto make(parameters... params) -> pointer_type { pointer_type p = new(allocate()) value_type(params...); + static_cast(p)->init(); + return p; } private: - static void* allocate() + static auto allocate() -> void* { - return allocator_type().allocate(1U, nullptr); + return allocator_type().allocate( std::size_t { UINT8_C(1) } ); } }; } -#endif // UTIL_FACTORY_2012_02_19_H_ +#endif // UTIL_FACTORY_2012_02_19_H /* + +// See also link at GodBolt: https://godbolt.org/z/WrTTa8Eq9 + #include +#include + class something : public util::factory_product { public: - something() { } - virtual ~something() { } + something() = default; + virtual ~something() = default; private: virtual void init() { } @@ -75,18 +84,31 @@ class something : public util::factory_product class another : public util::factory_product { public: - another(const int m, const int n) : my_m(m), - my_n(n) { } + explicit another(const int m = 0, const int n = 0) + : my_m(m), + my_n(n) { } + + ~another() override = default; - virtual ~another() { } + auto get_m() const -> int { return my_m; } + auto get_n() const -> int { return my_n; } private: - const int my_m; - const int my_n; + const int my_m { }; + const int my_n { }; - virtual void init() { } + auto init() -> void override { } }; -something* p_something = util::factory::make(); -another* p_another = util::factory::make(123, 456); +auto main() -> int +{ + something* p_something = util::factory::make(); + another* p_another = util::factory::make(123, 456); + + std::cout << p_another->get_n() << '\n'; + std::cout << p_another->get_m() << std::endl; + + delete p_something; + delete p_another; +} */ diff --git a/examples/chapter09_08a/src/util/memory/util_n_slot_array_allocator.h b/examples/chapter09_08a/src/util/memory/util_n_slot_array_allocator.h new file mode 100644 index 000000000..37b9b382b --- /dev/null +++ b/examples/chapter09_08a/src/util/memory/util_n_slot_array_allocator.h @@ -0,0 +1,195 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_N_SLOT_ARRAY_ALLOCATOR_2020_10_25_H // NOLINT(llvm-header-guard) + #define UTIL_N_SLOT_ARRAY_ALLOCATOR_2020_10_25_H + + #include + #include + #include + #include + + namespace util { + + // Forward declaration of n_slot_array_allocator template. + template + class n_slot_array_allocator; + + // Template partial specialization of n_slot_array_allocator template for void. + template + class n_slot_array_allocator + { + public: + using value_type = void; + using pointer = value_type*; + using const_pointer = const value_type*; + + template + struct rebind + { + using other = n_slot_array_allocator; + }; + }; + + template + class n_slot_array_allocator // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + { + private: + static constexpr std::uint_fast32_t slot_width = SlotWidth; + static constexpr std::size_t slot_count = SlotCount; + + using slot_array_type = std::array; + using slot_array_memory_type = std::array; + using slot_array_flags_type = std::array; + + public: + using size_type = std::size_t; + using value_type = typename slot_array_type::value_type; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + + constexpr n_slot_array_allocator() = default; // LCOV_EXCL_LINE + + constexpr n_slot_array_allocator(const n_slot_array_allocator&) = default; // LCOV_EXCL_LINE + + template + struct rebind + { + using other = n_slot_array_allocator; + }; + + constexpr auto max_size() const noexcept -> size_type { return slot_count; } + + constexpr auto address( reference x) const -> pointer { return &x; } + constexpr auto address(const_reference x) const -> const_pointer { return &x; } + + auto allocate(size_type count, const_pointer p_hint = nullptr) -> pointer + { + static_cast(count); + static_cast(p_hint); + + pointer p { nullptr }; + + // TBD: There is most likely significant optimization potential + // capable of being unlocked if a storage/lookup mechanism can be + // devised that uses a binary search when finding the next free slot. + + // (TBD) In fact, constant-time allocation probably possible, as shown in: + // SmallObjectAllocator from Modern C++ Design by Andrei Alexandrescu. + + for(auto i = static_cast(UINT8_C(0)); i < slot_count; ++i) + { + using local_flags_value_type = typename slot_array_flags_type::value_type; + + if(slot_flags[i] == static_cast(UINT8_C(0))) // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + { + slot_flags[i] = static_cast(UINT8_C(1)); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + + p = static_cast(slot_array_memory[i].data()); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + + if(i > slot_max_index) + { + slot_max_index = i; + + static_cast(slot_max_index); + } + + break; + } + } + + return p; + } + + auto construct(pointer p, const value_type& x) -> void + { + // The memory in the n-slot allocator already exists + // in an uninitialized form. Construction can safely + // simply set the value in the uninitialized memory. + + *p = x; + } + + auto destroy(pointer p) const -> void { static_cast(p); } // LCOV_EXCL_LINE + + auto deallocate(pointer p_slot, size_type sz) -> void + { + static_cast(sz); + + typename slot_array_memory_type::size_type index { }; + + for(auto& slot_array_memory_entry : slot_array_memory) + { + if(p_slot == static_cast(slot_array_memory_entry.data())) + { + using local_flags_value_type = typename slot_array_flags_type::value_type; + + slot_flags[index] = static_cast(UINT8_C(0)); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index) + + break; + } + + ++index; + } + } + + private: + static slot_array_memory_type slot_array_memory; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + static slot_array_flags_type slot_flags; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + static std::size_t slot_max_index; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) + }; + + template + typename n_slot_array_allocator::slot_array_memory_type n_slot_array_allocator::slot_array_memory; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,hicpp-uppercase-literal-suffix,readability-uppercase-literal-suffix) + + template + typename n_slot_array_allocator::slot_array_flags_type n_slot_array_allocator::slot_flags; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,hicpp-uppercase-literal-suffix,readability-uppercase-literal-suffix) + + template + std::size_t n_slot_array_allocator::slot_max_index; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables,hicpp-uppercase-literal-suffix,readability-uppercase-literal-suffix) + + // Global comparison operators (required by the standard). + template + auto operator==(const n_slot_array_allocator& left, + const n_slot_array_allocator& right) -> bool + { + static_cast(left.max_size()); + static_cast(right.max_size()); + + return true; + } + + template + auto operator!=(const n_slot_array_allocator& left, + const n_slot_array_allocator& right) -> bool + { + static_cast(left.max_size()); + static_cast(right.max_size()); + + return false; + } + + } // namespace util + +#endif // UTIL_N_SLOT_ARRAY_ALLOCATOR_2020_10_25_H diff --git a/examples/chapter09_08a/src/util/memory/util_ring_allocator.h b/examples/chapter09_08a/src/util/memory/util_ring_allocator.h index c824dea3c..7a3a48ef1 100644 --- a/examples/chapter09_08a/src/util/memory/util_ring_allocator.h +++ b/examples/chapter09_08a/src/util/memory/util_ring_allocator.h @@ -1,26 +1,26 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2021. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_RING_ALLOCATOR_2010_02_23_H_ - #define UTIL_RING_ALLOCATOR_2010_02_23_H_ +#ifndef UTIL_RING_ALLOCATOR_2010_02_23_H + #define UTIL_RING_ALLOCATOR_2010_02_23_H + + #include #include #include #include - #include - namespace util { class ring_allocator_base { public: - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; virtual ~ring_allocator_base() = default; @@ -41,7 +41,7 @@ // The ring allocator's memory allocation. template - static void* do_allocate(size_type chunk_size) + static auto do_allocate(size_type chunk_size) -> void* { ALIGNAS(16) static buffer_type buffer; @@ -80,14 +80,14 @@ }; // Global comparison operators (required by the standard). - inline bool operator==(const ring_allocator_base&, - const ring_allocator_base&) noexcept + inline auto operator==(const ring_allocator_base&, + const ring_allocator_base&) noexcept -> bool { return true; } - inline bool operator!=(const ring_allocator_base&, - const ring_allocator_base&) noexcept + inline auto operator!=(const ring_allocator_base&, + const ring_allocator_base&) noexcept -> bool { return false; } @@ -100,9 +100,9 @@ class ring_allocator : public ring_allocator_base { public: - typedef void value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; + using value_type = void; + using pointer = value_type*; + using const_pointer = const value_type*; template struct rebind @@ -119,11 +119,11 @@ static_assert(sizeof(T) <= buffer_type::size, "The size of the allocation object can not exceed the buffer size."); - typedef T value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; + using value_type = T; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; ring_allocator() noexcept = default; @@ -138,16 +138,16 @@ using other = ring_allocator; }; - size_type max_size() const noexcept + auto max_size() const noexcept -> size_type { return buffer_type::size / sizeof(value_type); } - pointer address( reference x) const { return &x; } - const_pointer address(const_reference x) const { return &x; } + auto address( reference x) const -> pointer { return &x; } + auto address(const_reference x) const -> const_pointer { return &x; } - pointer allocate(size_type count, - typename ring_allocator::const_pointer = nullptr) + auto allocate(size_type count, + typename ring_allocator::const_pointer = nullptr) -> pointer { const size_type chunk_size = count * sizeof(value_type); @@ -156,15 +156,15 @@ return static_cast(p); } - void construct(pointer p, const value_type& x) noexcept + auto construct(pointer p, const value_type& x) noexcept -> void { new(static_cast(p)) value_type(x); } - void destroy(pointer p) noexcept { p->~value_type(); } + auto destroy(pointer p) noexcept -> void { p->~value_type(); } - void deallocate(pointer, size_type) noexcept { } + auto deallocate(pointer, size_type) noexcept -> void { } }; } -#endif // UTIL_RING_ALLOCATOR_2010_02_23_H_ +#endif // UTIL_RING_ALLOCATOR_2010_02_23_H diff --git a/examples/chapter09_08a/src/util/utility/util_attribute.h b/examples/chapter09_08a/src/util/utility/util_attribute.h new file mode 100644 index 000000000..34175b3be --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_attribute.h @@ -0,0 +1,21 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2025. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_ATTRIBUTE_2025_08_09_H + #define UTIL_ATTRIBUTE_2025_08_09_H + + #if defined(ATTRIBUTE) + #undef ATTRIBUTE + #endif + + #if defined(_MSC_VER) + #define ATTRIBUTE(...) + #else + #define ATTRIBUTE(...) __attribute__((__VA_ARGS__)) + #endif + +#endif // UTIL_ATTRIBUTE_2025_08_09_H diff --git a/examples/chapter09_08a/src/util/utility/util_baselexical_cast.h b/examples/chapter09_08a/src/util/utility/util_baselexical_cast.h new file mode 100644 index 000000000..16f64a655 --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_baselexical_cast.h @@ -0,0 +1,173 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_BASELEXICAL_CAST_2020_06_28_H // NOLINT(llvm-header-guard) + #define UTIL_BASELEXICAL_CAST_2020_06_28_H + + #if ((defined(__cplusplus) && (__cplusplus >= 201703L)) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L))) + #if !(defined(__GNUC__) && defined(__AVR__)) + #define UTIL_BASELEXICAL_CAST_HAS_CHARCONV + #endif + #endif + + #if defined(UTIL_BASELEXICAL_CAST_HAS_CHARCONV) + #include + #include + #else + #include + #include + #include + #include + #endif + + namespace util { + + #if defined(UTIL_BASELEXICAL_CAST_HAS_CHARCONV) + + template(UINT8_C(10)), + const bool UpperCase = true> + auto baselexical_cast(const UnsignedIntegerType& u, char* first, char* last) -> const char* + { + constexpr auto my_base = static_cast(BaseRepresentation); + + const auto result = std::to_chars(first, last, u, my_base); + + return result.ptr; + } + + #else + + template + struct baselexical_cast_helper + { + private: + using output_value_type = typename std::iterator_traits::value_type; + + public: + static auto extract(output_value_type) noexcept -> output_value_type = delete; + }; + + template + struct baselexical_cast_helper(UINT8_C(16))> + { + private: + using output_value_type = typename std::iterator_traits::value_type; + + public: + static auto extract(output_value_type c) noexcept -> output_value_type + { + if(c <= static_cast(INT8_C(9))) + { + c = + static_cast + ( + c + static_cast('0') + ); + } + else if((c >= static_cast(0xA)) && (c <= static_cast(INT8_C(0xF)))) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers) + { + c = + static_cast + ( + static_cast(UpperCase ? static_cast('A') : static_cast('a')) + + static_cast(c - static_cast(INT8_C(0xA))) + ); + } + + return c; + } + }; + + template + struct baselexical_cast_helper(UINT8_C(10))> + { + private: + using output_value_type = typename std::iterator_traits::value_type; + + public: + static auto extract(output_value_type c) noexcept -> output_value_type + { + if(c <= static_cast(INT8_C(9))) + { + c = + static_cast + ( + c + static_cast('0') + ); + } + + return c; + } + }; + + template(UINT8_C(10)), + const bool UpperCase = true> + auto baselexical_cast(const UnsignedIntegerType& u, OutputIterator out, OutputIterator out_dummy) -> OutputIterator + { + static_cast(out_dummy); + + using unsigned_integer_type = UnsignedIntegerType; + using output_value_type = typename std::iterator_traits::value_type; + + if(u == static_cast(UINT8_C(0))) + { + *out = + static_cast + ( + baselexical_cast_helper::extract(static_cast(UINT8_C(0))) + ); + } + else + { + unsigned_integer_type x(u); + + auto out_first = out; + + while(x != static_cast(UINT8_C(0))) // NOLINT(altera-id-dependent-backward-branch) + { + const auto c = + static_cast + ( + x % static_cast(BaseRepresentation) + ); + + *out = + static_cast + ( + baselexical_cast_helper::extract(c) + ); + + x = + static_cast + ( + x / static_cast(BaseRepresentation) + ); + + if(x != static_cast(UINT8_C(0))) + { + ++out; + } + } + + std::reverse(out_first, out + static_cast(UINT8_C(1))); + } + + return out + static_cast(UINT8_C(1)); + } + + #endif + + } // namespace util + +#endif // UTIL_BASELEXICAL_CAST_2020_06_28_H diff --git a/examples/chapter09_08a/src/util/utility/util_bit_mask.h b/examples/chapter09_08a/src/util/utility/util_bit_mask.h index 27f117e8c..446bf4a8e 100644 --- a/examples/chapter09_08a/src/util/utility/util_bit_mask.h +++ b/examples/chapter09_08a/src/util/utility/util_bit_mask.h @@ -1,80 +1,100 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2018. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_BIT_MASK_2010_06_13_H_ - #define UTIL_BIT_MASK_2010_06_13_H_ +#ifndef UTIL_BIT_MASK_2010_06_13_H + #define UTIL_BIT_MASK_2010_06_13_H #include namespace util { template + const unsigned BitPos, + const unsigned BitCnt> struct bit_mask_multi_value { + private: // This bit mask contains bit_cnt continuous bits starting at bit_pos. + static constexpr unsigned bit_pos = BitPos; + static constexpr unsigned bit_cnt = BitCnt; + // Ensure that the data_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the data_type of the bit_mask template must be an integer type"); // Ensure that the data_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the data_type of the bit_mask template must be unsigned"); // Ensure that the requested bit mask is in range. - static_assert((bit_pos + bit_cnt) <= unsigned(std::numeric_limits::digits), + static_assert((bit_pos + bit_cnt) <= unsigned { std::numeric_limits::digits }, "the requested bit_mask value exceeds the maximum value of the data_type"); - static const data_type value = static_cast(static_cast(static_cast(~static_cast(0U)) >> (std::numeric_limits::digits - (bit_cnt + 1U))) << bit_pos); + public: + static constexpr data_type value = + static_cast + ( + static_cast + ( + static_cast(~static_cast(0U)) >> static_cast(static_cast(std::numeric_limits::digits) - (bit_cnt + 1U)) + ) << bit_pos + ); }; template - struct bit_mask_multi_value + const unsigned BitPos> + struct bit_mask_multi_value { + private: // This bit mask contains one bit at bit_pos. + static constexpr unsigned bit_pos = BitPos; + // Ensure that the data_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the data_type of the bit_mask template must be an integer type"); // Ensure that the data_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the data_type of the bit_mask template must be unsigned"); // Ensure that the requested bit mask is in range. static_assert((bit_pos + 1) <= unsigned(std::numeric_limits::digits), "the requested bit_mask value exceeds the maximum value of the data_type"); - static const data_type value = static_cast(static_cast(1U) << bit_pos); + public: + static constexpr data_type value = static_cast(static_cast(1U) << bit_pos); }; template + const unsigned BitPos> struct bit_mask_single_value { + private: // This bit mask contains one bit at bit_pos. + static constexpr unsigned bit_pos = BitPos; + // Ensure that the data_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the data_type of the bit_mask template must be an integer type"); // Ensure that the data_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the data_type of the bit_mask template must be unsigned"); // Ensure that the requested bit mask is in range. static_assert((bit_pos + 1) <= unsigned(std::numeric_limits::digits), "the requested bit_mask value exceeds the maximum value of the data_type"); + public: static const data_type value = static_cast(static_cast(1U) << bit_pos); }; } -#endif // UTIL_BIT_MASK_2010_06_13_H_ +#endif // UTIL_BIT_MASK_2010_06_13_H diff --git a/examples/chapter09_08a/src/util/utility/util_circular_buffer.h b/examples/chapter09_08a/src/util/utility/util_circular_buffer.h deleted file mode 100644 index 39e8c67c5..000000000 --- a/examples/chapter09_08a/src/util/utility/util_circular_buffer.h +++ /dev/null @@ -1,374 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2015. -// Distributed under the Boost Software License, -// Version 1.0. (See accompanying file LICENSE_1_0.txt -// or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef UTIL_CIRCULAR_BUFFER_2007_11_22_H_ - #define UTIL_CIRCULAR_BUFFER_2007_11_22_H_ - - #include - #include - #include - - namespace util - { - // Forward declaration of the circular_buffer class. - template - class circular_buffer; - - namespace circular_buffer_detail - { - template - struct circular_iterator : public std::iterator - { - public: - typedef std::iterator iterator_type; - - typedef typename iterator_type::value_type value_type; - typedef typename iterator_type::pointer pointer; - typedef typename iterator_type::reference reference; - typedef const reference const_reference; - typedef typename std::size_t size_type; - typedef typename iterator_type::difference_type difference_type; - - explicit circular_iterator(const pointer pb, - const pointer pc = pb) : buffer_pointer (pb), - circular_pointer(pc) { } - - ~circular_iterator() { } - - circular_iterator& operator=(const circular_iterator& other_iterator) - { - if(this != &other_iterator) - { - buffer_pointer = other_iterator.buffer_pointer; - circular_pointer = other_iterator.circular_pointer; - } - - return *this; - } - - const_reference operator*() const - { - return *circular_pointer; - } - - reference operator*() - { - return *const_cast(circular_pointer); - } - - circular_iterator& operator++() - { - ++circular_pointer; - - if(circular_pointer > (buffer_pointer + difference_type(N))) - { - circular_pointer = buffer_pointer; - } - - return *this; - } - - circular_iterator& operator--() - { - --circular_pointer; - - if(circular_pointer < buffer_pointer) - { - circular_pointer = buffer_pointer + difference_type(N); - } - - return *this; - } - - circular_iterator operator++(int) - { - circular_iterator tmp = *this; - - ++(*this); - - return tmp; - } - - circular_iterator operator--(int) - { - circular_iterator tmp = *this; - - --(*this); - - return tmp; - } - - circular_iterator& operator+=(difference_type n) - { - if(n > difference_type(0)) - { - circular_pointer += n; - - if(circular_pointer > (buffer_pointer + difference_type(N))) - { - circular_pointer -= difference_type(N); - } - } - else if(n < 0) - { - *this -= -n; - } - - return *this; - } - - circular_iterator& operator-=(difference_type n) - { - if(n > difference_type(0)) - { - circular_pointer -= n; - - if(circular_pointer < buffer_pointer) - { - circular_pointer += difference_type(N); - } - } - else if(n < 0) - { - *this += -n; - } - - return *this; - } - - private: - pointer buffer_pointer; - pointer circular_pointer; - - circular_iterator(); - - friend inline circular_iterator operator+(const circular_iterator& a, difference_type n) { return circular_iterator(a) += n; } - friend inline circular_iterator operator-(const circular_iterator& a, difference_type n) { return circular_iterator(a) -= n; } - - friend inline bool operator==(const circular_iterator& a, const circular_iterator& b) { return (a.circular_pointer == b.circular_pointer); } - friend inline bool operator!=(const circular_iterator& a, const circular_iterator& b) { return (a.circular_pointer != b.circular_pointer); } - - // TBD: Implement operator<(). - // TBD: Implement the remaining operators. - }; - } - - template - class circular_buffer - { - public: - static_assert(N > std::size_t(0U), - "Error: The circular_buffer class requires more than zero elements."); - - typedef T value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - typedef value_type& reference; - typedef const value_type& const_reference; - - typedef circular_buffer_detail::circular_iterator > iterator; - typedef circular_buffer_detail::circular_iterator > const_iterator; - - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - circular_buffer() : buffer (), - my_size(difference_type(0)), - first (buffer + difference_type(N)), - last (buffer + difference_type(N)) - { - std::fill(buffer, buffer + difference_type(N), value_type()); - } - - explicit circular_buffer(const size_type count, - const value_type value = value_type()) : buffer (), - my_size(difference_type(count)), - first (buffer + difference_type(N - count)), - last (buffer + difference_type(N)) - { - std::fill(buffer, buffer + difference_type(N - count), value_type()); - - std::fill(buffer + difference_type(N - count), buffer + difference_type(N), value); - } - - circular_buffer(const circular_buffer& other) : buffer (), - my_size(difference_type(other.size())), - first (buffer + difference_type(other.first - other.buffer)), - last (buffer + difference_type(other.last - other.buffer)) - { - std::copy(other.buffer, other.buffer + difference_type(N), buffer); - } - - ~circular_buffer() { } - - circular_buffer& operator=(const circular_buffer& other) - { - if(this != &other) - { - std::copy(other.buffer, other.buffer + difference_type(N), buffer); - - my_size = difference_type(other.size()); - - first = buffer + difference_type(other.first - other.buffer); - last = buffer + difference_type(other.last - other.buffer); - } - - return *this; - } - - static size_type capacity() { return N; } - - bool empty() const - { - return (my_size == difference_type(0U)); - } - - size_type size() const - { - return size_type(my_size); - } - - void clear() - { - first = buffer; - last = buffer + difference_type(N); - my_size = difference_type(0); - } - - void push_front(const value_type value) - { - --first; - - if(first < buffer) - { - first = buffer + difference_type(N - 1U); - } - - *first = value; - - if(my_size < difference_type(N)) - { - ++my_size; - } - } - - void pop_back() - { - if(my_size > difference_type(0)) - { - --my_size; - - // TBD: Do we actually need to manually call the destructor here? - last->~value_type(); - - --last; - - if(last <= buffer) - { - last = buffer + difference_type(N); - } - } - } - - iterator begin () { return iterator (buffer, first); } - const_iterator begin () const { return const_iterator(buffer, first); } - const_iterator cbegin() const { return const_iterator(buffer, first); } - iterator end () { return iterator (buffer, last); } - const_iterator end () const { return const_iterator(buffer, last); } - const_iterator cend () const { return const_iterator(buffer, last); } - - reverse_iterator rbegin () { return std::reverse_iterator (iterator (buffer, last)); } - const_reverse_iterator rbegin () const { return std::reverse_iterator(const_iterator(buffer, last)); } - const_reverse_iterator crbegin() const { return std::reverse_iterator(const_iterator(buffer, last)); } - reverse_iterator rend () { return std::reverse_iterator (iterator (buffer, first)); } - const_reverse_iterator rend () const { return std::reverse_iterator(const_iterator(buffer, first)); } - const_reverse_iterator crend () const { return std::reverse_iterator(const_iterator(buffer, first)); } - - reference front () { return *begin(); } - const_reference front () const { return *begin(); } - reference back () { return *(end() - iterator::difference_type(1)); } - const_reference back () const { return *(cend() - const_iterator::difference_type(1)); } - - private: - value_type buffer[N]; - difference_type my_size; - pointer first; - pointer last; - }; - } - - /* - #include - #include - #include - #include - - template - void do_something() - { - circular_buffer_type cb(1U, 1U); - - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - cb.push_front(2U); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - cb.push_front(3U); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - cb.pop_back(); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - cb.pop_back(); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - cb.pop_back(); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - cb.push_front(101U); - cb.push_front(102U); - cb.push_front(103U); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - for(auto it = cb.cbegin(); it != cb.cbegin() + cb.size(); ++it) { std::cout << *it << std::endl; } - for(auto it = cb.crbegin(); it != cb.crend(); ++it) { std::cout << *it << std::endl; } - - cb.pop_back(); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - cb.pop_back(); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - cb.push_front(42U); - std::cout << cb.size() << ", " << cb.front() << ", " << cb.back() << std::endl; - - circular_buffer_type other_cb; - - other_cb = cb; - - volatile unsigned debug = 0U; - - static_cast(debug); - } - - int main() - { - do_something>(); - } -*/ - -#endif // UTIL_CIRCULAR_BUFFER_2007_11_22_H_ diff --git a/examples/chapter09_08a/src/util/utility/util_communication.h b/examples/chapter09_08a/src/util/utility/util_communication.h index f9e58cf85..e8981ff55 100644 --- a/examples/chapter09_08a/src/util/utility/util_communication.h +++ b/examples/chapter09_08a/src/util/utility/util_communication.h @@ -8,16 +8,16 @@ #ifndef UTIL_COMMUNICATION_2012_05_31_H #define UTIL_COMMUNICATION_2012_05_31_H + #include + #include #include #include #include - #include - namespace util { - class communication_base : private util::noncopyable + class communication_base : private util::noncopyable // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: virtual ~communication_base() = default; @@ -32,9 +32,9 @@ template auto send_n(send_iterator_type first, send_iterator_type last) noexcept -> bool { - auto send_result = true; + bool send_result { true }; // NOLINT(altera-id-dependent-backward-branch) - while((first != last) && send_result) + while((first != last) && send_result) // NOLINT(altera-id-dependent-backward-branch) { using send_value_type = typename std::iterator_traits::value_type; @@ -50,11 +50,11 @@ communication_base() = default; private: - template + template friend class communication_multi_channel; }; - class communication_buffer_depth_one_byte : public communication_base + class communication_buffer_depth_one_byte : public communication_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { public: using buffer_type = std::uint8_t; @@ -62,7 +62,7 @@ ~communication_buffer_depth_one_byte() override = default; protected: - buffer_type recv_buffer { }; + buffer_type recv_buffer { }; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes) communication_buffer_depth_one_byte() = default; @@ -75,13 +75,18 @@ } }; - template - class communication_multi_channel : public communication_base + template + class communication_multi_channel : public communication_base // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { + private: + static constexpr std::size_t channel_count = ChannelCount; + public: + communication_multi_channel() = delete; + explicit communication_multi_channel(communication_base** p_com_channels) { - std::copy(p_com_channels, p_com_channels + channel_count, my_com_channels.begin()); + std::copy(p_com_channels, p_com_channels + channel_count, my_com_channels.begin()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } ~communication_multi_channel() override = default; @@ -112,13 +117,11 @@ } private: - std::array my_com_channels { }; - std::size_t my_index { }; - - communication_multi_channel() = delete; + std::array my_com_channels { }; // NOLINT(readability-identifier-naming) + std::size_t my_index { }; // NOLINT(readability-identifier-naming) static_assert(channel_count > 0U, "Error channel_count must be greater than zero."); }; - } + } // namespace util #endif // UTIL_COMMUNICATION_2012_05_31_H diff --git a/examples/chapter09_08a/src/util/utility/util_constexpr_algorithm_unsafe.h b/examples/chapter09_08a/src/util/utility/util_constexpr_algorithm_unsafe.h new file mode 100644 index 000000000..529664934 --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_constexpr_algorithm_unsafe.h @@ -0,0 +1,200 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2023. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_CONSTEXPR_ALGORITHM_UNSAFE_2023_11_23_H // NOLINT(llvm-header-guard) + #define UTIL_CONSTEXPR_ALGORITHM_UNSAFE_2023_11_23_H + + #include + #include + #include + #include + + namespace util { + + // Use a local, constexpr, unsafe implementation of the abs-function. + template + constexpr auto abs_unsafe(ArithmeticType val) -> ArithmeticType + { + return ((val > static_cast(INT8_C(0))) ? val : -val); + } + + // Use a local, constexpr, unsafe implementation of the fill-function. + template + constexpr auto fill_unsafe(DestinationIterator first, DestinationIterator last, ValueType val) -> void + { + while(first != last) + { + using local_destination_value_type = typename std::iterator_traits::value_type; + + *first++ = static_cast(val); + } + } + + // Use a local, constexpr, unsafe implementation of the copy-function. + template + constexpr auto copy_unsafe(InputIterator first, InputIterator last, DestinationIterator dest) -> DestinationIterator + { + while(first != last) + { + using local_destination_value_type = typename std::iterator_traits::value_type; + + #if (defined(__GNUC__) && (__GNUC__ > 9)) + #pragma GCC diagnostic ignored "-Wstringop-overflow" + #endif + *dest++ = static_cast(*first++); + #if (defined(__GNUC__) && (__GNUC__ > 9)) + #pragma GCC diagnostic pop + #endif + } + + return dest; + } + + // Use a local, constexpr, unsafe implementation of the copy-backward-function. + template + constexpr auto copy_backward_unsafe(InputIterator first, InputIterator last, DestinationIterator dest) -> DestinationIterator + { + using local_destination_value_type = typename std::iterator_traits::value_type; + + while(first != last) + { + *(--dest) = static_cast(*(--last)); + } + + return dest; + } + + // Use a local, constexpr, unsafe implementation of the max-function. + template + constexpr auto max_unsafe(const ArithmeticType& left, const ArithmeticType& right) -> ArithmeticType + { + return ((left < right) ? right : left); + } + + // Use a local, constexpr, unsafe implementation of the max-function. + template + constexpr auto min_unsafe(const ArithmeticType& left, const ArithmeticType& right) -> ArithmeticType + { + return ((right < left) ? right : left); + } + + template + constexpr auto lower_bound_unsafe(ForwardIt first, ForwardIt last, const T& value) -> ForwardIt + { + using local_iterator_type = ForwardIt; + + using local_difference_type = typename std::iterator_traits::difference_type; + + local_difference_type step { }; + + auto count = static_cast(last - first); // NOLINT(altera-id-dependent-backward-branch) + + local_iterator_type itr { }; + + while(count > static_cast(INT8_C(0))) // NOLINT(altera-id-dependent-backward-branch) + { + itr = first; + + step = static_cast(count / static_cast(INT8_C(2))); + + itr += step; + + if (*itr < value) + { + first = ++itr; + + count -= static_cast(step + static_cast(INT8_C(1))); + } + else + { + count = step; + } + } + + return first; + } + + template + constexpr auto swap_unsafe(T& left, T& right) -> void + { + auto tmp = static_cast(left); + + left = static_cast(right); + right = static_cast(tmp); + } + + template + constexpr auto swap_unsafe(T&& left, T&& right) -> void + { + auto tmp = static_cast(left); + + left = static_cast(right); + right = static_cast(tmp); + } + + template + constexpr auto find_if_unsafe(InputIt first, InputIt last, UnaryPredicate p) -> InputIt + { + for( ; first != last; ++first) + { + if (p(*first)) + { + return first; + } + } + + return last; + } + + template + constexpr auto find_if_not_unsafe(InputIt first, InputIt last, UnaryPredicate q) -> InputIt + { + for( ; first != last; ++first) + { + if (!q(*first)) + { + return first; + } + } + + return last; + } + + template + constexpr auto all_of_unsafe(InputIt first, InputIt last, UnaryPredicate p) -> bool + { + return (find_if_not_unsafe(first, last, p) == last); + } + + template + constexpr auto iter_swap_unsafe(IteratorType a, IteratorType b) -> void + { + // Non-standard behavior: + // The (dereferenced) left/right value-types are the same. + + using local_value_type = typename std::iterator_traits::value_type; + + swap_unsafe(static_cast(*a), static_cast(*b)); + } + + template + constexpr auto reverse_unsafe(BiDirectionalIterator first, BiDirectionalIterator last) -> void + { + // Ensure that the type of the iterator provided is actually bidirectional. + + for( ; ((first != last) && (first != --last)); ++first) + { + iter_swap_unsafe(first, last); + } + } + + } // namespace util + +#endif // UTIL_CONSTEXPR_ALGORITHM_UNSAFE_2023_11_23_H diff --git a/examples/chapter09_08a/src/util/utility/util_constexpr_cmath_unsafe.h b/examples/chapter09_08a/src/util/utility/util_constexpr_cmath_unsafe.h new file mode 100644 index 000000000..3223f52f9 --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_constexpr_cmath_unsafe.h @@ -0,0 +1,90 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2023. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_CONSTEXPR_CMATH_UNSAFE_2023_11_26_H // NOLINT(llvm-header-guard) + #define UTIL_CONSTEXPR_CMATH_UNSAFE_2023_11_26_H + + #include + + namespace util { + + template + constexpr auto frexp_unsafe(FloatingPointType x, int* expptr) -> FloatingPointType + { + using local_floating_point_type = FloatingPointType; + + local_floating_point_type result { }; + + const auto b_neg = (x < static_cast(0.0L)); + + if((x > static_cast(0.0L)) || b_neg) + { + local_floating_point_type f = (b_neg ? -x : x); // NOLINT(altera-id-dependent-backward-branch) + + auto e2 = static_cast(INT8_C(0)); + + constexpr auto two_pow_plus32 = + static_cast + ( + static_cast(0x10000) + * static_cast(0x10000) + ); + + constexpr auto two_pow_minus32 = static_cast(0.000000000232830643653869628906250000L); + + // TBD: Maybe optimize exponent reduction with a more clever kind of binary searching. + + while(f >= static_cast(two_pow_plus32)) // NOLINT(altera-id-dependent-backward-branch) + { + f = static_cast(f / static_cast(two_pow_plus32)); + e2 += static_cast(INT8_C(32)); + } + + while(f <= static_cast(two_pow_minus32)) // NOLINT(altera-id-dependent-backward-branch) + { + f = static_cast(f * static_cast(two_pow_plus32)); + e2 -= static_cast(INT8_C(32)); + } + + constexpr auto one_ldbl = static_cast(1.0L); + constexpr auto two_ldbl = static_cast(2.0L); + + while(f < static_cast(one_ldbl)) // NOLINT(altera-id-dependent-backward-branch) + { + f = static_cast(f * static_cast(two_ldbl)); + + --e2; + } + + while(f >= static_cast(one_ldbl)) // NOLINT(altera-id-dependent-backward-branch) + { + f = static_cast(f / static_cast(two_ldbl)); + + ++e2; + } + + if(expptr != nullptr) + { + *expptr = e2; + } + + result = ((!b_neg) ? f : -f); + } + else + { + if(expptr != nullptr) + { + *expptr = static_cast(INT8_C(0)); + } + } + + return result; + } + + } // namespace util + +#endif // UTIL_CONSTEXPR_CMATH_UNSAFE_2023_11_26_H diff --git a/examples/chapter09_08a/src/util/utility/util_countof.h b/examples/chapter09_08a/src/util/utility/util_countof.h index d3a144dd4..1524259e0 100644 --- a/examples/chapter09_08a/src/util/utility/util_countof.h +++ b/examples/chapter09_08a/src/util/utility/util_countof.h @@ -1,46 +1,26 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2014. +// Copyright Christopher Kormanyos 2014 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_COUNTOF_2014_09_29_H_ - #define UTIL_COUNTOF_2014_09_29_H_ +#ifndef UTIL_COUNTOF_2014_09_29_H + #define UTIL_COUNTOF_2014_09_29_H #include namespace util { - #if defined(__GNUC__) + template + inline constexpr auto countof(T(&c_array)[N]) -> std::size_t + { + static_assert(N > std::size_t(0U), "Error: util::countof requires an array size larger than zero."); - template - inline constexpr std::size_t countof(T(&c_array)[N]) - { - static_assert(N > std::size_t(0U), - "Sorry, util::countof requires an array size larger than zero."); + static_assert(sizeof(c_array[0U]) > std::size_t(0U), "Error: util::countof requires an element size larger than zero."); - static_assert(sizeof(c_array[0U]) > std::size_t(0U), - "Sorry, util::countof requires an element size larger than zero."); - - return sizeof(c_array) / sizeof(c_array[0U]); - } - - #else - - template - inline std::size_t countof(T(&c_array)[N]) - { - static_assert(N > std::size_t(0U), - "Sorry, util::countof requires an array size larger than zero."); - - static_assert(sizeof(c_array[0U]) > std::size_t(0U), - "Sorry, util::countof requires an element size larger than zero."); - - return sizeof(c_array) / sizeof(c_array[0U]); - } - - #endif + return sizeof(c_array) / sizeof(c_array[0U]); + } } -#endif // UTIL_COUNTOF_2014_09_29_H_ +#endif // UTIL_COUNTOF_2014_09_29_H diff --git a/examples/chapter09_08a/src/util/utility/util_display.h b/examples/chapter09_08a/src/util/utility/util_display.h new file mode 100644 index 000000000..b3176185f --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_display.h @@ -0,0 +1,46 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2019 - 2024. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_DISPLAY_2023_06_09_H + #define UTIL_DISPLAY_2023_06_09_H + + #include + #include + + #include + + namespace util { + + class display_multiline_base : private util::noncopyable + { + public: + virtual ~display_multiline_base() = default; + + virtual auto init() -> bool = 0; + + virtual auto write(const char* pstr, + const std::uint_fast8_t length, + const std::uint_fast8_t line_index) -> bool = 0; + + virtual auto clear_line(const unsigned = static_cast(UINT8_C(0))) -> bool = 0; + + virtual auto set_line_index(const std::uint8_t) -> bool = 0; + + protected: + display_multiline_base() = default; + + using timer_type = util::timer; + + static auto blocking_delay(const typename timer_type::tick_type blocking_delay_value) -> void + { + timer_type::blocking_delay(blocking_delay_value); + } + }; + + } // namespace util + +#endif // UTIL_DISPLAY_2023_06_09_H diff --git a/examples/chapter09_08a/src/util/utility/util_dynamic_array.h b/examples/chapter09_08a/src/util/utility/util_dynamic_array.h index a1a6bb3b1..9c9f18b97 100644 --- a/examples/chapter09_08a/src/util/utility/util_dynamic_array.h +++ b/examples/chapter09_08a/src/util/utility/util_dynamic_array.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2012 - 2022. +// Copyright Christopher Kormanyos 2012 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -46,11 +46,10 @@ using const_reverse_iterator = std::reverse_iterator; // Constructors. - explicit dynamic_array( size_type count = static_cast(UINT8_C(0)), - const_reference v = value_type(), - const allocator_type& a = allocator_type()) - : elem_count(count), - elems (nullptr) + explicit constexpr dynamic_array( size_type count = static_cast(UINT8_C(0)), + const_reference v = value_type(), + const allocator_type& a = allocator_type()) + : elem_count(count) { if(elem_count > static_cast(UINT8_C(0))) { @@ -69,9 +68,8 @@ } } - dynamic_array(const dynamic_array& other) - : elem_count(other.size()), - elems (nullptr) + constexpr dynamic_array(const dynamic_array& other) + : elem_count(other.size()) { allocator_type my_a; @@ -84,11 +82,10 @@ } template - dynamic_array(input_iterator first, - input_iterator last, - const allocator_type& a = allocator_type()) - : elem_count(static_cast(std::distance(first, last))), - elems (nullptr) + constexpr dynamic_array(input_iterator first, + input_iterator last, + const allocator_type& a = allocator_type()) + : elem_count(static_cast(std::distance(first, last))) { allocator_type my_a(a); @@ -100,10 +97,9 @@ std::copy(first, last, elems); } - dynamic_array(std::initializer_list lst, - const allocator_type& a = allocator_type()) - : elem_count(lst.size()), - elems (nullptr) + constexpr dynamic_array(std::initializer_list lst, + const allocator_type& a = allocator_type()) + : elem_count(lst.size()) { allocator_type my_a(a); @@ -116,35 +112,26 @@ } // Move constructor. - dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count), - elems (other.elems) + constexpr dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count), + elems (other.elems) { other.elem_count = static_cast(UINT8_C(0)); other.elems = nullptr; } // Destructor. - virtual ~dynamic_array() + virtual ~dynamic_array() // LCOV_EXCL_LINE { - pointer p = elems; // NOLINT(altera-id-dependent-backward-branch) - using local_allocator_traits_type = std::allocator_traits; allocator_type my_a; - while(p != elems + elem_count) // NOLINT(altera-id-dependent-backward-branch) - { - local_allocator_traits_type::destroy(my_a, p); - - ++p; - } - // Destroy the elements and deallocate the range. local_allocator_traits_type::deallocate(my_a, elems, elem_count); } // Assignment operator. - auto operator=(const dynamic_array& other) -> dynamic_array& + constexpr auto operator=(const dynamic_array& other) -> dynamic_array& { if(this != &other) { @@ -157,7 +144,7 @@ } // Move assignment operator. - auto operator=(dynamic_array&& other) noexcept -> dynamic_array& + constexpr auto operator=(dynamic_array&& other) noexcept -> dynamic_array& { std::swap(elem_count, other.elem_count); std::swap(elems, other.elems); @@ -166,22 +153,22 @@ } // Iterator members: - auto begin () noexcept -> iterator { return elems; } - auto end () noexcept -> iterator { return elems + elem_count; } - auto begin () const noexcept -> const_iterator { return elems; } - auto end () const noexcept -> const_iterator { return elems + elem_count; } - auto cbegin () const noexcept -> const_iterator { return elems; } - auto cend () const noexcept -> const_iterator { return elems + elem_count; } - auto rbegin () noexcept -> reverse_iterator { return reverse_iterator(elems + elem_count); } - auto rend () noexcept -> reverse_iterator { return reverse_iterator(elems); } - auto rbegin () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } - auto rend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } - auto crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } - auto crend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } + constexpr auto begin () noexcept -> iterator { return elems; } + constexpr auto end () noexcept -> iterator { return elems + elem_count; } + constexpr auto begin () const noexcept -> const_iterator { return elems; } + constexpr auto end () const noexcept -> const_iterator { return elems + elem_count; } + constexpr auto cbegin () const noexcept -> const_iterator { return elems; } + constexpr auto cend () const noexcept -> const_iterator { return elems + elem_count; } + constexpr auto rbegin () noexcept -> reverse_iterator { return reverse_iterator(elems + elem_count); } + constexpr auto rend () noexcept -> reverse_iterator { return reverse_iterator(elems); } + constexpr auto rbegin () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } + constexpr auto rend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } + constexpr auto crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } + constexpr auto crend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } // Raw pointer access. - auto data() noexcept -> pointer { return elems; } - auto data() const noexcept -> const_pointer { return elems; } + constexpr auto data() noexcept -> pointer { return elems; } + constexpr auto data() const noexcept -> const_pointer { return elems; } // Size and capacity. constexpr auto size () const noexcept -> size_type { return elem_count; } @@ -189,25 +176,25 @@ constexpr auto empty () const noexcept -> bool { return (elem_count == static_cast(UINT8_C(0))); } // Element access members. - auto operator[](const size_type i) noexcept -> reference { return elems[i]; } - auto operator[](const size_type i) const noexcept -> const_reference { return elems[i]; } + constexpr auto operator[](const size_type i) noexcept -> reference { return elems[i]; } + constexpr auto operator[](const size_type i) const noexcept -> const_reference { return elems[i]; } - auto front() noexcept -> reference { return elems[static_cast(UINT8_C(0))]; } - auto front() const noexcept -> const_reference { return elems[static_cast(UINT8_C(0))]; } + constexpr auto front() noexcept -> reference { return elems[static_cast(UINT8_C(0))]; } + constexpr auto front() const noexcept -> const_reference { return elems[static_cast(UINT8_C(0))]; } - auto back() noexcept -> reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } - auto back() const noexcept -> const_reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } + constexpr auto back() noexcept -> reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } + constexpr auto back() const noexcept -> const_reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } - auto at(const size_type i) noexcept -> reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } - auto at(const size_type i) const noexcept -> const_reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } + constexpr auto at(const size_type i) noexcept -> reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } + constexpr auto at(const size_type i) const noexcept -> const_reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } // Element manipulation members. - auto fill(const value_type& v) -> void + constexpr auto fill(const value_type& v) -> void { - std::fill_n(begin(), elem_count, v); + std::fill(begin(), begin() + elem_count, v); } - auto swap(dynamic_array& other) noexcept -> void + constexpr auto swap(dynamic_array& other) noexcept -> void { if(this != &other) { @@ -216,17 +203,15 @@ } } - auto swap(dynamic_array&& other) noexcept -> void + constexpr auto swap(dynamic_array&& other) noexcept -> void { - auto tmp = std::move(*this); - - *this = std::move(other); - other = std::move(tmp); + elems = std::move(other.elems); + elem_count = std::move(other.elem_count); } private: - mutable size_type elem_count; // NOLINT(readability-identifier-naming) - pointer elems; // NOLINT(readability-identifier-naming,altera-id-dependent-backward-branch) + size_type elem_count; // NOLINT(readability-identifier-naming) + pointer elems { nullptr }; // NOLINT(readability-identifier-naming,altera-id-dependent-backward-branch) }; template diff --git a/examples/chapter09_08a/src/util/utility/util_dynamic_bitset.h b/examples/chapter09_08a/src/util/utility/util_dynamic_bitset.h new file mode 100644 index 000000000..684aebaea --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_dynamic_bitset.h @@ -0,0 +1,58 @@ +#ifndef UTIL_DYNAMIC_BITSET_2018_02_03_H_ + #define UTIL_DYNAMIC_BITSET_2018_02_03_H_ + + #include + #include + #include + + namespace util + { + template> + class dynamic_bitset + { + public: + using allocator_type = alloc; + + static const std::size_t my_elem_count = (my_bit_count / 8U) + (((my_bit_count % 8U) != 0U) ? 1U : 0U); + + dynamic_bitset() : my_memory(allocator_type().allocate(my_elem_count)) + { + std::fill(my_memory, + my_memory + my_elem_count, + UINT8_C(0)); + } + + ~dynamic_bitset() + { + std::allocator_traits::deallocate(allocator_type(), my_memory, my_elem_count); + } + + void set(const std::size_t i) + { + my_memory[i / 8U] |= (UINT8_C(1) << (i % 8U)); + } + + void flip(const std::size_t i) + { + my_memory[i / 8U] ^= (UINT8_C(1) << (i % 8U)); + } + + bool test(const std::size_t i) const + { + const std::uint8_t test_value = (my_memory[i / 8U] & (UINT8_C(1) << (i % 8U))); + + return (test_value != 0U); + } + + static std::size_t size() + { + return my_bit_count; + } + + private: + std::uint8_t* my_memory; + }; + } // namespace util + +#endif // UTIL_DYNAMIC_BITSET_2018_02_03_H_ diff --git a/examples/chapter09_08a/src/util/utility/util_linear_interpolate.h b/examples/chapter09_08a/src/util/utility/util_linear_interpolate.h index 038571b56..f154433a5 100644 --- a/examples/chapter09_08a/src/util/utility/util_linear_interpolate.h +++ b/examples/chapter09_08a/src/util/utility/util_linear_interpolate.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2020. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_LINEAR_INTERPOLATE_2008_11_22_H_ - #define UTIL_LINEAR_INTERPOLATE_2008_11_22_H_ +#ifndef UTIL_LINEAR_INTERPOLATE_2008_11_22_H + #define UTIL_LINEAR_INTERPOLATE_2008_11_22_H #include @@ -15,18 +15,17 @@ template - y_type linear_interpolate(point_iterator pts_begin, - point_iterator pts_end, - const x_type& x, - const y_type& offset) + auto linear_interpolate(point_iterator pts_begin, + point_iterator pts_end, + const x_type& x, + const y_type& offset) -> y_type { if(pts_begin == pts_end) { // There are no data points to interpolate. return y_type(); } - else if( (x <= pts_begin->x) - || ((pts_begin + 1U) == pts_end)) + else if((x <= pts_begin->x) || ((pts_begin + 1U) == pts_end)) { // We are beneath the lower x-range or there // is only one data point to interpolate. @@ -58,4 +57,4 @@ } } -#endif // UTIL_LINEAR_INTERPOLATE_2008_11_22_H_ +#endif // UTIL_LINEAR_INTERPOLATE_2008_11_22_H diff --git a/examples/chapter09_08a/src/util/utility/util_narrow_cast.h b/examples/chapter09_08a/src/util/utility/util_narrow_cast.h new file mode 100644 index 000000000..6b4416a61 --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_narrow_cast.h @@ -0,0 +1,22 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright Christopher Kormanyos 2020. +// Distributed under the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef UTIL_NARROW_CAST_2020_09_24_H + #define UTIL_NARROW_CAST_2020_09_24_H + + #include + + namespace util + { + template + constexpr auto narrow_cast(U&& u) noexcept -> T + { + return static_cast(std::forward(u)); + } + } + +#endif // UTIL_NARROW_CAST_2020_09_24_H diff --git a/examples/chapter09_08a/src/util/utility/util_noncopyable.h b/examples/chapter09_08a/src/util/utility/util_noncopyable.h index d215f7229..8f45b4e99 100644 --- a/examples/chapter09_08a/src/util/utility/util_noncopyable.h +++ b/examples/chapter09_08a/src/util/utility/util_noncopyable.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2022. +// Copyright Christopher Kormanyos 2007 - 2023. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/examples/chapter09_08a/src/util/utility/util_nothing.h b/examples/chapter09_08a/src/util/utility/util_nothing.h index 692e46cbc..a5ff0c506 100644 --- a/examples/chapter09_08a/src/util/utility/util_nothing.h +++ b/examples/chapter09_08a/src/util/utility/util_nothing.h @@ -1,33 +1,35 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2018. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_NOTHING_2010_06_13_H_ - #define UTIL_NOTHING_2010_06_13_H_ +#ifndef UTIL_NOTHING_2010_06_13_H + #define UTIL_NOTHING_2010_06_13_H namespace util { // This is a structure that is used to represent *nothing*. struct nothing final { - nothing() = default; + constexpr nothing() = default; - nothing(const nothing&) { } + constexpr nothing(const nothing&) { } + constexpr nothing(nothing&&) noexcept { } ~nothing() = default; - nothing& operator=(const nothing&) { return *this; } + constexpr auto operator=(const nothing&) -> nothing& { return *this; } + constexpr auto operator=(nothing&&) noexcept -> nothing& { return *this; } }; - inline bool operator==(const nothing&, const nothing&) { return true; } - inline bool operator!=(const nothing&, const nothing&) { return false; } - inline bool operator< (const nothing&, const nothing&) { return false; } - inline bool operator<=(const nothing&, const nothing&) { return false; } - inline bool operator> (const nothing&, const nothing&) { return false; } - inline bool operator>=(const nothing&, const nothing&) { return false; } + inline constexpr auto operator==(const nothing&, const nothing&) noexcept -> bool { return true; } + inline constexpr auto operator!=(const nothing&, const nothing&) noexcept -> bool { return false; } + inline constexpr auto operator< (const nothing&, const nothing&) noexcept -> bool { return false; } + inline constexpr auto operator<=(const nothing&, const nothing&) noexcept -> bool { return false; } + inline constexpr auto operator> (const nothing&, const nothing&) noexcept -> bool { return false; } + inline constexpr auto operator>=(const nothing&, const nothing&) noexcept -> bool { return false; } } -#endif // UTIL_NOTHING_2010_06_13_H_ +#endif // UTIL_NOTHING_2010_06_13_H diff --git a/examples/chapter09_08a/src/util/utility/util_point.h b/examples/chapter09_08a/src/util/utility/util_point.h index 85cc2d65a..992fcecd0 100644 --- a/examples/chapter09_08a/src/util/utility/util_point.h +++ b/examples/chapter09_08a/src/util/utility/util_point.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2014. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_POINT_2008_11_22_H_ - #define UTIL_POINT_2008_11_22_H_ +#ifndef UTIL_POINT_2008_11_22_H + #define UTIL_POINT_2008_11_22_H namespace util { @@ -14,57 +14,62 @@ typename y_type = x_type> struct point { - x_type x; - y_type y; + x_type x { }; + y_type y { }; - point(const x_type& x0 = x_type(), - const y_type& y0 = y_type()) : x(x0), - y(y0) { } + explicit constexpr point(const x_type& x0 = x_type(), + const y_type& y0 = y_type()) : x { x0 }, + y { y0 } { } - point(const point& other) + constexpr point(const point& other) : x { other.x }, + y { other.y } { } + + constexpr point(point&& other) noexcept : x { other.x }, + y { other.y } { } + + ~point() = default; + + constexpr auto operator=(const point& other) -> point& { if(this != &other) { x = other.x; y = other.y; } - } - ~point() { } + return *this; + } - point& operator=(const point& other) + constexpr auto operator=(point&& other) noexcept -> point& { - if(this != &other) - { - x = other.x; - y = other.y; - } + x = other.x; + y = other.y; return *this; } - bool operator<(const point& other) const + constexpr auto operator<(const point& other) const -> bool { return (x < other.x); } }; template - bool operator==(const point& left, const point& right) + constexpr auto operator==(const point& left, const point& right) -> bool { return ( (left.x == right.x) && (left.y == right.y)); } template - bool operator!=(const point& left, const point& right) + constexpr auto operator!=(const point& left, const point& right) -> bool { return ( (left.x != right.x) || (left.y != right.y)); } template - bool operator<(const point& left, const point& right) + constexpr auto operator<(const point& left, const point& right) -> bool { return ((left.x < right.x) ? true @@ -74,22 +79,22 @@ } template - bool operator<=(const point& left, const point& right) + constexpr auto operator<=(const point& left, const point& right) -> bool { - return ((right < left) == false); + return (!(right < left)); } template - bool operator>(const point& left, const point& right) + constexpr auto operator>(const point& left, const point& right) -> bool { return (right < left); } template - bool operator>=(const point& left, const point& right) + constexpr auto operator>=(const point& left, const point& right) -> bool { - return ((left < right) == false); + return (!(left < right)); } - } + } // namespace util -#endif // UTIL_POINT_2008_11_22_H_ +#endif // UTIL_POINT_2008_11_22_H diff --git a/examples/chapter09_08a/src/util/utility/util_stopwatch.h b/examples/chapter09_08a/src/util/utility/util_stopwatch.h index a6f7951fa..a5cc101f0 100644 --- a/examples/chapter09_08a/src/util/utility/util_stopwatch.h +++ b/examples/chapter09_08a/src/util/utility/util_stopwatch.h @@ -1,12 +1,14 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2014. +// Copyright Christopher Kormanyos 2014 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_STOPWATCH_2014_01_07_H_ - #define UTIL_STOPWATCH_2014_01_07_H_ +#ifndef UTIL_STOPWATCH_2014_01_07_H + #define UTIL_STOPWATCH_2014_01_07_H + + #include namespace util { @@ -14,17 +16,21 @@ class stopwatch final { public: - typedef typename clock_type::duration duration_type; + using duration_type = typename clock_type::duration; + + using time_point_type = typename clock_type::time_point; stopwatch() : my_start(clock_type::now()) { } - stopwatch(typename clock_type::time_point start) : my_start(start) { } + explicit stopwatch(time_point_type start) : my_start(start) { } stopwatch(const stopwatch& other) : my_start(other.my_start) { } - ~stopwatch() { } + stopwatch(stopwatch&& other) noexcept : my_start(other.my_start) { } - stopwatch& operator=(const stopwatch& other) + ~stopwatch() = default; + + auto operator=(const stopwatch& other) -> stopwatch& { if(this != &other) { @@ -34,18 +40,25 @@ return *this; } - duration_type elapsed() const + auto operator=(stopwatch&& other) noexcept -> stopwatch& + { + my_start = other.my_start; + + return *this; + } + + auto elapsed() const -> duration_type { return clock_type::now() - my_start; } - void reset() + auto reset() -> void { my_start = clock_type::now(); } private: - typename clock_type::time_point my_start; + time_point_type my_start; }; } @@ -53,4 +66,4 @@ // const auto elapsed = std::chrono::duration_cast(my_stopwatch.elapsed()).count(); // const auto elapsed = std::chrono::duration_cast>(my_stopwatch.elapsed()).count(); -#endif // UTIL_STOPWATCH_2014_01_07_H_ +#endif // UTIL_STOPWATCH_2014_01_07_H diff --git a/examples/chapter09_08a/src/util/utility/util_swdm.h b/examples/chapter09_08a/src/util/utility/util_swdm.h new file mode 100644 index 000000000..3e95bc48e --- /dev/null +++ b/examples/chapter09_08a/src/util/utility/util_swdm.h @@ -0,0 +1,776 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info (AT) paland.com) +// 2014-2016, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// +// \brief Single Wire Debug Monitor +// This class is the single wire debug monitor, which allows easy inspecting and +// manipulating (setting) memory / variable data over a single wire/pin in embedded systems. +// NO DEPENDENCIES! NO UART! NO REQUIREMENTS! Just a 1 ms periodic tick is needed. That's all. +// +// SWDM uses a simple request/response protocol where the tester/PC is always the +// master generating the request and the device/board is the slave sending the response. +// The class below implements the SWDM slave. +// +// SWDM uses a service tick of 1ms, one bit is oversampled 4 times, which results +// in a baudrate of 250 bit/sec, every byte has a low start bit, a high stop bit and +// 8 data bits (LSB first). So a normal UART with 250 baud 8N1 can be used on the PC master side +// for transmission / reception. +// The line is used in half duplex bidirectional mode. It is high for idle / recessive levels +// and low when active / dominant. +// Use a resistor pulled-up open collector pin on the board site or set the pin as input +// on a high level in your custom set_line() function. +// +// Protocol: +// +// request: | 0x55 | mode | address | data | crc | +// +// 0x55 (1 byte) : +// Request sync byte +// +// mode (1 byte) : +// bit 0-3 : data length, 0: 1 byte, 2: 3 bytes ... 15: 16 bytes +// bit 4-5 : addr length, 0: 2 byte, 1: 3 byte, 2: 4 byte, 3: 8 byte +// bit 6 : 0: byte access, 1: type access valid for uint8, uint16, uint32 and uint64 data length +// bit 7 : 0: read data command, 1: write data command +// +// address (2 - 8 bytes) : +// Big-endian order, MSB - the most significant address byte is sent first +// +// data (0 - 16 bytes) : +// On read command, no data byte is transmitted, data field is skipped +// Byte access: The byte of the specified address is send first, ascending address order byte by byte +// Type access: MSB first, valid are 1,2,4 and 8 data bytes, the most significant data byte is sent first +// +// crc (1 byte) : +// One byte CRC, using CRC-8 (ITU-T), x^8 + x^2 + x + 1 polynomial +// CRC is build over mode, address and data bytes +// +// +// response: | 0xAA | data | crc | +// +// 0xAA (1 byte) : +// Response sync byte +// +// data (0 - 16 bytes) +// Requested data bytes of read command +// On write command no data is sent, the answer is | 0xAA | 0x00 | +// Byte access: The byte of the specified address is send first, ascending address order byte by byte +// Type access: MSB first, valid are 1, 2, 4 and 8 bytes, the most significant data byte is sent first +// +// crc (1 byte) : +// One byte CRC, using CRC-8 (ITU-T), x^8 + x^2 + x + 1 polynomial +// CRC is built over data bytes, in case of a write command, crc is 0x00 +// +// +// Usage: +// +// #include "swdm.h" +// +// Define (implement) the two low level line/pin access routines in your system +// or derive your own my_swdm class from swdm and define your access functions there. +// +// bool swdm::get_line() const +// { +// return the value of the according swdm interface line/pin +// } +// +// void swdm::set_line(bool value) const +// { +// set the state of the according swdm line/pin to value (true = high/idle, false = low) +// if you don't use an open collector driver, you MUST configure the pin as input for high/idle levels +// and before setting the line to false/low it must be configured as an output. +// } +// +// Create a singleton instance of swdm: +// +// static swdm& get_swdm() +// { +// static swdm _swdm; +// return _swdm; +// } +// +// And call the swdm service routine with a rate of 1000 Hz: +// +// void system_tick_1ms() +// { +// get_swdm().service(); +// } +// +// +// \version +// 2014-09-17 0.10 Initial version, ideas +// 2014-09-23 0.80 Alpha version +// 2015-02-05 0.90 Beta version, code clean up +// 2015-02-25 0.91 Minor bug fixes, cleanup, more docu +// 2016-04-13 0.92 Bug fixes and tests by B. Hempelmann and C. Kormanyos +// 2016-04-17 1.00 Minor cleanups, first released version +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef UTIL_SWDM_2016_04_11_H +#define UTIL_SWDM_2016_04_11_H + +#if defined(__has_include) + #if(__has_include()) + #include + + #define UTIL_SWDM_HAS_USER_DEFINED_PORT + #endif +#endif + +#include + +#include + +#if !defined(UTIL_SWDM_HAS_USER_DEFINED_PORT) +class dummy_port +{ + public: + static constexpr auto set_direction_output() noexcept -> void { } + static constexpr auto set_direction_input () noexcept -> void { } + static constexpr auto set_pin_high () noexcept -> void { } + static constexpr auto set_pin_low () noexcept -> void { } + static constexpr auto read_input_value () noexcept -> bool { return false; } + static constexpr auto toggle_pin () noexcept -> void { } +}; + +namespace mcal { namespace debug { + +using debug_monitor_port_type = dummy_port; + +} // namespace debug +} // namespace mcal + +#endif + +// Defines the oversampling rate +// The effective baud rate is the service_tick_rate / SWD_OVERSAMPLING_COUNT +// For a service_tick_rate of 1 ms, the baud rate is 250 for 4 times oversampling +#define SWDM_SAMPLE_PERIOD UINT8_C(4) + +// Defines the position where the bit is detected as a constant valid bit. +// Should be at 50 to 75% of the SAMPLE period, 0 is the first sample position +#define SWDM_SAMPLE_VALID_POS UINT8_C(2) + +// Defines the number of consecutive high samples to detect a line idle condition +#define SWDM_SAMPLE_IDLE_COUNT UINT8_C(40) + +// Define this switch for 64 bit address support. If undefined, up to 32 bit addresses are supported +// #define SWDM_64_BIT_ADDRESS_SUPPORT + + +namespace util { + +class swdm : private util::noncopyable +{ +public: + // default ctor + swdm() : uart_state_ (rx_start_bit), + prot_state_ (rx_sync), + bit_detect_last_state_ (true), + bit_detect_sample_count_(UINT8_C(0)), + bit_detect_idle_count_ (UINT8_C(0)) + { + // set pin to idle / recessive value + set_line(true); + } + + // Service routine, MUST be called periodically with 1000 Hz (1 ms) + void service() + { + if( (uart_state_ == tx_data_bits) + || (uart_state_ == tx_start_bit) + || (uart_state_ == tx_stop_bit)) + { + // transmission + if(bit_detect_sample_count_ == UINT8_C(0)) + { + // bit period done + uart(true); + } + } + else + { + // reception + bool line = get_line(); + + // sync is done on every level change + if(line != bit_detect_last_state_) + { + // line level has changed, new bit cell started + bit_detect_last_state_ = line; + bit_detect_sample_count_ = UINT8_C(0); + } + else + { + // no level change + if((bit_detect_sample_count_ == SWDM_SAMPLE_VALID_POS) && + (bit_detect_idle_count_ < SWDM_SAMPLE_IDLE_COUNT)) + { + // valid bit detected + uart(line); + } + + // idle detection + bit_detect_idle_count_ = (line ? (bit_detect_idle_count_ + UINT8_C(1)) : UINT8_C(0)); + + if(bit_detect_idle_count_ >= SWDM_SAMPLE_IDLE_COUNT) + { + // line is idle, reset uart + bit_detect_idle_count_ = SWDM_SAMPLE_IDLE_COUNT; + uart_state_ = rx_start_bit; + } + } + } + + if(++bit_detect_sample_count_ == SWDM_SAMPLE_PERIOD) + { + bit_detect_sample_count_ = UINT8_C(0); + } + } + +protected: + // Line (pin) access function to get the actual line / pin state + // This function MUST be defined somewhere in your project or in your derived class + // \return The actual state of the swdm line / pin: true = high (idle/recessive), false = low (active/dominant) + virtual bool get_line() const + { + return mcal::debug::debug_monitor_port_type::read_input_value(); + } + + + // Line (pin) access function to set the actual line / pin state + // This function MUST be defined somewhere in your project + // \param value The new state of the swdm line / pin: true = high (idle/recessive), false = low (active/dominant) + virtual void set_line(const bool value) const + { + if(value) + { + mcal::debug::debug_monitor_port_type::set_direction_input(); + } + else + { + mcal::debug::debug_monitor_port_type::set_direction_output(); + mcal::debug::debug_monitor_port_type::set_pin_low(); + } + } + +private: + // Software UART, called by the service routine, when a valid bit is received or when a bit should be transmitted + // \param bit The value of the received bit + void uart(const bool bit) + { + switch(uart_state_) + { + case rx_start_bit: + if((!bit)) + { + // start bit detected + uart_data_bit_count_ = UINT8_C(0); + uart_state_ = rx_data_bits; + } + break; + + case rx_data_bits: + // LSB is transmitted first + uart_buffer_ = static_cast(std::uint_fast8_t(uart_buffer_ >> UINT8_C(1)) | std::uint_fast8_t(bit ? UINT8_C(0x80) : UINT8_C(0x00))); + + if(++uart_data_bit_count_ >= UINT8_C(8)) + { + uart_state_ = rx_stop_bit; + } + + break; + + case rx_stop_bit: + uart_state_ = rx_start_bit; + + if(bit) + { + // valid byte received, if no stop bit is detected, it's a framing error, discard data + uart_rx_full(uart_buffer_); + } + else + { + // framing error, discard data + prot_state_ = rx_sync; // reset the protocol state, because a byte error decays the whole command + } + + break; + + case tx_start_bit: + // send start bit + set_line(false); + + uart_data_bit_count_ = UINT8_C(0); + uart_state_ = tx_data_bits; + + break; + + case tx_data_bits: + // send data bits, LSB is first + set_line((uart_buffer_ & UINT8_C(0x01)) != UINT8_C(0)); + uart_buffer_ >>= UINT8_C(1); + + if(++uart_data_bit_count_ >= UINT8_C(8)) + { + uart_state_ = tx_stop_bit; + } + + break; + + case tx_stop_bit: + // send stop bit + set_line(true); + + uart_state_ = rx_start_bit; + + // byte transmission complete, inform protocol (transmitter empty) + uart_tx_empty(); + + break; + + default: + break; + } + } + + + // UART transmit function + // \param data The character to send + void uart_send(const std::uint_fast8_t data) + { + uart_buffer_ = std::uint8_t(data); + uart_state_ = tx_start_bit; + } + + // This function is called by the (software) UART when the receiver is full + // \param data The received character + void uart_rx_full(const std::uint_fast8_t data) + { + switch(prot_state_) + { + case rx_sync: + if(data == request_sync_field) + { + prot_state_ = rx_mode; + } + + break; + + case rx_mode: + prot_mode_ = data; + prot_idx_ = UINT8_C(0); + prot_crc_ = UINT8_C(0); + prot_state_ = rx_addr; + + crc8(data); + + break; + + case rx_addr: + { + prot_addr_[prot_idx_++] = data; + crc8(data); + + const std::uint_fast8_t addr_width = (prot_mode_ & UINT8_C(0x30)) >> UINT8_C(4); + + if( ((addr_width == UINT8_C(0)) && (prot_idx_ == UINT8_C(2))) // 16 bit address + || ((addr_width == UINT8_C(1)) && (prot_idx_ == UINT8_C(3))) // 24 bit address + || ((addr_width == UINT8_C(2)) && (prot_idx_ == UINT8_C(4))) // 32 bit address + #if defined(SWDM_64_BIT_ADDRESS_SUPPORT) + || ((addr_width == UINT8_C(3)) && (prot_idx_ == UINT8_C(8))) // 64 bit address + #endif + ) + { + prot_idx_ = UINT8_C(0); + prot_state_ = (((prot_mode_ & UINT8_C(0x80)) != UINT8_C(0))? rx_data : rx_crc); + } + + break; + } + + case rx_data: + prot_data_[prot_idx_++] = data; + crc8(data); + + if(prot_idx_ > (prot_mode_ & UINT8_C(0x0F))) + { + prot_state_ = rx_crc; + } + + break; + + case rx_crc: + if(data == prot_crc_) + { + // CRC correct - execute request + request(); + + // send response + prot_state_ = tx_sync; + + // start the transmission + uart_tx_empty(); + } + else + { + // CRC error - discard command, wait for next rx sync byte + prot_state_ = rx_sync; + } + + break; + + default: + prot_state_ = rx_sync; + break; + + case tx_sync: + case tx_data: + case tx_crc: + break; + } + } + + // This function is called by the (software) UART when the transmitter is empty + void uart_tx_empty() + { + switch(prot_state_) + { + case tx_sync: + prot_idx_ = UINT8_C(0); + prot_crc_ = UINT8_C(0); + prot_state_ = (((prot_mode_ & UINT8_C(0x80)) != UINT8_C(0)) ? tx_crc : tx_data); // skip data on write command + + uart_send(response_sync_field); + + break; + + case tx_data: + uart_send(prot_data_[prot_idx_]); + crc8(prot_data_[prot_idx_]); + + if(++prot_idx_ >= ((prot_mode_ & UINT8_C(0x0F)) + UINT8_C(1))) + { + prot_state_ = tx_crc; + } + + break; + + case tx_crc: + uart_send(prot_crc_); + prot_state_ = rx_sync; + + break; + + default: + prot_state_ = rx_sync; + break; + + case rx_sync: + case rx_mode: + case rx_addr: + case rx_data: + case rx_crc: + break; + } + } + + // Process and execute the received request + void request() + { + // get address width + std::uint_fast8_t addr_width; + + switch((prot_mode_ & UINT32_C(0x30)) >> UINT8_C(4)) + { + case UINT8_C(0): addr_width = UINT8_C(2); break; // 16 bit address + case UINT8_C(1): addr_width = UINT8_C(3); break; // 24 bit address + + default : + case UINT8_C(2): addr_width = UINT8_C(4); break; // 32 bit address + + #if defined(SWDM_64_BIT_ADDRESS_SUPPORT) + case UINT8_C(3): addr_width = UINT8_C(8); break; // 64 bit address + #endif + } + + #if defined(SWDM_64_BIT_ADDRESS_SUPPORT) + std::uint64_t addr = UINT64_C(0); + #else + std::uint32_t addr = UINT32_C(0); + #endif + + // assemble address + for(std::uint_fast8_t i = UINT8_C(0); i < addr_width; ++i) + { + addr <<= UINT8_C(8); + addr |= prot_addr_[i]; + } + + // data length + const std::uint_fast8_t data_length = (prot_mode_ & UINT8_C(0x0F)) + UINT8_C(1); + + if((prot_mode_ & UINT8_C(0x80)) != UINT8_C(0)) + { + // write command + if(prot_mode_ & UINT8_C(0x40)) + { + // write type access + switch(data_length) + { + case 1U: + *reinterpret_cast(addr) = prot_data_[0U]; + break; + + case 2U: + { + const std::uint16_t value = + (static_cast(prot_data_[0U]) << UINT8_C(8)) + | (static_cast(prot_data_[1U])); + + *reinterpret_cast(addr) = value; + + break; + } + + case 4U: + { + const std::uint32_t value = + (static_cast(prot_data_[0U]) << UINT8_C(24)) + | (static_cast(prot_data_[1U]) << UINT8_C(16)) + | (static_cast(prot_data_[2U]) << UINT8_C( 8)) + | (static_cast(prot_data_[3U])); + + *reinterpret_cast(addr) = value; + + break; + } + + case 8U: + { + const std::uint64_t value = + (static_cast(prot_data_[0U]) << UINT8_C(56)) + | (static_cast(prot_data_[1U]) << UINT8_C(48)) + | (static_cast(prot_data_[2U]) << UINT8_C(40)) + | (static_cast(prot_data_[3U]) << UINT8_C(32)) + | (static_cast(prot_data_[4U]) << UINT8_C(24)) + | (static_cast(prot_data_[5U]) << UINT8_C(16)) + | (static_cast(prot_data_[6U]) << UINT8_C( 8)) + | (static_cast(prot_data_[7U])); + + *reinterpret_cast(addr) = value; + + break; + } + + default: + // invalid data type, use byte access + for(std::uint_fast8_t i = UINT8_C(0); i < data_length; i++) + { + *reinterpret_cast(addr++) = prot_data_[i]; + } + + break; + } + } + else + { + // write byte access + for(std::uint_fast8_t i = UINT8_C(0); i < data_length; i++) + { + *reinterpret_cast(addr++) = prot_data_[i]; + } + } + } + else + { + // read command + if((prot_mode_ & UINT8_C(0x40)) != UINT8_C(0)) + { + // read type access + switch(data_length) + { + case UINT8_C(1): + prot_data_[0U] = *reinterpret_cast(addr); + break; + + case UINT8_C(2): + { + std::uint16_t value = *reinterpret_cast(addr); + + for(std::int_fast8_t tries = UINT8_C(4); --tries && (value != *reinterpret_cast(addr)); value = *reinterpret_cast(addr)) + { + ; + } + + prot_data_[0U] = byte_part(value); // MSB + prot_data_[1U] = byte_part(value); // LSB + + break; + } + + case UINT8_C(4): + { + std::uint32_t value = *reinterpret_cast(addr); + + for(std::int_fast8_t tries = UINT8_C(4); --tries && (value != *reinterpret_cast(addr)); value = *reinterpret_cast(addr)) + { + ; + } + + prot_data_[0U] = byte_part(value); // MSB + prot_data_[1U] = byte_part(value); + prot_data_[2U] = byte_part(value); + prot_data_[3U] = byte_part(value); // LSB + + break; + } + + case UINT8_C(8): + { + std::uint64_t value = *reinterpret_cast(addr); + + for(std::int_fast8_t tries = UINT8_C(4); --tries && (value != *reinterpret_cast(addr)); value = *reinterpret_cast(addr)) + { + ; + } + + prot_data_[0U] = byte_part(value); // MSB + prot_data_[1U] = byte_part(value); + prot_data_[2U] = byte_part(value); + prot_data_[3U] = byte_part(value); + prot_data_[4U] = byte_part(value); + prot_data_[5U] = byte_part(value); + prot_data_[6U] = byte_part(value); + prot_data_[7U] = byte_part(value); // LSB + + break; + } + + default: + // invalid data type, use byte access + for(std::uint_fast8_t i = UINT8_C(0); i < data_length; i++) + { + prot_data_[i] = *reinterpret_cast(addr++); + } + + break; + } + } + else + { + // read byte access + for(std::uint_fast8_t i = UINT8_C(0); i < data_length; i++) + { + prot_data_[i] = *reinterpret_cast(addr++); + } + } + } + } + + //////////////////////////////////////////////////////////////////////// + // H E L P E R F U N C T I O N S + + // CRC-8 algorithm, using x^8 + x^2 + x + 1 polynomial + // Process data, CRC result is in prot_crc_ + // We use a shifter here instead of a table lookup to save code size, speed + // is not so important at the swdm baudrate of 250 baud. + // \param data Data to process + void crc8(std::uint_fast8_t data) + { + for(std::uint_fast8_t i = UINT8_C(8); i; i--) + { + const std::uint_fast8_t sum = (prot_crc_ ^ data) & UINT8_C(0x01); + + prot_crc_ >>= UINT8_C(1); + + if(sum != UINT8_C(0)) + { + prot_crc_ ^= UINT8_C(0x8C); + } + + data >>= UINT8_C(1); + } + } + + // Return the according byte of the given position + // \param Long Type of the value + // \param Position Byte position to return, 0 is LSB + // \param value The Long value + // \return The byte of the Long value at the given position + template + std::uint8_t byte_part(const LongType& value) const + { + return static_cast(value >> (Position * UINT8_C(8))); + } + +private: + static constexpr std::uint_fast8_t request_sync_field = UINT8_C(0x55); // Request sync field + static constexpr std::uint_fast8_t response_sync_field = UINT8_C(0xAA); // Response sync field + + typedef enum enum_state_type + { + rx_start_bit, + rx_data_bits, + rx_stop_bit, + tx_start_bit, + tx_data_bits, + tx_stop_bit + } + state_type; + + typedef enum enum_prot_state_type + { + rx_sync, + rx_mode, + rx_addr, + rx_data, + rx_crc, + tx_sync, + tx_data, + tx_crc + } + prot_state_type; + + state_type uart_state_; + std::uint_fast8_t uart_buffer_; + std::uint_fast8_t uart_data_bit_count_; + + prot_state_type prot_state_; + std::uint_fast8_t prot_mode_; + std::uint8_t prot_addr_[ 8U]; + std::uint8_t prot_data_[16U]; + std::uint_fast8_t prot_crc_; + std::uint_fast8_t prot_idx_; + + bool bit_detect_last_state_; + std::uint_fast8_t bit_detect_sample_count_; + std::uint_fast8_t bit_detect_idle_count_; +}; + +} // namespace util + +#endif // UTIL_SWDM_2016_04_11_H diff --git a/examples/chapter09_08a/src/util/utility/util_time.h b/examples/chapter09_08a/src/util/utility/util_time.h index 7f9653abb..4cbc605ac 100644 --- a/examples/chapter09_08a/src/util/utility/util_time.h +++ b/examples/chapter09_08a/src/util/utility/util_time.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2022. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,102 +8,119 @@ #ifndef UTIL_TIME_2010_04_10_H #define UTIL_TIME_2010_04_10_H - #include - #include - #include #include + #include + #include + namespace util { - template + template + struct default_timer_backend; + + template> + class timer; + + template + struct default_timer_backend + { + using tick_type = UnsignedTickType; + + constexpr static auto get_now() -> tick_type + { + return static_cast(mcal::gpt::secure::get_time_elapsed()); + } + }; + + template class timer { + private: + using backend_type = BackendType; + + public: + using tick_type = typename backend_type::tick_type; + private: static constexpr auto timer_mask = - static_cast + static_cast ( - (UINTMAX_C(1) << (std::numeric_limits::digits - 1)) - UINTMAX_C(1) + static_cast + ( + static_cast + ( + UINTMAX_C(1) << static_cast(std::numeric_limits::digits - 1) + ) + - UINTMAX_C(1) + ) ); public: - using tick_type = unsigned_tick_type; - template static constexpr auto microseconds(other_tick_type value_microseconds) noexcept -> tick_type { return static_cast(value_microseconds); } - template static constexpr auto milliseconds(other_tick_type value_milliseconds) noexcept -> tick_type { return static_cast(1000UL) * microseconds(value_milliseconds); } - template static constexpr auto seconds (other_tick_type value_seconds) noexcept -> tick_type { return static_cast(1000UL) * milliseconds(value_seconds ); } - template static constexpr auto minutes (other_tick_type value_minutes) noexcept -> tick_type { return static_cast( 60UL) * seconds (value_minutes ); } - template static constexpr auto hours (other_tick_type value_hours) noexcept -> tick_type { return static_cast( 60UL) * minutes (value_hours ); } - template static constexpr auto days (other_tick_type value_days) noexcept -> tick_type { return static_cast( 24UL) * hours (value_days ); } - template static constexpr auto weeks (other_tick_type value_weeks) noexcept -> tick_type { return static_cast( 7UL) * days (value_weeks ); } - - constexpr timer() noexcept = default; - - constexpr timer(tick_type tick_value) noexcept : my_tick(my_now() + tick_value) { } + template static constexpr auto milliseconds(other_tick_type value_milliseconds) noexcept -> tick_type { return static_cast(UINT16_C(1000)) * microseconds(value_milliseconds); } + template static constexpr auto seconds (other_tick_type value_seconds) noexcept -> tick_type { return static_cast(UINT16_C(1000)) * milliseconds(value_seconds ); } + template static constexpr auto minutes (other_tick_type value_minutes) noexcept -> tick_type { return static_cast(UINT16_C( 60)) * seconds (value_minutes ); } + template static constexpr auto hours (other_tick_type value_hours) noexcept -> tick_type { return static_cast(UINT16_C( 60)) * minutes (value_hours ); } + template static constexpr auto days (other_tick_type value_days) noexcept -> tick_type { return static_cast(UINT16_C( 24)) * hours (value_days ); } + template static constexpr auto weeks (other_tick_type value_weeks) noexcept -> tick_type { return static_cast(UINT16_C( 7)) * days (value_weeks ); } - constexpr timer(const timer& other) noexcept : my_tick(other.my_tick) { } + constexpr timer() = default; - constexpr timer(timer&& other) noexcept : my_tick(other.my_tick) { } + explicit constexpr timer(tick_type tick_value) : my_tick(my_now() + tick_value) { } - ~timer() noexcept = default; + constexpr timer(const timer& other) = default; - auto operator=(const timer& other) noexcept -> timer& - { - if(this != &other) - { - my_tick = other.my_tick; - } + constexpr timer(timer&& other) noexcept = default; - return *this; - } + ~timer() = default; - auto operator=(timer&& other) noexcept -> timer& - { - my_tick = other.my_tick; + constexpr auto operator=(const timer& other) -> timer& = default; - return *this; - } + constexpr auto operator=(timer&& other) noexcept -> timer& = default; - auto start_interval(const tick_type& tick_value) noexcept -> void + constexpr auto start_interval(const tick_type& tick_value) -> void { my_tick += tick_value; } - auto start_relative(const tick_type& tick_value) noexcept -> void + constexpr auto start_relative(const tick_type& tick_value) -> void { my_tick = my_now() + tick_value; } - constexpr auto timeout() const noexcept -> bool + constexpr auto timeout() const -> bool { return (static_cast(my_now() - my_tick) <= timer_mask); } - constexpr auto timeout_of_specific_timepoint(const tick_type timepoint) const noexcept -> bool + constexpr auto timeout_of_specific_timepoint(const tick_type timepoint) const -> bool { return (static_cast(timepoint - my_tick) <= timer_mask); } - auto set_mark() noexcept -> void + constexpr auto set_mark() -> void { return (my_tick = my_now()); } - static constexpr auto get_mark() noexcept -> tick_type + static constexpr auto get_mark() -> tick_type { return my_now(); } - constexpr auto get_ticks_since_mark() const noexcept -> tick_type + constexpr auto get_ticks_since_mark() const -> tick_type { return my_now() - my_tick; } - static auto blocking_delay(const tick_type& delay) noexcept -> void + static auto blocking_delay(const tick_type& delay) -> void { - const timer t_delay(delay); + const timer t_delay { delay }; // NOLINT(altera-id-dependent-backward-branch) - while(false == t_delay.timeout()) + while(!t_delay.timeout()) // NOLINT(altera-id-dependent-backward-branch) { mcal::wdg::secure::trigger(); } @@ -112,17 +129,17 @@ private: tick_type my_tick { my_now() }; - constexpr static auto my_now() noexcept -> tick_type + static constexpr auto my_now() -> tick_type { - return static_cast(mcal::gpt::secure::get_time_elapsed()); + return static_cast(backend_type::get_now()); } - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the timer tick_type must be unsigned"); static_assert(std::numeric_limits::digits <= std::numeric_limits::digits, "The width of the timer tick_type can not exceed the width of mcal::gpt::value_type"); }; - } + } // namespace util #endif // UTIL_TIME_2010_04_10_H diff --git a/examples/chapter09_08a/src/util/utility/util_two_part_data_manipulation.h b/examples/chapter09_08a/src/util/utility/util_two_part_data_manipulation.h index 7375d0cd7..282b5e6e6 100644 --- a/examples/chapter09_08a/src/util/utility/util_two_part_data_manipulation.h +++ b/examples/chapter09_08a/src/util/utility/util_two_part_data_manipulation.h @@ -1,28 +1,29 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2021. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H_ - #define UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H_ +#ifndef UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H + #define UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H - #include #include + #include + namespace util { template(std::numeric_limits::digits * 2)>::exact_type> - inline unsigned_long_type make_long(unsigned_short_type lo, unsigned_short_type hi) + inline constexpr auto make_long(unsigned_short_type lo, unsigned_short_type hi) -> unsigned_long_type { // Ensure that the unsigned_short_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_short_type of the make_long template must be an integer type"); // Ensure that the unsigned_long_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_long_type of the make_long template must be an integer type."); // Ensure that the unsigned_long_type has exactly twice the digits as the unsigned_short_type. @@ -30,11 +31,11 @@ "the unsigned_long_type of the make_long template must be twice as wide as the unsigned_short_type"); // Ensure that the unsigned_short_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the unsigned_short_type of the make_long template must be unsigned"); // Ensure that the unsigned_long_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the unsigned_long_type of the make_long template must be unsigned."); return static_cast(static_cast(static_cast(hi) << std::numeric_limits::digits) | lo); @@ -42,14 +43,14 @@ template(std::numeric_limits::digits * 2)>::exact_type> - inline unsigned_short_type lo_part(unsigned_long_type val) + inline constexpr auto lo_part(unsigned_long_type val) -> unsigned_short_type { // Ensure that the unsigned_short_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_short_type of the make_long template must be an integer type"); // Ensure that the unsigned_long_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_long_type of the make_long template must be an integer type."); // Ensure that the unsigned_long_type has exactly twice the digits as the unsigned_short_type. @@ -57,11 +58,11 @@ "the unsigned_long_type of the lo_part template must be twice as wide as the unsigned_short_type"); // Ensure that the unsigned_short_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the unsigned_short_type of the lo_part template must be unsigned"); // Ensure that the unsigned_long_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the long type of the lo_part template must be unsigned"); return static_cast(val); @@ -69,14 +70,14 @@ template(std::numeric_limits::digits * 2)>::exact_type> - inline unsigned_short_type hi_part(unsigned_long_type val) + inline constexpr auto hi_part(unsigned_long_type val) -> unsigned_short_type { // Ensure that the unsigned_short_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_short_type of the make_long template must be an integer type"); // Ensure that the unsigned_long_type is an integer type. - static_assert(std::numeric_limits::is_integer == true, + static_assert(std::numeric_limits::is_integer, "the unsigned_long_type of the make_long template must be an integer type."); // Ensure that the unsigned_long_type has exactly twice the digits as the unsigned_short_type. @@ -84,15 +85,15 @@ "the unsigned_long_type of the hi_part template must be twice as wide as the unsigned_short_type"); // Ensure that the unsigned_short_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the unsigned_short_type of the hi_part template must be unsigned"); // Ensure that the unsigned_long_type is unsigned. - static_assert(std::numeric_limits::is_signed == false, + static_assert((!std::numeric_limits::is_signed), "the unsigned_long_type of the hi_part template must be unsigned"); return static_cast(val >> std::numeric_limits::digits); } } -#endif // UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H_ +#endif // UTIL_TWO_PART_DATA_MANIPULATION_2010_06_13_H diff --git a/examples/chapter09_08a/src/util/utility/util_utype_helper.h b/examples/chapter09_08a/src/util/utility/util_utype_helper.h index e3f12c792..e6040965a 100644 --- a/examples/chapter09_08a/src/util/utility/util_utype_helper.h +++ b/examples/chapter09_08a/src/util/utility/util_utype_helper.h @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2021. +// Copyright Christopher Kormanyos 2007 - 2024. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef UTIL_UTYPE_HELPER_2012_01_23_H_ - #define UTIL_UTYPE_HELPER_2012_01_23_H_ +#ifndef UTIL_UTYPE_HELPER_2012_01_23_H + #define UTIL_UTYPE_HELPER_2012_01_23_H #include @@ -17,44 +17,44 @@ static_assert(utype_bit_count <= 64U, "the bit count of the unsigned type can not exceed 64"); - typedef std::uint64_t exact_type; + using exact_type = std::uint64_t; }; - template<> struct utype_helper<0U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<1U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<2U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<3U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<4U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<5U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<6U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<7U> { typedef std::uint8_t exact_type; }; - template<> struct utype_helper<8U> { typedef std::uint8_t exact_type; }; - - template<> struct utype_helper<9U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<10U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<11U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<12U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<13U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<14U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<15U> { typedef std::uint16_t exact_type; }; - template<> struct utype_helper<16U> { typedef std::uint16_t exact_type; }; - - template<> struct utype_helper<17U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<18U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<19U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<20U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<21U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<22U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<23U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<24U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<25U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<26U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<27U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<28U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<29U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<30U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<31U> { typedef std::uint32_t exact_type; }; - template<> struct utype_helper<32U> { typedef std::uint32_t exact_type; }; + template<> struct utype_helper<0U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<1U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<2U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<3U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<4U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<5U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<6U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<7U> { using exact_type = std::uint8_t; }; + template<> struct utype_helper<8U> { using exact_type = std::uint8_t; }; + + template<> struct utype_helper<9U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<10U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<11U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<12U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<13U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<14U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<15U> { using exact_type = std::uint16_t; }; + template<> struct utype_helper<16U> { using exact_type = std::uint16_t; }; + + template<> struct utype_helper<17U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<18U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<19U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<20U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<21U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<22U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<23U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<24U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<25U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<26U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<27U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<28U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<29U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<30U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<31U> { using exact_type = std::uint32_t; }; + template<> struct utype_helper<32U> { using exact_type = std::uint32_t; }; } -#endif // UTIL_UTYPE_HELPER_2012_01_23_H_ +#endif // UTIL_UTYPE_HELPER_2012_01_23_H diff --git a/examples/chapter09_08a/target/app/make/app_files.gmk b/examples/chapter09_08a/target/app/make/app_files.gmk index 7f0253e42..af608bbb2 100644 --- a/examples/chapter09_08a/target/app/make/app_files.gmk +++ b/examples/chapter09_08a/target/app/make/app_files.gmk @@ -6,6 +6,7 @@ FILES_CPP = $(PATH_APP)/app/led/app_led \ $(PATH_APP)/mcal/mcal \ $(PATH_APP)/mcal/mcal_gcc_cxx_completion \ $(PATH_APP)/mcal/$(TGT)/mcal_cpu \ + $(PATH_APP)/mcal/$(TGT)/mcal_eep \ $(PATH_APP)/mcal/$(TGT)/mcal_gpt \ $(PATH_APP)/mcal/$(TGT)/mcal_irq \ $(PATH_APP)/mcal/$(TGT)/mcal_led \ @@ -14,9 +15,9 @@ FILES_CPP = $(PATH_APP)/app/led/app_led \ $(PATH_APP)/mcal/$(TGT)/mcal_osc \ $(PATH_APP)/mcal/$(TGT)/mcal_port \ $(PATH_APP)/mcal/$(TGT)/mcal_pwm \ + $(PATH_APP)/mcal/$(TGT)/mcal_spi \ $(PATH_APP)/mcal/$(TGT)/mcal_wdg \ $(PATH_APP)/os/os \ - $(PATH_APP)/os/os_task_control_block \ $(PATH_APP)/sys/idle/sys_idle \ $(PATH_APP)/sys/mon/sys_mon \ $(PATH_APP)/sys/start/sys_start diff --git a/examples/chapter12_04/chapter12_04.cppproj b/examples/chapter12_04/chapter12_04.cppproj index e7f78bcb0..eb24b1785 100644 --- a/examples/chapter12_04/chapter12_04.cppproj +++ b/examples/chapter12_04/chapter12_04.cppproj @@ -149,6 +149,10 @@ + + + + @@ -292,6 +296,42 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile @@ -313,6 +353,24 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile @@ -382,31 +440,49 @@ compile - + compile - + + compile + + compile compile + + compile + + + compile + compile + + compile + compile + + compile + compile - + compile - + compile - + + compile + + compile @@ -415,6 +491,9 @@ compile + + compile + compile diff --git a/examples/chapter12_04a/readme.md b/examples/chapter12_04a/readme.md index 288390737..6e30cc161 100644 --- a/examples/chapter12_04a/readme.md +++ b/examples/chapter12_04a/readme.md @@ -17,7 +17,7 @@ is used. In this particular example, we have simply used the commercially-available, open-platform [STM32F100 Value Line Discovery Kit](https://www.st.com/en/evaluation-tools/stm32vldiscovery.html) -placed on a breadboard with soldered-on pins. +directly out-of-the-box. The wiring is straightforward. The blinking LED uses the blue colored user LED controlled by pin `portc.8`. The benchmark toggle pin is `portb.9`. diff --git a/examples/readme.md b/examples/readme.md index 9eef5b1b3..453adf3c7 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -96,7 +96,7 @@ of the mathematical constant $\pi$ up to $100,001$ decimal digits. Example ![chapter10_09](https://github.com/ckormanyos/real-time-cpp/tree/master/examples/chapter10_09) $100,001$ Digits of Pi on Raspberry Pi(R).\ This advanced example ports the Pi Spigot calculation of $100,001$ decimal digits of $\pi$ -to the powerful Arm(R)-based Raspberry Pi(R) single-board computer. +to the powerful ARM(R)-based Raspberry Pi(R) single-board computer. Example ![chapter11_07](https://github.com/ckormanyos/real-time-cpp/tree/master/examples/chapter11_07) Preemptive Multitasking.\ This example makes straightforward use of preemptive multitasking scheduling with a blinky-style application that features a main task and a low-priority background task. @@ -106,7 +106,8 @@ This example performs a variety of floating-point calculations of selected speci Example ![chapter12_04a](https://github.com/ckormanyos/real-time-cpp/tree/master/examples/chapter12_04a) Benchmarking Floating-Point Calculations (variation 32-bit microcontroller).\ The same special functions and arguments are used as in Example Chapter12_04. In variation 12_04a, however, -the open-platform STM32F100 Value Line Discovery Kit placed on a breadboard is used. +the open-platform [STM32F100 Value Line Discovery Kit](https://www.st.com/en/evaluation-tools/stm32vldiscovery.html) +is used directly out-of-the-box. Example ![chapter16_08](https://github.com/ckormanyos/real-time-cpp/tree/master/examples/chapter16_08) Generating and displaying 128-bit Random Prime Numbers.\ This advanced example uses an extended integer class to create 128-bit unsigned prime integers with primality testing performed via Miller-Rabin. diff --git a/ref_app/src/mcal/avr/mcal_led.cpp b/ref_app/src/mcal/avr/mcal_led.cpp index 2f99688e9..d61c6277c 100644 --- a/ref_app/src/mcal/avr/mcal_led.cpp +++ b/ref_app/src/mcal/avr/mcal_led.cpp @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2024. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -8,7 +8,7 @@ #include #include -auto mcal::led::led0() -> mcal::led::led_base& +auto mcal::led::led0() -> led_base& { using led0_port_type = mcal::port::port_pin #include -auto mcal::led::led0() -> mcal::led::led_base& +auto mcal::led::led0() -> led_base& { static mcal::led::led_console local_led0; diff --git a/ref_app/src/mcal/host/mcal_port.h b/ref_app/src/mcal/host/mcal_port.h index 85a2d865c..bae7087fd 100644 --- a/ref_app/src/mcal/host/mcal_port.h +++ b/ref_app/src/mcal/host/mcal_port.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2007 - 2024. +// Copyright Christopher Kormanyos 2007 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/ref_app/src/mcal/host/mcal_wdg_watchdog.h b/ref_app/src/mcal/host/mcal_wdg_watchdog.h index d93c2eda2..f6310da5d 100644 --- a/ref_app/src/mcal/host/mcal_wdg_watchdog.h +++ b/ref_app/src/mcal/host/mcal_wdg_watchdog.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////// -// Copyright Christopher Kormanyos 2013 - 2023. +// Copyright Christopher Kormanyos 2013 - 2025. // Distributed under the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/ref_app/target/micros/stm32f100/make/stm32f100_flags.gmk b/ref_app/target/micros/stm32f100/make/stm32f100_flags.gmk index 6a459e0bc..803ec8c59 100644 --- a/ref_app/target/micros/stm32f100/make/stm32f100_flags.gmk +++ b/ref_app/target/micros/stm32f100/make/stm32f100_flags.gmk @@ -24,7 +24,7 @@ TGT_ALLFLAGS = -O2 \ -mno-unaligned-access \ -mno-long-calls -TGT_CFLAGS = -std=c99 \ +TGT_CFLAGS = -std=c11 \ -Wunsuffixed-float-constants \ $(TGT_ALLFLAGS)