From: Gerhard Sittig Date: Wed, 30 Sep 2020 07:59:32 +0000 (+0200) Subject: serial-dmm: add support for the Brymen BM820s family X-Git-Url: http://sigrok.org/gitweb/?p=libsigrok.git;a=commitdiff_plain;h=6bee394deeedd22a54126bd2ec93702385b4b99b serial-dmm: add support for the Brymen BM820s family The BM820s series uses the same 10000 counts protocol as BM520s does, but lacks the capability of recording measurements. Re-use the bm52x DMM packet parser, but don't register the config get/set/list and acquisition start callbacks. It turns out that the packet request and packet validity check routines need to be individual, since 0x82 is used instead of 0x52 as a magic number in some places. Fortunately the complex payload parser is shared among BM520s and BM820s series. This was tested with a BM829s meter. --- diff --git a/src/dmm/bm52x.c b/src/dmm/bm52x.c index 728b70a6..69c01719 100644 --- a/src/dmm/bm52x.c +++ b/src/dmm/bm52x.c @@ -27,6 +27,16 @@ * http://brymen.com/product-html/PD02BM520s_protocolDL.html * http://brymen.com/product-html/images/DownloadList/ProtocolList/BM520-BM520s_List/BM520-BM520s-10000-count-professional-dual-display-mobile-logging-DMMs-protocol.zip * + * This parser was initially created for BM520s devices and tested with + * BM525s. The Brymen BM820s family of devices uses the same protocol, + * with just 0x82 instead of 0x52 in request packets and in the fixed + * fields of the responses. Which means that the packet parser can get + * shared among the BM520s and BM820s devices, but validity check needs + * to be individual, and the "wrong" packet request will end up without + * a response. Compared to BM520s the BM820s has dBm (in the protocol) + * and NCV (not seen in the protocol) and is non-logging (live only). + * BM820s support was tested with BM829s. + * * The parser implementation was tested with a Brymen BM525s meter. Some * of the responses differ from the vendor's documentation: * - Recording session total byte counts don't start after the byte count @@ -45,7 +55,6 @@ * - AVG is not available in BM525s and BM521s. * - LoZ, eliminating ghost voltages. * - LPF, low pass filter. - * - dBm is a BM829s feature only, not available in BM525s. * - low battery, emits sr_warn() but isn't seen in the feed. * - @, 4-20mA loop, % (main display, left hand side), Hi/Lo. Some of * these are in the vendor's documentation for the DMM packet but not @@ -64,8 +73,6 @@ * the full byte stream is necessary on one hand since random access * is not available, and useful on the other hand for consistency * checks. - * - The vendor's shipping box and user manual suggests a similarity of - * BM520s and BM820s meters. Can this DMM packet parser support both? */ #include @@ -102,7 +109,8 @@ struct brymen_bm52x_state { }; enum bm52x_reqtype { - REQ_LIVE_READ, + REQ_LIVE_READ_520, + REQ_LIVE_READ_820, REQ_REC_HEAD, REQ_REC_NEXT, REQ_REC_CURR, @@ -111,17 +119,19 @@ enum bm52x_reqtype { #ifdef HAVE_SERIAL_COMM static int bm52x_send_req(struct sr_serial_dev_inst *serial, enum bm52x_reqtype t) { - static const uint8_t req_live[] = { 0x00, 0x00, 0x52, 0x66, }; + static const uint8_t req_live_520[] = { 0x00, 0x00, 0x52, 0x66, }; + static const uint8_t req_live_820[] = { 0x00, 0x00, 0x82, 0x66, }; static const uint8_t req_head[] = { 0x00, 0x00, 0x52, 0x88, }; static const uint8_t req_next[] = { 0x00, 0x00, 0x52, 0x89, }; static const uint8_t req_curr[] = { 0x00, 0x00, 0x52, 0x8a, }; static const uint8_t *req_bytes[] = { - [REQ_LIVE_READ] = req_live, + [REQ_LIVE_READ_520] = req_live_520, + [REQ_LIVE_READ_820] = req_live_820, [REQ_REC_HEAD] = req_head, [REQ_REC_NEXT] = req_next, [REQ_REC_CURR] = req_curr, }; - static const size_t req_len = ARRAY_SIZE(req_live); + static const size_t req_len = ARRAY_SIZE(req_live_520); const uint8_t *p; size_t l; @@ -142,7 +152,12 @@ static int bm52x_send_req(struct sr_serial_dev_inst *serial, enum bm52x_reqtype SR_PRIV int sr_brymen_bm52x_packet_request(struct sr_serial_dev_inst *serial) { - return bm52x_send_req(serial, REQ_LIVE_READ); + return bm52x_send_req(serial, REQ_LIVE_READ_520); +} + +SR_PRIV int sr_brymen_bm82x_packet_request(struct sr_serial_dev_inst *serial) +{ + return bm52x_send_req(serial, REQ_LIVE_READ_820); } #endif @@ -167,6 +182,20 @@ SR_PRIV gboolean sr_brymen_bm52x_packet_valid(const uint8_t *buf) return TRUE; } +SR_PRIV gboolean sr_brymen_bm82x_packet_valid(const uint8_t *buf) +{ + if (buf[16] != 0x82) + return FALSE; + if (buf[17] != 0x82) + return FALSE; + if (buf[18] != 0x82) + return FALSE; + if (buf[19] != 0x82) + return FALSE; + + return TRUE; +} + /* * Data bytes in the DMM packet encode LCD segments in an unusual order * (bgcpafed) and in an unusual position (bit 4 being the decimal point @@ -628,7 +657,7 @@ static int bm52x_rec_next_rsp(struct sr_serial_dev_inst *serial, int ret; /* Seed internal state when sending the HEAD request. */ - if (req == REQ_REC_HEAD || req == REQ_LIVE_READ) + if (req == REQ_REC_HEAD || req == REQ_LIVE_READ_520) memset(&state->rsp, 0, sizeof(state->rsp)); /* Move unprocessed content to the front. */ @@ -647,7 +676,7 @@ static int bm52x_rec_next_rsp(struct sr_serial_dev_inst *serial, /* Add another response chunk to the read buffer. */ b = &state->rsp.buff[state->rsp.fill_pos]; - l = req == REQ_LIVE_READ ? 24 : 32; + l = req == REQ_LIVE_READ_520 ? 24 : 32; if (sizeof(state->rsp.buff) - state->rsp.fill_pos < l) return SR_ERR_BUG; ret = bm52x_send_req(serial, req); @@ -665,7 +694,7 @@ static int bm52x_rec_next_rsp(struct sr_serial_dev_inst *serial, GString *text; const char *req_text; - req_text = (req == REQ_LIVE_READ) ? "LIVE" : + req_text = (req == REQ_LIVE_READ_520) ? "LIVE" : (req == REQ_REC_HEAD) ? "MEM HEAD" : (req == REQ_REC_NEXT) ? "MEM NEXT" : (req == REQ_REC_CURR) ? "MEM CURR" : diff --git a/src/hardware/serial-dmm/api.c b/src/hardware/serial-dmm/api.c index 1b9a810b..9e050af7 100644 --- a/src/hardware/serial-dmm/api.c +++ b/src/hardware/serial-dmm/api.c @@ -127,7 +127,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) * happen to provide them. (This is a compromise to do it here, * and not extend the DMM_CONN() et al set of macros.) */ - if (dmm->packet_parse == sr_brymen_bm52x_parse) { + if (strcmp(dmm->di.name, "brymen-bm52x") == 0) { + /* Applicable to BM520s but not to BM820s. */ dmm->dmm_state_init = brymen_bm52x_state_init; dmm->dmm_state_free = brymen_bm52x_state_free; dmm->config_get = brymen_bm52x_config_get; @@ -379,6 +380,13 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers, sr_brymen_bm52x_packet_valid, sr_brymen_bm52x_parse, NULL ), + DMM_CONN( + "brymen-bm82x", brymen_bm52x, "Brymen", "BM82x", + "hid/bu86x", NULL, BRYMEN_BM52X_PACKET_SIZE, 4000, 500, + sr_brymen_bm82x_packet_request, + sr_brymen_bm82x_packet_valid, sr_brymen_bm52x_parse, + NULL + ), /* }}} */ /* bm85x based meters {{{ */ DMM_LEN( diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 6a85d694..9a672c7d 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -2344,8 +2344,11 @@ struct brymen_bm52x_info { size_t ch_idx; }; #ifdef HAVE_SERIAL_COMM SR_PRIV int sr_brymen_bm52x_packet_request(struct sr_serial_dev_inst *serial); +SR_PRIV int sr_brymen_bm82x_packet_request(struct sr_serial_dev_inst *serial); #endif SR_PRIV gboolean sr_brymen_bm52x_packet_valid(const uint8_t *buf); +SR_PRIV gboolean sr_brymen_bm82x_packet_valid(const uint8_t *buf); +/* BM520s and BM820s protocols are similar, the parse routine is shared. */ SR_PRIV int sr_brymen_bm52x_parse(const uint8_t *buf, float *floatval, struct sr_datafeed_analog *analog, void *info);