2 * This file is part of the libsigrok project.
4 * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
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.
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.
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/>.
24 /* Length of expected payload for each token. */
25 static const int token_payloads[][2] = {
26 { TOKEN_WEIGHT_TIME_FAST, 0 },
27 { TOKEN_WEIGHT_TIME_SLOW, 0 },
28 { TOKEN_HOLD_MAX, 0 },
29 { TOKEN_HOLD_MIN, 0 },
31 { TOKEN_MEAS_RANGE_OVER, 0 },
32 { TOKEN_MEAS_RANGE_UNDER, 0 },
33 { TOKEN_STORE_FULL, 0 },
34 { TOKEN_RECORDING_ON, 0 },
35 { TOKEN_MEAS_WAS_READOUT, 1 },
36 { TOKEN_MEAS_WAS_BARGRAPH, 0 },
37 { TOKEN_MEASUREMENT, 2 },
38 { TOKEN_HOLD_NONE, 0 },
39 { TOKEN_BATTERY_LOW, 0 },
40 { TOKEN_MEAS_RANGE_OK, 0 },
41 { TOKEN_STORE_OK, 0 },
42 { TOKEN_RECORDING_OFF, 0 },
43 { TOKEN_WEIGHT_FREQ_A, 1 },
44 { TOKEN_WEIGHT_FREQ_C, 1 },
45 { TOKEN_BATTERY_OK, 0 },
46 { TOKEN_MEAS_RANGE_30_80, 0 },
47 { TOKEN_MEAS_RANGE_30_130, 0 },
48 { TOKEN_MEAS_RANGE_50_100, 0 },
49 { TOKEN_MEAS_RANGE_80_130, 0 },
52 static int find_token_payload_len(unsigned char c)
56 for (i = 0; i < ARRAY_SIZE(token_payloads); i++) {
57 if (token_payloads[i][0] == c)
58 return token_payloads[i][1];
64 /* Process measurement or setting (0xa5 command). */
65 static void process_mset(const struct sr_dev_inst *sdi)
67 struct dev_context *devc;
68 struct sr_datafeed_packet packet;
69 struct sr_datafeed_analog_old analog;
75 if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
76 dbg = g_string_sized_new(128);
77 g_string_printf(dbg, "got command 0x%.2x token 0x%.2x",
78 devc->cmd, devc->token);
80 g_string_append_printf(dbg, " payload");
81 for (i = 0; i < devc->buf_len; i++)
82 g_string_append_printf(dbg, " %.2x", devc->buf[i]);
84 sr_spew("%s", dbg->str);
85 g_string_free(dbg, TRUE);
88 switch (devc->token) {
89 case TOKEN_WEIGHT_TIME_FAST:
90 devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
91 devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_S;
93 case TOKEN_WEIGHT_TIME_SLOW:
94 devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
95 devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_F;
97 case TOKEN_WEIGHT_FREQ_A:
98 devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
99 devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C;
101 case TOKEN_WEIGHT_FREQ_C:
102 devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
103 devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A;
106 devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MAX;
107 devc->cur_mqflags &= ~SR_MQFLAG_MIN;
110 devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MIN;
111 devc->cur_mqflags &= ~SR_MQFLAG_MAX;
113 case TOKEN_HOLD_NONE:
114 devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_HOLD);
116 case TOKEN_MEASUREMENT:
117 fvalue = ((devc->buf[0] & 0xf0) >> 4) * 100;
118 fvalue += (devc->buf[0] & 0x0f) * 10;
119 fvalue += ((devc->buf[1] & 0xf0) >> 4);
120 fvalue += (devc->buf[1] & 0x0f) / 10.0;
121 devc->last_spl = fvalue;
123 case TOKEN_MEAS_WAS_READOUT:
124 case TOKEN_MEAS_WAS_BARGRAPH:
125 if (devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN)) {
126 if (devc->token == TOKEN_MEAS_WAS_BARGRAPH) {
127 /* The device still sends bargraph measurements even
128 * when in max/min hold mode. Suppress them here, unless
129 * they're readout values. This duplicates the behavior
130 * of the device display exactly. */
134 memset(&analog, 0, sizeof(struct sr_datafeed_analog_old));
135 analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
136 analog.mqflags = devc->cur_mqflags;
137 analog.unit = SR_UNIT_DECIBEL_SPL;
138 analog.channels = sdi->channels;
139 analog.num_samples = 1;
140 analog.data = &devc->last_spl;
141 packet.type = SR_DF_ANALOG_OLD;
142 packet.payload = &analog;
143 sr_session_send(sdi, &packet);
146 if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
147 sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
149 case TOKEN_RECORDING_ON:
150 devc->recording = TRUE;
152 case TOKEN_RECORDING_OFF:
153 devc->recording = FALSE;
155 case TOKEN_MEAS_RANGE_30_80:
156 case TOKEN_MEAS_RANGE_30_130:
157 case TOKEN_MEAS_RANGE_50_100:
158 case TOKEN_MEAS_RANGE_80_130:
159 devc->cur_meas_range = devc->token;
163 case TOKEN_STORE_FULL:
164 case TOKEN_BATTERY_OK:
165 case TOKEN_BATTERY_LOW:
166 case TOKEN_MEAS_RANGE_OK:
167 case TOKEN_MEAS_RANGE_OVER:
168 case TOKEN_MEAS_RANGE_UNDER:
169 /* Not useful, or not expressible in sigrok. */
175 static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
176 uint64_t num_samples)
178 struct dev_context *devc;
179 struct sr_datafeed_packet packet;
180 struct sr_datafeed_analog_old analog;
181 float fbuf[SAMPLES_PER_PACKET];
186 for (i = 0; i < num_samples; i++) {
187 fbuf[i] = ((data[i * 2] & 0xf0) >> 4) * 100;
188 fbuf[i] += (data[i * 2] & 0x0f) * 10;
189 fbuf[i] += ((data[i * 2 + 1] & 0xf0) >> 4);
190 fbuf[i] += (data[i * 2 + 1] & 0x0f) / 10.0;
192 memset(&analog, 0, sizeof(struct sr_datafeed_analog_old));
193 analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
194 analog.mqflags = devc->cur_mqflags;
195 analog.unit = SR_UNIT_DECIBEL_SPL;
196 analog.channels = sdi->channels;
197 analog.num_samples = num_samples;
199 packet.type = SR_DF_ANALOG_OLD;
200 packet.payload = &analog;
201 sr_session_send(sdi, &packet);
203 devc->num_samples += analog.num_samples;
204 if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
205 sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
210 static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
213 struct dev_context *devc;
214 struct sr_datafeed_packet packet;
215 struct sr_datafeed_meta meta;
216 struct sr_config *src;
220 if (!(devc = sdi->priv))
224 /* Device is in hold mode */
225 devc->cur_mqflags |= SR_MQFLAG_HOLD;
227 if (devc->hold_last_sent == 0) {
228 /* First hold notification. */
229 devc->hold_last_sent = g_get_monotonic_time();
230 /* When the device leaves hold mode, it starts from scratch. */
231 devc->state = ST_INIT;
233 cur_time = g_get_monotonic_time();
234 if (cur_time - devc->hold_last_sent > HOLD_REPEAT_INTERVAL) {
235 /* Force the last measurement out again. */
237 devc->token = TOKEN_MEAS_WAS_READOUT;
240 devc->hold_last_sent = cur_time;
246 devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
247 devc->hold_last_sent = 0;
249 if (devc->state == ST_INIT) {
253 devc->state = ST_GET_TOKEN;
254 } else if (c == 0xbb) {
257 devc->state = ST_GET_LOG_HEADER;
258 sr_dbg("got command 0xbb");
260 } else if (devc->state == ST_GET_TOKEN) {
263 len = find_token_payload_len(devc->token);
264 if (len == -1 || len > 0) {
266 devc->state = ST_GET_DATA;
270 devc->state = ST_INIT;
272 } else if (devc->state == ST_GET_DATA) {
273 len = find_token_payload_len(devc->token);
275 /* We don't know this token. */
276 sr_dbg("Unknown 0xa5 token 0x%.2x", devc->token);
277 if (c == 0xa5 || c == 0xbb) {
278 /* Looks like a new command however. */
281 devc->state = ST_INIT;
283 devc->buf[devc->buf_len++] = c;
284 if (devc->buf_len > BUF_SIZE) {
285 /* Shouldn't happen, ignore. */
286 devc->state = ST_INIT;
290 devc->buf[devc->buf_len++] = c;
291 if (devc->buf_len == len) {
294 devc->state = ST_INIT;
295 } else if (devc->buf_len > BUF_SIZE) {
296 /* Shouldn't happen, ignore. */
297 devc->state = ST_INIT;
300 } else if (devc->state == ST_GET_LOG_HEADER) {
301 sr_dbg("log header: 0x%.2x", c);
302 if (devc->buf_len < 2)
303 devc->buf[devc->buf_len++] = c;
304 if (devc->buf_len == 2) {
305 sr_dbg("Device says it has %d bytes stored.",
306 ((devc->buf[0] << 8) + devc->buf[1]) - 100);
308 devc->state = ST_GET_LOG_RECORD_META;
310 } else if (devc->state == ST_GET_LOG_RECORD_META) {
311 sr_dbg("log meta: 0x%.2x", c);
312 if (c == RECORD_END) {
313 devc->state = ST_INIT;
314 /* Stop acquisition after transferring all stored
315 * records. Otherwise the frontend would have no
316 * way to tell where stored data ends and live
317 * measurements begin. */
318 sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi);
319 } else if (c == RECORD_DATA) {
321 devc->state = ST_GET_LOG_RECORD_DATA;
323 /* RECORD_DBA/RECORD_DBC + 7 bytes of metadata */
324 devc->buf[devc->buf_len++] = c;
325 if (devc->buf_len < 8)
326 /* Keep filling up the record header. */
328 if (devc->buf[0] == RECORD_DBA)
329 devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
330 else if (devc->buf[0] == RECORD_DBC)
331 devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
333 /* Shouldn't happen. */
334 sr_dbg("Unknown record token 0x%.2x", c);
337 packet.type = SR_DF_META;
338 packet.payload = &meta;
339 src = sr_config_new(SR_CONF_SAMPLE_INTERVAL,
340 g_variant_new_uint64(devc->buf[7] * 1000));
341 meta.config = g_slist_append(NULL, src);
342 sr_session_send(sdi, &packet);
346 } else if (devc->state == ST_GET_LOG_RECORD_DATA) {
347 sr_dbg("log data: 0x%.2x", c);
348 if (c == RECORD_DBA || c == RECORD_DBC || c == RECORD_DATA || c == RECORD_END) {
349 /* Work around off-by-one bug in device firmware. This
350 * happens only on the last record, i.e. before RECORD_END */
351 if (devc->buf_len & 1)
353 /* Done with this set of samples */
354 send_data(sdi, devc->buf, devc->buf_len / 2);
357 /* Process this meta marker in the right state. */
358 devc->state = ST_GET_LOG_RECORD_META;
359 process_byte(sdi, c, handle_packets);
361 devc->buf[devc->buf_len++] = c;
362 if (devc->buf_len == SAMPLES_PER_PACKET * 2) {
363 send_data(sdi, devc->buf, devc->buf_len / 2);
371 SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
373 const struct sr_dev_inst *sdi;
374 struct dev_context *devc;
375 struct sr_serial_dev_inst *serial;
376 unsigned char c, cmd;
380 if (!(sdi = cb_data))
385 if (revents == G_IO_IN) {
386 if (serial_read_nonblocking(serial, &c, 1) != 1)
388 process_byte(sdi, c, TRUE);
390 if (devc->enable_data_source_memory) {
391 if (devc->state == ST_GET_LOG_HEADER) {
392 /* Memory transfer started. */
393 devc->enable_data_source_memory = FALSE;
395 /* Tell device to start transferring from memory. */
396 cmd = CMD_TRANSFER_MEMORY;
397 serial_write_nonblocking(serial, &cmd, 1);
405 static int wait_for_token(const struct sr_dev_inst *sdi, int8_t *tokens, int timeout)
407 struct dev_context *devc;
408 struct sr_serial_dev_inst *serial;
415 devc->state = ST_INIT;
416 start_time = g_get_monotonic_time() / 1000;
418 if (serial_read_nonblocking(serial, &c, 1) != 1)
419 /* Device might have gone away. */
421 process_byte(sdi, c, FALSE);
422 if (devc->state != ST_INIT)
423 /* Wait for a whole packet to get processed. */
425 for (i = 0; tokens[i] != -1; i++) {
426 if (devc->token == tokens[i]) {
427 sr_spew("wait_for_token: got token 0x%.2x", devc->token);
431 if (timeout && g_get_monotonic_time() / 1000 - start_time > timeout)
432 return SR_ERR_TIMEOUT;
438 /* cmd is the command to send, tokens are the tokens that denote the state
439 * which the command affects. The first token is the desired state. */
440 static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
441 int8_t *tokens, int timeout)
443 struct dev_context *devc;
444 struct sr_serial_dev_inst *serial;
449 /* The device doesn't respond to commands very well. The
450 * only thing to do is wait for the token that will confirm
451 * whether the command worked or not, and resend if needed. */
453 if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
455 if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
457 if (devc->token == tokens[0])
465 SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
468 struct dev_context *devc;
472 if (devc->recording == -1) {
473 /* Didn't pick up device state yet. */
474 tokens[0] = TOKEN_RECORDING_ON;
475 tokens[1] = TOKEN_RECORDING_OFF;
477 if (wait_for_token(sdi, tokens, 510) != SR_OK)
480 *state = devc->token == TOKEN_RECORDING_ON;
485 SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi,
488 struct dev_context *devc;
494 /* The toggle below needs the desired state in first position. */
496 tokens[0] = TOKEN_RECORDING_ON;
497 tokens[1] = TOKEN_RECORDING_OFF;
499 tokens[0] = TOKEN_RECORDING_OFF;
500 tokens[1] = TOKEN_RECORDING_ON;
504 if (devc->recording == -1) {
505 /* Didn't pick up device state yet. */
506 if (wait_for_token(sdi, tokens, 0) != SR_OK)
508 if (devc->token == tokens[0])
511 } else if (devc->recording == state)
515 /* Recording state notifications are sent at 2Hz, so allow just over
516 * that, 510ms, for the state to come in. */
517 ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_RECORDING, tokens, 510);
522 SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi)
524 struct dev_context *devc;
530 cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
531 if (cur_setting == 0) {
532 /* Didn't pick up device state yet. */
533 tokens[0] = TOKEN_WEIGHT_FREQ_A;
534 tokens[1] = TOKEN_WEIGHT_FREQ_C;
536 if (wait_for_token(sdi, tokens, 0) != SR_OK)
538 if (devc->token == TOKEN_WEIGHT_FREQ_A)
539 return SR_MQFLAG_SPL_FREQ_WEIGHT_A;
541 return SR_MQFLAG_SPL_FREQ_WEIGHT_C;
546 SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw)
548 struct dev_context *devc;
549 int cur_setting, ret;
554 cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
555 if (cur_setting == freqw)
556 /* Already set to this frequency weighting. */
559 /* The toggle below needs the desired state in first position. */
560 if (freqw == SR_MQFLAG_SPL_FREQ_WEIGHT_A) {
561 tokens[0] = TOKEN_WEIGHT_FREQ_A;
562 tokens[1] = TOKEN_WEIGHT_FREQ_C;
564 tokens[0] = TOKEN_WEIGHT_FREQ_C;
565 tokens[1] = TOKEN_WEIGHT_FREQ_A;
569 if (cur_setting == 0) {
570 /* Didn't pick up device state yet. */
571 if (wait_for_token(sdi, tokens, 0) != SR_OK)
573 if (devc->token == tokens[0])
578 /* 10ms timeout seems to work best for this. */
579 ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_FREQ, tokens, 10);
584 SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi)
586 struct dev_context *devc;
592 cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
593 if (cur_setting == 0) {
594 /* Didn't pick up device state yet. */
595 tokens[0] = TOKEN_WEIGHT_TIME_FAST;
596 tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
598 if (wait_for_token(sdi, tokens, 0) != SR_OK)
600 if (devc->token == TOKEN_WEIGHT_TIME_FAST)
601 return SR_MQFLAG_SPL_TIME_WEIGHT_F;
603 return SR_MQFLAG_SPL_TIME_WEIGHT_S;
608 SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew)
610 struct dev_context *devc;
611 int cur_setting, ret;
616 cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
617 if (cur_setting == timew)
618 /* Already set to this time weighting. */
621 /* The toggle below needs the desired state in first position. */
622 if (timew == SR_MQFLAG_SPL_TIME_WEIGHT_F) {
623 tokens[0] = TOKEN_WEIGHT_TIME_FAST;
624 tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
626 tokens[0] = TOKEN_WEIGHT_TIME_SLOW;
627 tokens[1] = TOKEN_WEIGHT_TIME_FAST;
631 if (cur_setting == 0) {
632 /* Didn't pick up device state yet. */
633 if (wait_for_token(sdi, tokens, 0) != SR_OK)
635 if (devc->token == tokens[0])
640 /* 51ms timeout seems to work best for this. */
641 ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_TIME, tokens, 51);
646 SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
649 struct dev_context *devc;
654 if (devc->cur_mqflags == 0) {
655 tokens[0] = TOKEN_HOLD_MAX;
656 tokens[1] = TOKEN_HOLD_MIN;
657 tokens[2] = TOKEN_HOLD_NONE;
659 if (wait_for_token(sdi, tokens, 0) != SR_OK)
661 if (devc->token == TOKEN_HOLD_MAX)
662 devc->cur_mqflags = SR_MQFLAG_MAX;
663 else if (devc->token == TOKEN_HOLD_MIN)
664 devc->cur_mqflags = SR_MQFLAG_MIN;
666 *holdmode = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
671 SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode)
673 struct dev_context *devc;
674 int cur_setting, ret;
679 /* The toggle below needs the desired state in first position. */
680 if (holdmode == SR_MQFLAG_MAX) {
681 tokens[0] = TOKEN_HOLD_MAX;
682 tokens[1] = TOKEN_HOLD_MIN;
683 tokens[2] = TOKEN_HOLD_NONE;
684 } else if (holdmode == SR_MQFLAG_MIN) {
685 tokens[0] = TOKEN_HOLD_MIN;
686 tokens[1] = TOKEN_HOLD_MAX;
687 tokens[2] = TOKEN_HOLD_NONE;
689 tokens[0] = TOKEN_HOLD_NONE;
690 tokens[1] = TOKEN_HOLD_MAX;
691 tokens[2] = TOKEN_HOLD_MIN;
695 if (devc->cur_mqflags == 0) {
696 /* Didn't pick up device state yet. */
697 if (wait_for_token(sdi, tokens, 0) != SR_OK)
699 if (devc->token == tokens[0])
703 cur_setting = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
704 if (cur_setting == holdmode)
705 /* Already set correctly. */
709 /* 51ms timeout seems to work best for this. */
710 ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_HOLD_MAX_MIN, tokens, 51);
715 SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
716 uint64_t *low, uint64_t *high)
718 struct dev_context *devc;
722 if (devc->cur_meas_range == 0) {
723 tokens[0] = TOKEN_MEAS_RANGE_30_130;
724 tokens[1] = TOKEN_MEAS_RANGE_30_80;
725 tokens[2] = TOKEN_MEAS_RANGE_50_100;
726 tokens[3] = TOKEN_MEAS_RANGE_80_130;
728 if (wait_for_token(sdi, tokens, 0) != SR_OK)
730 devc->cur_meas_range = devc->token;
733 switch (devc->cur_meas_range) {
734 case TOKEN_MEAS_RANGE_30_130:
738 case TOKEN_MEAS_RANGE_30_80:
742 case TOKEN_MEAS_RANGE_50_100:
746 case TOKEN_MEAS_RANGE_80_130:
757 SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
758 uint64_t low, uint64_t high)
760 struct dev_context *devc;
762 int8_t token, tokens[6];
765 if (low == 30 && high == 130)
766 token = TOKEN_MEAS_RANGE_30_130;
767 else if (low == 30 && high == 80)
768 token = TOKEN_MEAS_RANGE_30_80;
769 else if (low == 50 && high == 100)
770 token = TOKEN_MEAS_RANGE_50_100;
771 else if (low == 80 && high == 130)
772 token = TOKEN_MEAS_RANGE_80_130;
776 sr_dbg("want 0x%.2x", token);
777 /* The toggle below needs the desired state in first position. */
779 tokens[1] = TOKEN_MEAS_RANGE_30_130;
780 tokens[2] = TOKEN_MEAS_RANGE_30_80;
781 tokens[3] = TOKEN_MEAS_RANGE_50_100;
782 tokens[4] = TOKEN_MEAS_RANGE_80_130;
785 if (devc->cur_meas_range == 0) {
786 /* 110ms should be enough for two of these announcements */
787 if (wait_for_token(sdi, tokens, 110) != SR_OK)
789 devc->cur_meas_range = devc->token;
792 if (devc->cur_meas_range == token)
793 /* Already set to this range. */
796 /* For measurement range, it works best to ignore announcements of the
797 * current setting and keep resending the toggle quickly. */
799 ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_MEAS_RANGE, tokens, 11);
804 SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
806 struct sr_serial_dev_inst *serial;
811 cmd = CMD_TOGGLE_POWER_OFF;
813 serial_flush(serial);
814 if (serial_write_nonblocking(serial, (const void *)&cmd, 1) != 1)
816 /* It never takes more than 23ms for the next token to arrive. */
818 if (serial_read_nonblocking(serial, &c, 1) != 1)
819 /* Device is no longer responding. Good! */
823 /* In case the user manually turns on the device again, reset
824 * the port back to blocking. */
825 serial_close(serial);
826 serial_open(serial, SERIAL_RDWR);