]> sigrok.org Git - libsigrok.git/blame - src/hardware/rdtech-tc/protocol.c
rdtech-tc: request keyword differs between CDC and BLE transports
[libsigrok.git] / src / hardware / rdtech-tc / protocol.c
CommitLineData
cae33a58
AS
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2020 Andreas Sandberg <andreas@sandberg.pp.se>
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>
ea5fc667 21
cae33a58 22#include <glib.h>
cae33a58 23#include <libsigrok/libsigrok.h>
ea5fc667
GS
24#include <math.h>
25#include <nettle/aes.h>
26#include <stdlib.h>
27#include <string.h>
28
cae33a58
AS
29#include "libsigrok-internal.h"
30#include "protocol.h"
31
861fa81f
GS
32#define PROBE_TO_MS 1000
33#define WRITE_TO_MS 1
34#define POLL_PERIOD_MS 100
cae33a58 35
a780870c
GS
36/*
37 * Response data (raw sample data) consists of three adjacent chunks
38 * of 64 bytes each. These chunks start with their magic string, and
39 * end in a 32bit checksum field. Measurement values are scattered
40 * across these 192 bytes total size. All multi-byte integer values
41 * are represented in little endian format. Typical size is 32 bits.
42 */
43
44#define MAGIC_PAC1 0x70616331 /* 'pac1' */
45#define MAGIC_PAC2 0x70616332 /* 'pac2' */
46#define MAGIC_PAC3 0x70616333 /* 'pac3' */
cae33a58 47
cae33a58 48#define PAC_LEN 64
a780870c 49#define PAC_CRC_POS (PAC_LEN - sizeof(uint32_t))
cae33a58
AS
50
51/* Offset to PAC block from start of poll data */
52#define OFF_PAC1 (0 * PAC_LEN)
53#define OFF_PAC2 (1 * PAC_LEN)
54#define OFF_PAC3 (2 * PAC_LEN)
a780870c 55#define TC_POLL_LEN (3 * PAC_LEN)
37b68953
GS
56#if TC_POLL_LEN > RDTECH_TC_RSPBUFSIZE
57# error "response length exceeds receive buffer space"
58#endif
cae33a58
AS
59
60#define OFF_MODEL 4
61#define LEN_MODEL 4
62
63#define OFF_FW_VER 8
64#define LEN_FW_VER 4
65
66#define OFF_SERIAL 12
67
68static const uint8_t AES_KEY[] = {
69 0x58, 0x21, 0xfa, 0x56, 0x01, 0xb2, 0xf0, 0x26,
70 0x87, 0xff, 0x12, 0x04, 0x62, 0x2a, 0x4f, 0xb0,
71 0x86, 0xf4, 0x02, 0x60, 0x81, 0x6f, 0x9a, 0x0b,
72 0xa7, 0xf1, 0x06, 0x61, 0x9a, 0xb8, 0x72, 0x88,
73};
74
b3df7668
GS
75static const struct rdtech_tc_channel_desc rdtech_tc_channels[] = {
76 { "V", { 0 + 48, BVT_LE_UINT32, 1, }, { 100, 1e6, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
77 { "I", { 0 + 52, BVT_LE_UINT32, 1, }, { 10, 1e6, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE },
78 { "D+", { 64 + 32, BVT_LE_UINT32, 1, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
79 { "D-", { 64 + 36, BVT_LE_UINT32, 1, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
80 { "E0", { 64 + 12, BVT_LE_UINT32, 1, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
81 { "E1", { 64 + 20, BVT_LE_UINT32, 1, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
cae33a58
AS
82};
83
a780870c 84static gboolean check_pac_crc(uint8_t *data)
cae33a58
AS
85{
86 uint16_t crc;
87 uint32_t crc_field;
88
a780870c
GS
89 crc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS);
90 crc_field = read_u32le(&data[PAC_CRC_POS]);
cae33a58
AS
91 if (crc != crc_field) {
92 sr_spew("CRC error. Calculated: %0x" PRIx16 ", expected: %0x" PRIx32,
93 crc, crc_field);
a780870c 94 return FALSE;
cae33a58 95 }
a780870c
GS
96
97 return TRUE;
cae33a58
AS
98}
99
5955b58c 100static int process_poll_pkt(struct dev_context *devc, uint8_t *dst)
cae33a58
AS
101{
102 struct aes256_ctx ctx;
a780870c 103 gboolean ok;
cae33a58
AS
104
105 aes256_set_decrypt_key(&ctx, AES_KEY);
106 aes256_decrypt(&ctx, TC_POLL_LEN, dst, devc->buf);
107
a780870c
GS
108 ok = TRUE;
109 ok &= read_u32be(&dst[OFF_PAC1]) == MAGIC_PAC1;
110 ok &= read_u32be(&dst[OFF_PAC2]) == MAGIC_PAC2;
111 ok &= read_u32be(&dst[OFF_PAC3]) == MAGIC_PAC3;
112 if (!ok) {
113 sr_err("Invalid poll response packet (magic values).");
114 return SR_ERR_DATA;
cae33a58
AS
115 }
116
a780870c
GS
117 ok &= check_pac_crc(&dst[OFF_PAC1]);
118 ok &= check_pac_crc(&dst[OFF_PAC2]);
119 ok &= check_pac_crc(&dst[OFF_PAC3]);
120 if (!ok) {
121 sr_err("Invalid poll response packet (checksum).");
122 return SR_ERR_DATA;
cae33a58
AS
123 }
124
125 return SR_OK;
126}
127
5955b58c 128SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc)
cae33a58 129{
37b68953
GS
130 static const char *poll_cmd_cdc = "getva";
131 static const char *poll_cmd_ble = "bgetva\r\n";
132
cae33a58
AS
133 int len;
134 uint8_t poll_pkt[TC_POLL_LEN];
135
37b68953
GS
136 /* Construct the request text. Which differs across transports. */
137 devc->is_bluetooth = ser_name_is_bt(serial);
138 snprintf(devc->req_text, sizeof(devc->req_text), "%s",
139 devc->is_bluetooth ? poll_cmd_ble : poll_cmd_cdc);
140 sr_dbg("is bluetooth %d -> poll request '%s'.",
141 devc->is_bluetooth, devc->req_text);
142
143 /* Transmit the request. */
861fa81f 144 len = serial_write_blocking(serial,
37b68953 145 devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
861fa81f 146 if (len < 0) {
a780870c 147 sr_err("Failed to send probe request.");
cae33a58
AS
148 return SR_ERR;
149 }
150
37b68953 151 /* Receive a response. */
861fa81f 152 len = serial_read_blocking(serial, devc->buf, TC_POLL_LEN, PROBE_TO_MS);
cae33a58
AS
153 if (len != TC_POLL_LEN) {
154 sr_err("Failed to read probe response.");
155 return SR_ERR;
156 }
157
158 if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
159 sr_err("Unrecognized TC device!");
160 return SR_ERR;
161 }
162
163 devc->channels = rdtech_tc_channels;
b3df7668 164 devc->channel_count = ARRAY_SIZE(rdtech_tc_channels);
a780870c
GS
165 devc->dev_info.model_name = g_strndup((const char *)&poll_pkt[OFF_MODEL], LEN_MODEL);
166 devc->dev_info.fw_ver = g_strndup((const char *)&poll_pkt[OFF_FW_VER], LEN_FW_VER);
167 devc->dev_info.serial_num = read_u32le(&poll_pkt[OFF_SERIAL]);
cae33a58
AS
168
169 return SR_OK;
170}
171
a82490b6 172SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi, gboolean force)
cae33a58 173{
c1f9428a 174 struct dev_context *devc;
a82490b6 175 int64_t now, elapsed;
c1f9428a 176 struct sr_serial_dev_inst *serial;
861fa81f 177 int len;
cae33a58 178
8817bd6f
GS
179 /*
180 * Don't send the request while receive data is being accumulated.
181 */
a82490b6 182 devc = sdi->priv;
e2bcf2e3 183 if (!force && devc->rdlen)
8817bd6f
GS
184 return SR_OK;
185
186 /*
187 * Send the request when the transmit interval was reached. Or
188 * when the caller forced the transmission.
189 */
a82490b6
GS
190 now = g_get_monotonic_time() / 1000;
191 elapsed = now - devc->cmd_sent_at;
861fa81f 192 if (!force && elapsed < POLL_PERIOD_MS)
a82490b6
GS
193 return SR_OK;
194
8817bd6f
GS
195 /*
196 * Transmit another measurement request. Only advance the
197 * interval after successful transmission.
198 */
c1f9428a 199 serial = sdi->conn;
861fa81f 200 len = serial_write_blocking(serial,
37b68953 201 devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
861fa81f 202 if (len < 0) {
cae33a58
AS
203 sr_err("Unable to send poll request.");
204 return SR_ERR;
205 }
a82490b6 206 devc->cmd_sent_at = now;
cae33a58
AS
207
208 return SR_OK;
209}
210
269f1e0e 211static int handle_poll_data(struct sr_dev_inst *sdi)
cae33a58 212{
c1f9428a 213 struct dev_context *devc;
cae33a58 214 uint8_t poll_pkt[TC_POLL_LEN];
b3df7668
GS
215 size_t ch_idx;
216 const struct rdtech_tc_channel_desc *pch;
269f1e0e 217 int ret;
b3df7668 218 float v;
cae33a58 219
c1f9428a 220 devc = sdi->priv;
e2bcf2e3
GS
221 sr_spew("Received poll packet (len: %zu).", devc->rdlen);
222 if (devc->rdlen < TC_POLL_LEN) {
223 sr_err("Insufficient poll packet length: %zu", devc->rdlen);
269f1e0e 224 return SR_ERR_DATA;
cae33a58
AS
225 }
226
227 if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
228 sr_err("Failed to process poll packet.");
269f1e0e 229 return SR_ERR_DATA;
cae33a58
AS
230 }
231
15ceaf9d
GS
232 ret = SR_OK;
233 std_session_send_df_frame_begin(sdi);
b3df7668
GS
234 for (ch_idx = 0; ch_idx < devc->channel_count; ch_idx++) {
235 pch = &devc->channels[ch_idx];
236 ret = bv_get_value(&v, &pch->spec, poll_pkt, TC_POLL_LEN);
237 if (ret != SR_OK)
15ceaf9d 238 break;
b3df7668 239 ret = feed_queue_analog_submit(devc->feeds[ch_idx], v, 1);
269f1e0e 240 if (ret != SR_OK)
15ceaf9d 241 break;
5955b58c 242 }
15ceaf9d 243 std_session_send_df_frame_end(sdi);
cae33a58 244
15ceaf9d 245 sr_sw_limits_update_frames_read(&devc->limits, 1);
269f1e0e
GS
246 if (sr_sw_limits_check(&devc->limits))
247 sr_dev_acquisition_stop(sdi);
248
15ceaf9d 249 return ret;
cae33a58
AS
250}
251
269f1e0e 252static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial)
cae33a58 253{
c1f9428a 254 struct dev_context *devc;
8817bd6f 255 size_t space;
cae33a58 256 int len;
269f1e0e 257 int ret;
cae33a58 258
8817bd6f 259 /* Receive data became available. Drain the transport layer. */
c1f9428a 260 devc = sdi->priv;
e2bcf2e3
GS
261 while (devc->rdlen < TC_POLL_LEN) {
262 space = sizeof(devc->buf) - devc->rdlen;
8817bd6f 263 len = serial_read_nonblocking(serial,
e2bcf2e3 264 &devc->buf[devc->rdlen], space);
269f1e0e
GS
265 if (len < 0)
266 return SR_ERR_IO;
267 if (len == 0)
268 return SR_OK;
e2bcf2e3 269 devc->rdlen += len;
cae33a58
AS
270 }
271
8817bd6f
GS
272 /*
273 * TODO Want to (re-)synchronize to the packet stream? The
274 * 'pac1' string literal would be a perfect match for that.
275 */
276
277 /* Process packets when their reception has completed. */
e2bcf2e3 278 while (devc->rdlen >= TC_POLL_LEN) {
269f1e0e
GS
279 ret = handle_poll_data(sdi);
280 if (ret != SR_OK)
281 return ret;
e2bcf2e3
GS
282 devc->rdlen -= TC_POLL_LEN;
283 if (devc->rdlen)
284 memmove(devc->buf, &devc->buf[TC_POLL_LEN], devc->rdlen);
269f1e0e 285 }
269f1e0e
GS
286
287 return SR_OK;
cae33a58
AS
288}
289
290SR_PRIV int rdtech_tc_receive_data(int fd, int revents, void *cb_data)
291{
292 struct sr_dev_inst *sdi;
293 struct dev_context *devc;
294 struct sr_serial_dev_inst *serial;
269f1e0e 295 int ret;
cae33a58
AS
296
297 (void)fd;
298
299 if (!(sdi = cb_data))
300 return TRUE;
cae33a58
AS
301 if (!(devc = sdi->priv))
302 return TRUE;
303
269f1e0e 304 /* Handle availability of receive data. */
cae33a58 305 serial = sdi->conn;
269f1e0e
GS
306 if (revents == G_IO_IN) {
307 ret = recv_poll_data(sdi, serial);
308 if (ret != SR_OK)
309 sr_dev_acquisition_stop(sdi);
310 }
cae33a58 311
269f1e0e 312 /* Check configured acquisition limits. */
cae33a58
AS
313 if (sr_sw_limits_check(&devc->limits)) {
314 sr_dev_acquisition_stop(sdi);
315 return TRUE;
316 }
317
269f1e0e
GS
318 /* Periodically retransmit measurement requests. */
319 (void)rdtech_tc_poll(sdi, FALSE);
cae33a58
AS
320
321 return TRUE;
322}