Wed, 18 Jan 2017 23:19:13 +0100
Stuff...
5 | 1 | #include "hp34comm.h" |
2 | #include "mbed.h" | |
3 | #include "CircularBuffer.h" | |
4 | ||
5 | /***** HP 34970A communication class ***/ | |
6 | ||
8 | 7 | #ifdef DEBUG2 |
5 | 8 | |
8 | 9 | DigitalOut inrx(D9); |
5 | 10 | |
11 | #endif | |
12 | ||
8 | 13 | DigitalOut lled(LED1); |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
14 | |
19 | 15 | #define RXTIMEOUT 0.05 |
16 | #define STARTUPRETRY 0.5 | |
17 | const uint8_t startup_seq[] = { | |
18 | 0x33, | |
19 | 0x01, | |
20 | 0x01, | |
21 | 0x40, | |
22 | // 0x02, | |
23 | }; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
24 | |
19 | 25 | const uint8_t startup_seq2[] = { |
26 | 0x33, | |
27 | 0x02, | |
28 | 0x00, | |
29 | 0x00, | |
30 | // 0x02, | |
31 | }; | |
32 | ||
33 | HPSerial::statemethod HPSerial::state_table[NUM_STATES] = { | |
34 | &HPSerial::do_state_initial, | |
35 | &HPSerial::do_state_command, | |
36 | &HPSerial::do_state_payload_size, | |
37 | &HPSerial::do_state_payload, | |
38 | &HPSerial::do_state_sending, | |
39 | &HPSerial::do_state_eot, | |
40 | }; | |
5 | 41 | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
42 | HPSerial::HPSerial(PinName tx, PinName rx): |
19 | 43 | serial(tx, rx), |
44 | cur_gstate(GSTATE_IDLE), | |
45 | ncmd(0) | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
46 | { |
19 | 47 | serial.baud(187500); |
48 | cur_state = STATE_IDLE; | |
49 | serial.attach(callback(this, &HPSerial::rxIrq), Serial::RxIrq); | |
50 | } | |
51 | ||
52 | void HPSerial::startup(void) { | |
53 | if (cur_gstate != GSTATE_STARTING) { | |
54 | //_startup(); | |
55 | cur_gstate = GSTATE_STARTING; | |
56 | } | |
57 | set_timer(0.002); // launch the startup in 10ms | |
58 | } | |
59 | ||
60 | void HPSerial::_startup(void) | |
61 | { | |
62 | cur_gstate = GSTATE_STARTING; | |
63 | tr_data.size = sizeof(startup_seq); | |
64 | tr_data.cmd = 0xFF; | |
65 | tr_data.pos = 0; | |
66 | for(uint8_t i=0; i<tr_data.size; i++) | |
67 | tr_data.payload[i] = startup_seq[i]; | |
68 | cur_state = do_state_sending(); | |
5 | 69 | } |
70 | ||
19 | 71 | void HPSerial::_startup2(void) |
72 | { | |
73 | cur_gstate = GSTATE_STARTING2; | |
74 | tr_data.size = sizeof(startup_seq2); | |
75 | tr_data.cmd = 0xFF; | |
76 | tr_data.pos = 0; | |
77 | for(uint8_t i=0; i<tr_data.size; i++) | |
78 | tr_data.payload[i] = startup_seq2[i]; | |
79 | cur_state = do_state_sending(); | |
80 | } | |
81 | ||
82 | void HPSerial::send(const uint8_t *buf, uint8_t size) | |
83 | { | |
84 | // tx_data-> | |
85 | //send(startup, sizeof(startup)/sizeof(startup[0])); | |
86 | } | |
87 | ||
88 | void HPSerial::sendkey(uint8_t keycode) | |
89 | { | |
90 | tr_data.size = 2; | |
91 | tr_data.cmd = 0xFF; | |
92 | tr_data.pos = 0; | |
93 | tr_data.payload[0] = 0x66; | |
94 | tr_data.payload[1] = keycode; | |
95 | cur_state = do_state_sending(); | |
96 | } | |
97 | ||
98 | bool HPSerial::cmd_available(void) | |
99 | { | |
5 | 100 | return !cmdbuf.empty(); |
101 | } | |
102 | ||
19 | 103 | bool HPSerial::pop(CMD& cmd) |
104 | { | |
5 | 105 | return cmdbuf.pop(cmd); |
106 | } | |
107 | ||
19 | 108 | bool HPSerial::cmd_buf_full(void) |
109 | { | |
5 | 110 | return cmdbuf.full(); |
111 | } | |
112 | ||
19 | 113 | unsigned int HPSerial::nerrors(uint8_t errorno) |
114 | { | |
5 | 115 | return errs[errorno]; |
116 | } | |
117 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
118 | void HPSerial::pushCmd(uint8_t cmd, uint8_t size, char *payload) { |
5 | 119 | CMD val; |
120 | uint8_t i; | |
121 | val.id = ncmd++; | |
122 | val.cmd = cmd; | |
123 | val.size = size; | |
124 | for(i=0; i<size; i++) | |
125 | val.value[i] = payload[i]; | |
126 | val.value[i] = 0x00; | |
127 | cmdbuf.push(val); | |
128 | } | |
129 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
130 | void HPSerial::send_ack(uint8_t c) { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
131 | serial.putc(c); |
19 | 132 | set_timer(RXTIMEOUT); // if nothing else happen in the next ms, reset |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
133 | } |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
134 | |
19 | 135 | HPSerial::state_t HPSerial::do_state_initial(uint8_t c) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
136 | { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
137 | // we are idle, incoming char is a handcheck |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
138 | // knwon handcheck values are 0x66 and 0x33 |
19 | 139 | set_timer(RXTIMEOUT); // reset the watchdog |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
140 | switch (c) { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
141 | case 0x33: |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
142 | send_ack(0xCC); |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
143 | return HPSerial::STATE_PAYLOAD_SIZE; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
144 | break; |
19 | 145 | case 0x55: // EoT |
146 | return HPSerial::STATE_IDLE; | |
147 | break; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
148 | case 0x66: |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
149 | send_ack(0x99); |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
150 | return HPSerial::STATE_COMMAND; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
151 | break; |
19 | 152 | case 0xFF: |
153 | return HPSerial::STATE_IDLE; | |
154 | default: // unknown value | |
155 | send_ack(0xFF); | |
156 | return HPSerial::STATE_IDLE; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
157 | } |
5 | 158 | } |
159 | ||
19 | 160 | HPSerial::state_t HPSerial::do_state_command(uint8_t c) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
161 | { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
162 | if (c == 0x55) { // EoT |
19 | 163 | return STATE_IDLE; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
164 | } |
5 | 165 | |
19 | 166 | tr_data.cmd = c; |
167 | tr_data.size = 0; | |
168 | tr_data.pos = 0; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
169 | send_ack(0x00); |
19 | 170 | |
171 | if (c == 0x86) { // shutdown | |
172 | pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); | |
173 | return HPSerial::STATE_IDLE; | |
174 | } | |
175 | return STATE_PAYLOAD_SIZE; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
176 | } |
5 | 177 | |
19 | 178 | HPSerial::state_t HPSerial::do_state_payload_size(uint8_t c) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
179 | { |
19 | 180 | tr_data.size = c; |
181 | tr_data.pos = 0; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
182 | send_ack(0x00); |
19 | 183 | return STATE_PAYLOAD; |
5 | 184 | } |
185 | ||
19 | 186 | HPSerial::state_t HPSerial::do_state_payload(uint8_t c) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
187 | { |
19 | 188 | tr_data.payload[tr_data.pos++] = c; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
189 | send_ack(0x00); |
19 | 190 | if (tr_data.pos >= tr_data.size) { |
191 | pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); | |
192 | return HPSerial::STATE_IDLE; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
193 | } |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
194 | return HPSerial::STATE_PAYLOAD; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
195 | } |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
196 | |
19 | 197 | HPSerial::state_t HPSerial::do_state_sending(uint8_t c) |
198 | { | |
199 | // ghee | |
200 | if (c == 0xFF) | |
201 | { | |
202 | tr_data.pos--; | |
203 | tr_data.payload[tr_data.pos] += 1; | |
204 | } | |
205 | // TODO: check ACK values (c is the received ack) | |
206 | if (tr_data.pos >= tr_data.size) | |
207 | { | |
208 | return do_state_eot(); | |
209 | } | |
210 | serial.putc(tr_data.payload[tr_data.pos++]); | |
211 | set_timer(RXTIMEOUT); | |
212 | return HPSerial::STATE_SENDING; | |
213 | } | |
214 | ||
215 | HPSerial::state_t HPSerial::do_state_eot(uint8_t c) | |
216 | { | |
217 | serial.putc(0x55); // EoT | |
218 | if (cur_gstate == GSTATE_STARTING) { | |
219 | cur_gstate = GSTATE_STARTING2; | |
220 | set_timer(0.002); // launch startup2 in 10ms | |
221 | } | |
222 | else { | |
223 | cur_gstate = GSTATE_IDLE; | |
224 | set_timer(); // We are IDLE, detach the timeouter | |
225 | } | |
226 | return STATE_IDLE; | |
227 | } | |
228 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
229 | HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state, |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
230 | uint8_t c) |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
231 | { |
19 | 232 | return (this->*(HPSerial::state_table[cur_state]))(c); |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
233 | }; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
234 | |
5 | 235 | void HPSerial::rxIrq(void) { |
236 | uint8_t val; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
237 | if(serial.readable()) { // no reason why we would end here without |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
238 | // this condition, but hey |
8 | 239 | #ifdef DEBUG2 |
5 | 240 | inrx=1; |
241 | #endif | |
9 | 242 | lled = 1; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
243 | val = serial.getc(); |
19 | 244 | cur_state = run_state(cur_state, val); |
9 | 245 | lled = 0; |
8 | 246 | #ifdef DEBUG2 |
5 | 247 | inrx=0; |
248 | #endif | |
249 | } | |
250 | } | |
251 | ||
252 | ||
253 | void HPSerial::timeout(void) { | |
19 | 254 | set_timer(); // detach the timeouter |
255 | if (cur_gstate == GSTATE_STARTING) | |
256 | _startup(); | |
257 | else if (cur_gstate == GSTATE_STARTING2) | |
258 | _startup2(); | |
259 | else // reset | |
260 | { | |
261 | cur_gstate = GSTATE_IDLE; | |
262 | cur_state = STATE_IDLE; | |
263 | } | |
5 | 264 | } |
19 | 265 | |
266 |