X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fdmm%2Fbm25x.c;fp=src%2Fdmm%2Fbm25x.c;h=67c2d04f6940b626c9370e35aecb9cd90ef05b00;hb=a24c3f4a899d61a6bfc837a1969dbacf42e2ea72;hp=0000000000000000000000000000000000000000;hpb=a01eab4a08e6da4db6fb90a607e98e16e2e5b24f;p=libsigrok.git diff --git a/src/dmm/bm25x.c b/src/dmm/bm25x.c new file mode 100644 index 00000000..67c2d04f --- /dev/null +++ b/src/dmm/bm25x.c @@ -0,0 +1,214 @@ +/* + * This file is part of the libsigrok project. + * + * Copyright (C) 2014 Janne Huttunen + * + * 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 3 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 . + */ + +/** + * @file + * + * Brymen BM25x serial protocol parser. + */ + +#include +#include "libsigrok.h" +#include "libsigrok-internal.h" + +#define LOG_PREFIX "brymen-bm25x" + +#define MAX_DIGITS 4 + +SR_PRIV gboolean sr_brymen_bm25x_packet_valid(const uint8_t *buf) +{ + int i; + + if (buf[0] != 2) + return FALSE; + + for (i = 1; i < BRYMEN_BM25X_PACKET_SIZE; i++) + if ((buf[i] >> 4) != i) + return FALSE; + + return TRUE; +} + +static int decode_digit(int num, const uint8_t *buf) +{ + int val; + + val = (buf[3 + 2 * num] & 0xe) | ((buf[4 + 2 * num] << 4) & 0xf0); + + switch (val) { + case 0xbe: return 0; + case 0xa0: return 1; + case 0xda: return 2; + case 0xf8: return 3; + case 0xe4: return 4; + case 0x7c: return 5; + case 0x7e: return 6; + case 0xa8: return 7; + case 0xfe: return 8; + case 0xfc: return 9; + case 0x00: return ' '; + case 0x40: return '-'; + case 0x16: return 'L'; + case 0x1e: return 'C'; + case 0x4e: return 'F'; + case 0x5e: return 'E'; + case 0x62: return 'n'; + case 0x42: return 'r'; + default: + sr_dbg("Unknown digit: 0x%02x.", val); + return -1; + } +} + +static int decode_point(const uint8_t *buf) +{ + int i, p = 0; + + for (i = 1; i < MAX_DIGITS; i++) { + if ((buf[11 - 2 * i] & 1) == 0) + continue; + if (p != 0) { + sr_spew("Multiple decimal points found!"); + return -1; + } + p = i; + } + + return p; +} + +static float scale_value(float val, int point, int digits) +{ + int pos; + + pos = point ? point + digits - MAX_DIGITS : 0; + + switch (pos) { + case 0: return val; + case 1: return val * 1e-1; + case 2: return val * 1e-2; + case 3: return val * 1e-3; + } + + sr_dbg("Invalid decimal point %d (%d digits).", point, digits); + + return NAN; +} + +static float decode_prefix(const uint8_t *buf) +{ + if (buf[11] & 2) return 1e+6; + if (buf[11] & 1) return 1e+3; + if (buf[13] & 1) return 1e-3; + if (buf[13] & 2) return 1e-6; + if (buf[12] & 1) return 1e-9; + + return 1.0f; +} + +static float decode_value(const uint8_t *buf) +{ + float val = 0.0f; + int i, digit; + + for (i = 0; i < MAX_DIGITS; i++) { + digit = decode_digit(i, buf); + if (i == 3 && (digit == 'C' || digit == 'F')) + break; + if (digit < 0 || digit > 9) + goto special; + val = 10.0 * val + digit; + } + + return scale_value(val, decode_point(buf), i); + +special: + if (decode_digit(1, buf) == 0 && decode_digit(2, buf) == 'L') + return INFINITY; + + return NAN; +} + +SR_PRIV int sr_brymen_bm25x_parse(const uint8_t *buf, float *floatval, + struct sr_datafeed_analog *analog, void *info) +{ + float val; + + (void)info; + + analog->mq = SR_MQ_GAIN; + analog->unit = SR_UNIT_UNITLESS; + analog->mqflags = 0; + + if (buf[1] & 8) + analog->mqflags |= SR_MQFLAG_AUTORANGE; + if (buf[1] & 4) + analog->mqflags |= SR_MQFLAG_DC; + if (buf[1] & 2) + analog->mqflags |= SR_MQFLAG_AC; + if (buf[1] & 1) + analog->mqflags |= SR_MQFLAG_RELATIVE; + if (buf[11] & 8) + analog->mqflags |= SR_MQFLAG_HOLD; + if (buf[13] & 8) + analog->mqflags |= SR_MQFLAG_MAX; + if (buf[14] & 8) + analog->mqflags |= SR_MQFLAG_MIN; + + if (buf[14] & 4) { + analog->mq = SR_MQ_VOLTAGE; + analog->unit = SR_UNIT_VOLT; + if ((analog->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0) + analog->mqflags |= SR_MQFLAG_DIODE; + } + if (buf[14] & 2) { + analog->mq = SR_MQ_CURRENT; + analog->unit = SR_UNIT_AMPERE; + } + if (buf[12] & 4) { + analog->mq = SR_MQ_RESISTANCE; + analog->unit = SR_UNIT_OHM; + } + if (buf[13] & 4) { + analog->mq = SR_MQ_CAPACITANCE; + analog->unit = SR_UNIT_FARAD; + } + if (buf[12] & 2) { + analog->mq = SR_MQ_FREQUENCY; + analog->unit = SR_UNIT_HERTZ; + } + + if (decode_digit(3, buf) == 'C') { + analog->mq = SR_MQ_TEMPERATURE; + analog->unit = SR_UNIT_CELSIUS; + } + if (decode_digit(3, buf) == 'F') { + analog->mq = SR_MQ_TEMPERATURE; + analog->unit = SR_UNIT_FAHRENHEIT; + } + + val = decode_value(buf) * decode_prefix(buf); + + if (buf[3] & 1) + val = -val; + + *floatval = val; + + return SR_OK; +}