Add MASTECH MS2115B support.

This commit is contained in:
Vitaliy Vorobyov 2019-05-01 15:54:14 +02:00 committed by Uwe Hermann
parent 16a8e58068
commit dcd212f7a2
4 changed files with 412 additions and 0 deletions

View File

@ -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 \

374
src/dmm/ms2115b.c Normal file
View File

@ -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;
}

View File

@ -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,

View File

@ -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