3 #include <mbed.h> |
3 #include <mbed.h> |
4 #include <CircularBuffer.h> |
4 #include <CircularBuffer.h> |
5 |
5 |
6 /***** HP 34970A communication class ***/ |
6 /***** HP 34970A communication class ***/ |
7 |
7 |
8 #ifdef DEBUG2 |
|
9 |
|
10 DigitalOut inrx(D9); |
|
11 |
|
12 #endif |
|
13 |
|
14 DigitalOut lled(LED3); |
|
15 |
|
16 #define RXTIMEOUT 50ms |
8 #define RXTIMEOUT 50ms |
17 #define STARTUPRETRY 0.5 |
9 #define STARTUPRETRY 0.5 |
18 |
10 |
19 uint8_t startup_seq[] = { |
11 uint8_t startup_seq[] = { |
20 0x33, |
12 0x33, |
21 0x02, |
13 0x02, // 0x02? |
22 0x00, |
14 0x00, |
23 0x00, // to be replaced by the actual keycode, if any |
15 0x00, |
24 }; |
16 }; |
25 |
17 |
26 HPSerial::statemethod HPSerial::state_table[NUM_STATES] = { |
18 HPSerial::statemethod HPSerial::state_table[NUM_STATES] = { |
27 &HPSerial::do_state_initial, |
19 &HPSerial::do_state_initial, // STATE_IDLE |
28 &HPSerial::do_state_command, |
20 &HPSerial::do_state_command, // STATE_COMMAND |
29 &HPSerial::do_state_payload_size, |
21 &HPSerial::do_state_payload_size, // STATE_PAYLOAD_SIZE |
30 &HPSerial::do_state_payload, |
22 &HPSerial::do_state_payload, // STATE_PAYLOAD |
31 &HPSerial::do_state_sending, |
23 &HPSerial::do_state_sending, // STATE_SENDING |
32 &HPSerial::do_state_eot, |
|
33 }; |
24 }; |
34 |
25 |
35 |
26 |
36 HPSerial::HPSerial(PinName tx, PinName rx): |
27 HPSerial::HPSerial(PinName tx, PinName rx): |
37 serial(tx, rx), |
28 serial(tx, rx), |
38 ncmd(0), |
29 ncmd(0), |
39 cur_gstate(GSTATE_IDLE) |
30 cur_gstate(GSTATE_IDLE) |
40 { |
31 { |
41 serial.baud(187500); |
32 serial.baud(187500); |
|
33 serial.format(8, BufferedSerial::Even, 1); |
42 cur_state = STATE_IDLE; |
34 cur_state = STATE_IDLE; |
43 serial.attach(callback(this, &HPSerial::rxIrq), SerialBase::RxIrq); |
35 serial.attach(callback(this, &HPSerial::rx_irq), SerialBase::RxIrq); |
44 } |
36 } |
45 |
37 |
46 void HPSerial::startup(uint8_t keycode) { |
38 void HPSerial::startup(uint8_t keycode) { |
|
39 cur_gstate = GSTATE_STARTING; |
|
40 |
47 if (keycode != 0xFF) { |
41 if (keycode != 0xFF) { |
48 startup_sed[2] = 0xFF; |
42 printf("Set startup keycode to %X\n", keycode); |
49 startup_sed[3] = keycode; |
43 startup_seq[2] = 0xFF; |
50 } |
44 startup_seq[3] = keycode; |
51 |
45 } |
52 cur_gstate = GSTATE_STARTING; |
46 else |
|
47 startup_seq[2] = 0x00; |
53 set_timer(10ms); // launch the startup in 10ms |
48 set_timer(10ms); // launch the startup in 10ms |
54 } |
49 } |
55 |
50 |
56 void HPSerial::_startup(void) |
51 void HPSerial::_startup(void) |
57 { |
52 { |
63 tr_data.size = 4; |
58 tr_data.size = 4; |
64 else |
59 else |
65 tr_data.size = 3; // sizeof(startup_seq); |
60 tr_data.size = 3; // sizeof(startup_seq); |
66 for(uint8_t i=0; i<tr_data.size; i++) |
61 for(uint8_t i=0; i<tr_data.size; i++) |
67 tr_data.payload[i] = startup_seq[i]; |
62 tr_data.payload[i] = startup_seq[i]; |
68 |
|
69 cur_state = do_state_sending(); |
63 cur_state = do_state_sending(); |
70 } |
64 } |
71 |
65 |
72 void HPSerial::sendkey(uint8_t keycode) |
66 void HPSerial::sendkey(uint8_t keycode) |
73 { |
67 { |
74 tr_data.size = 2; |
68 if (!sendbuf.full()) |
75 tr_data.cmd = 0xFF; |
69 sendbuf.push(keycode); |
76 tr_data.pos = 0; |
70 } |
77 tr_data.payload[0] = 0x66; |
71 |
78 tr_data.payload[1] = keycode; |
72 void HPSerial::send_key_when_idle() { |
79 cur_state = do_state_sending(); |
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 } |
80 } |
85 } |
81 |
86 |
82 bool HPSerial::cmd_available(void) |
87 bool HPSerial::cmd_available(void) |
83 { |
88 { |
84 return !cmdbuf.empty(); |
89 return !cmdbuf.empty(); |
110 val.value[i] = 0x00; |
115 val.value[i] = 0x00; |
111 cmdbuf.push(val); |
116 cmdbuf.push(val); |
112 } |
117 } |
113 |
118 |
114 void HPSerial::send_ack(uint8_t c) { |
119 void HPSerial::send_ack(uint8_t c) { |
115 serial.write(&c, 1); |
120 serial.write(&c, 1); |
116 set_timer(RXTIMEOUT); // if nothing else happen in the next ms, reset |
121 set_timer(RXTIMEOUT); // if nothing else happen in the next RXTIMEOUT ms, reset |
117 } |
122 } |
118 |
123 |
119 HPSerial::state_t HPSerial::do_state_initial(uint8_t c) |
124 HPSerial::state_t HPSerial::do_state_initial(uint8_t c) |
120 { |
125 { |
121 // we are idle, incoming char is a handcheck |
126 // we are idle, incoming char is a handcheck |
122 // knwon handcheck values are 0x66 and 0x33 |
127 // knwon handcheck values are 0x66 and 0x33 |
123 set_timer(RXTIMEOUT); // reset the watchdog |
128 set_timer(RXTIMEOUT); // reset the watchdog |
124 switch (c) { |
129 switch (c) { |
125 case 0x33: |
130 case 0x33: // XXX? when are we expecting a 0x33 here? |
126 send_ack(0xCC); |
131 send_ack(0xCC); |
127 return HPSerial::STATE_PAYLOAD_SIZE; |
132 return HPSerial::STATE_PAYLOAD_SIZE; |
128 break; |
133 break; |
129 case 0x55: // EoT |
134 case 0x55: // EoT |
130 return HPSerial::STATE_IDLE; |
135 return HPSerial::STATE_IDLE; |
171 { |
176 { |
172 tr_data.payload[tr_data.pos++] = c; |
177 tr_data.payload[tr_data.pos++] = c; |
173 send_ack(0x00); |
178 send_ack(0x00); |
174 if (tr_data.pos >= tr_data.size) { |
179 if (tr_data.pos >= tr_data.size) { |
175 pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); |
180 pushCmd(tr_data.cmd, tr_data.size, tr_data.payload); |
176 return HPSerial::STATE_IDLE; |
181 return STATE_IDLE; |
177 } |
182 } |
178 return HPSerial::STATE_PAYLOAD; |
183 return STATE_PAYLOAD; |
179 } |
184 } |
180 |
185 |
181 HPSerial::state_t HPSerial::do_state_sending(uint8_t c) |
186 HPSerial::state_t HPSerial::do_state_sending(uint8_t c) |
182 { |
187 { |
183 // ghee |
188 // ghee |
184 if (c == 0xFF) |
189 if (c == 0xFF) |
185 { // resend current char |
190 { // resend current char |
186 tr_data.pos--; |
191 tr_data.pos--; |
187 tr_data.payload[tr_data.pos] += 1; |
|
188 } |
192 } |
189 // TODO: check ACK values (c is the received ack) |
193 // TODO: check ACK values (c is the received ack) |
190 if (tr_data.pos >= tr_data.size) |
194 if (tr_data.pos >= tr_data.size) |
191 { |
195 { |
192 return do_state_eot(); |
196 c = 0x55; |
193 } |
197 serial.write(&c, 1); // EoT |
194 serial.write(&tr_data.payload[tr_data.pos++], 1); |
198 cur_gstate = GSTATE_IDLE; |
195 set_timer(RXTIMEOUT); |
199 set_timer(); // We are IDLE, detach the timeouter |
196 return HPSerial::STATE_SENDING; |
200 return STATE_IDLE; |
197 } |
201 } |
198 |
202 else |
199 HPSerial::state_t HPSerial::do_state_eot(uint8_t c) |
203 { |
200 { |
204 serial.write(&tr_data.payload[tr_data.pos++], 1); |
201 serial.write(&c, 1); // EoT |
205 set_timer(RXTIMEOUT); |
202 cur_gstate = GSTATE_IDLE; |
206 return STATE_SENDING; |
203 set_timer(); // We are IDLE, detach the timeouter |
207 } |
204 return STATE_IDLE; |
|
205 } |
208 } |
206 |
209 |
207 HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state, |
210 HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state, |
208 uint8_t c) |
211 uint8_t c) |
209 { |
212 { |
210 return (this->*(HPSerial::state_table[cur_state]))(c); |
213 return (this->*(HPSerial::state_table[cur_state]))(c); |
211 }; |
214 }; |
212 |
215 |
213 void HPSerial::rxIrq(void) { |
216 void HPSerial::rx_irq(void) { |
214 uint8_t val; |
217 uint8_t val; |
215 if(serial.readable()) |
218 if(serial.readable()) |
216 { // no reason why we would end here without |
219 { // no reason why we would end here without |
217 // this condition, but hey |
220 // this condition, but hey |
218 #ifdef DEBUG2 |
221 if (cur_gstate == GSTATE_IDLE) |
219 inrx=1; |
222 // occurs when the CPU starts a new transmission |
220 #endif |
223 // at this point, cur_state should be STATE_IDLE also (TODO add a check?) |
221 //lled = 1; |
224 cur_gstate = GSTATE_RX; |
222 //val = serial.getc(); |
|
223 serial.read(&val, 1); |
225 serial.read(&val, 1); |
224 cur_state = run_state(cur_state, val); |
226 cur_state = run_state(cur_state, val); |
225 //lled = 0; |
|
226 #ifdef DEBUG2 |
|
227 inrx=0; |
|
228 #endif |
|
229 } |
227 } |
230 } |
228 } |
231 |
229 |
232 |
230 |
233 void HPSerial::timeout(void) { |
231 void HPSerial::timeout(void) { |
234 set_timer(); // detach the timeouter |
232 set_timer(); // detach the timeouter |
235 if (cur_gstate == GSTATE_STARTING) |
233 if (cur_gstate == GSTATE_STARTING) |
236 _startup(); |
234 _startup(); |
237 else // reset |
235 else // CPU took too long to reply, reset |
238 { |
236 { |
239 cur_gstate = GSTATE_IDLE; |
237 cur_gstate = GSTATE_IDLE; |
240 cur_state = STATE_IDLE; |
238 cur_state = STATE_IDLE; |
241 } |
239 } |
242 } |
240 } |