Tue, 20 Sep 2016 23:50:45 +0200
several improvements
- add (used parts of) unigraphics in repo
- extract hp communication protocol listener in a dedicated file
5 | 1 | |
2 | #include "hp34comm.h" | |
3 | ||
4 | /***** HP 34970A communication class ***/ | |
5 | ||
6 | ||
7 | ||
8 | ||
9 | HPSerial::HPSerial(): | |
10 | ncmd(0), | |
11 | serial_tx(NC, HP_SERIAL_TX), serial_rx(NC, HP_SERIAL_RX) { | |
12 | ||
13 | //pc.printf("HPSerial init\n"); | |
14 | ||
15 | for(uint8_t i=0; i<MAX_ERRS; i++) | |
16 | errs[i] = 0; | |
17 | reset(); | |
18 | ||
19 | serial_tx.baud(187500); | |
20 | serial_tx.attach(this, &HPSerial::txIrq, Serial::RxIrq); //sic! | |
21 | ||
22 | serial_rx.baud(187500); | |
23 | serial_rx.attach(this, &HPSerial::rxIrq, Serial::RxIrq); | |
24 | } | |
25 | ||
26 | bool HPSerial::cmd_available(void) { | |
27 | return !cmdbuf.empty(); | |
28 | } | |
29 | ||
30 | bool HPSerial::pop(CMD& cmd) { | |
31 | return cmdbuf.pop(cmd); | |
32 | } | |
33 | ||
34 | bool HPSerial::cmd_buf_full(void) { | |
35 | return cmdbuf.full(); | |
36 | } | |
37 | ||
38 | unsigned int HPSerial::nerrors(uint8_t errorno) { | |
39 | return errs[errorno]; | |
40 | } | |
41 | ||
42 | ||
43 | ||
44 | void HPSerial::reset(uint8_t errorno=0xFF) { | |
45 | timeouter.detach(); | |
46 | head = 0; | |
47 | tx_state = Idle; | |
48 | setstatedbg(); | |
49 | tx_cmd = 0xFF; | |
50 | tx_ack = false; | |
51 | tx_len = 0xFF; | |
52 | memset(buf, 0, BUF_SIZE); | |
53 | if (errorno != 0xFF){ | |
54 | errs[errorno]++; | |
55 | pulse(errorno+1); | |
56 | } | |
57 | ||
58 | } | |
59 | ||
60 | void HPSerial::handleAck(uint8_t val) { | |
61 | if ((tx_state == Rx) & (tx_cmd == 0xFF) & (tx_ack == false) & (val == 0x66)) { | |
62 | // special case: keypad does not acknwledge and takes precedence | |
63 | // on the "bus" | |
64 | tx_state = Tx; | |
65 | setstatedbg(); | |
66 | } else | |
67 | ||
68 | if (tx_ack == true) | |
69 | reset(0); | |
70 | ||
71 | else | |
72 | if (tx_cmd == 0xFF) // still at the beginning of a packet, expect 0x99 as ack | |
73 | if (val == 0x99) | |
74 | { | |
75 | tx_ack = true; | |
76 | #ifdef DEBUG | |
77 | ack = 1; | |
78 | wait_us(2); | |
79 | ack = 0; | |
80 | #endif | |
81 | } | |
82 | else | |
83 | reset(1); | |
84 | ||
85 | else // expect 0x00 as ack | |
86 | if (val == 0x00) | |
87 | { | |
88 | tx_ack = true; | |
89 | #ifdef DEBUG | |
90 | ack = 1; | |
91 | wait_us(2); | |
92 | ack = 0; | |
93 | wait_us(2); | |
94 | ack = 1; | |
95 | wait_us(2); | |
96 | ack = 0; | |
97 | #endif | |
98 | } | |
99 | else | |
100 | reset(2); | |
101 | } | |
102 | ||
103 | void HPSerial::pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload) { | |
104 | CMD val; | |
105 | uint8_t i; | |
106 | val.id = ncmd++; | |
107 | val.direction = direction; | |
108 | val.cmd = cmd; | |
109 | val.size = size; | |
110 | for(i=0; i<size; i++) | |
111 | val.value[i] = payload[i]; | |
112 | val.value[i] = 0x00; | |
113 | cmdbuf.push(val); | |
114 | } | |
115 | ||
116 | void HPSerial::handleChar(uint8_t val) { | |
117 | if (tx_ack == false) | |
118 | reset(3); | |
119 | else // remaining of the state machine | |
120 | if (tx_cmd == 0xFF) { | |
121 | // begin of transmission, expect a cmd | |
122 | tx_cmd = val; | |
123 | tx_ack = false; | |
124 | if (tx_state == Rx) | |
125 | tx_len = 0xFF; | |
126 | else | |
127 | tx_len = 0x00; // no payload: tx_cmd is the key stroke | |
128 | } | |
129 | else if (tx_len == 0xFF) { | |
130 | // got a cmd, expect a payload size | |
131 | tx_len = val; | |
132 | tx_ack = false; | |
133 | } | |
134 | else if (tx_len > 0) { | |
135 | // a payload char | |
136 | buf[head++] = val; | |
137 | tx_len--; | |
138 | tx_ack = false; | |
139 | } | |
140 | else { // end of payload, manage sent content | |
141 | uint8_t cur_state = tx_state; | |
142 | pushCmd(tx_state, tx_cmd, head, buf); | |
143 | ||
144 | switch(val) { | |
145 | case 0x66: // a new transmisson | |
146 | reset(); | |
147 | tx_state = cur_state; | |
148 | setstatedbg(); | |
149 | break; | |
150 | case 0x55: | |
151 | reset(); | |
152 | break; | |
153 | default: | |
154 | reset(6); | |
155 | break; | |
156 | } | |
157 | } | |
158 | } | |
159 | ||
160 | ||
161 | ||
162 | void HPSerial::setstatedbg(void) { | |
163 | /* | |
164 | if (tx_state == Rx) | |
165 | staterx = 1; | |
166 | else | |
167 | staterx = 0; | |
168 | if (tx_state == Tx) | |
169 | statetx = 1; | |
170 | else | |
171 | statetx = 0; | |
172 | */ | |
173 | } | |
174 | ||
175 | void HPSerial::rxIrq(void) { | |
176 | uint8_t val; | |
177 | if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey | |
178 | #ifdef DEBUG | |
179 | inrx=1; | |
180 | #endif | |
181 | val = serial_rx.getc(); | |
182 | ||
183 | timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset | |
184 | ||
185 | if (tx_state == Idle) | |
186 | if (val == 0x66) { | |
187 | // no transmission in progress, expect a start of transmission | |
188 | tx_state = Rx; | |
189 | tx_ack = false; | |
190 | setstatedbg(); | |
191 | } | |
192 | else | |
193 | reset(4); | |
194 | ||
195 | else if (tx_state == Tx) // manage the acks | |
196 | handleAck(val); | |
197 | ||
198 | else | |
199 | handleChar(val); | |
200 | #ifdef DEBUG | |
201 | inrx=0; | |
202 | #endif | |
203 | } | |
204 | } | |
205 | ||
206 | void HPSerial::txIrq(void) { | |
207 | uint8_t val; | |
208 | if(serial_tx.readable()) { // no reason why we would end here without this condition, but hey | |
209 | #ifdef DEBUG | |
210 | intx=1; | |
211 | #endif | |
212 | val = serial_tx.getc(); | |
213 | ||
214 | timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset | |
215 | ||
216 | if (tx_state == Idle) | |
217 | if (val == 0x66) { | |
218 | // no transmission in progress, expect a start of transmission | |
219 | tx_state = Tx; | |
220 | tx_ack = false; | |
221 | setstatedbg(); | |
222 | } | |
223 | else | |
224 | reset(5); | |
225 | ||
226 | else if (tx_state == Rx) // manage the acks | |
227 | handleAck(val); | |
228 | ||
229 | else | |
230 | handleChar(val); | |
231 | } | |
232 | #ifdef DEBUG | |
233 | intx=0; | |
234 | #endif | |
235 | } | |
236 | ||
237 | void HPSerial::timeout(void) { | |
238 | if (tx_state != Idle) { | |
239 | reset(7); | |
240 | } | |
241 | } |