2 * This file is part of the libsigrok project.
4 * Copyright (C) 2020 Andreas Sandberg <andreas@sandberg.pp.se>
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.
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.
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/>.
23 #include <libsigrok/libsigrok.h>
25 #include <nettle/aes.h>
29 #include "libsigrok-internal.h"
32 #define PROBE_TO_MS 1000
34 #define POLL_PERIOD_MS 100
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.
44 #define MAGIC_PAC1 0x70616331 /* 'pac1' */
45 #define MAGIC_PAC2 0x70616332 /* 'pac2' */
46 #define MAGIC_PAC3 0x70616333 /* 'pac3' */
49 #define PAC_CRC_POS (PAC_LEN - sizeof(uint32_t))
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)
55 #define TC_POLL_LEN (3 * PAC_LEN)
56 #if TC_POLL_LEN > RDTECH_TC_RSPBUFSIZE
57 # error "response length exceeds receive buffer space"
68 static 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,
75 static const struct rdtech_tc_channel_desc rdtech_tc_channels[] = {
76 { "V", { 0 + 48, BVT_LE_UINT32, }, { 100, 1e6, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
77 { "I", { 0 + 52, BVT_LE_UINT32, }, { 10, 1e6, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE },
78 { "D+", { 64 + 32, BVT_LE_UINT32, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
79 { "D-", { 64 + 36, BVT_LE_UINT32, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
80 { "E0", { 64 + 12, BVT_LE_UINT32, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
81 { "E1", { 64 + 20, BVT_LE_UINT32, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
84 static gboolean check_pac_crc(uint8_t *data)
89 crc_calc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS);
90 crc_recv = read_u32le(&data[PAC_CRC_POS]);
91 if (crc_calc != crc_recv) {
92 sr_spew("CRC error. Calculated: %0x" PRIx16 ", expected: %0x" PRIx32,
100 static int process_poll_pkt(struct dev_context *devc, uint8_t *dst)
102 struct aes256_ctx ctx;
105 aes256_set_decrypt_key(&ctx, aes_key);
106 aes256_decrypt(&ctx, TC_POLL_LEN, dst, devc->buf);
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;
113 sr_err("Invalid poll response packet (magic values).");
117 ok &= check_pac_crc(&dst[OFF_PAC1]);
118 ok &= check_pac_crc(&dst[OFF_PAC2]);
119 ok &= check_pac_crc(&dst[OFF_PAC3]);
121 sr_err("Invalid poll response packet (checksum).");
125 if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
126 static const size_t chunk_max = 32;
128 const uint8_t *rdptr;
129 size_t rdlen, chunk_addr, chunk_len;
132 sr_spew("check passed on decrypted receive data");
138 if (chunk_len > chunk_max)
139 chunk_len = chunk_max;
140 txt = sr_hexdump_new(rdptr, chunk_len);
141 sr_spew("%04zx %s", chunk_addr, txt->str);
142 sr_hexdump_free(txt);
143 chunk_addr += chunk_len;
152 SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc)
154 static const char *poll_cmd_cdc = "getva";
155 static const char *poll_cmd_ble = "bgetva\r\n";
158 uint8_t poll_pkt[TC_POLL_LEN];
160 /* Construct the request text. Which differs across transports. */
161 devc->is_bluetooth = ser_name_is_bt(serial);
162 snprintf(devc->req_text, sizeof(devc->req_text), "%s",
163 devc->is_bluetooth ? poll_cmd_ble : poll_cmd_cdc);
164 sr_dbg("is bluetooth %d -> poll request '%s'.",
165 devc->is_bluetooth, devc->req_text);
167 /* Transmit the request. */
168 len = serial_write_blocking(serial,
169 devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
171 sr_err("Failed to send probe request.");
175 /* Receive a response. */
176 len = serial_read_blocking(serial, devc->buf, TC_POLL_LEN, PROBE_TO_MS);
177 if (len != TC_POLL_LEN) {
178 sr_err("Failed to read probe response.");
182 if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
183 sr_err("Unrecognized TC device!");
187 devc->channels = rdtech_tc_channels;
188 devc->channel_count = ARRAY_SIZE(rdtech_tc_channels);
189 devc->dev_info.model_name = g_strndup((const char *)&poll_pkt[OFF_MODEL], LEN_MODEL);
190 devc->dev_info.fw_ver = g_strndup((const char *)&poll_pkt[OFF_FW_VER], LEN_FW_VER);
191 devc->dev_info.serial_num = read_u32le(&poll_pkt[OFF_SERIAL]);
196 SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi, gboolean force)
198 struct dev_context *devc;
199 int64_t now, elapsed;
200 struct sr_serial_dev_inst *serial;
204 * Don't send the request while receive data is being accumulated.
205 * Defer request transmission when a previous request has not yet
206 * seen any response data at all (more probable to happen shortly
207 * after connecting to the peripheral).
213 if (!devc->rx_after_tx)
218 * Send the request when the transmit interval was reached. Or
219 * when the caller forced the transmission.
221 now = g_get_monotonic_time() / 1000;
222 elapsed = now - devc->cmd_sent_at;
223 if (!force && elapsed < POLL_PERIOD_MS)
227 * Transmit another measurement request. Only advance the
228 * interval after successful transmission.
231 len = serial_write_blocking(serial,
232 devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
234 sr_err("Unable to send poll request.");
237 devc->cmd_sent_at = now;
238 devc->rx_after_tx = 0;
243 static int handle_poll_data(struct sr_dev_inst *sdi)
245 struct dev_context *devc;
246 uint8_t poll_pkt[TC_POLL_LEN];
248 const struct rdtech_tc_channel_desc *pch;
253 sr_spew("Received poll packet (len: %zu).", devc->rdlen);
254 if (devc->rdlen < TC_POLL_LEN) {
255 sr_err("Insufficient poll packet length: %zu", devc->rdlen);
259 if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
260 sr_err("Failed to process poll packet.");
265 std_session_send_df_frame_begin(sdi);
266 for (ch_idx = 0; ch_idx < devc->channel_count; ch_idx++) {
267 pch = &devc->channels[ch_idx];
268 ret = bv_get_value_len(&v, &pch->spec, poll_pkt, TC_POLL_LEN);
271 ret = feed_queue_analog_submit(devc->feeds[ch_idx], v, 1);
275 std_session_send_df_frame_end(sdi);
277 sr_sw_limits_update_frames_read(&devc->limits, 1);
278 if (sr_sw_limits_check(&devc->limits))
279 sr_dev_acquisition_stop(sdi);
284 static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial)
286 struct dev_context *devc;
291 /* Receive data became available. Drain the transport layer. */
293 while (devc->rdlen < TC_POLL_LEN) {
294 space = sizeof(devc->buf) - devc->rdlen;
295 len = serial_read_nonblocking(serial,
296 &devc->buf[devc->rdlen], space);
302 devc->rx_after_tx += len;
306 * TODO Want to (re-)synchronize to the packet stream? The
307 * 'pac1' string literal would be a perfect match for that.
310 /* Process packets when their reception has completed. */
311 while (devc->rdlen >= TC_POLL_LEN) {
312 ret = handle_poll_data(sdi);
315 devc->rdlen -= TC_POLL_LEN;
317 memmove(devc->buf, &devc->buf[TC_POLL_LEN], devc->rdlen);
323 SR_PRIV int rdtech_tc_receive_data(int fd, int revents, void *cb_data)
325 struct sr_dev_inst *sdi;
326 struct dev_context *devc;
327 struct sr_serial_dev_inst *serial;
332 if (!(sdi = cb_data))
334 if (!(devc = sdi->priv))
337 /* Handle availability of receive data. */
339 if (revents == G_IO_IN) {
340 ret = recv_poll_data(sdi, serial);
342 sr_dev_acquisition_stop(sdi);
345 /* Check configured acquisition limits. */
346 if (sr_sw_limits_check(&devc->limits)) {
347 sr_dev_acquisition_stop(sdi);
351 /* Periodically retransmit measurement requests. */
352 (void)rdtech_tc_poll(sdi, FALSE);