]> sigrok.org Git - libsigrok.git/blob - src/hardware/uni-t-ut32x/protocol.c
85752419df24b748be888292071a1ca2b104f14d
[libsigrok.git] / src / hardware / uni-t-ut32x / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
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 <math.h>
23 #include "protocol.h"
24
25 #define SEP     "\r\n"
26 #define BLANK   ':'
27 #define NEG     ';'
28
29 /*
30  * Get a temperature value from a four-character buffer. The value is
31  * encoded in ASCII and the unit is deci-degrees (tenths of degrees).
32  */
33 static float parse_temperature(unsigned char *buf)
34 {
35         float temp;
36         int i;
37         gboolean negative;
38
39         negative = FALSE;
40         temp = 0.0;
41         for (i = 0; i < 4; i++) {
42                 if (buf[i] == BLANK)
43                         continue;
44                 if (buf[i] == NEG) {
45                         if (negative) {
46                                 sr_dbg("Double negative sign!");
47                                 return NAN;
48                         }
49                         negative = TRUE;
50                         continue;
51                 }
52                 if (buf[i] < '0' || buf[i] > '9') {
53                         sr_dbg("Invalid digit '%.2x'!", buf[i]);
54                         return NAN;
55                 }
56                 temp *= 10;
57                 temp += buf[i] - '0';
58         }
59         temp /= 10;
60         if (negative)
61                 temp = -temp;
62
63         return temp;
64 }
65
66 static void process_packet(struct sr_dev_inst *sdi)
67 {
68         struct dev_context *devc;
69         struct sr_datafeed_packet packet;
70         struct sr_datafeed_analog analog;
71         struct sr_analog_encoding encoding;
72         struct sr_analog_meaning meaning;
73         struct sr_analog_spec spec;
74         GString *spew;
75         float temp;
76         int i;
77         gboolean is_valid;
78
79         devc = sdi->priv;
80         sr_dbg("Received full 19-byte packet.");
81         if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
82                 spew = g_string_sized_new(60);
83                 for (i = 0; i < devc->packet_len; i++)
84                         g_string_append_printf(spew, "%.2x ", devc->packet[i]);
85                 sr_spew("%s", spew->str);
86                 g_string_free(spew, TRUE);
87         }
88
89         is_valid = TRUE;
90         if (devc->packet[1] == NEG && devc->packet[2] == NEG
91                         && devc->packet[3] == NEG && devc->packet[4] == NEG)
92                 /* No measurement: missing channel, empty storage location, ... */
93                 is_valid = FALSE;
94
95         temp = parse_temperature(devc->packet + 1);
96         if (isnan(temp))
97                 is_valid = FALSE;
98
99         if (is_valid) {
100                 sr_analog_init(&analog, &encoding, &meaning, &spec, 1);
101                 analog.meaning->mq = SR_MQ_TEMPERATURE;
102                 analog.meaning->mqflags = 0;
103                 switch (devc->packet[5] - '0') {
104                 case 1:
105                         analog.meaning->unit = SR_UNIT_CELSIUS;
106                         break;
107                 case 2:
108                         analog.meaning->unit = SR_UNIT_FAHRENHEIT;
109                         break;
110                 case 3:
111                         analog.meaning->unit = SR_UNIT_KELVIN;
112                         break;
113                 default:
114                         /* We can still pass on the measurement, whatever it is. */
115                         sr_dbg("Unknown unit 0x%.2x.", devc->packet[5]);
116                 }
117                 switch (devc->packet[13] - '0') {
118                 case 0:
119                         /* Channel T1. */
120                         analog.meaning->channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 0));
121                         break;
122                 case 1:
123                         /* Channel T2. */
124                         analog.meaning->channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 1));
125                         break;
126                 case 2:
127                 case 3:
128                         /* Channel T1-T2. */
129                         analog.meaning->channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 2));
130                         analog.meaning->mqflags |= SR_MQFLAG_RELATIVE;
131                         break;
132                 default:
133                         sr_err("Unknown channel 0x%.2x.", devc->packet[13]);
134                         is_valid = FALSE;
135                 }
136                 if (is_valid) {
137                         analog.num_samples = 1;
138                         analog.data = &temp;
139                         packet.type = SR_DF_ANALOG;
140                         packet.payload = &analog;
141                         sr_session_send(sdi, &packet);
142                         g_slist_free(analog.meaning->channels);
143                 }
144         }
145
146         /*
147          * We count packets even if the measurement was invalid. This way
148          * a sample limit on "Memory" data source still works: Unused
149          * memory slots come through as "----" measurements.
150          */
151         sr_sw_limits_update_samples_read(&devc->limits, 1);
152         if (sr_sw_limits_check(&devc->limits))
153                 sr_dev_acquisition_stop(sdi);
154 }
155
156 SR_PRIV void LIBUSB_CALL uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer)
157 {
158         struct dev_context *devc;
159         struct sr_dev_inst *sdi;
160         int hid_payload_len, ret;
161
162         sdi = transfer->user_data;
163         devc = sdi->priv;
164         if (transfer->actual_length == 8) {
165                 /* CH9325 encodes length in low nibble of first byte, with
166                  * bytes 1-7 being the (padded) payload. */
167                 hid_payload_len = transfer->buffer[0] & 0x0f;
168                 memcpy(devc->packet + devc->packet_len, transfer->buffer + 1,
169                                 hid_payload_len);
170                 devc->packet_len += hid_payload_len;
171                 if (devc->packet_len >= 2
172                                 && devc->packet[devc->packet_len - 2] == SEP[0]
173                                 && devc->packet[devc->packet_len - 1] == SEP[1]) {
174                         /* Got end of packet, but do we have a complete packet? */
175                         if (devc->packet_len == PACKET_SIZE)
176                                 process_packet(sdi);
177                         /* Either way, done with it. */
178                         devc->packet_len = 0;
179                 } else if (devc->packet_len > PACKET_SIZE) {
180                         /* Guard against garbage from the device overrunning
181                          * our packet buffer. */
182                         sr_dbg("Buffer overrun!");
183                         devc->packet_len = 0;
184                 }
185         }
186
187         /* Get the next transfer (unless we're shutting down). */
188         if (sdi->status != SR_ST_STOPPING) {
189                 if ((ret = libusb_submit_transfer(devc->xfer)) != 0) {
190                         sr_dbg("Failed to resubmit transfer: %s", libusb_error_name(ret));
191                         sdi->status = SR_ST_STOPPING;
192                         libusb_free_transfer(devc->xfer);
193                 }
194         } else
195                 libusb_free_transfer(devc->xfer);
196
197 }
198
199 SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data)
200 {
201         struct drv_context *drvc;
202         struct dev_context *devc;
203         struct sr_dev_driver *di;
204         struct sr_dev_inst *sdi;
205         struct sr_usb_dev_inst *usb;
206         struct timeval tv;
207         int len, ret;
208         unsigned char cmd[2];
209
210         (void)fd;
211         (void)revents;
212
213         if (!(sdi = cb_data))
214                 return TRUE;
215
216         di = sdi->driver;
217         drvc = di->context;
218
219         if (!(devc = sdi->priv))
220                 return TRUE;
221
222         memset(&tv, 0, sizeof(struct timeval));
223         libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
224                         NULL);
225
226         if (sdi->status == SR_ST_STOPPING) {
227                 usb_source_remove(sdi->session, drvc->sr_ctx);
228                 std_session_send_df_end(sdi);
229
230                 /* Tell the device to stop sending USB packets. */
231                 usb = sdi->conn;
232                 cmd[0] = 0x01;
233                 cmd[1] = CMD_STOP;
234                 ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
235                 if (ret != 0 || len != 2) {
236                         /* Warning only, doesn't matter. */
237                         sr_dbg("Failed to send stop command: %s", libusb_error_name(ret));
238                 }
239
240                 sdi->status = SR_ST_ACTIVE;
241                 return TRUE;
242         }
243
244         return TRUE;
245 }