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.
This commit is contained in:
parent
0931639a12
commit
6bee394dee
|
@ -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 <config.h>
|
||||
|
@ -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" :
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue