]> sigrok.org Git - libsigrok.git/blame - src/dmm/bm25x.c
Build: Set local include directories in Makefile.am
[libsigrok.git] / src / dmm / bm25x.c
CommitLineData
a24c3f4a
JH
1/*
2 * This file is part of the libsigrok project.
3 *
4 * Copyright (C) 2014 Janne Huttunen <jahuttun@gmail.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * @file
22 *
23 * Brymen BM25x serial protocol parser.
24 */
25
26#include <math.h>
c1aae900 27#include <libsigrok/libsigrok.h>
a24c3f4a
JH
28#include "libsigrok-internal.h"
29
30#define LOG_PREFIX "brymen-bm25x"
31
32#define MAX_DIGITS 4
33
34SR_PRIV gboolean sr_brymen_bm25x_packet_valid(const uint8_t *buf)
35{
36 int i;
37
38 if (buf[0] != 2)
39 return FALSE;
40
41 for (i = 1; i < BRYMEN_BM25X_PACKET_SIZE; i++)
42 if ((buf[i] >> 4) != i)
43 return FALSE;
44
45 return TRUE;
46}
47
48static int decode_digit(int num, const uint8_t *buf)
49{
50 int val;
51
52 val = (buf[3 + 2 * num] & 0xe) | ((buf[4 + 2 * num] << 4) & 0xf0);
53
54 switch (val) {
55 case 0xbe: return 0;
56 case 0xa0: return 1;
57 case 0xda: return 2;
58 case 0xf8: return 3;
59 case 0xe4: return 4;
60 case 0x7c: return 5;
61 case 0x7e: return 6;
62 case 0xa8: return 7;
63 case 0xfe: return 8;
64 case 0xfc: return 9;
65 case 0x00: return ' ';
66 case 0x40: return '-';
67 case 0x16: return 'L';
68 case 0x1e: return 'C';
69 case 0x4e: return 'F';
70 case 0x5e: return 'E';
71 case 0x62: return 'n';
72 case 0x42: return 'r';
73 default:
74 sr_dbg("Unknown digit: 0x%02x.", val);
75 return -1;
76 }
77}
78
79static int decode_point(const uint8_t *buf)
80{
81 int i, p = 0;
82
83 for (i = 1; i < MAX_DIGITS; i++) {
84 if ((buf[11 - 2 * i] & 1) == 0)
85 continue;
86 if (p != 0) {
87 sr_spew("Multiple decimal points found!");
88 return -1;
89 }
90 p = i;
91 }
92
93 return p;
94}
95
96static float scale_value(float val, int point, int digits)
97{
98 int pos;
99
100 pos = point ? point + digits - MAX_DIGITS : 0;
101
102 switch (pos) {
103 case 0: return val;
104 case 1: return val * 1e-1;
105 case 2: return val * 1e-2;
106 case 3: return val * 1e-3;
107 }
108
109 sr_dbg("Invalid decimal point %d (%d digits).", point, digits);
110
111 return NAN;
112}
113
114static float decode_prefix(const uint8_t *buf)
115{
116 if (buf[11] & 2) return 1e+6;
117 if (buf[11] & 1) return 1e+3;
118 if (buf[13] & 1) return 1e-3;
119 if (buf[13] & 2) return 1e-6;
120 if (buf[12] & 1) return 1e-9;
121
122 return 1.0f;
123}
124
125static float decode_value(const uint8_t *buf)
126{
127 float val = 0.0f;
128 int i, digit;
129
130 for (i = 0; i < MAX_DIGITS; i++) {
131 digit = decode_digit(i, buf);
132 if (i == 3 && (digit == 'C' || digit == 'F'))
133 break;
134 if (digit < 0 || digit > 9)
135 goto special;
136 val = 10.0 * val + digit;
137 }
138
139 return scale_value(val, decode_point(buf), i);
140
141special:
142 if (decode_digit(1, buf) == 0 && decode_digit(2, buf) == 'L')
143 return INFINITY;
144
145 return NAN;
146}
147
148SR_PRIV int sr_brymen_bm25x_parse(const uint8_t *buf, float *floatval,
149 struct sr_datafeed_analog *analog, void *info)
150{
151 float val;
152
153 (void)info;
154
155 analog->mq = SR_MQ_GAIN;
156 analog->unit = SR_UNIT_UNITLESS;
157 analog->mqflags = 0;
158
159 if (buf[1] & 8)
160 analog->mqflags |= SR_MQFLAG_AUTORANGE;
161 if (buf[1] & 4)
162 analog->mqflags |= SR_MQFLAG_DC;
163 if (buf[1] & 2)
164 analog->mqflags |= SR_MQFLAG_AC;
165 if (buf[1] & 1)
166 analog->mqflags |= SR_MQFLAG_RELATIVE;
167 if (buf[11] & 8)
168 analog->mqflags |= SR_MQFLAG_HOLD;
169 if (buf[13] & 8)
170 analog->mqflags |= SR_MQFLAG_MAX;
171 if (buf[14] & 8)
172 analog->mqflags |= SR_MQFLAG_MIN;
173
174 if (buf[14] & 4) {
175 analog->mq = SR_MQ_VOLTAGE;
176 analog->unit = SR_UNIT_VOLT;
177 if ((analog->mqflags & (SR_MQFLAG_DC | SR_MQFLAG_AC)) == 0)
178 analog->mqflags |= SR_MQFLAG_DIODE;
179 }
180 if (buf[14] & 2) {
181 analog->mq = SR_MQ_CURRENT;
182 analog->unit = SR_UNIT_AMPERE;
183 }
184 if (buf[12] & 4) {
185 analog->mq = SR_MQ_RESISTANCE;
186 analog->unit = SR_UNIT_OHM;
187 }
188 if (buf[13] & 4) {
189 analog->mq = SR_MQ_CAPACITANCE;
190 analog->unit = SR_UNIT_FARAD;
191 }
192 if (buf[12] & 2) {
193 analog->mq = SR_MQ_FREQUENCY;
194 analog->unit = SR_UNIT_HERTZ;
195 }
196
197 if (decode_digit(3, buf) == 'C') {
198 analog->mq = SR_MQ_TEMPERATURE;
199 analog->unit = SR_UNIT_CELSIUS;
200 }
201 if (decode_digit(3, buf) == 'F') {
202 analog->mq = SR_MQ_TEMPERATURE;
203 analog->unit = SR_UNIT_FAHRENHEIT;
204 }
205
206 val = decode_value(buf) * decode_prefix(buf);
207
208 if (buf[3] & 1)
209 val = -val;
210
211 *floatval = val;
212
213 return SR_OK;
214}