#define WRITE_TO_MS 1
#define POLL_PERIOD_MS 100
-static const char *poll_cmd = "getva";
-
/*
* Response data (raw sample data) consists of three adjacent chunks
* of 64 bytes each. These chunks start with their magic string, and
#define OFF_PAC2 (1 * PAC_LEN)
#define OFF_PAC3 (2 * PAC_LEN)
#define TC_POLL_LEN (3 * PAC_LEN)
+#if TC_POLL_LEN > RDTECH_TC_RSPBUFSIZE
+# error "response length exceeds receive buffer space"
+#endif
#define OFF_MODEL 4
#define LEN_MODEL 4
#define OFF_SERIAL 12
-static const uint8_t AES_KEY[] = {
+static const uint8_t aes_key[] = {
0x58, 0x21, 0xfa, 0x56, 0x01, 0xb2, 0xf0, 0x26,
0x87, 0xff, 0x12, 0x04, 0x62, 0x2a, 0x4f, 0xb0,
0x86, 0xf4, 0x02, 0x60, 0x81, 0x6f, 0x9a, 0x0b,
};
static const struct rdtech_tc_channel_desc rdtech_tc_channels[] = {
- { "V", { 0 + 48, BVT_LE_UINT32, 1, }, { 100, 1e6, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
- { "I", { 0 + 52, BVT_LE_UINT32, 1, }, { 10, 1e6, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE },
- { "D+", { 64 + 32, BVT_LE_UINT32, 1, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
- { "D-", { 64 + 36, BVT_LE_UINT32, 1, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
- { "E0", { 64 + 12, BVT_LE_UINT32, 1, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
- { "E1", { 64 + 20, BVT_LE_UINT32, 1, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
+ { "V", { 0 + 48, BVT_LE_UINT32, }, { 100, 1e6, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
+ { "I", { 0 + 52, BVT_LE_UINT32, }, { 10, 1e6, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE },
+ { "D+", { 64 + 32, BVT_LE_UINT32, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
+ { "D-", { 64 + 36, BVT_LE_UINT32, }, { 10, 1e3, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT },
+ { "E0", { 64 + 12, BVT_LE_UINT32, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
+ { "E1", { 64 + 20, BVT_LE_UINT32, }, { 1, 1e3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR },
};
static gboolean check_pac_crc(uint8_t *data)
{
- uint16_t crc;
- uint32_t crc_field;
+ uint16_t crc_calc;
+ uint32_t crc_recv;
- crc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS);
- crc_field = read_u32le(&data[PAC_CRC_POS]);
- if (crc != crc_field) {
+ crc_calc = sr_crc16(SR_CRC16_DEFAULT_INIT, data, PAC_CRC_POS);
+ crc_recv = read_u32le(&data[PAC_CRC_POS]);
+ if (crc_calc != crc_recv) {
sr_spew("CRC error. Calculated: %0x" PRIx16 ", expected: %0x" PRIx32,
- crc, crc_field);
+ crc_calc, crc_recv);
return FALSE;
}
struct aes256_ctx ctx;
gboolean ok;
- aes256_set_decrypt_key(&ctx, AES_KEY);
+ aes256_set_decrypt_key(&ctx, aes_key);
aes256_decrypt(&ctx, TC_POLL_LEN, dst, devc->buf);
ok = TRUE;
return SR_ERR_DATA;
}
+ if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+ static const size_t chunk_max = 32;
+
+ const uint8_t *rdptr;
+ size_t rdlen, chunk_addr, chunk_len;
+ GString *txt;
+
+ sr_spew("check passed on decrypted receive data");
+ rdptr = dst;
+ rdlen = TC_POLL_LEN;
+ chunk_addr = 0;
+ while (rdlen) {
+ chunk_len = rdlen;
+ if (chunk_len > chunk_max)
+ chunk_len = chunk_max;
+ txt = sr_hexdump_new(rdptr, chunk_len);
+ sr_spew("%04zx %s", chunk_addr, txt->str);
+ sr_hexdump_free(txt);
+ chunk_addr += chunk_len;
+ rdptr += chunk_len;
+ rdlen -= chunk_len;
+ }
+ }
+
return SR_OK;
}
SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_context *devc)
{
+ static const char *poll_cmd_cdc = "getva";
+ static const char *poll_cmd_ble = "bgetva\r\n";
+
int len;
uint8_t poll_pkt[TC_POLL_LEN];
+ /* Construct the request text. Which differs across transports. */
+ devc->is_bluetooth = ser_name_is_bt(serial);
+ snprintf(devc->req_text, sizeof(devc->req_text), "%s",
+ devc->is_bluetooth ? poll_cmd_ble : poll_cmd_cdc);
+ sr_dbg("is bluetooth %d -> poll request '%s'.",
+ devc->is_bluetooth, devc->req_text);
+
+ /* Transmit the request. */
len = serial_write_blocking(serial,
- poll_cmd, strlen(poll_cmd), WRITE_TO_MS);
+ devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
if (len < 0) {
sr_err("Failed to send probe request.");
return SR_ERR;
}
+ /* Receive a response. */
len = serial_read_blocking(serial, devc->buf, TC_POLL_LEN, PROBE_TO_MS);
if (len != TC_POLL_LEN) {
sr_err("Failed to read probe response.");
/*
* Don't send the request while receive data is being accumulated.
+ * Defer request transmission when a previous request has not yet
+ * seen any response data at all (more probable to happen shortly
+ * after connecting to the peripheral).
*/
devc = sdi->priv;
- if (!force && devc->rdlen)
- return SR_OK;
+ if (!force) {
+ if (devc->rdlen)
+ return SR_OK;
+ if (!devc->rx_after_tx)
+ return SR_OK;
+ }
/*
* Send the request when the transmit interval was reached. Or
*/
serial = sdi->conn;
len = serial_write_blocking(serial,
- poll_cmd, strlen(poll_cmd), WRITE_TO_MS);
+ devc->req_text, strlen(devc->req_text), WRITE_TO_MS);
if (len < 0) {
sr_err("Unable to send poll request.");
return SR_ERR;
}
devc->cmd_sent_at = now;
+ devc->rx_after_tx = 0;
return SR_OK;
}
std_session_send_df_frame_begin(sdi);
for (ch_idx = 0; ch_idx < devc->channel_count; ch_idx++) {
pch = &devc->channels[ch_idx];
- ret = bv_get_value(&v, &pch->spec, poll_pkt, TC_POLL_LEN);
+ ret = bv_get_value_len(&v, &pch->spec, poll_pkt, TC_POLL_LEN);
if (ret != SR_OK)
break;
- ret = feed_queue_analog_submit(devc->feeds[ch_idx], v, 1);
+ ret = feed_queue_analog_submit_one(devc->feeds[ch_idx], v, 1);
if (ret != SR_OK)
break;
}
if (len == 0)
return SR_OK;
devc->rdlen += len;
+ devc->rx_after_tx += len;
}
/*