]> sigrok.org Git - libsigrok.git/blob - src/dmm/bm25x.c
67c2d04f6940b626c9370e35aecb9cd90ef05b00
[libsigrok.git] / src / dmm / bm25x.c
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>
27 #include "libsigrok.h"
28 #include "libsigrok-internal.h"
29
30 #define LOG_PREFIX "brymen-bm25x"
31
32 #define MAX_DIGITS 4
33
34 SR_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
48 static 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
79 static 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
96 static 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
114 static 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
125 static 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
141 special:
142         if (decode_digit(1, buf) == 0 && decode_digit(2, buf) == 'L')
143                 return INFINITY;
144
145         return NAN;
146 }
147
148 SR_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 }