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