Sun, 01 Nov 2020 22:21:19 +0100
Many improvements
- add support for dimm-based selection,
- add support for poweroff (at least power thr display off),
- add support for the initial key pressed during initialization sequence,
- fix a race condition (sending a keycode while receiving a message)
- add support for the shift button
- many code cleanups and improvements
5 | 1 | #include "hp34comm.h" |
28
424d792fea4f
compile for nucleo f446re & f303re with mbed 6
David Douard <david.douard@sdfa3.org>
parents:
21
diff
changeset
|
2 | |
424d792fea4f
compile for nucleo f446re & f303re with mbed 6
David Douard <david.douard@sdfa3.org>
parents:
21
diff
changeset
|
3 | #include <mbed.h> |
424d792fea4f
compile for nucleo f446re & f303re with mbed 6
David Douard <david.douard@sdfa3.org>
parents:
21
diff
changeset
|
4 | #include <CircularBuffer.h> |
5 | 5 | |
6 | /***** HP 34970A communication class ***/ | |
7 | ||
37
07e8ca2bdf6d
Extracted the display related functions in a Display class
David Douard <david.douard@sdf3.org>
parents:
28
diff
changeset
|
8 | #define RXTIMEOUT 50ms |
19 | 9 | #define STARTUPRETRY 0.5 |
21 | 10 | |
39
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
11 | uint8_t startup_seq[] = { |
19 | 12 | 0x33, |
44 | 13 | 0x02, // 0x02? |
19 | 14 | 0x00, |
44 | 15 | 0x00, |
19 | 16 | }; |
17 | ||
18 | HPSerial::statemethod HPSerial::state_table[NUM_STATES] = { | |
44 | 19 | &HPSerial::do_state_initial, // STATE_IDLE |
20 | &HPSerial::do_state_command, // STATE_COMMAND | |
21 | &HPSerial::do_state_payload_size, // STATE_PAYLOAD_SIZE | |
22 | &HPSerial::do_state_payload, // STATE_PAYLOAD | |
23 | &HPSerial::do_state_sending, // STATE_SENDING | |
19 | 24 | }; |
5 | 25 | |
37
07e8ca2bdf6d
Extracted the display related functions in a Display class
David Douard <david.douard@sdf3.org>
parents:
28
diff
changeset
|
26 | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
27 | HPSerial::HPSerial(PinName tx, PinName rx): |
19 | 28 | serial(tx, rx), |
37
07e8ca2bdf6d
Extracted the display related functions in a Display class
David Douard <david.douard@sdf3.org>
parents:
28
diff
changeset
|
29 | ncmd(0), |
07e8ca2bdf6d
Extracted the display related functions in a Display class
David Douard <david.douard@sdf3.org>
parents:
28
diff
changeset
|
30 | cur_gstate(GSTATE_IDLE) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
31 | { |
21 | 32 | serial.baud(187500); |
44 | 33 | serial.format(8, BufferedSerial::Even, 1); |
19 | 34 | cur_state = STATE_IDLE; |
44 | 35 | serial.attach(callback(this, &HPSerial::rx_irq), SerialBase::RxIrq); |
19 | 36 | } |
37 | ||
39
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
38 | void HPSerial::startup(uint8_t keycode) { |
44 | 39 | cur_gstate = GSTATE_STARTING; |
40 | ||
39
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
41 | if (keycode != 0xFF) { |
44 | 42 | printf("Set startup keycode to %X\n", keycode); |
43 | startup_seq[2] = 0xFF; | |
44 | startup_seq[3] = keycode; | |
39
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
45 | } |
44 | 46 | else |
47 | startup_seq[2] = 0x00; | |
37
07e8ca2bdf6d
Extracted the display related functions in a Display class
David Douard <david.douard@sdf3.org>
parents:
28
diff
changeset
|
48 | set_timer(10ms); // launch the startup in 10ms |
19 | 49 | } |
50 | ||
51 | void HPSerial::_startup(void) | |
52 | { | |
53 | cur_gstate = GSTATE_STARTING; | |
54 | tr_data.cmd = 0xFF; | |
55 | tr_data.pos = 0; | |
39
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
56 | |
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
57 | if (startup_seq[2] == 0xFF) |
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
58 | tr_data.size = 4; |
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
59 | else |
63c6a720cb97
hp34comm: add support for boot keycode
David Douard <david.douard@sdf3.org>
parents:
37
diff
changeset
|
60 | tr_data.size = 3; // sizeof(startup_seq); |
19 | 61 | for(uint8_t i=0; i<tr_data.size; i++) |
62 | tr_data.payload[i] = startup_seq[i]; | |
63 | cur_state = do_state_sending(); | |
5 | 64 | } |
65 | ||
19 | 66 | void HPSerial::sendkey(uint8_t keycode) |
67 | { | |
44 | 68 | if (!sendbuf.full()) |
69 | sendbuf.push(keycode); | |
70 | } | |
71 | ||
72 | void HPSerial::send_key_when_idle() { | |
73 | if (!sendbuf.empty() && cur_gstate == GSTATE_IDLE) | |
74 | { | |
75 | uint8_t keycode; | |
76 | cur_gstate = GSTATE_TX; | |
77 | sendbuf.pop(keycode); | |
78 | tr_data.size = 2; | |
79 | tr_data.cmd = 0xFF; | |
80 | tr_data.pos = 0; | |
81 | tr_data.payload[0] = 0x66; | |
82 | tr_data.payload[1] = keycode; | |
83 | cur_state = do_state_sending(); | |
84 | } | |
19 | 85 | } |
86 | ||
87 | bool HPSerial::cmd_available(void) | |
88 | { | |
5 | 89 | return !cmdbuf.empty(); |
90 | } | |
91 | ||
19 | 92 | bool HPSerial::pop(CMD& cmd) |
93 | { | |
5 | 94 | return cmdbuf.pop(cmd); |
95 | } | |
96 | ||
19 | 97 | bool HPSerial::cmd_buf_full(void) |
98 | { | |
5 | 99 | return cmdbuf.full(); |
100 | } | |
101 | ||
19 | 102 | unsigned int HPSerial::nerrors(uint8_t errorno) |
21 | 103 | { |
5 | 104 | return errs[errorno]; |
105 | } | |
106 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
107 | void HPSerial::pushCmd(uint8_t cmd, uint8_t size, char *payload) { |
5 | 108 | CMD val; |
109 | uint8_t i; | |
110 | val.id = ncmd++; | |
111 | val.cmd = cmd; | |
112 | val.size = size; | |
113 | for(i=0; i<size; i++) | |
114 | val.value[i] = payload[i]; | |
115 | val.value[i] = 0x00; | |
116 | cmdbuf.push(val); | |
117 | } | |
118 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
119 | void HPSerial::send_ack(uint8_t c) { |
44 | 120 | serial.write(&c, 1); |
121 | set_timer(RXTIMEOUT); // if nothing else happen in the next RXTIMEOUT ms, reset | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
122 | } |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
123 | |
19 | 124 | 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
|
125 | { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
126 | // 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
|
127 | // knwon handcheck values are 0x66 and 0x33 |
19 | 128 | 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
|
129 | switch (c) { |
44 | 130 | case 0x33: // XXX? when are we expecting a 0x33 here? |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
131 | send_ack(0xCC); |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
132 | return HPSerial::STATE_PAYLOAD_SIZE; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
133 | break; |
19 | 134 | case 0x55: // EoT |
135 | return HPSerial::STATE_IDLE; | |
136 | break; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
137 | case 0x66: |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
138 | send_ack(0x99); |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
139 | return HPSerial::STATE_COMMAND; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
140 | break; |
19 | 141 | case 0xFF: |
142 | return HPSerial::STATE_IDLE; | |
143 | default: // unknown value | |
144 | send_ack(0xFF); | |
145 | return HPSerial::STATE_IDLE; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
146 | } |
5 | 147 | } |
148 | ||
19 | 149 | 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
|
150 | { |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
151 | if (c == 0x55) { // EoT |
19 | 152 | return STATE_IDLE; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
153 | } |
5 | 154 | |
19 | 155 | tr_data.cmd = c; |
156 | tr_data.size = 0; | |
157 | tr_data.pos = 0; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
158 | send_ack(0x00); |
19 | 159 | |
160 | if (c == 0x86) { // shutdown | |
161 | pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); | |
162 | return HPSerial::STATE_IDLE; | |
21 | 163 | } |
19 | 164 | return STATE_PAYLOAD_SIZE; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
165 | } |
5 | 166 | |
19 | 167 | 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
|
168 | { |
19 | 169 | tr_data.size = c; |
170 | tr_data.pos = 0; | |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
171 | send_ack(0x00); |
19 | 172 | return STATE_PAYLOAD; |
5 | 173 | } |
174 | ||
19 | 175 | 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
|
176 | { |
19 | 177 | 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
|
178 | send_ack(0x00); |
19 | 179 | if (tr_data.pos >= tr_data.size) { |
180 | pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); | |
44 | 181 | return STATE_IDLE; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
182 | } |
44 | 183 | return STATE_PAYLOAD; |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
184 | } |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
185 | |
19 | 186 | HPSerial::state_t HPSerial::do_state_sending(uint8_t c) |
187 | { | |
188 | // ghee | |
189 | if (c == 0xFF) | |
21 | 190 | { // resend current char |
191 | tr_data.pos--; | |
192 | } | |
19 | 193 | // TODO: check ACK values (c is the received ack) |
194 | if (tr_data.pos >= tr_data.size) | |
21 | 195 | { |
44 | 196 | c = 0x55; |
197 | serial.write(&c, 1); // EoT | |
198 | cur_gstate = GSTATE_IDLE; | |
199 | set_timer(); // We are IDLE, detach the timeouter | |
200 | return STATE_IDLE; | |
21 | 201 | } |
44 | 202 | else |
203 | { | |
204 | serial.write(&tr_data.payload[tr_data.pos++], 1); | |
205 | set_timer(RXTIMEOUT); | |
206 | return STATE_SENDING; | |
207 | } | |
19 | 208 | } |
209 | ||
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
210 | HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state, |
44 | 211 | uint8_t c) |
18
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
212 | { |
19 | 213 | 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
|
214 | }; |
4fd621551d55
[full replacement] implement a state machine for Rx
David Douard <david.douard@logilab.fr>
parents:
16
diff
changeset
|
215 | |
44 | 216 | void HPSerial::rx_irq(void) { |
5 | 217 | uint8_t val; |
21 | 218 | if(serial.readable()) |
219 | { // no reason why we would end here without | |
220 | // this condition, but hey | |
44 | 221 | if (cur_gstate == GSTATE_IDLE) |
222 | // occurs when the CPU starts a new transmission | |
223 | // at this point, cur_state should be STATE_IDLE also (TODO add a check?) | |
224 | cur_gstate = GSTATE_RX; | |
28
424d792fea4f
compile for nucleo f446re & f303re with mbed 6
David Douard <david.douard@sdfa3.org>
parents:
21
diff
changeset
|
225 | serial.read(&val, 1); |
19 | 226 | cur_state = run_state(cur_state, val); |
5 | 227 | } |
228 | } | |
229 | ||
230 | ||
231 | void HPSerial::timeout(void) { | |
19 | 232 | set_timer(); // detach the timeouter |
233 | if (cur_gstate == GSTATE_STARTING) | |
234 | _startup(); | |
44 | 235 | else // CPU took too long to reply, reset |
19 | 236 | { |
237 | cur_gstate = GSTATE_IDLE; | |
238 | cur_state = STATE_IDLE; | |
239 | } | |
5 | 240 | } |