]> sigrok.org Git - libsigrok.git/blob - src/hardware/microchip-pickit2/protocol.c
17cc7586ac4baa80255467674ce6c3b443013a0d
[libsigrok.git] / src / hardware / microchip-pickit2 / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2018 Gerhard Sittig <gerhard.sittig@gmx.net>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include "protocol.h"
23
24 #define PICKIT2_PACKET_LENGTH   64
25 #define PICKIT2_USB_ENDPOINT    1
26 #define PICKIT2_USB_TIMEOUT     250
27
28 #define PICKIT2_CMD_CHKSTAT     0xa2
29 #define PICKIT2_CMD_CHKVOLT     0xa3
30 #define PICKIT2_CMD_READ        0xac
31 #define PICKIT2_CMD_PADCHAR     0xad
32 #define PICKIT2_CMD_SETUP       0xb8
33 #define PICKIT2_CMD_SETPOS      0xb9
34
35 #define PICKIT2_SEL_BANK0       0x06
36 #define PICKIT2_SEL_BANK1       0x07
37
38 struct pickit2_cmd {
39         size_t length;
40         uint8_t raw[PICKIT2_PACKET_LENGTH];
41 };
42
43 static void pickit2_cmd_clear(struct pickit2_cmd *cmd)
44 {
45
46         if (!cmd)
47                 return;
48         memset(&cmd->raw[0], PICKIT2_CMD_PADCHAR, PICKIT2_PACKET_LENGTH);
49         cmd->length = 0;
50 }
51
52 static void pickit2_cmd_append(struct pickit2_cmd *cmd, uint8_t b)
53 {
54
55         if (!cmd)
56                 return;
57         if (cmd->length == PICKIT2_PACKET_LENGTH)
58                 return;
59         cmd->raw[cmd->length++] = b;
60 }
61
62 static int pickit2_usb_send(const struct sr_dev_inst *sdi, struct pickit2_cmd *cmd)
63 {
64         struct sr_usb_dev_inst *usb;
65         int ret, sent;
66         GString *text;
67
68         if (!cmd)
69                 return SR_OK;
70         usb = sdi->conn;
71         if (!usb)
72                 return SR_ERR_ARG;
73
74         text = sr_hexdump_new(&cmd->raw[0], cmd->length);
75         sr_dbg("usb sent: %s", text->str);
76         sr_hexdump_free(text);
77
78         ret = libusb_interrupt_transfer(usb->devhdl,
79                 LIBUSB_ENDPOINT_OUT | PICKIT2_USB_ENDPOINT,
80                 &cmd->raw[0], PICKIT2_PACKET_LENGTH,
81                 &sent, PICKIT2_USB_TIMEOUT);
82         if (ret < 0) {
83                 sr_err("USB transmit error: %s.", libusb_error_name(ret));
84                 return SR_ERR_IO;
85         }
86         if (sent != PICKIT2_PACKET_LENGTH) {
87                 sr_err("USB short send: %d/%d bytes.",
88                         sent, PICKIT2_PACKET_LENGTH);
89                 return SR_ERR_IO;
90         }
91
92         return SR_OK;
93 }
94
95 static int pickit2_usb_recv(const struct sr_dev_inst *sdi, struct pickit2_cmd *cmd)
96 {
97         struct sr_usb_dev_inst *usb;
98         int ret, rcvd;
99         GString *text;
100
101         if (!cmd)
102                 return SR_ERR_ARG;
103         usb = sdi->conn;
104         if (!usb)
105                 return SR_ERR_ARG;
106
107         ret = libusb_interrupt_transfer(usb->devhdl,
108                 LIBUSB_ENDPOINT_IN | PICKIT2_USB_ENDPOINT,
109                 &cmd->raw[0], PICKIT2_PACKET_LENGTH,
110                 &rcvd, PICKIT2_USB_TIMEOUT);
111         if (ret < 0) {
112                 if (ret == LIBUSB_ERROR_TIMEOUT)
113                         sr_dbg("USB receive error: %s.", libusb_error_name(ret));
114                 else
115                         sr_err("USB receive error: %s.", libusb_error_name(ret));
116                 return SR_ERR_IO;
117         }
118
119         text = sr_hexdump_new(&cmd->raw[0], rcvd);
120         sr_dbg("usb recv: %s", text->str);
121         sr_hexdump_free(text);
122
123         cmd->length = rcvd;
124         if (rcvd != PICKIT2_PACKET_LENGTH) {
125                 sr_err("USB short recv: %d/%d bytes.",
126                         rcvd, PICKIT2_PACKET_LENGTH);
127                 return SR_ERR_IO;
128         }
129
130         return SR_OK;
131 }
132
133 /* Send a request, (optionally) keep reading until response became available. */
134 static int pickit2_usb_send_recv(const struct sr_dev_inst *sdi,
135         struct pickit2_cmd *send_cmd, struct pickit2_cmd *recv_cmd, int do_wait)
136 {
137         int ret;
138
139         /* Send the command when one got specified. Ignore errors. */
140         if (send_cmd)
141                 (void)pickit2_usb_send(sdi, send_cmd);
142
143         /*
144          * Try receiving data, always ignore errors. When requested by
145          * the caller then keep receiving until response data became
146          * available.
147          */
148         if (!recv_cmd)
149                 return SR_OK;
150         do {
151                 ret = pickit2_usb_recv(sdi, recv_cmd);
152                 if (ret == SR_OK)
153                         return SR_OK;
154                 if (!do_wait)
155                         return ret;
156         } while (1);
157         /* UNREACH */
158 }
159
160 SR_PRIV int microchip_pickit2_setup_trigger(const struct sr_dev_inst *sdi)
161 {
162         static const uint8_t trigger_channel_masks[PICKIT2_CHANNEL_COUNT] = {
163                 /* Bit positions for channels in trigger registers. */
164                 0x04, 0x08, 0x10,
165         };
166         static const uint16_t captureratio_magics[] = {
167                 /* TODO
168                  * How to exactly calculate these magic 16bit values?
169                  * They seem to neither match a percentage value nor a
170                  * sample count (assuming 1 window holds 1K samples).
171                  * As long as the formula is unknown, we are stuck with
172                  * looking up magic values from a table of few pre-sets.
173                  */
174                 0x0000,                 /* unspecified ratio value */
175                 0x03cc, 0x000a, 0x0248, /* 10%/50%/90% in the first window */
176                 0x07b4, 0x0b9c, 0x0f84, /* 10% "plus 1/2/3 window widths" */
177         };
178
179         struct dev_context *devc;
180         uint8_t trig_en, trig_lvl, trig_edge, trig_rep, trig_div;
181         uint16_t trig_pos;
182         uint64_t rate;
183         size_t trig_pos_idx, ch_idx;
184         uint8_t ch_mask, ch_cond;
185         struct pickit2_cmd cmd;
186
187         devc = sdi->priv;
188
189         /* Translate user specs to internal setup values. */
190         trig_en = trig_lvl = trig_edge = 0;
191         for (ch_idx = 0; ch_idx < PICKIT2_CHANNEL_COUNT; ch_idx++) {
192                 if (!devc->triggers[ch_idx])
193                         continue;
194                 ch_mask = trigger_channel_masks[ch_idx];
195                 ch_cond = devc->triggers[ch_idx];
196                 trig_en |= ch_mask;
197                 switch (ch_cond) {
198                 case SR_TRIGGER_ONE:
199                 case SR_TRIGGER_RISING:
200                         trig_lvl |= ch_mask;
201                         break;
202                 }
203                 switch (ch_cond) {
204                 case SR_TRIGGER_FALLING:
205                 case SR_TRIGGER_RISING:
206                         trig_edge |= ch_mask;
207                         break;
208                 }
209         }
210         trig_rep = 1;
211         trig_rep = MIN(trig_rep, 255);
212         trig_rep = MAX(trig_rep, 1);
213         if (!trig_en)
214                 trig_rep = 0;
215         rate = devc->samplerates[devc->curr_samplerate_idx];
216         rate = SR_MHZ(1) / rate - 1;
217         trig_div = rate & 0xff;
218         trig_pos_idx = devc->trigpos;
219         if (trig_pos_idx >= ARRAY_SIZE(captureratio_magics))
220                 trig_pos_idx = 0;
221         trig_pos = captureratio_magics[trig_pos_idx];
222
223         /* Construct the SETUP packet. */
224         pickit2_cmd_clear(&cmd);
225         pickit2_cmd_append(&cmd, PICKIT2_CMD_SETUP);
226         pickit2_cmd_append(&cmd, 0x01);
227         pickit2_cmd_append(&cmd, trig_en);
228         pickit2_cmd_append(&cmd, trig_lvl);
229         pickit2_cmd_append(&cmd, trig_edge);
230         pickit2_cmd_append(&cmd, trig_rep);
231         pickit2_cmd_append(&cmd, trig_pos % 256);
232         pickit2_cmd_append(&cmd, trig_pos / 256);
233         pickit2_cmd_append(&cmd, trig_div);
234
235         /*
236          * Transmit the SETUP packet. Only send it out, poll for the
237          * response later. When a trigger is involved, the response may
238          * take considerable amounts of time to arrive. We want apps
239          * to remain responsive during that period of time.
240          */
241         (void)pickit2_usb_send_recv(sdi, &cmd, NULL, FALSE);
242
243         return SR_OK;
244 }
245
246 /* Read specified bank data at given offset into caller provided buffer. */
247 static int pickit2_retrieve_bank(struct sr_dev_inst *sdi,
248         size_t bank_idx, size_t offset, uint8_t **buf, size_t *len)
249 {
250         struct pickit2_cmd send_cmd, recv_cmd;
251         int ret;
252         size_t copy_iter, copy_len;
253
254         /* Construct and send the SETPOS packet. No response expected. */
255         pickit2_cmd_clear(&send_cmd);
256         pickit2_cmd_append(&send_cmd, PICKIT2_CMD_SETPOS);
257         pickit2_cmd_append(&send_cmd, offset & 0xff);
258         pickit2_cmd_append(&send_cmd, PICKIT2_SEL_BANK0 + bank_idx);
259         ret = pickit2_usb_send_recv(sdi, &send_cmd, NULL, FALSE);
260         if (ret != SR_OK)
261                 return ret;
262         sr_dbg("read bank: pos set");
263
264         /* Run two READ cycles, get 2x 64 bytes => 128 bytes raw data. */
265         pickit2_cmd_clear(&send_cmd);
266         pickit2_cmd_append(&send_cmd, PICKIT2_CMD_READ);
267         copy_iter = 2;
268         while (copy_iter-- > 0) {
269                 ret = pickit2_usb_send_recv(sdi, &send_cmd, &recv_cmd, TRUE);
270                 if (ret != SR_OK)
271                         return ret;
272                 copy_len = MIN(PICKIT2_PACKET_LENGTH, *len);
273                 memcpy(*buf, &recv_cmd.raw[0], copy_len);
274                 *buf += copy_len;
275                 *len -= copy_len;
276         }
277
278         return SR_OK;
279 }
280
281 /* Read all of the (banked, raw) sample data after acquisition completed. */
282 static int pickit2_retrieve_sample_data(struct sr_dev_inst *sdi)
283 {
284         struct dev_context *devc;
285         uint8_t *rdpos;
286         size_t rdlen;
287         int ret;
288
289         devc = sdi->priv;
290         rdpos = &devc->samples_raw[0];
291         rdlen = sizeof(devc->samples_raw);
292
293         ret = pickit2_retrieve_bank(sdi, 0, 0x00, &rdpos, &rdlen);
294         if (ret)
295                 return ret;
296         ret = pickit2_retrieve_bank(sdi, 0, 0x80, &rdpos, &rdlen);
297         if (ret)
298                 return ret;
299         ret = pickit2_retrieve_bank(sdi, 1, 0x00, &rdpos, &rdlen);
300         if (ret)
301                 return ret;
302         ret = pickit2_retrieve_bank(sdi, 1, 0x80, &rdpos, &rdlen);
303         if (ret)
304                 return ret;
305
306         return SR_OK;
307 }
308
309 /* Send converted sample data to the sigrok session. */
310 static int pickit2_submit_logic_data(struct sr_dev_inst *sdi)
311 {
312         struct dev_context *devc;
313         struct {
314                 uint8_t raw_mask, conv_mask;
315         } ch_map[PICKIT2_CHANNEL_COUNT] = {
316                 { 0x04, 0x01, },
317                 { 0x08, 0x02, },
318                 { 0x01, 0x04, },
319         };
320         uint8_t *raw_buf, raw_byte, *conv_buf;
321         size_t raw_len, conv_len;
322         uint64_t limit;
323         struct sr_datafeed_packet packet;
324         struct sr_datafeed_logic logic;
325
326         devc = sdi->priv;
327
328         /*
329          * TODO Manipulate (or create) the above channel mapping table.
330          * Remove disabled channels, create dense output format.
331          * Could:
332          * - Loop over the index, check the corresponding channel's
333          *   state, clear out the conv_mask part and shift down all
334          *   subsequent conv_mask parts.
335          */
336
337         /*
338          * Convert raw dump (two samples per byte, at odd positions) to
339          * internal sigrok format (one sample per byte, at increasing
340          * offsets which start at 0).
341          */
342 #define handle_nibble(n) do { \
343         uint8_t conv_byte; \
344         size_t ch_idx; \
345         conv_byte = 0x00; \
346         for (ch_idx = 0; ch_idx < PICKIT2_CHANNEL_COUNT; ch_idx++) { \
347                 if ((n) & ch_map[ch_idx].raw_mask) \
348                         conv_byte |= ch_map[ch_idx].conv_mask; \
349         } \
350         *conv_buf++ = conv_byte; \
351         conv_len++; \
352 } while (0)
353
354         raw_len = sizeof(devc->samples_raw);
355         raw_buf = &devc->samples_raw[raw_len];
356         conv_buf = &devc->samples_conv[0];
357         conv_len = 0;
358         while (raw_len-- > 0) {
359                 raw_byte = *(--raw_buf);
360                 handle_nibble((raw_byte >> 0) & 0x0f);
361                 handle_nibble((raw_byte >> 4) & 0x0f);
362         }
363
364         /* Submit a logic packet to the sigrok session. */
365         packet.type = SR_DF_LOGIC;
366         packet.payload = &logic;
367         logic.unitsize = sizeof(uint8_t);
368         logic.data = &devc->samples_conv[0];
369         logic.length = conv_len;
370         limit = devc->sw_limits.limit_samples;
371         if (limit && limit < logic.length)
372                 logic.length = limit;
373         sr_session_send(sdi, &packet);
374
375         return SR_OK;
376 }
377
378 static gboolean pickit2_status_is_cancel(uint16_t status)
379 {
380         /* "Button press" and "transfer timeout" translate to "cancelled". */
381         static const uint16_t status_cancel_mask = 0x4004;
382
383         sr_dbg("recv: status 0x%04x", status);
384         if ((status & status_cancel_mask) == status_cancel_mask)
385                 return TRUE;
386         return FALSE;
387 }
388
389 /* Periodically invoked poll routine, checking for incoming receive data. */
390 SR_PRIV int microchip_pickit2_receive_data(int fd, int revents, void *cb_data)
391 {
392         struct sr_dev_inst *sdi;
393         struct dev_context *devc;
394         struct pickit2_cmd cmd;
395         int ret;
396         uint16_t status;
397
398         (void)fd;
399         (void)revents;
400
401         sdi = cb_data;
402         if (!sdi)
403                 return TRUE;
404         devc = sdi->priv;
405         if (!devc)
406                 return TRUE;
407
408         /* Waiting for the trigger condition? */
409         if (devc->state == STATE_WAIT) {
410                 /* Keep waiting until status becomes available. */
411                 ret = pickit2_usb_send_recv(sdi, NULL, &cmd, FALSE);
412                 if (ret != SR_OK)
413                         return TRUE;
414                 /* Check status flags for cancel requests. */
415                 devc->state = STATE_DATA;
416                 status = RL16(&cmd.raw[0]);
417                 if (pickit2_status_is_cancel(status)) {
418                         sr_info("User cancelled acquisition.");
419                         sr_dev_acquisition_stop(sdi);
420                         return TRUE;
421                 }
422                 sr_dbg("recv: Data has become available.");
423                 /* FALLTHROUGH */
424         }
425
426         /*
427          * Retrieve acquired sample data (blocking, acquisition has
428          * completed and samples are few), and stop acquisition (have
429          * the poll routine unregistered).
430          */
431         ret = pickit2_retrieve_sample_data(sdi);
432         if (ret != SR_OK)
433                 return ret;
434         ret = pickit2_submit_logic_data(sdi);
435         if (ret != SR_OK)
436                 return ret;
437         sr_dev_acquisition_stop(sdi);
438         return TRUE;
439 }