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