]> sigrok.org Git - libsigrok.git/blob - src/hardware/hantek-4032l/protocol.c
hantek-4032l: Add initial driver implementation.
[libsigrok.git] / src / hardware / hantek-4032l / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2016 Andreas Zschunke <andreas.zschunke@gmx.net>
5  * Copyright (C) 2017 Andrej Valek <andy@skyrain.eu>
6  * Copyright (C) 2017 Uwe Hermann <uwe@hermann-uwe.de>
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <config.h>
23 #include "protocol.h"
24
25 #define H4032L_USB_TIMEOUT 500
26
27 enum h4032l_cmd {
28         CMD_CONFIGURE = 0x2b1a, /* Also arms the logic analyzer. */
29         CMD_STATUS = 0x4b3a,
30         CMD_GET = 0x6b5a
31 };
32
33 struct __attribute__((__packed__)) h4032l_status_packet {
34         uint32_t magic;
35         uint32_t values;
36         uint32_t status;
37 };
38
39 SR_PRIV int h4032l_receive_data(int fd, int revents, void *cb_data)
40 {
41         struct timeval tv;
42         struct drv_context *drvc;
43
44         (void)fd;
45         (void)revents;
46
47         drvc = (struct drv_context *)cb_data;
48
49         tv.tv_sec = tv.tv_usec = 0;
50         libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
51
52         return TRUE;
53 }
54
55 void LIBUSB_CALL h4032l_usb_callback(struct libusb_transfer *transfer)
56 {
57         const struct sr_dev_inst *sdi = transfer->user_data;
58         struct dev_context *devc = sdi->priv;
59         struct drv_context *drvc = sdi->driver->context;
60         struct sr_usb_dev_inst *usb = sdi->conn;
61         gboolean cmd = FALSE;
62         uint32_t max_samples = 512 / sizeof(uint32_t);
63         uint32_t *buffer;
64         struct h4032l_status_packet *status;
65         struct sr_datafeed_packet packet;
66         struct sr_datafeed_logic logic;
67         uint32_t number_samples;
68         int ret;
69
70         if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
71                 sr_err("%s error: %d.", __func__, transfer->status);
72                 return;
73         }
74
75         buffer = (uint32_t *)transfer->buffer;
76
77         switch (devc->status) {
78         case H4032L_STATUS_IDLE:
79                 sr_err("USB callback called in idle.");
80                 break;
81         case H4032L_STATUS_CMD_CONFIGURE:
82                 /* Select status request as next. */
83                 cmd = TRUE;
84                 devc->cmd_pkt.cmd = CMD_STATUS;
85                 devc->status = H4032L_STATUS_CMD_STATUS;
86                 break;
87         case H4032L_STATUS_CMD_STATUS:
88                 /* Select status request as next. */
89                 devc->status = H4032L_STATUS_RESPONSE_STATUS;
90                 break;
91         case H4032L_STATUS_RESPONSE_STATUS:
92                 /*
93                  * Check magic and if status is complete, then select
94                  * First Transfer as next.
95                  */
96                 status = (struct h4032l_status_packet *)transfer->buffer;
97                 if (status->magic != H4032L_STATUS_PACKET_MAGIC) {
98                         devc->status = H4032L_STATUS_CMD_STATUS;
99                         devc->cmd_pkt.cmd = CMD_STATUS;
100                         cmd = TRUE;
101                 } else if (status->status == 2) {
102                         devc->status = H4032L_STATUS_RESPONSE_STATUS_CONTINUE;
103                 } else {
104                         devc->status = H4032L_STATUS_RESPONSE_STATUS_RETRY;
105                 }
106                 break;
107         case H4032L_STATUS_RESPONSE_STATUS_RETRY:
108                 devc->status = H4032L_STATUS_CMD_STATUS;
109                 devc->cmd_pkt.cmd = CMD_STATUS;
110                 cmd = TRUE;
111                 break;
112         case H4032L_STATUS_RESPONSE_STATUS_CONTINUE:
113                 devc->status = H4032L_STATUS_CMD_GET;
114                 devc->cmd_pkt.cmd = CMD_GET;
115                 cmd = TRUE;
116                 break;
117         case H4032L_STATUS_CMD_GET:
118                 devc->status = H4032L_STATUS_FIRST_TRANSFER;
119                 break;
120         case H4032L_STATUS_FIRST_TRANSFER:
121                 if (buffer[0] != H4032L_START_PACKET_MAGIC) {
122                         sr_err("Mismatch magic number of start poll.");
123                         devc->status = H4032L_STATUS_IDLE;
124                         break;
125                 }
126                 devc->status = H4032L_STATUS_TRANSFER;
127                 max_samples--;
128                 buffer++;
129                 break;
130         case H4032L_STATUS_TRANSFER:
131                 number_samples = (devc->remaining_samples < max_samples) ? devc->remaining_samples : max_samples;
132                 devc->remaining_samples -= number_samples;
133                 packet.type = SR_DF_LOGIC;
134                 packet.payload = &logic;
135                 logic.length = number_samples * sizeof(uint32_t);
136                 logic.unitsize = sizeof(uint32_t);
137                 logic.data = buffer;
138                 sr_session_send(sdi, &packet);
139                 sr_dbg("Remaining: %d %08X %08X.", devc->remaining_samples,
140                         buffer[0], buffer[1]);
141                 if (devc->remaining_samples == 0) {
142                         std_session_send_df_end(sdi);
143                         usb_source_remove(sdi->session, drvc->sr_ctx);
144                         devc->status = H4032L_STATUS_IDLE;
145                         if (buffer[number_samples] != H4032L_END_PACKET_MAGIC)
146                                 sr_err("Mismatch magic number of end poll.");
147                 }
148                 break;
149         }
150
151         if (devc->status != H4032L_STATUS_IDLE) {
152                 if (cmd) {
153                         /* Setup new USB cmd packet, reuse transfer object. */
154                         sr_dbg("New command: %d.", devc->status);
155                         libusb_fill_bulk_transfer(transfer, usb->devhdl,
156                                 2 | LIBUSB_ENDPOINT_OUT,
157                                 (unsigned char *)&devc->cmd_pkt,
158                                 sizeof(struct h4032l_cmd_pkt),
159                                 h4032l_usb_callback, (void *)sdi,
160                                 H4032L_USB_TIMEOUT);
161                 } else {
162                         /* Setup new USB poll packet, reuse transfer object. */
163                         sr_dbg("Poll: %d.", devc->status);
164                         libusb_fill_bulk_transfer(transfer, usb->devhdl,
165                                 6 | LIBUSB_ENDPOINT_IN,
166                                 devc->buffer, ARRAY_SIZE(devc->buffer),
167                                 h4032l_usb_callback,
168                                 (void *)sdi, H4032L_USB_TIMEOUT);
169                 }
170                 /* Send prepared usb packet. */
171                 if ((ret = libusb_submit_transfer(transfer)) != 0) {
172                         sr_err("Failed to submit transfer: %s.",
173                                libusb_error_name(ret));
174                         devc->status = H4032L_STATUS_IDLE;
175                 }
176         } else {
177                 sr_dbg("Now idle.");
178         }
179
180         if (devc->status == H4032L_STATUS_IDLE)
181                 libusb_free_transfer(transfer);
182 }
183
184 uint16_t h4032l_voltage2pwm(double voltage)
185 {
186         /*
187          * word PwmA - channel A Vref PWM value, pseudocode:
188          * -6V < ThresholdVoltage < +6V
189          * Vref = 1.8 - ThresholdVoltage
190          * if Vref > 10.0
191          *      Vref = 10.0
192          * if Vref < -5.0
193          *      Vref = -5.0
194          * pwm = ToInt((Vref + 5.0) / 15.0 * 4096.0)
195          * if pwm > 4095
196          *      pwm = 4095
197          */
198         voltage = 1.8 - voltage;
199         if (voltage > 10.0)
200                 voltage = 10.0;
201         else if (voltage < -5.0)
202                 voltage = -5.0;
203
204         return (uint16_t) ((voltage + 5.0) * (4096.0 / 15.0));
205 }
206
207 SR_PRIV int h4032l_start(const struct sr_dev_inst *sdi)
208 {
209         struct dev_context *devc = sdi->priv;
210         struct sr_usb_dev_inst *usb = sdi->conn;
211         struct libusb_transfer *transfer;
212         int ret;
213
214         /* Send configure command to arm the logic analyzer. */
215         devc->cmd_pkt.cmd = CMD_CONFIGURE;
216         devc->status = H4032L_STATUS_CMD_CONFIGURE;
217         devc->remaining_samples = devc->cmd_pkt.sample_size;
218
219         transfer = libusb_alloc_transfer(0);
220
221         libusb_fill_bulk_transfer(transfer, usb->devhdl,
222                 2 | LIBUSB_ENDPOINT_OUT, (unsigned char *)&devc->cmd_pkt,
223                 sizeof(struct h4032l_cmd_pkt), h4032l_usb_callback,
224                 (void *)sdi, H4032L_USB_TIMEOUT);
225
226         if ((ret = libusb_submit_transfer(transfer)) != 0) {
227                 sr_err("Failed to submit transfer: %s.", libusb_error_name(ret));
228                 libusb_free_transfer(transfer);
229                 return SR_ERR;
230         }
231
232         std_session_send_df_header(sdi);
233
234         return SR_OK;
235 }
236
237 SR_PRIV int h4032l_dev_open(struct sr_dev_inst *sdi)
238 {
239         struct drv_context *drvc = sdi->driver->context;
240         struct sr_usb_dev_inst *usb = sdi->conn;
241         struct libusb_device_descriptor des;
242         libusb_device **devlist;
243         int ret = SR_ERR, i, device_count;
244         char connection_id[64];
245
246         device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
247         if (device_count < 0) {
248                 sr_err("Failed to get device list: %s.",
249                        libusb_error_name(device_count));
250                 return SR_ERR;
251         }
252
253         for (i = 0; i < device_count; i++) {
254                 libusb_get_device_descriptor(devlist[i], &des);
255
256                 if (des.idVendor != H4032L_USB_VENDOR ||
257                     des.idProduct != H4032L_USB_PRODUCT)
258                         continue;
259
260                 if ((sdi->status == SR_ST_INITIALIZING) ||
261                     (sdi->status == SR_ST_INACTIVE)) {
262                         /* Check device by its physical USB bus/port address. */
263                         usb_get_port_path(devlist[i], connection_id,
264                                           sizeof(connection_id));
265                         if (strcmp(sdi->connection_id, connection_id))
266                                 /* This is not the one. */
267                                 continue;
268                 }
269
270                 if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
271                         if (usb->address == 0xff)
272                                 /*
273                                  * First time we touch this device after FW
274                                  * upload, so we don't know the address yet.
275                                  */
276                                 usb->address =
277                                     libusb_get_device_address(devlist[i]);
278                 } else {
279                         sr_err("Failed to open device: %s.",
280                                libusb_error_name(ret));
281                         ret = SR_ERR;
282                         break;
283                 }
284
285                 ret = SR_OK;
286                 break;
287         }
288
289         libusb_free_device_list(devlist, 1);
290         return ret;
291 }