*
* Brymen BM86x serial protocol parser. The USB protocol (for the cable)
* and the packet description (for the meter) were retrieved from:
- * http://brymen.com/product-html/Download2.html
- * http://brymen.com/product-html/PD02BM860s_protocolDL.html
- * http://brymen.com/product-html/images/DownloadList/ProtocolList/BM860-BM860s_List/BM860-BM860s-500000-count-dual-display-DMMs-protocol.pdf
+ * http://www.brymen.com/Download2.html
+ * http://www.brymen.com/PD02BM860s_protocolDL.html
+ * http://www.brymen.com/images/DownloadList/ProtocolList/BM860-BM860s_List/BM860-BM860s-500000-count-dual-display-DMMs-protocol.pdf
+ * http://web.archive.org/web/20191231053213/http://www.brymen.com/images/DownloadList/ProtocolList/BM860-BM860s_List/BM860-BM860s-500000-count-dual-display-DMMs-protocol.pdf
*/
#include <config.h>
{
static const uint8_t request[] = { 0x00, 0x00, 0x86, 0x66, };
- sr_spew("%s() sending request", __func__);
serial_write_nonblocking(serial, request, sizeof(request));
return SR_OK;
SR_PRIV gboolean sr_brymen_bm86x_packet_valid(const uint8_t *buf)
{
- GString *text;
-
- if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
- text = sr_hexdump_new(buf, BRYMEN_BM86X_PACKET_SIZE);
- sr_spew("%s() checking DMM packet: %s", __func__, text->str);
- sr_hexdump_free(text);
- }
-
/*
* "Model ID3" (3rd HID report, byte 3) is the only documented
* fixed value, and must be 0x86. All other positions either depend
if (buf[19] != 0x86)
return FALSE;
+ /*
+ * 2021-05 update: The devices that we have seen in the field do
+ * provide four bytes which we can synchronize to. Which happens
+ * to match the bm52x and bm82x devices' protocol. This condition
+ * is not documented by the vendor, but improves reliability of
+ * the re-synchronization for slight offsets, which were seen
+ * in the field, and which would have kept failing in an earlier
+ * implementation.
+ */
+ if (buf[16] != 0x86)
+ return FALSE;
+ if (buf[17] != 0x86)
+ return FALSE;
+ if (buf[18] != 0x86)
+ return FALSE;
+
return TRUE;
}
int ret, digits, is_diode, over_limit, scale;
uint8_t ind1, ind15;
+ temp_unit = '\0';
if (ch_idx == 0) {
/*
* Main display. Note that _some_ of the second display's
} else if (buf[15] & 0x80) {
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
analog->meaning->unit = SR_UNIT_PERCENTAGE;
- } else if (buf[ 2] & 0x0a) {
+ } else if ((buf[2] & 0x0a) && temp_unit) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog->meaning->unit = SR_UNIT_FAHRENHEIT;
analog->encoding->digits = digits;
analog->spec->spec_digits = digits;
} else if (ch_idx == 1) {
- /* Secondary display. */
+ /*
+ * Secondary display. Also inspect _some_ primary display
+ * data, to determine the secondary display's validity.
+ */
+ (void)brymen_bm86x_parse_digits(&buf[2], 6, txtbuf,
+ NULL, &temp_unit, NULL, 0x80);
ret = brymen_bm86x_parse_digits(&buf[9], 4, txtbuf,
- floatval, &temp_unit, &digits, 0x10);
+ floatval, NULL, &digits, 0x10);
+ if (ret != SR_OK)
+ return;
/* SI unit. */
if (buf[14] & 0x08) {
} else if (buf[14] & 0x04) {
analog->meaning->mq = SR_MQ_FREQUENCY;
analog->meaning->unit = SR_UNIT_HERTZ;
- } else if (buf[9] & 0x40) {
+ } else if ((buf[9] & 0x40) && temp_unit) {
analog->meaning->mq = SR_MQ_TEMPERATURE;
if (temp_unit == 'F')
analog->meaning->unit = SR_UNIT_FAHRENHEIT;