Add MASTECH MS2115B support.
This commit is contained in:
parent
16a8e58068
commit
dcd212f7a2
|
@ -155,6 +155,7 @@ libsigrok_la_SOURCES += \
|
|||
src/dmm/fs9922.c \
|
||||
src/dmm/m2110.c \
|
||||
src/dmm/metex14.c \
|
||||
src/dmm/ms2115b.c \
|
||||
src/dmm/ms8250d.c \
|
||||
src/dmm/rs9lcd.c \
|
||||
src/dmm/ut372.c \
|
||||
|
|
|
@ -0,0 +1,374 @@
|
|||
/*
|
||||
* This file is part of the libsigrok project.
|
||||
*
|
||||
* Copyright (C) 2019 Vitaliy Vorobyov
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* MASTECH MS2115B protocol parser.
|
||||
*
|
||||
* Sends 9 bytes.
|
||||
* D0 D1 D2 D3 D4 D5 D6 D7 D8 D9
|
||||
*
|
||||
* D0 = 0x55 - sync byte
|
||||
*
|
||||
* D1 - mode:
|
||||
* bits:
|
||||
* B7..B4 ??
|
||||
* B3 - func
|
||||
* B2..B0:
|
||||
* 0 - A 600/1000 (func=0 AC, func=1 DC), signed
|
||||
* 1 - A 60 (func=0 AC, func=1 DC), signed
|
||||
* 2 - V (func=0 AC, func=1 DC), signed
|
||||
* 3 - diode/beep (func=0 buz, func=1 diode)
|
||||
* 4 - resistance
|
||||
* 5 - capacitance
|
||||
* 6 - hz
|
||||
*
|
||||
* D2 - range
|
||||
*
|
||||
* D3 - frq range
|
||||
*
|
||||
* D4 main value LSB
|
||||
* D5 main value MSB
|
||||
*
|
||||
* (secondary value, hz, min/max, rel)
|
||||
* D6 secondary value LSB
|
||||
* D7 secondary value MSB
|
||||
*
|
||||
* D8 - flags
|
||||
* bits:
|
||||
* B7..B1:??
|
||||
* B0 - 0 - auto, 1 - manual
|
||||
*
|
||||
* resistance:
|
||||
* 55 04 00 00 9B 18 00 00 01 (0.L, manual) 600.0 Ohm (x 0.1)
|
||||
* 55 04 01 00 9B 18 00 00 01 (0.L, manual) 6.000 kOhm (x 0.001)
|
||||
* 55 04 02 00 9B 18 00 00 01 (0.L, manual) 60.00 kOhm (x 0.01)
|
||||
* 55 04 03 00 9B 18 00 00 01 (0.L, manual) 600.0 kOhm (x 0.1)
|
||||
* 55 04 04 00 9B 18 00 00 01 (0.L, manual) 6.000 MOhm (x 0.001)
|
||||
* 55 04 05 00 9B 18 00 00 00 (0.L, auto) 60.00 MOhm (x 0.01)
|
||||
*
|
||||
* capacitance:
|
||||
* 55 05 00 00 04 00 00 00 00 (4nF, auto)
|
||||
* 55 05 00 00 05 00 00 00 01 (5nF, manual) 6.000 nF (x 0.001)
|
||||
* 55 05 01 00 03 19 00 00 01 (0.L nF, manual) 60.00 nF (x 0.01)
|
||||
* 55 05 02 00 D4 03 00 00 01 (980.0 nF, manual) 600.0 nF (x 0.1)
|
||||
* 55 05 03 00 63 00 00 00 01 (0.099 uF, manual) 6.000 uF (x 0.001)
|
||||
* 55 05 04 00 40 18 00 00 01 (0.L uF, manual)
|
||||
* 55 05 04 00 F0 00 00 00 01 (2.40 uF, manual) 60.00 uF (x 0.01)
|
||||
* 55 05 05 00 17 00 00 00 01 (2.3 uF, manual) 600.0 uF (x 0.1)
|
||||
* 55 05 06 00 02 00 00 00 01 (0.002 mF, manual) 6.000 mF (x 0.001)
|
||||
* 55 05 07 00 2F 00 00 00 01 (0.47 mF, manual) 60.00 mF (x 0.01)
|
||||
*
|
||||
* voltage:
|
||||
* 55 02 00 00 00 00 00 00 01 (0.0mV, manual) 600.0 mV (x 0.1)
|
||||
* 55 02 01 00 00 00 00 00 00 (0.000V, auto)
|
||||
* 55 02 01 00 00 00 00 00 01 (0.000V, manual) 6.000 V (x 0.001)
|
||||
* 55 02 02 00 00 00 00 00 01 (0.00V, manual) 60.00 V (x 0.01)
|
||||
* 55 02 03 00 00 00 00 00 01 (0.0V, manual) 600.0 V (x 0.1)
|
||||
* 55 02 04 00 00 00 00 00 01 (0V, manual) 1000 V (x 1)
|
||||
*
|
||||
* - Communication parameters: Unidirectional, 1200/8n1
|
||||
* - CP2102 USB to UART bridge controller
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
#include <libsigrok/libsigrok.h>
|
||||
#include "libsigrok-internal.h"
|
||||
|
||||
#define LOG_PREFIX "ms2115b"
|
||||
|
||||
static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
|
||||
const struct ms2115b_info *info)
|
||||
{
|
||||
/* Measurement modes */
|
||||
if (info->is_volt) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
}
|
||||
if (info->is_ampere) {
|
||||
analog->meaning->mq = SR_MQ_CURRENT;
|
||||
analog->meaning->unit = SR_UNIT_AMPERE;
|
||||
}
|
||||
if (info->is_ohm) {
|
||||
analog->meaning->mq = SR_MQ_RESISTANCE;
|
||||
analog->meaning->unit = SR_UNIT_OHM;
|
||||
}
|
||||
if (info->is_hz) {
|
||||
analog->meaning->mq = SR_MQ_FREQUENCY;
|
||||
analog->meaning->unit = SR_UNIT_HERTZ;
|
||||
}
|
||||
if (info->is_farad) {
|
||||
analog->meaning->mq = SR_MQ_CAPACITANCE;
|
||||
analog->meaning->unit = SR_UNIT_FARAD;
|
||||
}
|
||||
if (info->is_beep) {
|
||||
analog->meaning->mq = SR_MQ_CONTINUITY;
|
||||
analog->meaning->unit = SR_UNIT_BOOLEAN;
|
||||
*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
|
||||
}
|
||||
if (info->is_diode) {
|
||||
analog->meaning->mq = SR_MQ_VOLTAGE;
|
||||
analog->meaning->unit = SR_UNIT_VOLT;
|
||||
}
|
||||
|
||||
if (info->is_duty_cycle)
|
||||
analog->meaning->mq = SR_MQ_DUTY_CYCLE;
|
||||
|
||||
if (info->is_percent)
|
||||
analog->meaning->unit = SR_UNIT_PERCENTAGE;
|
||||
|
||||
/* Measurement related flags */
|
||||
if (info->is_ac)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AC;
|
||||
if (info->is_dc)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DC;
|
||||
if (info->is_auto)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_AUTORANGE;
|
||||
if (info->is_diode)
|
||||
analog->meaning->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
|
||||
}
|
||||
|
||||
SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf)
|
||||
{
|
||||
sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
|
||||
buf[7], buf[8]);
|
||||
|
||||
if (buf[0] == 0x55)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Mode values equal to received data */
|
||||
enum {
|
||||
MODE_A600_1000 = 0,
|
||||
MODE_A60 = 1,
|
||||
MODE_V = 2,
|
||||
MODE_DIODE_BEEP = 3,
|
||||
MODE_OHM = 4,
|
||||
MODE_CAP = 5,
|
||||
MODE_HZ = 6,
|
||||
};
|
||||
|
||||
static const int res_exp[] = {
|
||||
-1, /* 600.0 Ohm (x 0.1) */
|
||||
-3 + 3, /* 6.000 kOhm (x 0.001) */
|
||||
-2 + 3, /* 60.00 kOhm (x 0.01) */
|
||||
-1 + 3, /* 600.0 kOhm (x 0.1) */
|
||||
-3 + 6, /* 6.000 MOhm (x 0.001) */
|
||||
-2 + 6, /* 60.00 MOhm (x 0.01) */
|
||||
};
|
||||
|
||||
static const int cap_exp[] = {
|
||||
-3 - 9, /* 6.000 nF (x 0.001) */
|
||||
-2 - 9, /* 60.00 nF (x 0.01) */
|
||||
-1 - 9, /* 600.0 nF (x 0.1) */
|
||||
-3 - 6, /* 6.000 uF (x 0.001) */
|
||||
-2 - 6, /* 60.00 uF (x 0.01) */
|
||||
-1 - 6, /* 600.0 uF (x 0.1) */
|
||||
-3 - 3, /* 6.000 mF (x 0.001) */
|
||||
-2 - 3, /* 60.00 mF (x 0.01) */
|
||||
};
|
||||
|
||||
static const int hz_exp[] = {
|
||||
-2, /* 60.00 Hz (x 0.01) */
|
||||
-1, /* 600.0 Hz (x 0.1) */
|
||||
-3 + 3, /* 6.000 kHz (x 0.001) */
|
||||
-2 + 3, /* 60.00 kHz (x 0.01) */
|
||||
-1 + 3, /* 600.0 kHz (x 0.1) */
|
||||
-3 + 6, /* 6.000 MHz (x 0.001) */
|
||||
-2 + 6, /* 60.00 MHz (x 0.01) */
|
||||
};
|
||||
|
||||
static const int v_exp[] = {
|
||||
-1 - 3, /* 600.0 mV (x 0.1) */
|
||||
-3, /* 6.000 V (x 0.001) */
|
||||
-2, /* 60.00 V (x 0.01) */
|
||||
-1, /* 600.0 V (x 0.1) */
|
||||
0, /* 1000 V (x 1) */
|
||||
};
|
||||
|
||||
SR_PRIV const char *ms2115b_channel_formats[MS2115B_DISPLAY_COUNT] = {
|
||||
"main", "sub",
|
||||
};
|
||||
|
||||
static int ms2115b_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
int exponent = 0;
|
||||
float up_limit = 6000.0;
|
||||
gboolean sign = FALSE;
|
||||
|
||||
uint32_t mode = (buf[1] & 7);
|
||||
gboolean func = (buf[1] & 8) ? TRUE : FALSE;
|
||||
uint32_t range = (buf[2] & 7);
|
||||
|
||||
struct ms2115b_info *info_local = info;
|
||||
|
||||
enum eev121gw_display display = info_local->ch_idx;
|
||||
memset(info_local, 0, sizeof(*info_local));
|
||||
info_local->ch_idx = display;
|
||||
|
||||
switch (display) {
|
||||
case MS2115B_DISPLAY_MAIN:
|
||||
switch (mode) {
|
||||
case MODE_A600_1000:
|
||||
exponent = -1;
|
||||
sign = TRUE;
|
||||
info_local->is_ampere = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_A60:
|
||||
exponent = -2;
|
||||
sign = TRUE;
|
||||
info_local->is_ampere = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_V:
|
||||
if (range >= ARRAY_SIZE(v_exp))
|
||||
return SR_ERR;
|
||||
exponent = v_exp[range];
|
||||
sign = TRUE;
|
||||
info_local->is_volt = TRUE;
|
||||
if (func)
|
||||
info_local->is_dc = TRUE;
|
||||
else
|
||||
info_local->is_ac = TRUE;
|
||||
break;
|
||||
case MODE_DIODE_BEEP:
|
||||
if (func) {
|
||||
exponent = -3;
|
||||
up_limit = 2500.0;
|
||||
info_local->is_diode = TRUE;
|
||||
} else {
|
||||
info_local->is_beep = TRUE;
|
||||
}
|
||||
break;
|
||||
case MODE_OHM:
|
||||
if (range >= ARRAY_SIZE(res_exp))
|
||||
return SR_ERR;
|
||||
exponent = res_exp[range];
|
||||
info_local->is_ohm = TRUE;
|
||||
break;
|
||||
case MODE_CAP:
|
||||
if (range >= ARRAY_SIZE(cap_exp))
|
||||
return SR_ERR;
|
||||
exponent = cap_exp[range];
|
||||
info_local->is_farad = TRUE;
|
||||
break;
|
||||
case MODE_HZ:
|
||||
range = (buf[3] & 7);
|
||||
if (range >= ARRAY_SIZE(hz_exp))
|
||||
return SR_ERR;
|
||||
exponent = hz_exp[range];
|
||||
info_local->is_hz = TRUE;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (sign) {
|
||||
*floatval = RL16S(buf + 4); /* signed 16bit value */
|
||||
} else {
|
||||
*floatval = RL16(buf + 4); /* unsigned 16bit value */
|
||||
}
|
||||
|
||||
info_local->is_auto = (buf[8] & 1) ? FALSE : TRUE;
|
||||
break;
|
||||
case MS2115B_DISPLAY_SUB:
|
||||
switch (mode) {
|
||||
case MODE_A600_1000:
|
||||
case MODE_A60:
|
||||
case MODE_V:
|
||||
if (func) /* DC */
|
||||
return SR_ERR_NA;
|
||||
|
||||
/* AC */
|
||||
info_local->is_hz = TRUE;
|
||||
exponent = -2;
|
||||
break;
|
||||
case MODE_HZ:
|
||||
info_local->is_duty_cycle = TRUE;
|
||||
info_local->is_percent = TRUE;
|
||||
exponent = -1;
|
||||
break;
|
||||
default:
|
||||
return SR_ERR_NA;
|
||||
}
|
||||
|
||||
*floatval = RL16(buf + 6); /* unsigned 16bit value */
|
||||
break;
|
||||
default:
|
||||
return SR_ERR;
|
||||
}
|
||||
|
||||
if (fabsf(*floatval) > up_limit) {
|
||||
sr_spew("Over limit.");
|
||||
*floatval = INFINITY;
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
*floatval *= powf(10, exponent);
|
||||
|
||||
handle_flags(analog, floatval, info_local);
|
||||
|
||||
analog->encoding->digits = -exponent;
|
||||
analog->spec->spec_digits = -exponent;
|
||||
|
||||
return SR_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a protocol packet.
|
||||
*
|
||||
* @param buf Buffer containing the 9-byte protocol packet. Must not be NULL.
|
||||
* @param floatval Pointer to a float variable. That variable will contain the
|
||||
* result value upon parsing success. Must not be NULL.
|
||||
* @param analog Pointer to a struct sr_datafeed_analog. The struct will be
|
||||
* filled with data according to the protocol packet.
|
||||
* Must not be NULL.
|
||||
* @param info Pointer to a struct ms2115b_info. The struct will be filled
|
||||
* with data according to the protocol packet. Must not be NULL.
|
||||
*
|
||||
* @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
|
||||
* 'analog' variable contents are undefined and should not be used.
|
||||
*/
|
||||
SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info)
|
||||
{
|
||||
int ret;
|
||||
int ch_idx;
|
||||
struct ms2115b_info *info_local = info;
|
||||
|
||||
ch_idx = info_local->ch_idx;
|
||||
ret = ms2115b_parse(buf, floatval, analog, info);
|
||||
info_local->ch_idx = ch_idx + 1;
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -140,6 +140,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options)
|
|||
dmm->channel_count = EEV121GW_DISPLAY_COUNT;
|
||||
dmm->channel_formats = eev121gw_channel_formats;
|
||||
}
|
||||
if (dmm->packet_parse == sr_ms2115b_parse) {
|
||||
dmm->channel_count = MS2115B_DISPLAY_COUNT;
|
||||
dmm->channel_formats = ms2115b_channel_formats;
|
||||
}
|
||||
for (ch_idx = 0; ch_idx < dmm->channel_count; ch_idx++) {
|
||||
size_t ch_num;
|
||||
const char *fmt;
|
||||
|
@ -453,6 +457,15 @@ SR_REGISTER_DEV_DRIVER_LIST(serial_dmm_drivers,
|
|||
NULL
|
||||
),
|
||||
/* }}} */
|
||||
/* ms2115b based meters {{{ */
|
||||
DMM(
|
||||
"mastech-ms2115b", ms2115b,
|
||||
"MASTECH", "MS2115B", "1200/8n1",
|
||||
1200, MS2115B_PACKET_SIZE, 0, 0, NULL,
|
||||
sr_ms2115b_packet_valid, sr_ms2115b_parse,
|
||||
NULL
|
||||
),
|
||||
/* }}} */
|
||||
/* ms8250d based meters {{{ */
|
||||
DMM(
|
||||
"mastech-ms8250d", ms8250d,
|
||||
|
|
|
@ -1260,6 +1260,30 @@ SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info);
|
|||
SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info);
|
||||
SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info);
|
||||
|
||||
/*--- dmm/ms2115b.c ---------------------------------------------------------*/
|
||||
|
||||
#define MS2115B_PACKET_SIZE 9
|
||||
|
||||
enum ms2115b_display {
|
||||
MS2115B_DISPLAY_MAIN,
|
||||
MS2115B_DISPLAY_SUB,
|
||||
MS2115B_DISPLAY_COUNT,
|
||||
};
|
||||
|
||||
struct ms2115b_info {
|
||||
/* Selected channel. */
|
||||
size_t ch_idx;
|
||||
gboolean is_ac, is_dc, is_auto;
|
||||
gboolean is_diode, is_beep, is_farad;
|
||||
gboolean is_ohm, is_ampere, is_volt, is_hz;
|
||||
gboolean is_duty_cycle, is_percent;
|
||||
};
|
||||
|
||||
extern SR_PRIV const char *ms2115b_channel_formats[];
|
||||
SR_PRIV gboolean sr_ms2115b_packet_valid(const uint8_t *buf);
|
||||
SR_PRIV int sr_ms2115b_parse(const uint8_t *buf, float *floatval,
|
||||
struct sr_datafeed_analog *analog, void *info);
|
||||
|
||||
/*--- dmm/ms8250d.c ---------------------------------------------------------*/
|
||||
|
||||
#define MS8250D_PACKET_SIZE 18
|
||||
|
|
Loading…
Reference in New Issue