]> sigrok.org Git - libsigrok.git/blob - src/hardware/serial-dmm/protocol.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / serial-dmm / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me@gmail.com>
5  * Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <libsigrok/libsigrok.h>
27 #include "libsigrok-internal.h"
28 #include "protocol.h"
29
30 static void log_dmm_packet(const uint8_t *buf, size_t len)
31 {
32         GString *text;
33
34         if (sr_log_loglevel_get() < SR_LOG_DBG)
35                 return;
36
37         text = sr_hexdump_new(buf, len);
38         sr_dbg("DMM packet: %s", text->str);
39         sr_hexdump_free(text);
40 }
41
42 static void handle_packet(struct sr_dev_inst *sdi,
43         const uint8_t *buf, size_t len, void *info)
44 {
45         struct dmm_info *dmm;
46         struct dev_context *devc;
47         float floatval;
48         double doubleval;
49         struct sr_datafeed_packet packet;
50         struct sr_datafeed_analog analog;
51         struct sr_analog_encoding encoding;
52         struct sr_analog_meaning meaning;
53         struct sr_analog_spec spec;
54         gboolean sent_sample;
55         struct sr_channel *channel;
56         size_t ch_idx;
57
58         dmm = (struct dmm_info *)sdi->driver;
59
60         log_dmm_packet(buf, len);
61         devc = sdi->priv;
62
63         sent_sample = FALSE;
64         memset(info, 0, dmm->info_size);
65         for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) {
66                 /* Note: digits/spec_digits will be overridden by the DMM parsers. */
67                 sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
68
69                 channel = g_slist_nth_data(sdi->channels, ch_idx);
70                 analog.meaning->channels = g_slist_append(NULL, channel);
71                 analog.num_samples = 1;
72                 analog.meaning->mq = 0;
73
74                 if (dmm->packet_parse) {
75                         dmm->packet_parse(buf, &floatval, &analog, info);
76                         analog.data = &floatval;
77                         analog.encoding->unitsize = sizeof(floatval);
78                 } else if (dmm->packet_parse_len) {
79                         dmm->packet_parse_len(dmm->dmm_state, buf, len,
80                                 &doubleval, &analog, info);
81                         analog.data = &doubleval;
82                         analog.encoding->unitsize = sizeof(doubleval);
83                 }
84
85                 /* If this DMM needs additional handling, call the resp. function. */
86                 if (dmm->dmm_details)
87                         dmm->dmm_details(&analog, info);
88
89                 if (analog.meaning->mq != 0 && channel->enabled) {
90                         /* Got a measurement. */
91                         packet.type = SR_DF_ANALOG;
92                         packet.payload = &analog;
93                         sr_session_send(sdi, &packet);
94                         sent_sample = TRUE;
95                 }
96         }
97
98         if (sent_sample) {
99                 sr_sw_limits_update_samples_read(&devc->limits, 1);
100         }
101 }
102
103 /** Request packet, if required. */
104 SR_PRIV int req_packet(struct sr_dev_inst *sdi)
105 {
106         struct dmm_info *dmm;
107         struct dev_context *devc;
108         struct sr_serial_dev_inst *serial;
109         uint64_t now, left, next;
110         int ret;
111
112         dmm = (struct dmm_info *)sdi->driver;
113         if (!dmm->packet_request)
114                 return SR_OK;
115
116         devc = sdi->priv;
117         serial = sdi->conn;
118
119         now = g_get_monotonic_time();
120         if (devc->req_next_at && now < devc->req_next_at) {
121                 left = (devc->req_next_at - now) / 1000;
122                 sr_spew("Not re-requesting yet, %" PRIu64 "ms left.", left);
123                 return SR_OK;
124         }
125
126         sr_spew("Requesting next packet.");
127         ret = dmm->packet_request(serial);
128         if (ret < 0) {
129                 sr_err("Failed to request packet: %d.", ret);
130                 return ret;
131         }
132
133         if (dmm->req_timeout_ms) {
134                 next = now + dmm->req_timeout_ms * 1000;
135                 devc->req_next_at = next;
136         }
137
138         return SR_OK;
139 }
140
141 static void handle_new_data(struct sr_dev_inst *sdi, void *info)
142 {
143         struct dmm_info *dmm;
144         struct dev_context *devc;
145         struct sr_serial_dev_inst *serial;
146         int ret;
147         size_t read_len, check_pos, check_len, pkt_size, copy_len;
148         uint8_t *check_ptr;
149         uint64_t deadline;
150
151         dmm = (struct dmm_info *)sdi->driver;
152
153         devc = sdi->priv;
154         serial = sdi->conn;
155
156         /* Add the maximum available RX data we can get to the local buffer. */
157         read_len = DMM_BUFSIZE - devc->buflen;
158         ret = serial_read_nonblocking(serial, &devc->buf[devc->buflen], read_len);
159         if (ret == 0)
160                 return; /* No new bytes, nothing to do. */
161         if (ret < 0) {
162                 sr_err("Serial port read error: %d.", ret);
163                 return;
164         }
165         devc->buflen += ret;
166
167         /*
168          * Process packets when their reception has completed, or keep
169          * trying to synchronize to the stream of input data.
170          */
171         check_pos = 0;
172         while (check_pos < devc->buflen) {
173                 /* Got the (minimum) amount of receive data for a packet? */
174                 check_len = devc->buflen - check_pos;
175                 if (check_len < dmm->packet_size)
176                         break;
177                 sr_dbg("Checking: pos %zu, len %zu.", check_pos, check_len);
178
179                 /* Is it a valid packet? */
180                 check_ptr = &devc->buf[check_pos];
181                 if (dmm->packet_valid_len) {
182                         ret = dmm->packet_valid_len(dmm->dmm_state,
183                                 check_ptr, check_len, &pkt_size);
184                         if (ret == SR_PACKET_NEED_RX) {
185                                 sr_dbg("Need more RX data.");
186                                 break;
187                         }
188                         if (ret == SR_PACKET_INVALID) {
189                                 sr_dbg("Not a valid packet, searching.");
190                                 check_pos++;
191                                 continue;
192                         }
193                 } else if (dmm->packet_valid) {
194                         if (!dmm->packet_valid(check_ptr)) {
195                                 sr_dbg("Not a valid packet, searching.");
196                                 check_pos++;
197                                 continue;
198                         }
199                         pkt_size = dmm->packet_size;
200                 }
201
202                 /* Process the package. */
203                 sr_dbg("Valid packet, size %zu, processing", pkt_size);
204                 handle_packet(sdi, check_ptr, pkt_size, info);
205                 check_pos += pkt_size;
206
207                 /* Arrange for the next packet request if needed. */
208                 if (!dmm->packet_request)
209                         continue;
210                 if (dmm->req_timeout_ms || dmm->req_delay_ms) {
211                         deadline = g_get_monotonic_time();
212                         deadline += dmm->req_delay_ms * 1000;
213                         devc->req_next_at = deadline;
214                 }
215                 req_packet(sdi);
216                 continue;
217         }
218
219         /* If we have any data left, move it to the beginning of our buffer. */
220         if (devc->buflen > check_pos) {
221                 copy_len = devc->buflen - check_pos;
222                 memmove(&devc->buf[0], &devc->buf[check_pos], copy_len);
223         }
224         devc->buflen -= check_pos;
225
226         /*
227          * If the complete buffer filled up and none of it got processed,
228          * discard the unprocessed buffer, re-sync to the stream in later
229          * calls again.
230          */
231         if (devc->buflen == sizeof(devc->buf)) {
232                 sr_info("Drop unprocessed RX data, try to re-sync to stream.");
233                 devc->buflen = 0;
234         }
235 }
236
237 int receive_data(int fd, int revents, void *cb_data)
238 {
239         struct sr_dev_inst *sdi;
240         struct dev_context *devc;
241         struct dmm_info *dmm;
242         void *info;
243
244         (void)fd;
245
246         if (!(sdi = cb_data))
247                 return TRUE;
248
249         if (!(devc = sdi->priv))
250                 return TRUE;
251
252         dmm = (struct dmm_info *)sdi->driver;
253
254         if (revents == G_IO_IN) {
255                 /* Serial data arrived. */
256                 info = g_malloc(dmm->info_size);
257                 handle_new_data(sdi, info);
258                 g_free(info);
259         } else {
260                 /* Timeout; send another packet request if DMM needs it. */
261                 if (dmm->packet_request && (req_packet(sdi) < 0))
262                         return FALSE;
263         }
264
265         if (sr_sw_limits_check(&devc->limits))
266                 sr_dev_acquisition_stop(sdi);
267
268         return TRUE;
269 }