X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Frdtech-tc%2Fprotocol.c;h=291604a0c524e6887381d77d9a837263751793c2;hb=3ed4b109b5975b82dbf3e9f276c4e54a266634db;hp=f2a439e4dacbcbbe0c1975ea562d1f6cdf9496ee;hpb=8817bd6f5d9a92fcc582e3b51ea4cda3abc13b2a;p=libsigrok.git diff --git a/src/hardware/rdtech-tc/protocol.c b/src/hardware/rdtech-tc/protocol.c index f2a439e4..291604a0 100644 --- a/src/hardware/rdtech-tc/protocol.c +++ b/src/hardware/rdtech-tc/protocol.c @@ -33,8 +33,6 @@ #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 @@ -55,6 +53,9 @@ static const char *poll_cmd = "getva"; #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 @@ -64,33 +65,32 @@ static const char *poll_cmd = "getva"; #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, 0xa7, 0xf1, 0x06, 0x61, 0x9a, 0xb8, 0x72, 0x88, }; -static const struct binary_analog_channel rdtech_tc_channels[] = { - { "V", { 0 + 48, BVT_LE_UINT32, 1e-4, }, 4, SR_MQ_VOLTAGE, SR_UNIT_VOLT }, - { "I", { 0 + 52, BVT_LE_UINT32, 1e-5, }, 5, SR_MQ_CURRENT, SR_UNIT_AMPERE }, - { "D+", { 64 + 32, BVT_LE_UINT32, 1e-2, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT }, - { "D-", { 64 + 36, BVT_LE_UINT32, 1e-2, }, 2, SR_MQ_VOLTAGE, SR_UNIT_VOLT }, - { "E0", { 64 + 12, BVT_LE_UINT32, 1e-3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR }, - { "E1", { 64 + 20, BVT_LE_UINT32, 1e-3, }, 3, SR_MQ_ENERGY, SR_UNIT_WATT_HOUR }, - ALL_ZERO, +static const struct rdtech_tc_channel_desc rdtech_tc_channels[] = { + { "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; } @@ -102,7 +102,7 @@ static int process_poll_pkt(struct dev_context *devc, uint8_t *dst) 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; @@ -122,21 +122,57 @@ static int process_poll_pkt(struct dev_context *devc, uint8_t *dst) 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."); @@ -149,6 +185,7 @@ SR_PRIV int rdtech_tc_probe(struct sr_serial_dev_inst *serial, struct dev_contex } devc->channels = rdtech_tc_channels; + devc->channel_count = ARRAY_SIZE(rdtech_tc_channels); devc->dev_info.model_name = g_strndup((const char *)&poll_pkt[OFF_MODEL], LEN_MODEL); devc->dev_info.fw_ver = g_strndup((const char *)&poll_pkt[OFF_FW_VER], LEN_FW_VER); devc->dev_info.serial_num = read_u32le(&poll_pkt[OFF_SERIAL]); @@ -165,10 +202,17 @@ SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi, gboolean force) /* * 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->buflen) - 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 @@ -185,12 +229,13 @@ SR_PRIV int rdtech_tc_poll(const struct sr_dev_inst *sdi, gboolean force) */ 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; } @@ -199,14 +244,15 @@ static int handle_poll_data(struct sr_dev_inst *sdi) { struct dev_context *devc; uint8_t poll_pkt[TC_POLL_LEN]; - size_t i; - GSList *ch; + size_t ch_idx; + const struct rdtech_tc_channel_desc *pch; int ret; + float v; devc = sdi->priv; - sr_spew("Received poll packet (len: %zu).", devc->buflen); - if (devc->buflen < TC_POLL_LEN) { - sr_err("Insufficient poll packet length: %zu", devc->buflen); + sr_spew("Received poll packet (len: %zu).", devc->rdlen); + if (devc->rdlen < TC_POLL_LEN) { + sr_err("Insufficient poll packet length: %zu", devc->rdlen); return SR_ERR_DATA; } @@ -215,20 +261,24 @@ static int handle_poll_data(struct sr_dev_inst *sdi) return SR_ERR_DATA; } - i = 0; - for (ch = sdi->channels; ch; ch = g_slist_next(ch)) { - ret = bv_send_analog_channel(sdi, ch->data, - &devc->channels[i], poll_pkt, TC_POLL_LEN); - i++; + ret = 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_len(&v, &pch->spec, poll_pkt, TC_POLL_LEN); if (ret != SR_OK) - return ret; + break; + ret = feed_queue_analog_submit_one(devc->feeds[ch_idx], v, 1); + if (ret != SR_OK) + break; } + std_session_send_df_frame_end(sdi); - sr_sw_limits_update_samples_read(&devc->limits, 1); + sr_sw_limits_update_frames_read(&devc->limits, 1); if (sr_sw_limits_check(&devc->limits)) sr_dev_acquisition_stop(sdi); - return SR_OK; + return ret; } static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *serial) @@ -240,15 +290,16 @@ static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *se /* Receive data became available. Drain the transport layer. */ devc = sdi->priv; - while (devc->buflen < TC_POLL_LEN) { - space = sizeof(devc->buf) - devc->buflen; + while (devc->rdlen < TC_POLL_LEN) { + space = sizeof(devc->buf) - devc->rdlen; len = serial_read_nonblocking(serial, - &devc->buf[devc->buflen], space); + &devc->buf[devc->rdlen], space); if (len < 0) return SR_ERR_IO; if (len == 0) return SR_OK; - devc->buflen += len; + devc->rdlen += len; + devc->rx_after_tx += len; } /* @@ -257,13 +308,13 @@ static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *se */ /* Process packets when their reception has completed. */ - while (devc->buflen >= TC_POLL_LEN) { + while (devc->rdlen >= TC_POLL_LEN) { ret = handle_poll_data(sdi); if (ret != SR_OK) return ret; - devc->buflen -= TC_POLL_LEN; - if (devc->buflen) - memmove(&devc->buf[0], &devc->buf[TC_POLL_LEN], devc->buflen); + devc->rdlen -= TC_POLL_LEN; + if (devc->rdlen) + memmove(devc->buf, &devc->buf[TC_POLL_LEN], devc->rdlen); } return SR_OK;