Tue, 11 Oct 2016 21:44:04 +0200
foldme
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); | |
12 | DigitalOut staterx(D7); | |
13 | DigitalOut statetx(D8); | |
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; | |
94 | wait_us(2); | |
95 | ack = 1; | |
96 | wait_us(2); | |
97 | ack = 0; | |
5 | 98 | #endif |
9 | 99 | } |
100 | else | |
101 | reset(2); | |
5 | 102 | } |
103 | ||
104 | void HPSerial::pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload) { | |
105 | CMD val; | |
106 | uint8_t i; | |
107 | val.id = ncmd++; | |
108 | val.direction = direction; | |
109 | val.cmd = cmd; | |
110 | val.size = size; | |
111 | for(i=0; i<size; i++) | |
112 | val.value[i] = payload[i]; | |
113 | val.value[i] = 0x00; | |
114 | cmdbuf.push(val); | |
115 | } | |
116 | ||
117 | void HPSerial::handleChar(uint8_t val) { | |
118 | if (tx_ack == false) | |
119 | reset(3); | |
120 | else // remaining of the state machine | |
121 | if (tx_cmd == 0xFF) { | |
122 | // begin of transmission, expect a cmd | |
123 | tx_cmd = val; | |
124 | tx_ack = false; | |
9 | 125 | tx_len = 0xFF; |
5 | 126 | } |
127 | else if (tx_len == 0xFF) { | |
128 | // got a cmd, expect a payload size | |
129 | tx_len = val; | |
130 | tx_ack = false; | |
131 | } | |
9 | 132 | else if (tx_len == 0x55) { |
133 | // packet was in fact a keystroke, tx_cmd is in fact the key | |
134 | // stroke and no payload is expected | |
135 | pushCmd((TrState)Tx, tx_cmd, 0, NULL); | |
136 | reset(); | |
137 | } | |
5 | 138 | else if (tx_len > 0) { |
139 | // a payload char | |
140 | buf[head++] = val; | |
141 | tx_len--; | |
142 | tx_ack = false; | |
143 | } | |
144 | else { // end of payload, manage sent content | |
145 | uint8_t cur_state = tx_state; | |
8 | 146 | pushCmd((TrState)tx_state, tx_cmd, head, (char*)buf); |
5 | 147 | |
148 | switch(val) { | |
149 | case 0x66: // a new transmisson | |
150 | reset(); | |
151 | tx_state = cur_state; | |
152 | setstatedbg(); | |
153 | break; | |
154 | case 0x55: | |
155 | reset(); | |
156 | break; | |
157 | default: | |
158 | reset(6); | |
159 | break; | |
160 | } | |
161 | } | |
162 | } | |
163 | ||
164 | ||
165 | ||
166 | void HPSerial::setstatedbg(void) { | |
8 | 167 | #ifdef DEBUG2 |
5 | 168 | if (tx_state == Rx) |
8 | 169 | staterx = 1; |
5 | 170 | else |
8 | 171 | staterx = 0; |
5 | 172 | if (tx_state == Tx) |
8 | 173 | statetx = 1; |
5 | 174 | else |
8 | 175 | statetx = 0; |
176 | #endif | |
5 | 177 | } |
178 | ||
179 | void HPSerial::rxIrq(void) { | |
180 | uint8_t val; | |
181 | if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey | |
8 | 182 | #ifdef DEBUG2 |
5 | 183 | inrx=1; |
184 | #endif | |
9 | 185 | lled = 1; |
5 | 186 | val = serial_rx.getc(); |
187 | ||
188 | timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset | |
189 | ||
190 | if (tx_state == Idle) | |
191 | if (val == 0x66) { | |
192 | // no transmission in progress, expect a start of transmission | |
193 | tx_state = Rx; | |
194 | tx_ack = false; | |
195 | setstatedbg(); | |
196 | } | |
8 | 197 | else { |
5 | 198 | reset(4); |
8 | 199 | } |
9 | 200 | else if (tx_ack == false) // manage the acks |
5 | 201 | handleAck(val); |
202 | else | |
203 | handleChar(val); | |
9 | 204 | lled = 0; |
8 | 205 | #ifdef DEBUG2 |
5 | 206 | inrx=0; |
207 | #endif | |
208 | } | |
209 | } | |
210 | ||
211 | ||
212 | void HPSerial::timeout(void) { | |
213 | if (tx_state != Idle) { | |
214 | reset(7); | |
215 | } | |
216 | } |