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