]> sigrok.org Git - libsigrok.git/blame - src/hardware/appa-55ii/protocol.c
Remove some unneeded double-spaces.
[libsigrok.git] / src / hardware / appa-55ii / protocol.c
CommitLineData
5e7a8e57
AJ
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2013 Aurelien Jacobs <aurel@gnuage.org>
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
6ec6c43b 20#include <config.h>
81a9ab72
AJ
21#include <string.h>
22#include <math.h>
5e7a8e57
AJ
23#include "protocol.h"
24
81a9ab72 25typedef enum {
d9251a2c
UH
26 LIVE_DATA = 0x00,
27 LOG_METADATA = 0x11,
28 LOG_DATA = 0x14,
29 LOG_START = 0x18,
30 LOG_END = 0x19,
9ee78f23 31} packet_type;
81a9ab72
AJ
32
33static gboolean appa_55ii_checksum(const uint8_t *buf)
34{
7574e58c
BV
35 int i, size, checksum;
36
37 size = buf[3] + 4;
38 checksum = 0;
39 for (i = 0; i < size; i++)
81a9ab72 40 checksum += buf[i];
7574e58c 41
81a9ab72
AJ
42 return buf[size] == (checksum & 0xFF);
43}
44
45SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf)
46{
47 if (buf[0] == 0x55 && buf[1] == 0x55 && buf[3] <= 32
7574e58c 48 && appa_55ii_checksum(buf))
81a9ab72 49 return TRUE;
7574e58c 50
81a9ab72
AJ
51 return FALSE;
52}
53
54static uint64_t appa_55ii_flags(const uint8_t *buf)
55{
7574e58c
BV
56 uint8_t disp_mode;
57 uint64_t flags;
58
59 disp_mode = buf[4 + 13];
60 flags = 0;
61 if ((disp_mode & 0xF0) == 0x20)
62 flags |= SR_MQFLAG_HOLD;
63 if ((disp_mode & 0x0C) == 0x04)
64 flags |= SR_MQFLAG_MAX;
65 if ((disp_mode & 0x0C) == 0x08)
66 flags |= SR_MQFLAG_MIN;
67 if ((disp_mode & 0x0C) == 0x0C)
68 flags |= SR_MQFLAG_AVG;
81a9ab72
AJ
69
70 return flags;
71}
72
7b78449e 73static float appa_55ii_temp(const uint8_t *buf, int ch, int *digits)
81a9ab72 74{
7574e58c
BV
75 const uint8_t *ptr;
76 int16_t temp;
77 uint8_t flags;
78
ba7dd8bb 79 ptr = buf + 4 + 14 + 3 * ch;
7574e58c
BV
80 temp = RL16(ptr);
81 flags = ptr[2];
7b78449e 82 *digits = 0;
7574e58c
BV
83
84 if (flags & 0x60)
85 return INFINITY;
7b78449e
AJ
86 else if (flags & 1) {
87 *digits = 1;
7574e58c 88 return (float)temp / 10;
7b78449e 89 } else
7574e58c 90 return (float)temp;
81a9ab72
AJ
91}
92
93static void appa_55ii_live_data(struct sr_dev_inst *sdi, const uint8_t *buf)
94{
76b4d4f4 95 struct dev_context *devc;
81a9ab72 96 struct sr_datafeed_packet packet;
0417ada0
UH
97 struct sr_datafeed_analog analog;
98 struct sr_analog_encoding encoding;
99 struct sr_analog_meaning meaning;
100 struct sr_analog_spec spec;
ba7dd8bb 101 struct sr_channel *ch;
7b78449e
AJ
102 float value;
103 int i, digits;
81a9ab72 104
76b4d4f4
UH
105 devc = sdi->priv;
106
81a9ab72
AJ
107 if (devc->data_source != DATA_SOURCE_LIVE)
108 return;
109
3f239f08 110 for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
ba7dd8bb
UH
111 ch = g_slist_nth_data(sdi->channels, i);
112 if (!ch->enabled)
81a9ab72 113 continue;
81a9ab72 114
7b78449e
AJ
115 value = appa_55ii_temp(buf, i, &digits);
116
117 sr_analog_init(&analog, &encoding, &meaning, &spec, digits);
118 analog.num_samples = 1;
119 analog.data = &value;
120 analog.meaning->mq = SR_MQ_TEMPERATURE;
121 analog.meaning->unit = SR_UNIT_CELSIUS;
122 analog.meaning->mqflags = appa_55ii_flags(buf);
123 analog.meaning->channels = g_slist_append(NULL, ch);
124
125 packet.type = SR_DF_ANALOG;
126 packet.payload = &analog;
127 sr_session_send(sdi, &packet);
128 g_slist_free(analog.meaning->channels);
129 }
81a9ab72 130
e2492a33 131 sr_sw_limits_update_samples_read(&devc->limits, 1);
81a9ab72
AJ
132}
133
134static void appa_55ii_log_metadata(struct sr_dev_inst *sdi, const uint8_t *buf)
135{
7574e58c
BV
136 struct dev_context *devc;
137
138 devc = sdi->priv;
81a9ab72
AJ
139 devc->num_log_records = (buf[5] << 8) + buf[4];
140}
141
142static void appa_55ii_log_data_parse(struct sr_dev_inst *sdi)
143{
7574e58c
BV
144 struct dev_context *devc;
145 struct sr_datafeed_packet packet;
0417ada0
UH
146 struct sr_datafeed_analog analog;
147 struct sr_analog_encoding encoding;
148 struct sr_analog_meaning meaning;
149 struct sr_analog_spec spec;
ba7dd8bb 150 struct sr_channel *ch;
3f239f08 151 float values[APPA_55II_NUM_CHANNELS], *val_ptr;
7574e58c
BV
152 const uint8_t *buf;
153 int16_t temp;
154 int offset, i;
155
156 devc = sdi->priv;
157 offset = 0;
81a9ab72
AJ
158
159 while (devc->log_buf_len >= 20 && devc->num_log_records > 0) {
7574e58c
BV
160 buf = devc->log_buf + offset;
161 val_ptr = values;
81a9ab72 162
76b4d4f4 163 /* FIXME: Timestamp should be sent in the packet. */
81a9ab72
AJ
164 sr_dbg("Timestamp: %02d:%02d:%02d", buf[2], buf[3], buf[4]);
165
a005472f 166 sr_analog_init(&analog, &encoding, &meaning, &spec, 1);
81a9ab72 167 analog.num_samples = 1;
0417ada0
UH
168 analog.meaning->mq = SR_MQ_TEMPERATURE;
169 analog.meaning->unit = SR_UNIT_CELSIUS;
81a9ab72
AJ
170 analog.data = values;
171
3f239f08 172 for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
7574e58c 173 temp = RL16(buf + 12 + 2 * i);
ba7dd8bb
UH
174 ch = g_slist_nth_data(sdi->channels, i);
175 if (!ch->enabled)
81a9ab72 176 continue;
0417ada0 177 analog.meaning->channels = g_slist_append(analog.meaning->channels, ch);
81a9ab72
AJ
178 *val_ptr++ = temp == 0x7FFF ? INFINITY : (float)temp / 10;
179 }
180
0417ada0 181 packet.type = SR_DF_ANALOG;
81a9ab72 182 packet.payload = &analog;
695dc859 183 sr_session_send(sdi, &packet);
0417ada0 184 g_slist_free(analog.meaning->channels);
81a9ab72 185
e2492a33 186 sr_sw_limits_update_samples_read(&devc->limits, 1);
81a9ab72
AJ
187 devc->log_buf_len -= 20;
188 offset += 20;
189 devc->num_log_records--;
190 }
191
192 memmove(devc->log_buf, devc->log_buf + offset, devc->log_buf_len);
193}
194
195static void appa_55ii_log_data(struct sr_dev_inst *sdi, const uint8_t *buf)
196{
7574e58c
BV
197 struct dev_context *devc;
198 const uint8_t *ptr;
199 unsigned int size;
200 int s;
81a9ab72 201
7574e58c 202 devc = sdi->priv;
81a9ab72
AJ
203 if (devc->data_source != DATA_SOURCE_MEMORY)
204 return;
205
76b4d4f4 206 ptr = buf + 4;
7574e58c 207 size = buf[3];
81a9ab72 208 while (size > 0) {
7574e58c 209 s = MIN(size, sizeof(devc->log_buf) - devc->log_buf_len);
81a9ab72
AJ
210 memcpy(devc->log_buf + devc->log_buf_len, ptr, s);
211 devc->log_buf_len += s;
212 size -= s;
213 ptr += s;
214
215 appa_55ii_log_data_parse(sdi);
216 }
217}
218
219static void appa_55ii_log_end(struct sr_dev_inst *sdi)
220{
7574e58c 221 struct dev_context *devc;
81a9ab72 222
7574e58c 223 devc = sdi->priv;
81a9ab72
AJ
224 if (devc->data_source != DATA_SOURCE_MEMORY)
225 return;
226
695dc859 227 sdi->driver->dev_acquisition_stop(sdi);
81a9ab72
AJ
228}
229
230static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
7574e58c 231 const uint8_t *buf, int len)
81a9ab72
AJ
232{
233 if (len < 5)
7574e58c
BV
234 /* Need more data. */
235 return NULL;
81a9ab72
AJ
236
237 if (buf[0] != 0x55 || buf[1] != 0x55)
7574e58c
BV
238 /* Try to re-synchronize on a packet start. */
239 return buf + 1;
81a9ab72 240
7574e58c
BV
241 if (len < 5 + buf[3])
242 /* Need more data. */
243 return NULL;
81a9ab72
AJ
244
245 if (!appa_55ii_checksum(buf))
7574e58c
BV
246 /* Skip broken packet. */
247 return buf + 4 + buf[3] + 1;
81a9ab72 248
9ee78f23 249 switch ((packet_type)buf[2]) {
7574e58c
BV
250 case LIVE_DATA:
251 appa_55ii_live_data(sdi, buf);
252 break;
253 case LOG_METADATA:
254 appa_55ii_log_metadata(sdi, buf);
255 break;
256 case LOG_DATA:
257 appa_55ii_log_data(sdi, buf);
258 break;
259 case LOG_START:
260 break;
261 case LOG_END:
262 appa_55ii_log_end(sdi);
263 break;
76b4d4f4
UH
264 default:
265 sr_warn("Invalid packet type: 0x%02x.", buf[2]);
266 break;
81a9ab72
AJ
267 }
268
269 return buf + 4 + buf[3] + 1;
270}
271
5e7a8e57
AJ
272SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
273{
81a9ab72 274 struct sr_dev_inst *sdi;
5e7a8e57 275 struct dev_context *devc;
81a9ab72
AJ
276 struct sr_serial_dev_inst *serial;
277 const uint8_t *ptr, *next_ptr, *end_ptr;
278 int len;
5e7a8e57
AJ
279
280 (void)fd;
281
81a9ab72 282 if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
5e7a8e57 283 return TRUE;
81a9ab72
AJ
284 serial = sdi->conn;
285
286 /* Try to get as much data as the buffer can hold. */
287 len = sizeof(devc->buf) - devc->buf_len;
25dd0831 288 len = serial_read_nonblocking(serial, devc->buf + devc->buf_len, len);
81a9ab72
AJ
289 if (len < 1) {
290 sr_err("Serial port read error: %d.", len);
291 return FALSE;
292 }
293 devc->buf_len += len;
294
295 /* Now look for packets in that data. */
296 ptr = devc->buf;
297 end_ptr = ptr + devc->buf_len;
298 while ((next_ptr = appa_55ii_parse_data(sdi, ptr, end_ptr - ptr)))
299 ptr = next_ptr;
5e7a8e57 300
81a9ab72
AJ
301 /* If we have any data left, move it to the beginning of our buffer. */
302 memmove(devc->buf, ptr, end_ptr - ptr);
303 devc->buf_len -= ptr - devc->buf;
304
305 /* If buffer is full and no valid packet was found, wipe buffer. */
306 if (devc->buf_len >= sizeof(devc->buf)) {
307 devc->buf_len = 0;
308 return FALSE;
309 }
310
e2492a33 311 if (sr_sw_limits_check(&devc->limits)) {
695dc859 312 sdi->driver->dev_acquisition_stop(sdi);
5e7a8e57 313 return TRUE;
81a9ab72 314 }
5e7a8e57 315
5e7a8e57
AJ
316 return TRUE;
317}