]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/safe_numerics/example/example93.cpp
1 //////////////////////////////////////////////////////////////////
4 // Copyright (c) 2015 Robert Ramey
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
12 // include headers to support safe integers
13 #include <boost/safe_numerics/cpp.hpp>
14 #include <boost/safe_numerics/exception.hpp>
15 #include <boost/safe_numerics/safe_integer.hpp>
16 #include <boost/safe_numerics/safe_integer_range.hpp>
17 #include <boost/safe_numerics/safe_integer_literal.hpp>
19 // use same type promotion as used by the pic compiler
20 // target compiler XC8 supports:
21 using pic16_promotion
= boost::safe_numerics::cpp
<
26 32 // long long 32 bits
29 // ***************************
30 // 1. Specify exception policies so we will generate a
31 // compile time error whenever an operation MIGHT fail.
33 // ***************************
34 // generate runtime errors if operation could fail
35 using exception_policy
= boost::safe_numerics::default_exception_policy
;
37 // generate compile time errors if operation could fail
38 using trap_policy
= boost::safe_numerics::loose_trap_policy
;
40 // ***************************
41 // 2. Create a macro named literal an integral value
42 // that can be evaluated at compile time.
43 #define literal(n) make_safe_literal(n, pic16_promotion, void)
45 // For min speed of 2 mm / sec (24.8 format)
46 // sec / step = sec / 2 mm * 2 mm / rotation * rotation / 200 steps
47 #define C0 literal(5000 << 8)
49 // For max speed of 400 mm / sec
50 // sec / step = sec / 400 mm * 2 mm / rotation * rotation / 200 steps
51 #define C_MIN literal(25 << 8)
54 C0
< make_safe_literal(0xffffff, pic16_promotion
,trap_policy
),
55 "Largest step too long"
58 C_MIN
> make_safe_literal(0, pic16_promotion
,trap_policy
),
59 "Smallest step must be greater than zero"
62 // ***************************
63 // 3. Create special ranged types for the motor program
64 // These wiil guarantee that values are in the expected
65 // ranges and permit compile time determination of when
66 // exceptional conditions might occur.
68 using pic_register_t
= boost::safe_numerics::safe
<
71 trap_policy
// use for compiling and running tests
74 // note: the maximum value of step_t would be:
75 // 50000 = 500 mm / 2 mm/rotation * 200 steps/rotation.
76 // But in one expression the value of number of steps * 4 is
77 // used. To prevent introduction of error, permit this
78 // type to hold the larger value.
79 using step_t
= boost::safe_numerics::safe_unsigned_range
<
87 using position_t
= boost::safe_numerics::safe_unsigned_range
<
89 50000, // 500 mm / 2 mm/rotation * 200 steps/rotation
94 // next end of step timer value in format 24.8
95 // where the .8 is the number of bits in the fractional part.
96 using ccpr_t
= boost::safe_numerics::safe
<
102 // pulse length in format 24.8
103 // note: this value is constrainted to be a positive value. But
104 // we still need to make it a signed type. We get an arithmetic
105 // error when moving to a negative step number.
106 using c_t
= boost::safe_numerics::safe_unsigned_range
<
113 // 32 bit unsigned integer used for temporary purposes
114 using temp_t
= boost::safe_numerics::safe_unsigned_range
<
120 // index into phase table
121 // note: The legal values are 0-3. So why must this be a signed
122 // type? Turns out that expressions like phase_ix + d
123 // will convert both operands to unsigned. This in turn will
124 // create an exception. So leave it signed even though the
125 // value is greater than zero.
126 using phase_ix_t
= boost::safe_numerics::safe_signed_range
<
133 // settings for control value output
135 using phase_t
= boost::safe_numerics::safe
<
141 // direction of rotation
142 using direction_t
= boost::safe_numerics::safe_signed_range
<
149 // some number of microseconds
150 using microseconds
= boost::safe_numerics::safe
<
156 // ***************************
157 // emulate PIC features on the desktop
159 // filter out special keyword used only by XC8 compiler
161 // filter out XC8 enable/disable global interrupts
165 // emulate PIC special registers
167 pic_register_t INTCON
;
168 pic_register_t CCP1IE
;
169 pic_register_t CCP2IE
;
170 pic_register_t PORTC
;
171 pic_register_t TRISC
;
172 pic_register_t T3CON
;
173 pic_register_t T1CON
;
175 pic_register_t CCPR2H
;
176 pic_register_t CCPR2L
;
177 pic_register_t CCPR1H
;
178 pic_register_t CCPR1L
;
179 pic_register_t CCP1CON
;
180 pic_register_t CCP2CON
;
181 pic_register_t TMR1H
;
182 pic_register_t TMR1L
;
184 // ***************************
185 // special checked type for bits - values restricted to 0 or 1
186 using safe_bit_t
= boost::safe_numerics::safe_unsigned_range
<
193 // create type used to map PIC bit names to
194 // correct bit in PIC register
195 template<typename T
, std::int8_t N
>
198 constexpr explicit bit(T
& rhs
) :
201 // special functions for assignment of literal
202 constexpr bit
& operator=(decltype(literal(1))){
203 m_word
|= literal(1 << N
);
206 constexpr bit
& operator=(decltype(literal(0))){
207 m_word
&= ~literal(1 << N
);
210 // operator to convert to 0 or 1
211 constexpr operator safe_bit_t () const {
212 return m_word
>> literal(N
) & literal(1);
216 // define bits for T1CON register
218 bit
<pic_register_t
, 7> RD16
{T1CON
};
219 bit
<pic_register_t
, 5> T1CKPS1
{T1CON
};
220 bit
<pic_register_t
, 4> T1CKPS0
{T1CON
};
221 bit
<pic_register_t
, 3> T1OSCEN
{T1CON
};
222 bit
<pic_register_t
, 2> T1SYNC
{T1CON
};
223 bit
<pic_register_t
, 1> TMR1CS
{T1CON
};
224 bit
<pic_register_t
, 0> TMR1ON
{T1CON
};
227 // define bits for T1CON register
229 bit
<pic_register_t
, 7> GEI
{INTCON
};
230 bit
<pic_register_t
, 5> PEIE
{INTCON
};
231 bit
<pic_register_t
, 4> TMR0IE
{INTCON
};
232 bit
<pic_register_t
, 3> RBIE
{INTCON
};
233 bit
<pic_register_t
, 2> TMR0IF
{INTCON
};
234 bit
<pic_register_t
, 1> INT0IF
{INTCON
};
235 bit
<pic_register_t
, 0> RBIF
{INTCON
};
243 // round 24.8 format to microseconds
244 microseconds
to_microseconds(ccpr_t t
){
245 return (t
+ literal(128)) / literal(256);
248 using result_t
= uint8_t;
249 const result_t success
= 1;
250 const result_t fail
= 0;
252 // move motor to the indicated target position in steps
253 result_t
test(position_t new_position
){
255 std::cout
<< "move motor to " << new_position
<< '\n';
256 motor_run(new_position
);
259 << "delay(us)(24.8)" << ' '
260 << "delay(us)" << ' '
262 << "motor position" << '\n';
264 std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c
)));
266 ccpr_t last_ccpr
= ccpr
;
268 std::cout
<< i
<< ' '
270 << to_microseconds(last_c
) << ' '
271 << std::hex
<< last_ccpr
<< std::dec
<< ' '
272 << motor_position
<< '\n';
275 catch(const std::exception
& e
){
276 std::cout
<< e
.what() << '\n';
283 std::cout
<< "start test\n";
284 result_t result
= success
;
287 // move motor to position 1000
288 result
&= test(literal(9000));
289 // move to the left before zero position
290 // fails to compile !
291 // result &= ! test(-10);
292 // move motor to position 200
293 result
&= test(literal(200));
294 // move motor to position 200 again! Should result in no movement.
295 result
&= test(literal(200));
296 // move motor to position 50000.
297 result
&= test(literal(50000));
298 // move motor back to position 0.
299 result
&= test(literal(0));
302 std::cout
<< "test interrupted\n";
305 std::cout
<< "end test\n";
306 return result
== success
? EXIT_SUCCESS
: EXIT_FAILURE
;