diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/safe_numerics/example | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/safe_numerics/example')
37 files changed, 2447 insertions, 0 deletions
diff --git a/src/boost/libs/safe_numerics/example/CMakeLists.txt b/src/boost/libs/safe_numerics/example/CMakeLists.txt new file mode 100644 index 00000000..d00186e7 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/CMakeLists.txt @@ -0,0 +1,52 @@ +# CMake build control file for safe numerics Library Examples + +########################### +# examples + +message( STATUS "Runtimes are stored in ${CMAKE_CURRENT_BINARY_DIR}" ) + +set(run_examples_list + example1 + example2 + example3 + example4 + example5 + example6 + example7 + example8 + example10 + example11 + example13 + example14 + example15 + example18 + example19 + example20 + # example81 # requires console input + example82 + example83 + # example84 # requires console input + example92 + example93 +) + +foreach(test_name ${run_examples_list}) + test_run_pass(${test_name}) + set_target_properties(${test_name} PROPERTIES FOLDER "run test examples") +endforeach(test_name) + +# end examples targets +#################### + +########################### +# add misc files to IDE + +file(GLOB misc_files + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c" +) +add_custom_target(miscellaneous SOURCES ${misc_files}) +set_target_properties(miscellaneous PROPERTIES FOLDER "examples") + +# end headers in IDE +#################### diff --git a/src/boost/libs/safe_numerics/example/Jamfile.v2 b/src/boost/libs/safe_numerics/example/Jamfile.v2 new file mode 100644 index 00000000..321c3acd --- /dev/null +++ b/src/boost/libs/safe_numerics/example/Jamfile.v2 @@ -0,0 +1,31 @@ +# Boost.SafeNumerics Library test Jamfile +# +# Copyright (c) 2017 Robert Ramey +# +# 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 + +import testing ; + +run example1.cpp ; +run example11.cpp ; +run example2.cpp ; +run example3.cpp ; +run example4.cpp ; +run example5.cpp ; +run example6.cpp ; +run example7.cpp ; +run example8.cpp ; +compile-fail example81.cpp ; +# run example81.cpp ; # requires console input +run example82.cpp ; +run example83.cpp ; +# run example84.cpp ; # requires console input +run example10.cpp ; +run example11.cpp ; +run example13.cpp ; +run example15.cpp ; +run example92.cpp ; +run example93.cpp ; + diff --git a/src/boost/libs/safe_numerics/example/Motor.c b/src/boost/libs/safe_numerics/example/Motor.c new file mode 100644 index 00000000..cc9e91c5 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/Motor.c @@ -0,0 +1,179 @@ +// Demo program for stepper motor control with linear ramps +// Hardware: PIC18F252, L6219 +#include "18F252.h" + +// PIC18F252 SFRs +#byte TRISC = 0xf94 +#byte T3CON = 0xfb1 +#byte CCP2CON = 0xfba +#byte CCPR2L = 0xfbb +#byte CCPR2H = 0xfbc +#byte CCP1CON = 0xfbd +#byte CCPR1L = 0xfbe +#byte CCPR1H = 0xfbf +#byte T1CON = 0xfcd +#byte TMR1L = 0xfce +#byte TMR1H = 0xfcf +#bit TMR1ON = T1CON.0 + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 50000 +#define C_MIN 2500 + +// ramp state-machine states +#define ramp_idle 0 +#define ramp_up 1 +#define ramp_max 2 +#define ramp_down 3 +#define ramp_last 4 + +// Types: int8,int16,int32=8,16,32bit integers, unsigned by default +int8 ramp_sts=ramp_idle; +signed int16 motor_pos = 0; // absolute step number +signed int16 pos_inc=0; // motor_pos increment +int16 phase=0; // ccpPhase[phase_ix] +int8 phase_ix=0; // index to ccpPhase[] +int8 phase_inc; // phase_ix increment +int8 run_flg; // true while motor is running +int16 ccpr; // copy of CCPR1&2 +int16 c; // integer delay count +int16 step_no; // progress of move +int16 step_down; // start of down-ramp +int16 move; // total steps to move +int16 midpt; // midpoint of move +int32 c32; // 24.8 fixed point delay count +signed int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +int16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +// compiler-specific ISR declaration +#INT_CCP1 +void isr_motor_step() +{ // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value: add step delay count + switch (ramp_sts) + { + case ramp_up: // accel + if (step_no==midpt) + { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move)<<2)+1; + if (!(move & 1)) + { // even move: repeat last delay before decel + denom +=4; + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move-1) + { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom+=4; + c32 -= (c32<<1)/denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32+128)>>8; // round 24.8format->int16 + if (c <= C_MIN) + { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) + { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move)<<2)+5; + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + disable_interrupts(INT_CCP1); + run_flg = FALSE; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts!=ramp_idle) + { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + if (ramp_sts!=ramp_last) // else repeat last action: no step + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // set CCP action on next match + CCP2CON = phase >> 8; + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(short pos_new) +{ // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) // get direction & #steps + { + move = motor_pos-pos_new; + pos_inc = -1; + phase_inc = 0xff; + } + else if (pos_new != motor_pos) + { + move = pos_new-motor_pos; + pos_inc = 1; + phase_inc = 1; + } + else return; // already there + midpt = (move-1)>>1; + c = C0; + c32 = c<<8; // keep c in 24.8 fixed-point format for ramp calcs + step_no = 0; // step counter + denom = 1; // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = TRUE; + TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H,TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // sets action on match + CCP2CON = phase >> 8; + current_on(); // current in motor windings + enable_interrupts(INT_CCP1); + TMR1ON=1; // restart timer1; +} // motor_run() + + +void initialize() +{ + disable_interrupts(GLOBAL); + disable_interrupts(INT_CCP1); + disable_interrupts(INT_CCP2); + output_c(0); + set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + enable_interrupts(GLOBAL); +} // initialize() + +void main() +{ + initialize(); + while (1) + { // repeat 5 revs forward & back + motor_run(1000); + while (run_flg); + motor_run(0); + while (run_flg); + } +} // main() +// end of file motor.c diff --git a/src/boost/libs/safe_numerics/example/example1.cpp b/src/boost/libs/safe_numerics/example/example1.cpp new file mode 100644 index 00000000..2d2f67fd --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example1.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + std::cout << "example 1:"; + std::cout << "undetected erroneous expression evaluation" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + try{ + std::int8_t x = 127; + std::int8_t y = 2; + std::int8_t z; + // this produces an invalid result ! + z = x + y; + std::cout << "error NOT detected!" << std::endl; + std::cout << (int)z << " != " << (int)x << " + " << (int)y << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + // solution: replace int with safe<int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<std::int8_t> x = INT_MAX; + safe<std::int8_t> y = 2; + safe<std::int8_t> z; + // rather than producing an invalid result an exception is thrown + z = x + y; + } + catch(const std::exception & e){ + // which we can catch here + std::cout << "error detected:" << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example10.cpp b/src/boost/libs/safe_numerics/example/example10.cpp new file mode 100644 index 00000000..f6796974 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example10.cpp @@ -0,0 +1,45 @@ +#include <iostream> +#include <cstdint> + +#include <boost/safe_numerics/safe_integer.hpp> + +using namespace std; +using namespace boost::safe_numerics; + +void f(const unsigned int & x, const int8_t & y){ + cout << x * y << endl; +} +void safe_f( + const safe<unsigned int> & x, + const safe<int8_t> & y +){ + cout << x * y << endl; +} + +int main(){ + cout << "example 4: "; + cout << "mixing types produces surprising results" << endl; + try { + std::cout << "Not using safe numerics" << std::endl; + // problem: mixing types produces surprising results. + f(100, 100); // works as expected + f(100, -100); // wrong result - unnoticed + cout << "error NOT detected!" << endl;; + } + catch(const std::exception & e){ + // never arrive here + cout << "error detected:" << e.what() << endl;; + } + try { + // solution: use safe types + std::cout << "Using safe numerics" << std::endl; + safe_f(100, 100); // works as expected + safe_f(100, -100); // throw error + cout << "error NOT detected!" << endl;; + } + catch(const std::exception & e){ + cout << "error detected:" << e.what() << endl;; + } + return 0; +} + diff --git a/src/boost/libs/safe_numerics/example/example11.cpp b/src/boost/libs/safe_numerics/example/example11.cpp new file mode 100644 index 00000000..51c17f05 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example11.cpp @@ -0,0 +1,42 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char * []){ + std::cout << "example 1:"; + std::cout << "undetected erroneous expression evaluation" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + // problem: arithmetic operations can yield incorrect results. + try{ + std::int8_t x = 127; + std::int8_t y = 2; + std::int8_t z; + // this produces an invalid result ! + z = x + y; + std::cout << z << " != " << x + y << std::endl; + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + // solution: replace std::int8_t with safe<std::int8_t> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<std::int8_t> x = 127; + safe<std::int8_t> y = 2; + // rather than producing and invalid result an exception is thrown + safe<std::int8_t> z = x + y; + } + catch(const std::exception & e){ + // which can catch here + std::cout << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example13.cpp b/src/boost/libs/safe_numerics/example/example13.cpp new file mode 100644 index 00000000..f78c6dc5 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example13.cpp @@ -0,0 +1,36 @@ +#include <stdexcept> +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + // problem: cannot recover from arithmetic errors + std::cout << "example 7: "; + std::cout << "cannot recover from arithmetic errors" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + + try{ + int x = 1; + int y = 0; + // can't do this as it will crash the program with no + // opportunity for recovery - comment out for example + // std::cout << x / y; + std::cout << "error cannot be handled at runtime!" << std::endl; + } + catch(const std::exception &){ + std::cout << "error handled at runtime!" << std::endl; + } + // solution: replace int with safe<int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + const safe<int> x = 1; + const safe<int> y = 0; + std::cout << x / y; + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception & e){ + std::cout << "error handled at runtime!" << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example14.cpp b/src/boost/libs/safe_numerics/example/example14.cpp new file mode 100644 index 00000000..44a206d2 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example14.cpp @@ -0,0 +1,37 @@ +#include <stdexcept> +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + // problem: cannot recover from arithmetic errors + std::cout << "example 8: "; + std::cout << "cannot detect compile time arithmetic errors" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + + try{ + const int x = 1; + const int y = 0; + // will emit warning at compile time + // will leave an invalid result at runtime. + std::cout << x / y; // will display "0"! + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + // solution: replace int with safe<int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + const safe<int> x = 1; + const safe<int> y = 0; + // constexpr const safe<int> z = x / y; // note constexpr here! + std::cout << x / y; // error would be detected at runtime + std::cout << " error NOT detected!" << std::endl; + } + catch(const std::exception & e){ + std::cout << "error detected:" << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example15.cpp b/src/boost/libs/safe_numerics/example/example15.cpp new file mode 100644 index 00000000..829dff29 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example15.cpp @@ -0,0 +1,45 @@ +#include <iostream> +#include <limits> + +#include <boost/rational.hpp> +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + // simple demo of rational library + const boost::rational<int> r {1, 2}; + std::cout << "r = " << r << std::endl; + const boost::rational<int> q {-2, 4}; + std::cout << "q = " << q << std::endl; + // display the product + std::cout << "r * q = " << r * q << std::endl; + + // problem: rational doesn't handle integer overflow well + const boost::rational<int> c {1, INT_MAX}; + std::cout << "c = " << c << std::endl; + const boost::rational<int> d {1, 2}; + std::cout << "d = " << d << std::endl; + // display the product - wrong answer + std::cout << "c * d = " << c * d << std::endl; + + // solution: use safe integer in rational definition + using safe_rational = boost::rational< + boost::safe_numerics::safe<int> + >; + + // use rationals created with safe_t + const safe_rational sc {1, INT_MAX}; + std::cout << "c = " << sc << std::endl; + const safe_rational sd {1, 2}; + std::cout << "d = " << sd << std::endl; + std::cout << "c * d = "; + try { + // multiply them. This will overflow + std::cout << sc * sd << std::endl; + } + catch (std::exception const& e) { + // catch exception due to multiplication overflow + std::cout << e.what() << std::endl; + } + + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example16.cpp b/src/boost/libs/safe_numerics/example/example16.cpp new file mode 100644 index 00000000..d6782452 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example16.cpp @@ -0,0 +1,16 @@ +#include <boost/safe_numerics/safe_integer.hpp> +using namespace boost::safe_numerics; + +int f(int i){ + return i; +} + +using safe_t = safe<long>; + +int main(){ + const long x = 97; + f(x); // OK - implicit conversion to int + const safe_t y = 97; + f(y); // Also OK - checked implicit conversion to int + return 0; +}
\ No newline at end of file diff --git a/src/boost/libs/safe_numerics/example/example17.cpp b/src/boost/libs/safe_numerics/example/example17.cpp new file mode 100644 index 00000000..372be9cc --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example17.cpp @@ -0,0 +1,16 @@ +#include <boost/safe_numerics/safe_integer.hpp> +using namespace boost::safe_numerics; + +int f(int i){ + return i; +} + +using safe_t = safe<long, native, loose_trap_policy>; + +int main(){ + const long x = 97; + f(x); // OK - implicit conversion to int + const safe_t y = 97; + f(y); // Would be OK, but will invoke compile time error + return 0; +}
\ No newline at end of file diff --git a/src/boost/libs/safe_numerics/example/example18.cpp b/src/boost/libs/safe_numerics/example/example18.cpp new file mode 100644 index 00000000..bb59602e --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example18.cpp @@ -0,0 +1,19 @@ +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/safe_integer_literal.hpp> + +using namespace boost::safe_numerics; + +int f(int i){ + return i; +} + +template<intmax_t N> +using safe_literal = safe_signed_literal<N, native, loose_trap_policy>; + +int main(){ + const long x = 97; + f(x); // OK - implicit conversion to int + const safe_literal<97> y; + f(y); // OK - y is a type with min/max = 97; + return 0; +}
\ No newline at end of file diff --git a/src/boost/libs/safe_numerics/example/example19.cpp b/src/boost/libs/safe_numerics/example/example19.cpp new file mode 100644 index 00000000..e9cd4648 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example19.cpp @@ -0,0 +1,32 @@ +#include <type_traits> +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/safe_integer_range.hpp> + +#include <boost/safe_numerics/utility.hpp> + +using namespace boost::safe_numerics; + +void f(){ + safe_unsigned_range<7, 24> i; + // since the range is included in [0,255], the underlying type of i + // will be an unsigned char. + i = 0; // throws out_of_range exception + i = 9; // ok + i *= 9; // throws out_of_range exception + i = -1; // throws out_of_range exception + std::uint8_t j = 4; + auto k = i + j; + + // if either or both types are safe types, the result is a safe type + // determined by promotion policy. In this instance + // the range of i is [7, 24] and the range of j is [0,255]. + // so the type of k will be a safe type with a range of [7,279] + static_assert( + is_safe<decltype(k)>::value + && std::numeric_limits<decltype(k)>::min() == 7 + && std::numeric_limits<decltype(k)>::max() == 279, + "k is a safe range of [7,279]" + ); +} + +int main(){} diff --git a/src/boost/libs/safe_numerics/example/example2.cpp b/src/boost/libs/safe_numerics/example/example2.cpp new file mode 100644 index 00000000..3866fe85 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example2.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + std::cout << "example 2:"; + std::cout << "undetected overflow in data type" << std::endl; + // problem: undetected overflow + std::cout << "Not using safe numerics" << std::endl; + try{ + int x = INT_MAX; + // the following silently produces an incorrect result + ++x; + std::cout << x << " != " << INT_MAX << " + 1" << std::endl; + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + // solution: replace int with safe<int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<int> x = INT_MAX; + // throws exception when result is past maximum possible + ++x; + assert(false); // never arrive here + } + catch(const std::exception & e){ + std::cout << e.what() << std::endl; + std::cout << "error detected!" << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example20.cpp b/src/boost/libs/safe_numerics/example/example20.cpp new file mode 100644 index 00000000..160995d0 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example20.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/checked_result.hpp> +#include <boost/safe_numerics/checked_result_operations.hpp> + +int main(){ + using ext_uint = boost::safe_numerics::checked_result<unsigned int>; + const ext_uint x{4}; + const ext_uint y{3}; + + // operation is a success! + std::cout << "success! x - y = " << x - y; + + // subtraction would result in -1, and invalid result for an unsigned value + std::cout << "problem: y - x = " << y - x; + + const ext_uint z = y - x; + std::cout << "z = " << z; + // sum of two negative overflows is a negative overflow. + std::cout << "z + z" << z + z; + + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example3.cpp b/src/boost/libs/safe_numerics/example/example3.cpp new file mode 100644 index 00000000..15b810eb --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example3.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + std::cout << "example 3:"; + std::cout << "undetected underflow in data type" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + // problem: decrement can yield incorrect result + try{ + unsigned int x = 0; + // the following silently produces an incorrect result + --x; + std::cout << x << " != " << -1 << std::endl; + + // when comparing int and unsigned int, C++ converts + // the int to unsigned int so the following assertion + // fails to detect the above error! + assert(x == -1); + + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + // never arrive here + std::cout << "error detected!" << std::endl; + } + // solution: replace unsigned int with safe<unsigned int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<unsigned int> x = 0; + // decrement unsigned to less than zero throws exception + --x; + assert(false); // never arrive here + } + catch(const std::exception & e){ + std::cout << e.what() << std::endl; + std::cout << "error detected!" << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example4.cpp b/src/boost/libs/safe_numerics/example/example4.cpp new file mode 100644 index 00000000..d3b8eae7 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example4.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2018Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(){ + std::cout << "example 4: "; + std::cout << "implicit conversions change data values" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + + // problem: implicit conversions change data values + try{ + signed int a{-1}; + unsigned int b{1}; + std::cout << "a is " << a << " b is " << b << '\n'; + if(a < b){ + std::cout << "a is less than b\n"; + } + else{ + std::cout << "b is less than a\n"; + } + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + // never arrive here - just produce the wrong answer! + std::cout << "error detected!" << std::endl; + return 1; + } + + // solution: replace int with safe<int> and unsigned int with safe<unsigned int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<signed int> a{-1}; + safe<unsigned int> b{1}; + std::cout << "a is " << a << " b is " << b << '\n'; + if(a < b){ + std::cout << "a is less than b\n"; + } + else{ + std::cout << "b is less than a\n"; + } + std::cout << "error NOT detected!" << std::endl; + return 1; + } + catch(const std::exception & e){ + // never arrive here - just produce the correct answer! + std::cout << e.what() << std::endl; + std::cout << "error detected!" << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example5.cpp b/src/boost/libs/safe_numerics/example/example5.cpp new file mode 100644 index 00000000..efb3d2ea --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example5.cpp @@ -0,0 +1,39 @@ +#include <stdexcept> +#include <iostream> +#include <array> + +#include <boost/safe_numerics/safe_integer_range.hpp> + +void detected_msg(bool detected){ + std::cout << (detected ? "error detected!" : "error NOT detected! ") << std::endl; +} + +int main(int, const char *[]){ + // problem: array index values can exceed array bounds + std::cout << "example 5: "; + std::cout << "array index values can exceed array bounds" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + std::array<int, 37> i_array; + + // unsigned int i_index = 43; + // the following corrupts memory. + // This may or may not be detected at run time. + // i_array[i_index] = 84; // comment this out so it can be tested! + std::cout << "error NOT detected!" << std::endl; + + // solution: replace unsigned array index with safe_unsigned_range + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + using i_index_t = safe_unsigned_range<0, i_array.size() - 1>; + i_index_t i_index; + i_index = 36; // this works fine + i_array[i_index] = 84; + i_index = 43; // throw exception here! + std::cout << "error NOT detected!" << std::endl; // so we never arrive here + } + catch(const std::exception & e){ + std::cout << "error detected:" << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example6.cpp b/src/boost/libs/safe_numerics/example/example6.cpp new file mode 100644 index 00000000..fbd44a8e --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example6.cpp @@ -0,0 +1,41 @@ +#include <stdexcept> +#include <sstream> +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + // problem: checking of externally produced value can be overlooked + std::cout << "example 6: "; + std::cout << "checking of externally produced value can be overlooked" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + + std::istringstream is("12317289372189 1231287389217389217893"); + + try{ + int x, y; + is >> x >> y; // get integer values from the user + std::cout << x << ' ' << y << std::endl; + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + + // solution: assign externally retrieved values to safe equivalents + std::cout << "Using safe numerics" << std::endl; + { + using namespace boost::safe_numerics; + safe<int> x, y; + is.seekg(0); + try{ + is >> x >> y; // get integer values from the user + std::cout << x << ' ' << y << std::endl; + std::cout << "error NOT detected!" << std::endl; + } + catch(const std::exception & e){ + std::cout << "error detected:" << e.what() << std::endl; + } + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example7.cpp b/src/boost/libs/safe_numerics/example/example7.cpp new file mode 100644 index 00000000..076abfd8 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example7.cpp @@ -0,0 +1,84 @@ +#include <cassert> +#include <stdexcept> +#include <sstream> +#include <iostream> + +#include <boost/safe_numerics/safe_integer_range.hpp> + +// NOT using safe numerics - enforce program contract explicitly +// return total number of minutes +unsigned int contract_convert( + const unsigned int & hours, + const unsigned int & minutes +) { + // check that parameters are within required limits + // invokes a runtime cost EVERYTIME the function is called + // and the overhead of supporting an interrupt. + // note high runtime cost! + if(minutes > 59) + throw std::domain_error("minutes exceeded 59"); + if(hours > 23) + throw std::domain_error("hours exceeded 23"); + return hours * 60 + minutes; +} + +// Use safe numerics to enforce program contract automatically +// define convenient typenames for hours and minutes hh:mm +using hours_t = boost::safe_numerics::safe_unsigned_range<0, 23>; +using minutes_t = boost::safe_numerics::safe_unsigned_range<0, 59>; +using minutes_total_t = boost::safe_numerics::safe_unsigned_range<0, 59>; + +// return total number of minutes +// type returned is safe_unsigned_range<0, 24*60 - 1> +auto convert(const hours_t & hours, const minutes_t & minutes) { + // no need to test pre-conditions + // input parameters are guaranteed to hold legitimate values + // no need to test post-conditions + // return value guaranteed to hold result + return hours * 60 + minutes; +} + +unsigned int test1(unsigned int hours, unsigned int minutes){ + // problem: checking of externally produced value can be expensive + // invalid parameters - detected - but at a heavy cost + return contract_convert(hours, minutes); +} + +auto test2(unsigned int hours, unsigned int minutes){ + // solution: use safe numerics + // safe types can be implicitly constructed base types + // construction guarentees corectness + // return value is known to fit in unsigned int + return convert(hours, minutes); +} + +auto test3(unsigned int hours, unsigned int minutes){ + // actually we don't even need the convert function any more + return hours_t(hours) * 60 + minutes_t(minutes); +} + +int main(int, const char *[]){ + std::cout << "example 7: "; + std::cout << "enforce contracts with zero runtime cost" << std::endl; + + unsigned int total_minutes; + + try { + total_minutes = test3(17, 83); + std::cout << "total minutes = " << total_minutes << std::endl; + } + catch(const std::exception & e){ + std::cout << "parameter error detected" << std::endl; + } + + try { + total_minutes = test3(17, 10); + std::cout << "total minutes = " << total_minutes << std::endl; + } + catch(const std::exception & e){ + // should never arrive here + std::cout << "parameter error erroneously detected" << std::endl; + return 1; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example8.cpp b/src/boost/libs/safe_numerics/example/example8.cpp new file mode 100644 index 00000000..a8229f19 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example8.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2018 Robert Ramey +// +// 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 <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> + +int main(int, const char *[]){ + std::cout << "example 8:"; + std::cout << "undetected erroneous expression evaluation" << std::endl; + std::cout << "Not using safe numerics" << std::endl; + try{ + unsigned int x = 127; + unsigned int y = 2; + unsigned int z; + // this produces an invalid result ! + z = y - x; + std::cout << "error NOT detected!" << std::endl; + std::cout << z << " != " << y << " - " << x << std::endl; + } + catch(const std::exception &){ + std::cout << "error detected!" << std::endl; + } + // solution: replace int with safe<int> + std::cout << "Using safe numerics" << std::endl; + try{ + using namespace boost::safe_numerics; + safe<unsigned int> x = 127; + safe<unsigned int> y = 2; + safe<unsigned int> z; + // rather than producing an invalid result an exception is thrown + z = y - x; + std::cout << "error NOT detected!" << std::endl; + std::cout << z << " != " << y << " - " << x << std::endl; + } + catch(const std::exception & e){ + // which we can catch here + std::cout << "error detected:" << e.what() << std::endl; + } + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example81.cpp b/src/boost/libs/safe_numerics/example/example81.cpp new file mode 100644 index 00000000..5c7fc236 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example81.cpp @@ -0,0 +1,18 @@ +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/exception_policies.hpp> // include exception policies + +using safe_t = boost::safe_numerics::safe< + int, + boost::safe_numerics::native, + boost::safe_numerics::loose_trap_policy // note use of "loose_trap_exception" policy! +>; + +int main(int argc, const char * argv[]){ + std::cout << "example 81:\n"; + safe_t x(INT_MAX); + safe_t y(2); + safe_t z = x + y; // will fail to compile ! + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example82.cpp b/src/boost/libs/safe_numerics/example/example82.cpp new file mode 100644 index 00000000..0e49e9e7 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example82.cpp @@ -0,0 +1,23 @@ +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/exception_policies.hpp> +#include <boost/safe_numerics/automatic.hpp> +#include "safe_format.hpp" // prints out range and value of any type + +using safe_t = boost::safe_numerics::safe< + int, + boost::safe_numerics::automatic, // note use of "automatic" policy!!! + boost::safe_numerics::loose_trap_policy +>; + +int main(int, const char *[]){ + std::cout << "example 82:\n"; + safe_t x(INT_MAX); + safe_t y = 2; + std::cout << "x = " << safe_format(x) << std::endl; + std::cout << "y = " << safe_format(y) << std::endl; + std::cout << "x + y = " << safe_format(x + y) << std::endl; + return 0; +} + diff --git a/src/boost/libs/safe_numerics/example/example83.cpp b/src/boost/libs/safe_numerics/example/example83.cpp new file mode 100644 index 00000000..3d345b62 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example83.cpp @@ -0,0 +1,37 @@ +#include <iostream> + +#include <boost/safe_numerics/safe_integer_range.hpp> +#include <boost/safe_numerics/safe_integer_literal.hpp> +#include <boost/safe_numerics/exception.hpp> +#include <boost/safe_numerics/native.hpp> +#include "safe_format.hpp" // prints out range and value of any type + +using namespace boost::safe_numerics; + +// create a type for holding small integers in a specific range +using safe_t = safe_signed_range< + -24, + 82, + native, // C++ type promotion rules work OK for this example + loose_trap_policy // catch problems at compile time +>; + +// create a type to hold one specific value +template<int I> +using const_safe_t = safe_signed_literal<I, native, loose_trap_policy>; + +// We "know" that C++ type promotion rules will work such that +// addition will never overflow. If we change the program to break this, +// the usage of the loose_trap_policy promotion policy will prevent compilation. +int main(int, const char *[]){ + std::cout << "example 83:\n"; + + constexpr const const_safe_t<10> x; + std::cout << "x = " << safe_format(x) << std::endl; + constexpr const const_safe_t<67> y; + std::cout << "y = " << safe_format(y) << std::endl; + const safe_t z = x + y; + std::cout << "x + y = " << safe_format(x + y) << std::endl; + std::cout << "z = " << safe_format(z) << std::endl; + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example84.cpp b/src/boost/libs/safe_numerics/example/example84.cpp new file mode 100644 index 00000000..68285af2 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example84.cpp @@ -0,0 +1,53 @@ +#include <stdexcept> +#include <iostream> + +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/safe_integer_range.hpp> +#include <boost/safe_numerics/automatic.hpp> +#include <boost/safe_numerics/exception.hpp> + +#include "safe_format.hpp" // prints out range and value of any type + +using namespace boost::safe_numerics; + +using safe_t = safe_signed_range< + -24, + 82, + automatic, + loose_trap_policy +>; + +// define variables used for input +using input_safe_t = safe_signed_range< + -24, + 82, + automatic, // we don't need automatic in this case + loose_exception_policy // assignment of out of range value should throw +>; + +// function arguments can never be outside of limits +auto f(const safe_t & x, const safe_t & y){ + auto z = x + y; // we know that this cannot fail + std::cout << "z = " << safe_format(z) << std::endl; + std::cout << "(x + y) = " << safe_format(x + y) << std::endl; + std::cout << "(x - y) = " << safe_format(x - y) << std::endl; + return z; +} + +int main(int argc, const char * argv[]){ + std::cout << "example 84:\n"; + input_safe_t x, y; + try{ + std::cout << "type in values in format x y:" << std::flush; + std::cin >> x >> y; // read varibles, maybe throw exception + } + catch(const std::exception & e){ + // none of the above should trap. Mark failure if they do + std::cout << e.what() << std::endl; + return 1; + } + std::cout << "x" << safe_format(x) << std::endl; + std::cout << "y" << safe_format(y) << std::endl; + std::cout << safe_format(f(x, y)) << std::endl; + return 0; +} diff --git a/src/boost/libs/safe_numerics/example/example91.cpp b/src/boost/libs/safe_numerics/example/example91.cpp new file mode 100644 index 00000000..f3bc4872 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example91.cpp @@ -0,0 +1,90 @@ +////////////////////////////////////////////////////////////////// +// example91.cpp +// +// Copyright (c) 2015 Robert Ramey +// +// 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 <iostream> +#include <limits> + +#include <boost/safe_numerics/cpp.hpp> +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics//safe_integer_range.hpp> + +// use same type promotion as used by the pic compiler +// see the following comment in motor.c +// Types: int8,int16,int32=8,16,32bit integers + +using pic16_promotion = boost::safe_numerics::cpp< + 8, // char + 8, // short + 8, // int + 16, // long + 32 // long long +>; + +// define safe types used desktop version of the program. In conjunction +// with the promotion policy above, this will permit us to guarantee that +// the resulting program will be free of arithmetic errors introduced by +// C expression syntax and type promotion with no runtime penalty +template <typename T> // T is char, int, etc data type +using safe_t = boost::safe_numerics::safe< + T, + pic16_promotion, + boost::safe_numerics::default_exception_policy // use for compiling and running tests +>; +using safe_bool_t = boost::safe_numerics::safe_unsigned_range< + 0, + 1, + pic16_promotion, + boost::safe_numerics::default_exception_policy // use for compiling and running tests +>; + +#define DESKTOP +#include "motor1.c" + +#include <chrono> +#include <thread> + +void sleep(int16){ + std::this_thread::sleep_for(std::chrono::microseconds(ccpr)); +} + +int main(){ + std::cout << "start test\n"; + try{ + initialize(); + motor_run(100); + do{ + isr_motor_step(); + }while (run_flg); + + // move motor to position 1000 + motor_run(1000); + do{ + sleep(ccpr); + isr_motor_step(); + }while (run_flg); + + // move back to position 0 + motor_run(0); + do{ + sleep(ccpr); + isr_motor_step(); + }while (run_flg); + } + catch(std::exception & e){ + std::cout << e.what() << '\n'; + // we expect to trap an exception + return 0; + } + catch(...){ + std::cout << "test interrupted\n"; + return 1; + } + std::cout << "end test\n"; + return 1; +} diff --git a/src/boost/libs/safe_numerics/example/example92.cpp b/src/boost/libs/safe_numerics/example/example92.cpp new file mode 100644 index 00000000..cec7928f --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example92.cpp @@ -0,0 +1,207 @@ +////////////////////////////////////////////////////////////////// +// example92.cpp +// +// Copyright (c) 2015 Robert Ramey +// +// 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 <iostream> + +// *************************** +// 1. include headers to support safe integers +#include <boost/safe_numerics/cpp.hpp> +#include <boost/safe_numerics/exception.hpp> +#include <boost/safe_numerics/safe_integer.hpp> + +// *************************** +// 2. specify a promotion policy to support proper emulation of +// PIC types on the desktop +using pic16_promotion = boost::safe_numerics::cpp< + 8, // char 8 bits + 16, // short 16 bits + 16, // int 16 bits + 16, // long 16 bits + 32 // long long 32 bits +>; + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 (50000 << 8) +#define C_MIN (2500 << 8) + +static_assert(C0 < 0xffffff, "Largest step too long"); +static_assert(C_MIN > 0, "Smallest step must be greater than zero"); +static_assert(C_MIN < C0, "Smallest step must be smaller than largest step"); + +// *************************** +// 3. define PIC integer type names to be safe integer types of he same size. + +template <typename T> // T is char, int, etc data type +using safe_t = boost::safe_numerics::safe< + T, + pic16_promotion +>; + +// alias original program's integer types to corresponding PIC safe types +// In conjunction with the promotion policy above, this will permit us to +// guarantee that the resulting program will be free of arithmetic errors +// introduced by C expression syntax and type promotion with no runtime penalty + +typedef safe_t<int8_t> int8; +typedef safe_t<int16_t> int16; +typedef safe_t<int32_t> int32; +typedef safe_t<uint8_t> uint8; +typedef safe_t<uint16_t> uint16; +typedef safe_t<uint32_t> uint32; + +// *************************** +// 4. emulate PIC features on the desktop + +// filter out special keyword used only by XC8 compiler +#define __interrupt +// filter out XC8 enable/disable global interrupts +#define ei() +#define di() + +// emulate PIC special registers +uint8 RCON; +uint8 INTCON; +uint8 CCP1IE; +uint8 CCP2IE; +uint8 PORTC; +uint8 TRISC; +uint8 T3CON; +uint8 T1CON; + +uint8 CCPR2H; +uint8 CCPR2L; +uint8 CCPR1H; +uint8 CCPR1L; +uint8 CCP1CON; +uint8 CCP2CON; +uint8 TMR1H; +uint8 TMR1L; + +// create type used to map PIC bit names to +// correct bit in PIC register +template<typename T, std::int8_t N> +struct bit { + T & m_word; + constexpr explicit bit(T & rhs) : + m_word(rhs) + {} + constexpr bit & operator=(int b){ + if(b != 0) + m_word |= (1 << N); + else + m_word &= ~(1 << N); + return *this; + } + constexpr operator int () const { + return m_word >> N & 1; + } +}; + +// define bits for T1CON register +struct { + bit<uint8, 7> RD16{T1CON}; + bit<uint8, 5> T1CKPS1{T1CON}; + bit<uint8, 4> T1CKPS0{T1CON}; + bit<uint8, 3> T1OSCEN{T1CON}; + bit<uint8, 2> T1SYNC{T1CON}; + bit<uint8, 1> TMR1CS{T1CON}; + bit<uint8, 0> TMR1ON{T1CON}; +} T1CONbits; + +// define bits for T1CON register +struct { + bit<uint8, 7> GEI{INTCON}; + bit<uint8, 5> PEIE{INTCON}; + bit<uint8, 4> TMR0IE{INTCON}; + bit<uint8, 3> RBIE{INTCON}; + bit<uint8, 2> TMR0IF{INTCON}; + bit<uint8, 1> INT0IF{INTCON}; + bit<uint8, 0> RBIF{INTCON}; +} INTCONbits; + +// *************************** +// 5. include the environment independent code we want to test +#include "motor2.c" + +#include <chrono> +#include <thread> + +// round 24.8 format to microseconds +int32 to_microseconds(uint32 t){ + return (t + 128) / 256; +} + +using result_t = uint8_t; +const result_t success = 1; +const result_t fail = 0; + +// move motor to the indicated target position in steps +result_t test(int32 m){ + try { + std::cout << "move motor to " << m << '\n'; + motor_run(m); + std::cout + << "step #" << ' ' + << "delay(us)(24.8)" << ' ' + << "delay(us)" << ' ' + << "CCPR" << ' ' + << "motor position" << '\n'; + do{ + std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c))); + uint32 last_c = c; + uint32 last_ccpr = ccpr; + isr_motor_step(); + std::cout + << step_no << ' ' + << last_c << ' ' + << to_microseconds(last_c) << ' ' + << std::hex << last_ccpr << std::dec << ' ' + << motor_pos << '\n'; + }while(run_flg); + } + catch(const std::exception & e){ + std::cout << e.what() << '\n'; + return fail; + } + return success; +} + +int main(){ + std::cout << "start test\n"; + result_t result = success; + try{ + initialize(); + // move motor to position 1000 + result &= test(1000); + // move motor to position 200 + result &= test(200); + // move motor to position 200 again! Should result in no movement. + result &= test(200); + // move back to position 0 + result &= test(0); + // *************************** + // 6. error detected here! data types can't handle enough + // steps to move the carriage from end to end! Suppress this + // test for now. + // move motor to position 50000. +// result &= test(50000); + // move motor back to position 0. + result &= test(0); + } + catch(const std::exception & e){ + std::cout << e.what() << '\n'; + return 1; + } + catch(...){ + std::cout << "test interrupted\n"; + return EXIT_FAILURE; + } + std::cout << "end test\n"; + return result == success ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/boost/libs/safe_numerics/example/example93.cpp b/src/boost/libs/safe_numerics/example/example93.cpp new file mode 100644 index 00000000..658c6316 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/example93.cpp @@ -0,0 +1,299 @@ +////////////////////////////////////////////////////////////////// +// example93.cpp +// +// Copyright (c) 2015 Robert Ramey +// +// 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 <iostream> + +// include headers to support safe integers +#include <boost/safe_numerics/cpp.hpp> +#include <boost/safe_numerics/exception.hpp> +#include <boost/safe_numerics/safe_integer.hpp> +#include <boost/safe_numerics/safe_integer_range.hpp> +#include <boost/safe_numerics/safe_integer_literal.hpp> + +// use same type promotion as used by the pic compiler +// target compiler XC8 supports: +using pic16_promotion = boost::safe_numerics::cpp< + 8, // char 8 bits + 16, // short 16 bits + 16, // int 16 bits + 16, // long 16 bits + 32 // long long 32 bits +>; + +// *************************** +// 1. Specify exception policies so we will generate a +// compile time error whenever an operation MIGHT fail. + +// *************************** +// generate runtime errors if operation could fail +using exception_policy = boost::safe_numerics::default_exception_policy; + +// generate compile time errors if operation could fail +using trap_policy = boost::safe_numerics::loose_trap_policy; + +// *************************** +// 2. Create a macro named literal an integral value +// that can be evaluated at compile time. +#define literal(n) make_safe_literal(n, pic16_promotion, void) + +// For min speed of 2 mm / sec (24.8 format) +// sec / step = sec / 2 mm * 2 mm / rotation * rotation / 200 steps +#define C0 literal(5000 << 8) + +// For max speed of 400 mm / sec +// sec / step = sec / 400 mm * 2 mm / rotation * rotation / 200 steps +#define C_MIN literal(25 << 8) + +static_assert( + C0 < make_safe_literal(0xffffff, pic16_promotion,trap_policy), + "Largest step too long" +); +static_assert( + C_MIN > make_safe_literal(0, pic16_promotion,trap_policy), + "Smallest step must be greater than zero" +); + +// *************************** +// 3. Create special ranged types for the motor program +// These wiil guarantee that values are in the expected +// ranges and permit compile time determination of when +// exceptional conditions might occur. + +using pic_register_t = boost::safe_numerics::safe< + uint8_t, + pic16_promotion, + trap_policy // use for compiling and running tests +>; + +// note: the maximum value of step_t would be: +// 50000 = 500 mm / 2 mm/rotation * 200 steps/rotation. +// But in one expression the value of number of steps * 4 is +// used. To prevent introduction of error, permit this +// type to hold the larger value. +using step_t = boost::safe_numerics::safe_unsigned_range< + 0, + 200000, + pic16_promotion, + exception_policy +>; + +// position +using position_t = boost::safe_numerics::safe_unsigned_range< + 0, + 50000, // 500 mm / 2 mm/rotation * 200 steps/rotation + pic16_promotion, + exception_policy +>; + +// next end of step timer value in format 24.8 +// where the .8 is the number of bits in the fractional part. +using ccpr_t = boost::safe_numerics::safe< + uint32_t, + pic16_promotion, + exception_policy +>; + +// pulse length in format 24.8 +// note: this value is constrainted to be a positive value. But +// we still need to make it a signed type. We get an arithmetic +// error when moving to a negative step number. +using c_t = boost::safe_numerics::safe_unsigned_range< + C_MIN, + C0, + pic16_promotion, + exception_policy +>; + +// index into phase table +// note: The legal values are 0-3. So why must this be a signed +// type? Turns out that expressions like phase_ix + d +// will convert both operands to unsigned. This in turn will +// create an exception. So leave it signed even though the +// value is greater than zero. +using phase_ix_t = boost::safe_numerics::safe_signed_range< + 0, + 3, + pic16_promotion, + trap_policy +>; + +// settings for control value output +using phase_t = boost::safe_numerics::safe< + uint16_t, + pic16_promotion, + trap_policy +>; + +// direction of rotation +using direction_t = boost::safe_numerics::safe_signed_range< + -1, + +1, + pic16_promotion, + trap_policy +>; + +// some number of microseconds +using microseconds = boost::safe_numerics::safe< + uint32_t, + pic16_promotion, + trap_policy +>; + +// *************************** +// emulate PIC features on the desktop + +// filter out special keyword used only by XC8 compiler +#define __interrupt +// filter out XC8 enable/disable global interrupts +#define ei() +#define di() + +// emulate PIC special registers +pic_register_t RCON; +pic_register_t INTCON; +pic_register_t CCP1IE; +pic_register_t CCP2IE; +pic_register_t PORTC; +pic_register_t TRISC; +pic_register_t T3CON; +pic_register_t T1CON; + +pic_register_t CCPR2H; +pic_register_t CCPR2L; +pic_register_t CCPR1H; +pic_register_t CCPR1L; +pic_register_t CCP1CON; +pic_register_t CCP2CON; +pic_register_t TMR1H; +pic_register_t TMR1L; + +// *************************** +// special checked type for bits - values restricted to 0 or 1 +using safe_bit_t = boost::safe_numerics::safe_unsigned_range< + 0, + 1, + pic16_promotion, + trap_policy +>; + +// create type used to map PIC bit names to +// correct bit in PIC register +template<typename T, std::int8_t N> +struct bit { + T & m_word; + constexpr explicit bit(T & rhs) : + m_word(rhs) + {} + // special functions for assignment of literal + constexpr bit & operator=(decltype(literal(1))){ + m_word |= literal(1 << N); + return *this; + } + constexpr bit & operator=(decltype(literal(0))){ + m_word &= ~literal(1 << N); + return *this; + } + // operator to convert to 0 or 1 + constexpr operator safe_bit_t () const { + return m_word >> literal(N) & literal(1); + } +}; + +// define bits for T1CON register +struct { + bit<pic_register_t, 7> RD16{T1CON}; + bit<pic_register_t, 5> T1CKPS1{T1CON}; + bit<pic_register_t, 4> T1CKPS0{T1CON}; + bit<pic_register_t, 3> T1OSCEN{T1CON}; + bit<pic_register_t, 2> T1SYNC{T1CON}; + bit<pic_register_t, 1> TMR1CS{T1CON}; + bit<pic_register_t, 0> TMR1ON{T1CON}; +} T1CONbits; + +// define bits for T1CON register +struct { + bit<pic_register_t, 7> GEI{INTCON}; + bit<pic_register_t, 5> PEIE{INTCON}; + bit<pic_register_t, 4> TMR0IE{INTCON}; + bit<pic_register_t, 3> RBIE{INTCON}; + bit<pic_register_t, 2> TMR0IF{INTCON}; + bit<pic_register_t, 1> INT0IF{INTCON}; + bit<pic_register_t, 0> RBIF{INTCON}; +} INTCONbits; + +#include "motor3.c" + +#include <chrono> +#include <thread> + +// round 24.8 format to microseconds +microseconds to_microseconds(ccpr_t t){ + return (t + literal(128)) / literal(256); +} + +using result_t = uint8_t; +const result_t success = 1; +const result_t fail = 0; + +// move motor to the indicated target position in steps +result_t test(position_t new_position){ + try { + std::cout << "move motor to " << new_position << '\n'; + motor_run(new_position); + std::cout + << "step #" << ' ' + << "delay(us)(24.8)" << ' ' + << "delay(us)" << ' ' + << "CCPR" << ' ' + << "motor position" << '\n'; + while(busy()){ + std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c))); + c_t last_c = c; + ccpr_t last_ccpr = ccpr; + isr_motor_step(); + std::cout << i << ' ' + << last_c << ' ' + << to_microseconds(last_c) << ' ' + << std::hex << last_ccpr << std::dec << ' ' + << motor_position << '\n'; + }; + } + catch(const std::exception & e){ + std::cout << e.what() << '\n'; + return fail; + } + return success; +} + +int main(){ + std::cout << "start test\n"; + result_t result = success; + try { + initialize(); + // move motor to position 1000 + result &= test(literal(1000)); + // move to the left before zero position + // fails to compile ! + // result &= ! test(-10); + // move motor to position 200 + result &= test(literal(200)); + // move motor to position 200 again! Should result in no movement. + result &= test(literal(200)); + // move motor to position 50000. + result &= test(literal(50000)); + // move motor back to position 0. + result &= test(literal(0)); + } + catch(...){ + std::cout << "test interrupted\n"; + return EXIT_FAILURE; + } + std::cout << "end test\n"; + return result == success ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/boost/libs/safe_numerics/example/motor1.c b/src/boost/libs/safe_numerics/example/motor1.c new file mode 100644 index 00000000..d8fb51b9 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor1.c @@ -0,0 +1,152 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Copyright (c) 2015 Robert Ramey + * + * 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) + */ + +// ramp state-machine states +enum ramp_state { + ramp_idle = 0, + ramp_up = 1, + ramp_max = 2, + ramp_down = 3, + ramp_last = 4, +}; + +enum ramp_state ramp_sts=ramp_idle; +int16 motor_pos = 0; // absolute step number +int16 pos_inc=0; // motor_pos increment +uint16 phase=0; // ccpPhase[phase_ix] +uint8 phase_ix=0; // index to ccpPhase[] +uint8 phase_inc; // phase_ix increment +uint8 run_flg; // true while motor is running +uint16 ccpr; // copy of CCPR1&2 +uint16 c; // integer delay count +uint16 step_no; // progress of move +uint16 step_down; // start of down-ramp +uint16 move; // total steps to move +uint16 midpt; // midpoint of move +uint32 c32; // 24.8 fixed point delay count +int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +uint16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +uint16 make16(uint8 l, uint8 r) { + return (uint16) l << 8 + r; +} + +// compiler-specific ISR declaration + +void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value + switch (ramp_sts) { + case ramp_up: // accel + if (step_no == midpt) { // midpoint: decel + ramp_sts = ramp_down; + denom = ((step_no - move) << 2) + 1; + if (!(move & 1)) { // even move: repeat last delay before decel + denom += 4; + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move - 1) { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom += 4; + c32 -= (c32 << 1) / denom; // ramp algorithm + // beware confict with foreground code if long div not reentrant + c = (c32 + 128) >> 8; // round 24.8format->int16 + if (c <= C_MIN) { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) { // start decel + ramp_sts = ramp_down; + denom = ((step_no - move) << 2) + 5; + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + CCP1IE = 0; // disable_interrupts(INT_CCP1); + run_flg = false; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts != ramp_idle) { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + if (ramp_sts != ramp_last) // else repeat last action: no step + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // set CCP action on next match + CCP2CON = phase >> 8; + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(int16 pos_new) { // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) { // get direction & #steps + move = motor_pos - pos_new; + pos_inc = -1; + phase_inc = 0xff; + } + else if (pos_new != motor_pos) { + move = pos_new - motor_pos; + pos_inc = 1; + phase_inc = 1; + } else return; // already there + midpt = (move - 1) >> 1; + c = C0; + c32 = c << 8; // keep c in 24.8 fixed-point format for ramp calcs + step_no = 0; // step counter + denom = 1; // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = true; + T1CONbits.TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H, TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // sets action on match + CCP2CON = phase >> 8; + current_on(); // current in motor windings + CCP1IE = 1; // enable_interrupts(INT_CCP1); + T1CONbits.TMR1ON = 1; // restart timer1; +} // motor_run() + +void initialize() { + di(); // disable_interrupts(GLOBAL); + CCP1IE = 0; // disable_interrupts(INT_CCP1); + CCP2IE = 0; // disable_interrupts(INT_CCP2); + PORTC = 0; // output_c(0); + TRISC = 0; // set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + INTCONbits.PEIE = 1; + INTCONbits.RBIF = 0; + ei(); // enable_interrupts(GLOBAL); +} // initialize() diff --git a/src/boost/libs/safe_numerics/example/motor2.c b/src/boost/libs/safe_numerics/example/motor2.c new file mode 100644 index 00000000..78e08fef --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor2.c @@ -0,0 +1,169 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Copyright (c) 2015 Robert Ramey + * + * 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) + */ + +// ramp state-machine states +enum ramp_state { + ramp_idle = 0, + ramp_up = 1, + ramp_max = 2, + ramp_down = 3, + ramp_last = 4, +}; + +enum ramp_state ramp_sts=ramp_idle; +int16 motor_pos = 0; // absolute step number +int16 pos_inc=0; // motor_pos increment +uint16 phase=0; // ccpPhase[phase_ix] +uint8 phase_ix=0; // index to ccpPhase[] +uint8 phase_inc; // phase_ix increment +uint8 run_flg; // true while motor is running +// *************************** +// 1. keep track of total delay count +uint32 ccpr; // 24.8 fixed point delay count +uint32 c; // 24.8 fixed point delay count increment +uint16 step_no; // progress of move +uint16 step_down; // start of down-ramp +uint16 move; // total steps to move +uint16 midpt; // midpoint of move +int16 denom; // 4.n+1 in ramp algo + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +uint16 const ccpPhase[] = {0x909, 0x908, 0x808, 0x809}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +uint16 make16(uint8 l, uint8 r) { + return (uint16) l << 8 + r; +} + +// compiler-specific ISR declaration + +void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ + ccpr += c; // next comparator value + switch (ramp_sts) { + case ramp_up: // accel + if (step_no == midpt) { // midpoint: decel + ramp_sts = ramp_down; + // *************************** + // 2. convert shift to multiplication + // 3. avoid negative result from subtraction of unsigned values + // denom = ((step_no - move) << 2) + 1; + if(step_no > move) + denom = ((step_no - move) * 4) + 1; + else + denom = ((move - step_no) * 4) - 1; + if (!(move & 1)) { // even move: repeat last delay before decel + denom += 4; + break; + } + } + // no break: share code for ramp algo + case ramp_down: // decel + if (step_no == move - 1) { // next irq is cleanup (no step) + ramp_sts = ramp_last; + break; + } + denom += 4; + // calculate increment/decrement in delay count + // *************************** + // 3. avoid negative result from subtraction of unsigned values + // c -= (c << 1) / denom; // ramp algorithm + if(denom > 0) + c -= (c << 1) / denom; + else + c += (c << 1) / -denom; + + if (c <= C_MIN) { // go to constant speed + ramp_sts = ramp_max; + step_down = move - step_no; + c = C_MIN; + break; + } + break; + case ramp_max: // constant speed + if (step_no == step_down) { // start decel + ramp_sts = ramp_down; + // *************************** + // 2. convert shift to multiplication + // 3. avoid negative result from subtraction of unsigned values + // denom = ((step_no - move) << 2) + 1; + denom = 5 - ((move - step_no) * 4); + } + break; + default: // last step: cleanup + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + CCP1IE = 0; // disable_interrupts(INT_CCP1); + run_flg = false; // move complete + break; + } // switch (ramp_sts) + if (ramp_sts != ramp_idle) { + motor_pos += pos_inc; + ++step_no; + CCPR2H = CCPR1H = (ccpr >> 8); // timer value at next CCP match + CCPR2L = CCPR1L = (ccpr & 0xff); + if (ramp_sts != ramp_last) // else repeat last action: no step + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // set CCP action on next match + CCP2CON = phase >> 8; + } // if (ramp_sts != ramp_idle) +} // isr_motor_step() + +void motor_run(int16 pos_new) { // set up to drive motor to pos_new (absolute step#) + if (pos_new < motor_pos) { // get direction & #steps + move = motor_pos - pos_new; + pos_inc = -1; + phase_inc = 0xff; + } + else if (pos_new != motor_pos) { + move = pos_new - motor_pos; + pos_inc = 1; + phase_inc = 1; + } else return; // already there + midpt = (move - 1) >> 1; + c = C0; + step_no = 0; // step counter + denom = 1; // 4.n+1, n=0 + ramp_sts = ramp_up; // start ramp state-machine + run_flg = true; + T1CONbits.TMR1ON = 0; // stop timer1; + ccpr = make16(TMR1H, TMR1L); // 16bit value of Timer1 + ccpr += 1000; // 1st step + irq 1ms after timer1 restart + CCPR2H = CCPR1H = (ccpr >> 8); + CCPR2L = CCPR1L = (ccpr & 0xff); + phase_ix = (phase_ix + phase_inc) & 3; + phase = ccpPhase[phase_ix]; + CCP1CON = phase & 0xff; // sets action on match + CCP2CON = phase >> 8; + current_on(); // current in motor windings + CCP1IE = 1; // enable_interrupts(INT_CCP1); + T1CONbits.TMR1ON = 1; // restart timer1; +} // motor_run() + +void initialize() { + di(); // disable_interrupts(GLOBAL); + CCP1IE = 0; // disable_interrupts(INT_CCP1); + CCP2IE = 0; // disable_interrupts(INT_CCP2); + PORTC = 0; // output_c(0); + TRISC = 0; // set_tris_c(0); + T3CON = 0; + T1CON = 0x35; + INTCONbits.PEIE = 1; + INTCONbits.RBIF = 0; + ei(); // enable_interrupts(GLOBAL); +} // initialize() diff --git a/src/boost/libs/safe_numerics/example/motor3.c b/src/boost/libs/safe_numerics/example/motor3.c new file mode 100644 index 00000000..c6175d36 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor3.c @@ -0,0 +1,195 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Copyright (c) 2015 Robert Ramey + * + * 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 <assert.h> + +// ramp state-machine states +enum ramp_state { + ramp_idle = 0, + ramp_up = 1, + ramp_const = 2, + ramp_down = 3, +}; + +// *************************** +// 1. Define state variables using custom strong types + +// initial setup +enum ramp_state ramp_sts; +position_t motor_position; +position_t m; // target position +position_t m2; // midpoint or point where acceleration changes +direction_t d; // direction of traval -1 or +1 + +// curent state along travel +step_t i; // step number +c_t c; // 24.8 fixed point delay count increment +ccpr_t ccpr; // 24.8 fixed point delay count +phase_ix_t phase_ix; // motor phase index + +// *************************** +// 2. Surround all literal values with the "literal" keyword + +// Config data to make CCP1&2 generate quadrature sequence on PHASE pins +// Action on CCP match: 8=set+irq; 9=clear+irq +phase_t const ccpPhase[] = { + literal(0x909), + literal(0x908), + literal(0x808), + literal(0x809) +}; // 00,01,11,10 + +void current_on(){/* code as needed */} // motor drive current +void current_off(){/* code as needed */} // reduce to holding value + +// *************************** +// 3. Refactor code to make it easier to understand +// and relate to the documentation + +bool busy(){ + return ramp_idle != ramp_sts; +} + +// set outputs to energize motor coils +void update(ccpr_t ccpr, phase_ix_t phase_ix){ + // energize correct windings + const phase_t phase = ccpPhase[phase_ix]; + CCP1CON = phase & literal(0xff); // set CCP action on next match + CCP2CON = phase >> literal(8); + // timer value at next CCP match + CCPR1H = literal(0xff) & (ccpr >> literal(8)); + CCPR1L = literal(0xff) & ccpr; +} + +// compiler-specific ISR declaration +// *************************** +// 4. Rewrite interrupt handler in a way which mirrors the orginal +// description of the algorithm and minimizes usage of state variable, +// accumulated values, etc. +void __interrupt isr_motor_step(void) { // CCP1 match -> step pulse + IRQ + // *** possible exception + // motor_position += d; + // use the following to avoid mixing exception policies which is an error + if(d < 0) + --motor_position; + else + ++motor_position; + // *** possible exception + ++i; + // calculate next difference in time + for(;;){ + switch (ramp_sts) { + case ramp_up: // acceleration + if (i == m2) { + ramp_sts = ramp_down; + continue; + } + // equation 13 + // *** possible negative overflow on update of c + c -= literal(2) * c / (literal(4) * i + literal(1)); + if(c < C_MIN){ + c = C_MIN; + ramp_sts = ramp_const; + // *** possible exception + m2 = m - i; // new inflection point + continue; + } + break; + case ramp_const: // constant speed + if(i > m2) { + ramp_sts = ramp_down; + continue; + } + break; + case ramp_down: // deceleration + if (i == m) { + ramp_sts = ramp_idle; + current_off(); // reduce motor current to holding value + CCP1IE = literal(0); // disable_interrupts(INT_CCP1); + return; + } + // equation 14 + // *** possible positive overflow on update of c + // note: re-arrange expression to avoid negative result + // from difference of two unsigned values + c += literal(2) * c / (literal(4) * (m - i) - literal(1)); + if(c > C0){ + c = C0; + } + break; + default: + // should never arrive here! + assert(false); + } // switch (ramp_sts) + break; + } + assert(c <= C0 && c >= C_MIN); + // *** possible exception + ccpr = literal(0xffffff) & (ccpr + c); + phase_ix = (phase_ix + d) & literal(3); + update(ccpr, phase_ix); +} // isr_motor_step() + +// set up to drive motor to pos_new (absolute step#) +void motor_run(position_t new_position) { + if(new_position > motor_position){ + d = literal(1); + // *** possible exception + m = new_position - motor_position; + } + else + if(motor_position > new_position){ + d = literal(-1); + // *** possible exception + m = motor_position - new_position; + } + else{ + d = literal(0); + m = literal(0); + ramp_sts = ramp_idle; // start ramp state-machine + return; + } + + i = literal(0); + m2 = m / literal(2); + + ramp_sts = ramp_up; // start ramp state-machine + + T1CONbits.TMR1ON = literal(0); // stop timer1; + + current_on(); // current in motor windings + + c = C0; + ccpr = (TMR1H << literal(8) | TMR1L) + C0 + literal(1000); + phase_ix = d & literal(3); + update(ccpr, phase_ix); + + CCP1IE = literal(1); // enable_interrupts(INT_CCP1); + T1CONbits.TMR1ON = literal(1); // restart timer1; +} // motor_run() + +void initialize() { + di(); // disable_interrupts(GLOBAL); + motor_position = literal(0); + CCP1IE = literal(0); // disable_interrupts(INT_CCP1); + CCP2IE = literal(0); // disable_interrupts(INT_CCP2); + PORTC = literal(0); // output_c(0); + TRISC = literal(0); // set_tris_c(0); + T3CON = literal(0); + T1CON = literal(0x35); + INTCONbits.PEIE = literal(1); + INTCONbits.RBIF = literal(0); + ei(); // enable_interrupts(GLOBAL); +} // initialize() diff --git a/src/boost/libs/safe_numerics/example/motor_test1.c b/src/boost/libs/safe_numerics/example/motor_test1.c new file mode 100644 index 00000000..afe54cb7 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor_test1.c @@ -0,0 +1,44 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Compile with on Microchip XC8 compiler with the command line: + * XC8 --chip=18F252 motor_test1.c + * + * Copyright (c) 2015 Robert Ramey + * + * 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 <xc.h> +#include <stdint.h> +#include <stdbool.h> /* For true/false definition */ + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 (50000 << 8) +#define C_MIN (2500 << 8) + +#include "motor1.c" + +void main() { + initialize(); + while (1) { // repeat 5 revs forward & back + motor_run(1000); + while (run_flg); + motor_run(0); + while (run_flg); + } +} // main() diff --git a/src/boost/libs/safe_numerics/example/motor_test2.c b/src/boost/libs/safe_numerics/example/motor_test2.c new file mode 100644 index 00000000..23f70576 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor_test2.c @@ -0,0 +1,48 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Compile with on Microchip XC8 compiler with the command line: + * XC8 --chip=18F252 motor_test2.c + * + * Copyright (c) 2015 Robert Ramey + * + * 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 <xc.h> +#include <stdint.h> +#include <stdbool.h> /* For true/false definition */ + +// *************************** +// alias integer types standard C integer types +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; + +// 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps) +#define C0 (50000*8l) +#define C_MIN (2500*8) + +#include "motor2.c" + +void main() { + initialize(); + while (1) { // repeat 5 revs forward & back + motor_run(1000); + while (run_flg); + motor_run(0); + while (run_flg); + motor_run(50000); + while (run_flg); + } +} // main() diff --git a/src/boost/libs/safe_numerics/example/motor_test3.c b/src/boost/libs/safe_numerics/example/motor_test3.c new file mode 100644 index 00000000..0ef5a022 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/motor_test3.c @@ -0,0 +1,58 @@ +/* + * david austin + * http://www.embedded.com/design/mcus-processors-and-socs/4006438/Generate-stepper-motor-speed-profiles-in-real-time + * DECEMBER 30, 2004 + * + * Demo program for stepper motor control with linear ramps + * Hardware: PIC18F252, L6219 + * + * Compile with on Microchip XC8 compiler with the command line: + * XC8 --chip=18F252 motor_test3.c + * + * Copyright (c) 2015 Robert Ramey + * + * 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 <xc.h> + +// 8 MHz internal clock +#define _XTAL_FREQ 8000000 + +#include <stdint.h> +#include <stdbool.h> /* For true/false definition */ + +// *************************** +// nullify macro for literals +#define literal(n) n + +// *************************** +// map strong types to appropriate underlying types. +typedef uint16_t position_t; +typedef int16_t step_t; +typedef uint32_t ccpr_t; +typedef int32_t c_t; +typedef uint16_t phase_t; +typedef uint8_t phase_ix_t; +typedef int8_t direction_t; + +// 1st step=10ms; max speed=300rpm (based on 1MHz timer, 1.8deg steps) +#define C_MIN literal((1000 << 8)) +#define C0 literal((10000 << 8)) + +#include "motor3.c" + +void main() { + initialize(); + // move motor to position 200 + motor_run(200); + while(busy()) __delay_ms(100); + // move motor to position 1000 + motor_run(1000); + while(busy()) __delay_ms(100); + // move back to position 0 + motor_run(200); + while(busy()) __delay_ms(100); +} // main() diff --git a/src/boost/libs/safe_numerics/example/picsfr.h b/src/boost/libs/safe_numerics/example/picsfr.h new file mode 100644 index 00000000..a100731c --- /dev/null +++ b/src/boost/libs/safe_numerics/example/picsfr.h @@ -0,0 +1,29 @@ +////////////////////////////////////////////////////////////////// +// picsfr.h +// Copyright (c) 2015 Robert Ramey +// +// 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) +// +// Put these in a separate file so they can conditionally included. +// This is necessary since their mere inclusion will cause syntax +// errors on some compilers. + +#ifndef PICSFR_H +#define PICSFR_H + +#byte TRISC = 0xf94 +#byte T3CON = 0xfb1 +#byte CCP2CON = 0xfba +#byte CCPR2L = 0xfbb +#byte CCPR2H = 0xfbc +#byte CCP1CON = 0xfbd +#byte CCPR1L = 0xfbe +#byte CCPR1H = 0xfbf +#byte T1CON = 0xfcd +#byte TMR1L = 0xfce +#byte TMR1H = 0xfcf +#bit TMR1ON = T1CON.0 + +#endif // PICSFR_H diff --git a/src/boost/libs/safe_numerics/example/safe_format.hpp b/src/boost/libs/safe_numerics/example/safe_format.hpp new file mode 100644 index 00000000..317c2201 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/safe_format.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_SAFE_FORMAT_HPP +#define BOOST_SAFE_FORMAT_HPP + +// Copyright (c) 2015 Robert Ramey +// +// 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 <ostream> +#include <typeinfo> + +#include <boost/core/demangle.hpp> +#include <boost/safe_numerics/safe_common.hpp> + +namespace { + +// create an output manipulator which prints variable type and limits +// as well as value +template<typename T> +struct safe_format_impl { + const T & m_t; + safe_format_impl(const T & t) : + m_t(t) + {} + template <class charT, class Traits> + friend std::basic_ostream<charT,Traits> & + operator<<( + std::basic_ostream<charT,Traits> & os, + const safe_format_impl<T> & f + ){ + return os + << "<" + << boost::core::demangle(typeid( + typename boost::safe_numerics::base_type<T>::type + ).name() + ) + << ">[" + << std::numeric_limits<T>::min() << "," + << std::numeric_limits<T>::max() << "] = " + << f.m_t; + } +}; + +} // anonymous namespace + +template<typename T> +auto safe_format(const T & t){ + return safe_format_impl<T>(t); +} + +#endif // BOOST_SAFE_FORMAT_HPP diff --git a/src/boost/libs/safe_numerics/example/stepper-motor.pdf b/src/boost/libs/safe_numerics/example/stepper-motor.pdf Binary files differnew file mode 100644 index 00000000..7088a779 --- /dev/null +++ b/src/boost/libs/safe_numerics/example/stepper-motor.pdf |