]> sigrok.org Git - libsigrok.git/blob - src/hardware/rdtech-tc/protocol.c
rdtech-tc: use size_t for memory sizes and indices
[libsigrok.git] / src / hardware / rdtech-tc / protocol.c
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>
21
22 #include <glib.h>
23 #include <libsigrok/libsigrok.h>
24 #include <math.h>
25 #include <nettle/aes.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "libsigrok-internal.h"
30 #include "protocol.h"
31
32 #define SERIAL_WRITE_TIMEOUT_MS 1
33
34 #define TC_POLL_PERIOD_MS 100
35 #define TC_TIMEOUT_MS 1000
36
37 static const char *poll_cmd = "getva";
38
39 /*
40  * Response data (raw sample data) consists of three adjacent chunks
41  * of 64 bytes each. These chunks start with their magic string, and
42  * end in a 32bit checksum field. Measurement values are scattered
43  * across these 192 bytes total size. All multi-byte integer values
44  * are represented in little endian format. Typical size is 32 bits.
45  */
46
47 #define MAGIC_PAC1      0x70616331      /* 'pac1' */
48 #define MAGIC_PAC2      0x70616332      /* 'pac2' */
49 #define MAGIC_PAC3      0x70616333      /* 'pac3' */
50
51 #define PAC_LEN 64
52 #define PAC_CRC_POS (PAC_LEN - sizeof(uint32_t))
53
54 /* Offset to PAC block from start of poll data */
55 #define OFF_PAC1 (0 * PAC_LEN)
56 #define OFF_PAC2 (1 * PAC_LEN)
57 #define OFF_PAC3 (2 * PAC_LEN)
58 #define TC_POLL_LEN (3 * PAC_LEN)
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
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,
73 };
74
75 static const struct binary_analog_channel rdtech_tc_channels[] = {
76         { "V",  {   0 + 48, BVT_LE_UINT32, 1e-4, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
77         { "I",  {   0 + 52, BVT_LE_UINT32, 1e-5, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE },
78         { "D+", {  64 + 32, BVT_LE_UINT32, 1e-2, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
79         { "D-", {  64 + 36, BVT_LE_UINT32, 1e-2, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
80         { "E0", {  64 + 12, BVT_LE_UINT32, 1e-3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
81         { "E1", {  64 + 20, BVT_LE_UINT32, 1e-3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
82         ALL_ZERO,
83 };
84
85 static gboolean check_pac_crc(uint8_t *data)
86 {
87         uint16_t crc;
88         uint32_t crc_field;
89
90         crc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS);
91         crc_field = read_u32le(&data[PAC_CRC_POS]);
92         if (crc != crc_field) {
93                 sr_spew("CRC error. Calculated: %0x" PRIx16 ", expected: %0x" PRIx32,
94                         crc, crc_field);
95                 return FALSE;
96         }
97
98         return TRUE;
99 }
100
101 static int process_poll_pkt(struct dev_context *devc, uint8_t *dst)
102 {
103         struct aes256_ctx ctx;
104         gboolean ok;
105
106         aes256_set_decrypt_key(&ctx, AES_KEY);
107         aes256_decrypt(&ctx, TC_POLL_LEN, dst, devc->buf);
108
109         ok = TRUE;
110         ok &= read_u32be(&dst[OFF_PAC1]) == MAGIC_PAC1;
111         ok &= read_u32be(&dst[OFF_PAC2]) == MAGIC_PAC2;
112         ok &= read_u32be(&dst[OFF_PAC3]) == MAGIC_PAC3;
113         if (!ok) {
114                 sr_err("Invalid poll response packet (magic values).");
115                 return SR_ERR_DATA;
116         }
117
118         ok &= check_pac_crc(&dst[OFF_PAC1]);
119         ok &= check_pac_crc(&dst[OFF_PAC2]);
120         ok &= check_pac_crc(&dst[OFF_PAC3]);
121         if (!ok) {
122                 sr_err("Invalid poll response packet (checksum).");
123                 return SR_ERR_DATA;
124         }
125
126         return SR_OK;
127 }
128
129 SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc)
130 {
131         int len;
132         uint8_t poll_pkt[TC_POLL_LEN];
133
134         if (serial_write_blocking(serial, poll_cmd, strlen(poll_cmd),
135                         SERIAL_WRITE_TIMEOUT_MS) < 0) {
136                 sr_err("Failed to send probe request.");
137                 return SR_ERR;
138         }
139
140         len = serial_read_blocking(serial, devc->buf, TC_POLL_LEN, TC_TIMEOUT_MS);
141         if (len != TC_POLL_LEN) {
142                 sr_err("Failed to read probe response.");
143                 return SR_ERR;
144         }
145
146         if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
147                 sr_err("Unrecognized TC device!");
148                 return SR_ERR;
149         }
150
151         devc->channels = rdtech_tc_channels;
152         devc->dev_info.model_name = g_strndup((const char *)&poll_pkt[OFF_MODEL], LEN_MODEL);
153         devc->dev_info.fw_ver = g_strndup((const char *)&poll_pkt[OFF_FW_VER], LEN_FW_VER);
154         devc->dev_info.serial_num = read_u32le(&poll_pkt[OFF_SERIAL]);
155
156         return SR_OK;
157 }
158
159 SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi)
160 {
161         struct dev_context *devc;
162         struct sr_serial_dev_inst *serial;
163
164         serial = sdi->conn;
165         if (serial_write_blocking(serial, poll_cmd, strlen(poll_cmd),
166                         SERIAL_WRITE_TIMEOUT_MS) < 0) {
167                 sr_err("Unable to send poll request.");
168                 return SR_ERR;
169         }
170
171         devc = sdi->priv;
172         devc->cmd_sent_at = g_get_monotonic_time() / 1000;
173
174         return SR_OK;
175 }
176
177 static void handle_poll_data(const struct sr_dev_inst *sdi)
178 {
179         struct dev_context *devc;
180         uint8_t poll_pkt[TC_POLL_LEN];
181         size_t i;
182         GSList *ch;
183
184         devc = sdi->priv;
185         sr_spew("Received poll packet (len: %zu).", devc->buflen);
186         if (devc->buflen != TC_POLL_LEN) {
187                 sr_err("Unexpected poll packet length: %zu", devc->buflen);
188                 return;
189         }
190
191         if (process_poll_pkt(devc, poll_pkt) != SR_OK) {
192                 sr_err("Failed to process poll packet.");
193                 return;
194         }
195
196         for (ch = sdi->channels, i = 0; ch; ch = g_slist_next(ch), i++) {
197                 bv_send_analog_channel(sdi, ch->data,
198                         &devc->channels[i], poll_pkt, TC_POLL_LEN);
199         }
200
201         sr_sw_limits_update_samples_read(&devc->limits, 1);
202 }
203
204 static void recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial)
205 {
206         struct dev_context *devc;
207         int len;
208
209         /* Serial data arrived. */
210         devc = sdi->priv;
211         while (devc->buflen < TC_POLL_LEN) {
212                 len = serial_read_nonblocking(serial, devc->buf + devc->buflen, 1);
213                 if (len < 1)
214                         return;
215
216                 devc->buflen++;
217         }
218
219         if (devc->buflen == TC_POLL_LEN)
220                 handle_poll_data(sdi);
221
222         devc->buflen = 0;
223 }
224
225 SR_PRIV int rdtech_tc_receive_data(int fd, int revents, void *cb_data)
226 {
227         struct sr_dev_inst *sdi;
228         struct dev_context *devc;
229         struct sr_serial_dev_inst *serial;
230         int64_t now, elapsed;
231
232         (void)fd;
233
234         if (!(sdi = cb_data))
235                 return TRUE;
236         if (!(devc = sdi->priv))
237                 return TRUE;
238
239         serial = sdi->conn;
240         if (revents == G_IO_IN)
241                 recv_poll_data(sdi, serial);
242
243         if (sr_sw_limits_check(&devc->limits)) {
244                 sr_dev_acquisition_stop(sdi);
245                 return TRUE;
246         }
247
248         now = g_get_monotonic_time() / 1000;
249         elapsed = now - devc->cmd_sent_at;
250         if (elapsed > TC_POLL_PERIOD_MS)
251                 rdtech_tc_poll(sdi);
252
253         return TRUE;
254 }