X-Git-Url: https://sigrok.org/gitweb/?p=libsigrok.git;a=blobdiff_plain;f=src%2Fhardware%2Frdtech-tc%2Fprotocol.c;h=291604a0c524e6887381d77d9a837263751793c2;hp=ef1cd34bf817462f647f9c2cc9ff634bea5d9f52;hb=HEAD;hpb=e2bcf2e3b4190877c64ffdbb6a99d64a063cc402 diff --git a/src/hardware/rdtech-tc/protocol.c b/src/hardware/rdtech-tc/protocol.c index ef1cd34b..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,7 +65,7 @@ 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, @@ -72,24 +73,24 @@ static const uint8_t AES_KEY[] = { }; 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; } @@ -101,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; @@ -121,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."); @@ -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->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 @@ -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; } @@ -220,10 +265,10 @@ static int handle_poll_data(struct sr_dev_inst *sdi) 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; } @@ -254,6 +299,7 @@ static int recv_poll_data(struct sr_dev_inst *sdi, struct sr_serial_dev_inst *se if (len == 0) return SR_OK; devc->rdlen += len; + devc->rx_after_tx += len; } /*