1 //////////////////////////////////////////////////////////////////
2 // example92.cpp
3 //
4 // Copyright (c) 2015 Robert Ramey
5 //
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)
9
10 #include <iostream>
11
12 // ***************************
13 // 1. include headers to support safe integers
14 #include <boost/safe_numerics/cpp.hpp>
15 #include <boost/safe_numerics/exception.hpp>
16 #include <boost/safe_numerics/safe_integer.hpp>
17
18 // ***************************
19 // 2. specify a promotion policy to support proper emulation of
20 // PIC types on the desktop
21 using pic16_promotion = boost::safe_numerics::cpp<
22 8, // char 8 bits
23 16, // short 16 bits
24 16, // int 16 bits
25 16, // long 16 bits
26 32 // long long 32 bits
27 >;
28
29 // 1st step=50ms; max speed=120rpm (based on 1MHz timer, 1.8deg steps)
30 #define C0 (50000 << 8)
31 #define C_MIN (2500 << 8)
32
33 static_assert(C0 < 0xffffff, "Largest step too long");
34 static_assert(C_MIN > 0, "Smallest step must be greater than zero");
35 static_assert(C_MIN < C0, "Smallest step must be smaller than largest step");
36
37 // ***************************
38 // 3. define PIC integer type names to be safe integer types of he same size.
39
40 template <typename T> // T is char, int, etc data type
41 using safe_t = boost::safe_numerics::safe<
42 T,
43 pic16_promotion
44 >;
45
46 // alias original program's integer types to corresponding PIC safe types
47 // In conjunction with the promotion policy above, this will permit us to
48 // guarantee that the resulting program will be free of arithmetic errors
49 // introduced by C expression syntax and type promotion with no runtime penalty
50
51 typedef safe_t<int8_t> int8;
52 typedef safe_t<int16_t> int16;
53 typedef safe_t<int32_t> int32;
54 typedef safe_t<uint8_t> uint8;
55 typedef safe_t<uint16_t> uint16;
56 typedef safe_t<uint32_t> uint32;
57
58 // ***************************
59 // 4. emulate PIC features on the desktop
60
61 // filter out special keyword used only by XC8 compiler
62 #define __interrupt
63 // filter out XC8 enable/disable global interrupts
64 #define ei()
65 #define di()
66
67 // emulate PIC special registers
68 uint8 RCON;
69 uint8 INTCON;
70 uint8 CCP1IE;
71 uint8 CCP2IE;
72 uint8 PORTC;
73 uint8 TRISC;
74 uint8 T3CON;
75 uint8 T1CON;
76
77 uint8 CCPR2H;
78 uint8 CCPR2L;
79 uint8 CCPR1H;
80 uint8 CCPR1L;
81 uint8 CCP1CON;
82 uint8 CCP2CON;
83 uint8 TMR1H;
84 uint8 TMR1L;
85
86 // create type used to map PIC bit names to
87 // correct bit in PIC register
88 template<typename T, std::int8_t N>
89 struct bit {
90 T & m_word;
bitbit91 constexpr explicit bit(T & rhs) :
92 m_word(rhs)
93 {}
operator =bit94 constexpr bit & operator=(int b){
95 if(b != 0)
96 m_word |= (1 << N);
97 else
98 m_word &= ~(1 << N);
99 return *this;
100 }
operator intbit101 constexpr operator int () const {
102 return m_word >> N & 1;
103 }
104 };
105
106 // define bits for T1CON register
107 struct {
108 bit<uint8, 7> RD16{T1CON};
109 bit<uint8, 5> T1CKPS1{T1CON};
110 bit<uint8, 4> T1CKPS0{T1CON};
111 bit<uint8, 3> T1OSCEN{T1CON};
112 bit<uint8, 2> T1SYNC{T1CON};
113 bit<uint8, 1> TMR1CS{T1CON};
114 bit<uint8, 0> TMR1ON{T1CON};
115 } T1CONbits;
116
117 // define bits for T1CON register
118 struct {
119 bit<uint8, 7> GEI{INTCON};
120 bit<uint8, 5> PEIE{INTCON};
121 bit<uint8, 4> TMR0IE{INTCON};
122 bit<uint8, 3> RBIE{INTCON};
123 bit<uint8, 2> TMR0IF{INTCON};
124 bit<uint8, 1> INT0IF{INTCON};
125 bit<uint8, 0> RBIF{INTCON};
126 } INTCONbits;
127
128 // ***************************
129 // 5. include the environment independent code we want to test
130 #include "motor2.c"
131
132 #include <chrono>
133 #include <thread>
134
135 // round 24.8 format to microseconds
to_microseconds(uint32 t)136 int32 to_microseconds(uint32 t){
137 return (t + 128) / 256;
138 }
139
140 using result_t = uint8_t;
141 const result_t success = 1;
142 const result_t fail = 0;
143
144 // move motor to the indicated target position in steps
test(int32 m)145 result_t test(int32 m){
146 try {
147 std::cout << "move motor to " << m << '\n';
148 motor_run(m);
149 std::cout
150 << "step #" << ' '
151 << "delay(us)(24.8)" << ' '
152 << "delay(us)" << ' '
153 << "CCPR" << ' '
154 << "motor position" << '\n';
155 do{
156 std::this_thread::sleep_for(std::chrono::microseconds(to_microseconds(c)));
157 uint32 last_c = c;
158 uint32 last_ccpr = ccpr;
159 isr_motor_step();
160 std::cout
161 << step_no << ' '
162 << last_c << ' '
163 << to_microseconds(last_c) << ' '
164 << std::hex << last_ccpr << std::dec << ' '
165 << motor_pos << '\n';
166 }while(run_flg);
167 }
168 catch(const std::exception & e){
169 std::cout << e.what() << '\n';
170 return fail;
171 }
172 return success;
173 }
174
main()175 int main(){
176 std::cout << "start test\n";
177 result_t result = success;
178 try{
179 initialize();
180 // move motor to position 1000
181 result &= test(1000);
182 // move motor to position 200
183 result &= test(200);
184 // move motor to position 200 again! Should result in no movement.
185 result &= test(200);
186 // move back to position 0
187 result &= test(0);
188 // ***************************
189 // 6. error detected here! data types can't handle enough
190 // steps to move the carriage from end to end! Suppress this
191 // test for now.
192 // move motor to position 50000.
193 // result &= test(50000);
194 // move motor back to position 0.
195 result &= test(0);
196 }
197 catch(const std::exception & e){
198 std::cout << e.what() << '\n';
199 return 1;
200 }
201 catch(...){
202 std::cout << "test interrupted\n";
203 return EXIT_FAILURE;
204 }
205 std::cout << "end test\n";
206 return result == success ? EXIT_SUCCESS : EXIT_FAILURE;
207 }
208