serial-dmm, metex14: add support for multiple channels per DMM
Optionally create multiple analog channels in serial-dmm's scan() routine. Allow the meters' parse routines to fill in more than one analog value from the inspection of a single packet. Use "large" (4 times 14 bytes) packets for the Metex M-3860M and the PeakTech 4390A meters, and have those large packets parsed by wrapping the routines for regular 14-byte Metex packets, and sending four values to the session bus after reception of one large packet. Thanks to Frank Stettner <frank-stettner@gmx.net> for testing and fixing the initial implementation of this extension.
This commit is contained in:
parent
51e1f5661c
commit
556a926d43
|
@ -313,6 +313,25 @@ SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf)
|
||||||
|
{
|
||||||
|
struct metex14_info info;
|
||||||
|
size_t ch_idx;
|
||||||
|
const uint8_t *ch_buf;
|
||||||
|
|
||||||
|
ch_buf = buf;
|
||||||
|
for (ch_idx = 0; ch_idx < 4; ch_idx++) {
|
||||||
|
if (ch_buf[13] != '\r')
|
||||||
|
return FALSE;
|
||||||
|
memset(&info, 0x00, sizeof(info));
|
||||||
|
parse_flags((const char *)ch_buf, &info);
|
||||||
|
if (!flags_valid(&info))
|
||||||
|
return FALSE;
|
||||||
|
ch_buf += METEX14_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a protocol packet.
|
* Parse a protocol packet.
|
||||||
*
|
*
|
||||||
|
@ -354,3 +373,34 @@ SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
|
||||||
|
|
||||||
return SR_OK;
|
return SR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse one out of four values of a four-display Metex14 variant.
|
||||||
|
*
|
||||||
|
* The caller's 'info' parameter can be used to track the channel index,
|
||||||
|
* as long as the information is kept across calls to the 14-byte packet
|
||||||
|
* parse routine (which clears the 'info' container).
|
||||||
|
*
|
||||||
|
* Since analog values have further details in the 'analog' parameter,
|
||||||
|
* passing multiple values per parse routine call is problematic. So we
|
||||||
|
* prefer the approach of passing one value per call, which is most
|
||||||
|
* reliable and shall fit every similar device with multiple displays.
|
||||||
|
*
|
||||||
|
* The meters which use this parse routine send one 14-byte packet per
|
||||||
|
* display. Each packet has the regular Metex14 layout.
|
||||||
|
*/
|
||||||
|
SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval,
|
||||||
|
struct sr_datafeed_analog *analog, void *info)
|
||||||
|
{
|
||||||
|
struct metex14_info *info_local;
|
||||||
|
size_t ch_idx;
|
||||||
|
const uint8_t *ch_buf;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
info_local = info;
|
||||||
|
ch_idx = info_local->ch_idx;
|
||||||
|
ch_buf = buf + ch_idx * METEX14_PACKET_SIZE;
|
||||||
|
rc = sr_metex14_parse(ch_buf, floatval, analog, info);
|
||||||
|
info_local->ch_idx = ch_idx + 1;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
int dropped, ret;
|
int dropped, ret;
|
||||||
size_t len;
|
size_t len;
|
||||||
uint8_t buf[128];
|
uint8_t buf[128];
|
||||||
|
size_t ch_idx;
|
||||||
|
char ch_name[12];
|
||||||
|
|
||||||
dmm = (struct dmm_info *)di;
|
dmm = (struct dmm_info *)di;
|
||||||
|
|
||||||
|
@ -131,7 +133,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
||||||
sdi->inst_type = SR_INST_SERIAL;
|
sdi->inst_type = SR_INST_SERIAL;
|
||||||
sdi->conn = serial;
|
sdi->conn = serial;
|
||||||
sdi->priv = devc;
|
sdi->priv = devc;
|
||||||
sr_channel_new(sdi, 0, SR_CHANNEL_ANALOG, TRUE, "P1");
|
dmm->channel_count = 1;
|
||||||
|
if (dmm->packet_parse == sr_metex14_4packets_parse)
|
||||||
|
dmm->channel_count = 4;
|
||||||
|
for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) {
|
||||||
|
snprintf(ch_name, sizeof(ch_name), "P%zu", ch_idx);
|
||||||
|
sr_channel_new(sdi, ch_idx, SR_CHANNEL_ANALOG, TRUE, ch_name);
|
||||||
|
}
|
||||||
devices = g_slist_append(devices, sdi);
|
devices = g_slist_append(devices, sdi);
|
||||||
|
|
||||||
scan_cleanup:
|
scan_cleanup:
|
||||||
|
@ -197,7 +205,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi)
|
||||||
.context = NULL, \
|
.context = NULL, \
|
||||||
}, \
|
}, \
|
||||||
VENDOR, MODEL, CONN, BAUDRATE, PACKETSIZE, TIMEOUT, DELAY, \
|
VENDOR, MODEL, CONN, BAUDRATE, PACKETSIZE, TIMEOUT, DELAY, \
|
||||||
REQUEST, VALID, PARSE, DETAILS, sizeof(struct CHIPSET##_info) \
|
REQUEST, 1, VALID, PARSE, DETAILS, sizeof(struct CHIPSET##_info) \
|
||||||
}).di
|
}).di
|
||||||
|
|
||||||
SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers,
|
SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers,
|
||||||
|
@ -440,8 +448,8 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers,
|
||||||
DMM(
|
DMM(
|
||||||
"metex-m3860m", metex14,
|
"metex-m3860m", metex14,
|
||||||
"Metex", "M-3860M", "9600/7n2/rts=0/dtr=1", 9600,
|
"Metex", "M-3860M", "9600/7n2/rts=0/dtr=1", 9600,
|
||||||
METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
|
4 * METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
|
||||||
sr_metex14_packet_valid, sr_metex14_parse,
|
sr_metex14_4packets_valid, sr_metex14_4packets_parse,
|
||||||
NULL
|
NULL
|
||||||
),
|
),
|
||||||
DMM(
|
DMM(
|
||||||
|
@ -475,8 +483,8 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers,
|
||||||
DMM(
|
DMM(
|
||||||
"peaktech-4390a", metex14,
|
"peaktech-4390a", metex14,
|
||||||
"PeakTech", "4390A", "9600/7n2/rts=0/dtr=1", 9600,
|
"PeakTech", "4390A", "9600/7n2/rts=0/dtr=1", 9600,
|
||||||
METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
|
4 * METEX14_PACKET_SIZE, 0, 0, sr_metex14_packet_request,
|
||||||
sr_metex14_packet_valid, sr_metex14_parse,
|
sr_metex14_4packets_valid, sr_metex14_4packets_parse,
|
||||||
NULL
|
NULL
|
||||||
),
|
),
|
||||||
DMM(
|
DMM(
|
||||||
|
|
|
@ -49,31 +49,42 @@ static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi,
|
||||||
struct sr_analog_meaning meaning;
|
struct sr_analog_meaning meaning;
|
||||||
struct sr_analog_spec spec;
|
struct sr_analog_spec spec;
|
||||||
struct dev_context *devc;
|
struct dev_context *devc;
|
||||||
|
gboolean sent_sample;
|
||||||
|
size_t ch_idx;
|
||||||
|
|
||||||
dmm = (struct dmm_info *)sdi->driver;
|
dmm = (struct dmm_info *)sdi->driver;
|
||||||
|
|
||||||
log_dmm_packet(buf);
|
log_dmm_packet(buf);
|
||||||
devc = sdi->priv;
|
devc = sdi->priv;
|
||||||
|
|
||||||
/* Note: digits/spec_digits will be overridden by the DMM parsers. */
|
sent_sample = FALSE;
|
||||||
sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
|
memset(info, 0, dmm->info_size);
|
||||||
|
for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) {
|
||||||
|
/* Note: digits/spec_digits will be overridden by the DMM parsers. */
|
||||||
|
sr_analog_init(&analog, &encoding, &meaning, &spec, 0);
|
||||||
|
|
||||||
analog.meaning->channels = sdi->channels;
|
analog.meaning->channels =
|
||||||
analog.num_samples = 1;
|
g_slist_append(NULL, g_slist_nth_data(sdi->channels, ch_idx));
|
||||||
analog.meaning->mq = 0;
|
analog.num_samples = 1;
|
||||||
|
analog.meaning->mq = 0;
|
||||||
|
|
||||||
dmm->packet_parse(buf, &floatval, &analog, info);
|
dmm->packet_parse(buf, &floatval, &analog, info);
|
||||||
analog.data = &floatval;
|
analog.data = &floatval;
|
||||||
|
|
||||||
/* If this DMM needs additional handling, call the resp. function. */
|
/* If this DMM needs additional handling, call the resp. function. */
|
||||||
if (dmm->dmm_details)
|
if (dmm->dmm_details)
|
||||||
dmm->dmm_details(&analog, info);
|
dmm->dmm_details(&analog, info);
|
||||||
|
|
||||||
if (analog.meaning->mq != 0) {
|
if (analog.meaning->mq != 0) {
|
||||||
/* Got a measurement. */
|
/* Got a measurement. */
|
||||||
packet.type = SR_DF_ANALOG;
|
packet.type = SR_DF_ANALOG;
|
||||||
packet.payload = &analog;
|
packet.payload = &analog;
|
||||||
sr_session_send(sdi, &packet);
|
sr_session_send(sdi, &packet);
|
||||||
|
sent_sample = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sent_sample) {
|
||||||
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
sr_sw_limits_update_samples_read(&devc->limits, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ struct dmm_info {
|
||||||
int64_t req_delay_ms;
|
int64_t req_delay_ms;
|
||||||
/** Packet request function. */
|
/** Packet request function. */
|
||||||
int (*packet_request)(struct sr_serial_dev_inst *);
|
int (*packet_request)(struct sr_serial_dev_inst *);
|
||||||
|
/** Number of channels / displays. */
|
||||||
|
size_t channel_count;
|
||||||
/** Packet validation function. */
|
/** Packet validation function. */
|
||||||
gboolean (*packet_valid)(const uint8_t *);
|
gboolean (*packet_valid)(const uint8_t *);
|
||||||
/** Packet parsing function. */
|
/** Packet parsing function. */
|
||||||
|
|
|
@ -1273,6 +1273,7 @@ SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
|
||||||
#define METEX14_PACKET_SIZE 14
|
#define METEX14_PACKET_SIZE 14
|
||||||
|
|
||||||
struct metex14_info {
|
struct metex14_info {
|
||||||
|
size_t ch_idx;
|
||||||
gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature;
|
gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature;
|
||||||
gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad;
|
gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad;
|
||||||
gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro;
|
gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro;
|
||||||
|
@ -1286,6 +1287,9 @@ SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial);
|
||||||
SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf);
|
SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf);
|
||||||
SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
|
SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
|
||||||
struct sr_datafeed_analog *analog, void *info);
|
struct sr_datafeed_analog *analog, void *info);
|
||||||
|
SR_PRIV gboolean sr_metex14_4packets_valid(const uint8_t *buf);
|
||||||
|
SR_PRIV int sr_metex14_4packets_parse(const uint8_t *buf, float *floatval,
|
||||||
|
struct sr_datafeed_analog *analog, void *info);
|
||||||
|
|
||||||
/*--- hardware/dmm/rs9lcd.c -------------------------------------------------*/
|
/*--- hardware/dmm/rs9lcd.c -------------------------------------------------*/
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue