* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/** @file
+ * Gossen Metrawatt Metrahit 1x/2x drivers
+ * @private
+ */
+
#include <string.h>
#include "protocol.h"
/* Serial communication parameters for Metrahit 1x/2x with 'RS232' adaptor */
#define SERIALCOMM_1X_RS232 "8228/6n1/dtr=1/rts=1/flow=0" /* =8192, closer with divider */
#define SERIALCOMM_2X_RS232 "9600/6n1/dtr=1/rts=1/flow=0"
+#define SERIALCOMM_2X "9600/8n1/dtr=1/rts=1/flow=0"
#define VENDOR_GMC "Gossen Metrawatt"
SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
-static struct sr_dev_driver *di = &gmc_mh_1x_2x_rs232_driver_info;
static const int32_t hwopts[] = {
SR_CONF_CONN,
static const int32_t hwcaps[] = {
SR_CONF_MULTIMETER,
+ SR_CONF_THERMOMETER, /**< All GMC 1x/2x multimeters seem to support this */
SR_CONF_LIMIT_SAMPLES,
SR_CONF_LIMIT_MSEC,
SR_CONF_CONTINUOUS,
};
+/* TODO:
+ * - For the 29S SR_CONF_ENERGYMETER, too.
+ * - SR_CONF_PATTERN_MODE for some 2x devices
+ * - SR_CONF_DATALOG for 22M, 26M, 29S and storage adaptors.
+ * Need to implement device-specific lists.
+ */
+
+/** Init driver gmc_mh_1x_2x_rs232. */
static int init(struct sr_context *sr_ctx)
{
- return std_init(sr_ctx, di, LOG_PREFIX);
+ return std_init(sr_ctx, &gmc_mh_1x_2x_rs232_driver_info, LOG_PREFIX);
}
/**
gboolean serialcomm_given;
devices = NULL;
- drvc = di->priv;
+ drvc = (&gmc_mh_1x_2x_rs232_driver_info)->priv;
drvc->instances = NULL;
conn = serialcomm = NULL;
model = METRAHIT_NONE;
sdi->conn = serial;
sdi->priv = devc;
- sdi->driver = di;
+ sdi->driver = &gmc_mh_1x_2x_rs232_driver_info;
if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1")))
return NULL;
sdi->probes = g_slist_append(sdi->probes, probe);
static GSList *dev_list(void)
{
- return ((struct drv_context *)(di->priv))->instances;
+ return ((struct drv_context *)(gmc_mh_1x_2x_rs232_driver_info.priv))->instances;
}
static int dev_clear(void)
{
- return std_dev_clear(di, NULL);
+ return std_dev_clear(&gmc_mh_1x_2x_rs232_driver_info, NULL);
}
static int dev_close(struct sr_dev_inst *sdi)
return dev_clear();
}
-/** TODO */
+/** Get value of configuration item */
static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
const struct sr_probe_group *probe_group)
{
int ret;
+ ret = SR_OK;
+ struct dev_context *devc;
- (void)sdi;
- (void)data;
(void)probe_group;
+ if (!sdi || !(devc = sdi->priv))
+ return SR_ERR_ARG;
+
ret = SR_OK;
switch (key) {
- /* TODO */
+ case SR_CONF_LIMIT_SAMPLES:
+ *data = g_variant_new_uint64(devc->limit_samples);
+ break;
+ case SR_CONF_LIMIT_MSEC:
+ *data = g_variant_new_uint64(devc->limit_msec);
+ break;
default:
return SR_ERR_NA;
}
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/** @file
+ * Gossen Metrawatt Metrahit 1x/2x drivers
+ * @private
+ */
+
#include <math.h>
#include <string.h>
#include "protocol.h"
if (ctmv >= 0x02) {
devc->mqflags |= SR_MQFLAG_AC;
if (devc->model >= METRAHIT_24S)
- devc->model |= SR_MQFLAG_RMS;
+ devc->mqflags |= SR_MQFLAG_RMS;
}
break;
case 0x04: /* 00100 mA DC */
devc->unit = SR_UNIT_FARAD;
devc->scale *= 0.1;
break;
- case 0x0a: /* 01010 dB */
+ case 0x0a: /* 01010 dBV */
devc->mq = SR_MQ_VOLTAGE;
devc->unit = SR_UNIT_DECIBEL_VOLT;
devc->mqflags |= SR_MQFLAG_AC;
+ if (devc->model >= METRAHIT_24S)
+ devc->mqflags |= SR_MQFLAG_RMS;
break;
case 0x0b: /* 01011 Hz U ACDC */
case 0x0c: /* 01100 Hz U AC */
devc->mqflags |= SR_MQFLAG_DC;
break;
case 0x0d: /* 01101 W on power, mA range (29S only) */
+ devc->scale *= 0.001;
+ /* Fall through! */
case 0x0e: /* 01110 W on power, A range (29S only) */
- /* TODO: Differences between Send Mode and bidir protocol here */
devc->mq = SR_MQ_POWER;
devc->unit = SR_UNIT_WATT;
break;
if (ctmv == 0x0f) {
devc->mq = SR_MQ_VOLTAGE;
devc->mqflags |= SR_MQFLAG_DIODE;
- devc->scale *= 0.1;
} else {
devc->mq = SR_MQ_CONTINUITY;
devc->scale *= 0.00001;
}
/**
- * Decode range/sign/acdc byte special chars, Metrahit 2x.
+ * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR.
*
- * @param[in] rs Rance/sign byte.
+ * @param[in] rs Range/sign byte.
*/
static void decode_rs_2x(uint8_t rs, struct dev_context *devc)
{
/* Sign */
if (((devc->scale > 0) && (rs & 0x08)) ||
- ((devc->scale < 0) && !(rs & 0x08)))
+ ((devc->scale < 0) && !(rs & 0x08)))
devc->scale *= -1.0;
/* Range */
devc->scale *= pow(10.0, -3);
else if (devc->vmains_29S)
devc->scale *= pow(10.0, range - 2);
- else if(devc->mqflags & SR_MQFLAG_AC)
+ else
devc->scale *= pow(10.0, range - 6);
- else /* "Undocumented feature": Between AC and DC
- scaling differs by 1. */
- devc->scale *= pow(10.0, range - 5);
break;
case SR_MQ_CURRENT:
- if (devc->scale1000 == -1)
- devc->scale *= pow(10.0, range - 5);
- else
- devc->scale *= pow(10.0, range - 4);
+ if (devc->scale1000 != -1) /* uA, mA */
+ range += 1;/* mA and A ranges differ by 10^4, not 10^3!*/
+ devc->scale *= pow(10.0, range - 6);
break;
case SR_MQ_RESISTANCE:
devc->scale *= pow(10.0, range - 3);
devc->scale *= pow(10.0, - 2);
break;
case SR_MQ_CAPACITANCE:
+ if (range == 7)
+ range -= 1; /* Same value as range 6 */
devc->scale *= pow(10.0, range - 13);
break;
/* TODO: 29S Mains measurements. */
devc->num_samples++;
}
-/** Process 6-byte data message, Metrahit 1x/2x. */
+/** Process 6-byte data message, Metrahit 1x/2x send mode. */
static void process_msg_dta_6(struct sr_dev_inst *sdi)
{
struct dev_context *devc;
decode_rs_16(bc(devc->buf[0]), devc);
else if (devc->model < METRAHIT_2X)
decode_rs_18(bc(devc->buf[0]), devc);
- else
+ else {
decode_rs_2x(bc(devc->buf[0]), devc);
+ devc->scale *= 10; /* Compensate for format having only 5 digits, decode_rs_2x() assumes 6. */
+ }
/* Bytes 1-5, digits (ls first). */
for (cnt = 0; cnt < 5; cnt++) {
}
devc->value += pow(10.0, cnt) * dgt;
}
- sr_spew("process_msg_dta_6() value=%f scale=%f scalet=%d",
+
+ sr_spew("process_msg_dta_6() value=%f scale=%f scale1000=%d",
devc->value, devc->scale, devc->scale1000);
if (devc->value != NAN)
devc->value *= devc->scale * pow(1000.0, devc->scale1000);
/* Now decode numbers */
for (cnt = 0; cnt < 5; cnt++) {
dgt = bc(devc->buf[5 + cnt]);
- if (dgt >= 10) { /* Overload */
+ if (dgt == 11) { /* Empty digit */
+ dgt = 0;
+ }
+ else if (dgt >= 12) { /* Overload */
devc->value = NAN;
devc->scale = 1.0;
break;
case 0x0f: /* 1111b */
return METRAHIT_24S;
case 0x05: /* 0101b */
- return METRAHIT_25SM;
+ return METRAHIT_25S;
case 0x01: /* 0001b */
- return METRAHIT_26S;
+ return METRAHIT_26SM;
case 0x0c: /* 1100b */
return METRAHIT_28S;
case 0x0e: /* 1110b */
}
}
-/**
- * Decode model in bidirectional mode.
+/** Convert GMC model code in bidirectional mode to sigrok-internal one.
*
- * @param[in] mcode Model code.
+ * @param[in] mcode Model code.
*
- * @return Model code.
+ * @return Model code.
*/
-SR_PRIV int gmc_decode_model_bidi(uint8_t mcode)
+SR_PRIV int gmc_decode_model_bd(uint8_t mcode)
{
- switch (mcode) {
+ switch (mcode & 0x1f) {
case 2:
return METRAHIT_22SM;
case 3:
case 4:
return METRAHIT_24S;
case 5:
- return METRAHIT_25SM;
+ return METRAHIT_25S;
case 1:
- return METRAHIT_26S;
+ return METRAHIT_26SM;
case 12:
return METRAHIT_28S;
case 14:
}
}
+/** Convert sigrok-internal model code to string.
+ *
+ * @param[in] mcode Model code.
+ *
+ * @return Model code string.
+ */
SR_PRIV const char *gmc_model_str(enum model mcode)
{
switch (mcode) {
return "METRAHit 23S";
case METRAHIT_24S:
return "METRAHit 24S";
- case METRAHIT_25SM:
- return "METRAHit 25S/M";
- case METRAHIT_26S:
- return "METRAHit 26S";
+ case METRAHIT_25S:
+ return "METRAHit 25S";
+ case METRAHIT_26SM:
+ return "METRAHit 26S/M";
case METRAHIT_28S:
return "METRAHit 28S";
case METRAHIT_29S:
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/** @file
+ * Gossen Metrawatt Metrahit 1x/2x drivers
+ * @private
+ */
+
#ifndef LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
#define LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
#define MSGID_DTA 0x20 /**< Start of data message, displayed, averaged */
#define MSGID_DATA 0x30 /**< Data byte in message */
-#define MSGC_MASK 0x0f /**< Mask to get message byte contents */
+#define MSGC_MASK 0x0f /**< Mask to get message byte contents in send mode */
#define MSGSRC_MASK 0xc0 /**< Mask to get bits related to message source */
METRAHIT_22SM = 22,
METRAHIT_23S = 23,
METRAHIT_24S = 24,
- METRAHIT_25SM = 25,
- METRAHIT_26S = 26,
+ METRAHIT_25S = 25,
+ METRAHIT_26SM = 26,
METRAHIT_28S = 28,
METRAHIT_29S = 29,
};
-/** Convert GMC model code in send mode to sigrok-internal one. */
-SR_PRIV int gmc_decode_model_sm(uint8_t mcode);
-
-/**
- * Convert GMC model code in bidirectional mode to sigrok-internal one.
- *
- * @param[in] mcode Model code.
- *
- * @return Model code.
- */
-SR_PRIV int gmc_decode_model_bidi(uint8_t mcode);
-
/** Get model string from sigrok-internal model code. */
SR_PRIV const char *gmc_model_str(enum model mcode);
};
SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int gmc_decode_model_sm(uint8_t mcode);
#endif