]> sigrok.org Git - libsigrok.git/blob - src/hardware/colead-slm/protocol.c
Reorganize project tree.
[libsigrok.git] / src / hardware / colead-slm / protocol.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2012 Bert Vermeulen <bert@biot.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 #include <stdlib.h>
21 #include <glib.h>
22 #include "libsigrok.h"
23 #include "libsigrok-internal.h"
24 #include "protocol.h"
25 #include <errno.h>
26 #include <string.h>
27
28 static void process_packet(const struct sr_dev_inst *sdi)
29 {
30         struct dev_context *devc;
31         struct sr_datafeed_packet packet;
32         struct sr_datafeed_analog analog;
33         GString *dbg;
34         float fvalue;
35         int checksum, mode, i;
36
37         devc = sdi->priv;
38         if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
39                 dbg = g_string_sized_new(128);
40                 g_string_printf(dbg, "received packet:");
41                 for (i = 0; i < 10; i++)
42                         g_string_append_printf(dbg, " %.2x", (devc->buf)[i]);
43                 sr_spew("%s", dbg->str);
44                 g_string_free(dbg, TRUE);
45         }
46
47         if (devc->buf[0] != 0x08 || devc->buf[1] != 0x04) {
48                 sr_dbg("invalid packet header.");
49                 return;
50         }
51
52         if (devc->buf[8] != 0x01) {
53                 sr_dbg("invalid measurement.");
54                 return;
55         }
56
57         checksum = 0;
58         for (i = 0; i < 9; i++)
59                 checksum += devc->buf[i];
60         if ((checksum & 0xff) != devc->buf[9]) {
61                 sr_dbg("invalid packet checksum.");
62                 return;
63         }
64
65         fvalue = 0.0;
66         for (i = 3; i < 8; i++) {
67                 if (devc->buf[i] > 0x09)
68                         continue;
69                 fvalue *= 10;
70                 fvalue += devc->buf[i];
71         }
72         fvalue /= 10;
73
74         memset(&analog, 0, sizeof(struct sr_datafeed_analog));
75         analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
76         analog.unit = SR_UNIT_DECIBEL_SPL;
77         analog.channels = sdi->channels;
78         analog.num_samples = 1;
79         analog.data = &fvalue;
80
81         /* High nibble should only have 0x01 or 0x02. */
82         mode = (devc->buf[2] >> 4) & 0x0f;
83         if (mode == 0x02)
84                 analog.mqflags |= SR_MQFLAG_HOLD;
85         else if (mode != 0x01) {
86                 sr_dbg("unknown measurement mode 0x%.2x", mode);
87                 return;
88         }
89
90         /* Low nibble has 14 combinations of direct/long-term average,
91          * time scale of that average, frequency weighting, and time
92          * weighting. */
93         mode = devc->buf[2] & 0x0f;
94         switch (mode) {
95                 case 0x0:
96                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
97                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
98                         break;
99                 case 0x1:
100                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
101                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
102                         break;
103                 case 0x2:
104                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
105                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
106                         break;
107                 case 0x3:
108                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
109                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
110                         break;
111                 case 0x4:
112                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
113                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
114                         break;
115                 case 0x5:
116                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
117                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
118                         break;
119                 case 0x6:
120                         analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
121                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
122                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
123                         break;
124                 case 0x7:
125                         analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
126                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
127                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
128                         break;
129                 case 0x8:
130                         /* 10-second mean, but we don't have MQ flags to express it. */
131                         analog.mqflags |= SR_MQFLAG_SPL_LAT \
132                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
133                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
134                         break;
135                 case 0x9:
136                         /* Mean over a time period between 11 seconds and 24 hours.
137                          * Which is so silly that there's no point in expressing
138                          * either this or the previous case.  */
139                         analog.mqflags |= SR_MQFLAG_SPL_LAT \
140                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
141                                         | SR_MQFLAG_SPL_TIME_WEIGHT_F;
142                         break;
143                 case 0xa:
144                         /* 10-second mean. */
145                         analog.mqflags |= SR_MQFLAG_SPL_LAT \
146                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
147                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
148                         break;
149                 case 0xb:
150                         /* Mean over a time period between 11 seconds and 24 hours. */
151                         analog.mqflags |= SR_MQFLAG_SPL_LAT \
152                                         | SR_MQFLAG_SPL_FREQ_WEIGHT_A \
153                                         | SR_MQFLAG_SPL_TIME_WEIGHT_S;
154                         break;
155                 case 0xc:
156                         /* Internal calibration on 1kHz sine at 94dB, not useful
157                          * to anything but the device. */
158                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
159                         break;
160                 case 0xd:
161                         /* Internal calibration on 1kHz sine at 94dB, not useful
162                          * to anything but the device. */
163                         analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
164                         break;
165                 default:
166                         sr_dbg("unknown configuration 0x%.2x", mode);
167                         return;
168                         break;
169         }
170
171         packet.type = SR_DF_ANALOG;
172         packet.payload = &analog;
173         sr_session_send(devc->cb_data, &packet);
174
175         devc->num_samples++;
176
177 }
178
179 SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
180 {
181         const struct sr_dev_inst *sdi;
182         struct dev_context *devc;
183         struct sr_serial_dev_inst *serial;
184         int len;
185         char buf[128];
186
187         (void)fd;
188
189         if (!(sdi = cb_data))
190                 return TRUE;
191
192         if (!(devc = sdi->priv))
193                 return TRUE;
194
195         if (revents != G_IO_IN)
196                 /* Timeout event. */
197                 return TRUE;
198
199         serial = sdi->conn;
200         if (devc->state == IDLE) {
201                 if (serial_read(serial, buf, 128) != 1 || buf[0] != 0x10)
202                         /* Nothing there, or caught the tail end of a previous packet,
203                          * or some garbage. Unless it's a single "data ready" byte,
204                          * we don't want it. */
205                         return TRUE;
206                 /* Got 0x10, "measurement ready". */
207                 if (serial_write(serial, "\x20", 1) == -1)
208                         sr_err("unable to send command: %s", strerror(errno));
209                 else {
210                         devc->state = COMMAND_SENT;
211                         devc->buflen = 0;
212                 }
213         } else {
214                 len = serial_read(serial, devc->buf + devc->buflen,
215                                 10 - devc->buflen);
216                 if (len < 1)
217                         return TRUE;
218                 devc->buflen += len;
219                 if (devc->buflen > 10) {
220                         sr_dbg("buffer overrun");
221                         devc->state = IDLE;
222                         return TRUE;
223                 }
224                 if (devc->buflen == 10) {
225                         /* If we got here, we're sure the device sent a "data ready"
226                          * notification, we asked for data, and got it. */
227                         process_packet(sdi);
228                         devc->state = IDLE;
229                 }
230         }
231
232         return TRUE;
233 }