]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * This file is part of the libsigrok project. | |
3 | * | |
4 | * Copyright (C) 2019-2020 Gerhard Sittig <gerhard.sittig@gmx.net> | |
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 | #ifndef LIBSIGROK_HARDWARE_UNI_T_UT181A_PROTOCOL_H | |
21 | #define LIBSIGROK_HARDWARE_UNI_T_UT181A_PROTOCOL_H | |
22 | ||
23 | #include <glib.h> | |
24 | #include <libsigrok/libsigrok.h> | |
25 | #include <stdint.h> | |
26 | ||
27 | #include "libsigrok-internal.h" | |
28 | ||
29 | #define LOG_PREFIX "uni-t-ut181a" | |
30 | ||
31 | /* | |
32 | * Optional features. Tunables. | |
33 | */ | |
34 | #define UT181A_WITH_TIMESTAMP 0 | |
35 | #define UT181A_WITH_SER_ECHO 0 | |
36 | ||
37 | /* | |
38 | * The largest frame we expect to receive is chunked record data. Which | |
39 | * can span up to 256 items which each occupy 9 bytes, plus some header | |
40 | * before the items array. Be generous and prepare to receive several | |
41 | * frames in a row, e.g. when synchronizing to the packet stream at the | |
42 | * start of a session or after communication failure. | |
43 | * | |
44 | * The largest frame we expect to transmit is a "start record" command. | |
45 | * Which contains 18 bytes of payload (plus 6 bytes of frame envelope). | |
46 | */ | |
47 | #define RECV_BUFF_SIZE 4096 | |
48 | #define SEND_BUFF_SIZE 32 | |
49 | #define SEND_TO_MS 100 | |
50 | ||
51 | /* | |
52 | * The device can hold several recordings, their number is under the | |
53 | * user's control and dynamic at runtime. It's assumed that there is an | |
54 | * absolute upper bound of 20 recordings at any time. Names are under | |
55 | * user control, too (auto-preset, then editable), and a maximum label | |
56 | * length is assumed from the protocol description. | |
57 | * | |
58 | * Update 2020-03-17 | |
59 | * Turns out that 20 is *not* the limit on the number of recordings. | |
60 | * Nor do I believe that 20K or 10K is the limit. It may be the total | |
61 | * of the number of recordings and their sample counts which may not | |
62 | * exceed 10K, while saved measurements can be up to 20K? This is just | |
63 | * a guess though, the "Operating Manual" does not specify a limit, | |
64 | * nor does it discuss a dependency beyond mentioning the 10K/20K | |
65 | * figures. | |
66 | */ | |
67 | #define MAX_REC_COUNT 20 | |
68 | #define MAX_REC_NAMELEN 12 | |
69 | ||
70 | #define MAX_RANGE_INDEX 8 | |
71 | ||
72 | /* Literals look weird as numbers. LE format makes them readable on the wire. */ | |
73 | #define FRAME_MAGIC 0xcdab /* Becomes the AB CD byte sequence. */ | |
74 | #define REPLY_CODE_OK 0x4b4f /* Becomes the "OK" text. */ | |
75 | #define REPLY_CODE_ERR 0x5245 /* Becomes the "ER" text. */ | |
76 | ||
77 | enum ut181a_channel_idx { | |
78 | UT181A_CH_MAIN, | |
79 | UT181A_CH_AUX1, | |
80 | UT181A_CH_AUX2, | |
81 | UT181A_CH_AUX3, | |
82 | UT181A_CH_BAR, | |
83 | #if UT181A_WITH_TIMESTAMP | |
84 | UT181A_CH_TIME, | |
85 | #endif | |
86 | }; | |
87 | ||
88 | enum ut181_cmd_code { | |
89 | CMD_CODE_INVALID = 0x00, | |
90 | CMD_CODE_SET_MODE = 0x01, | |
91 | CMD_CODE_SET_RANGE = 0x02, | |
92 | CMD_CODE_SET_REFERENCE = 0x03, | |
93 | CMD_CODE_SET_MIN_MAX = 0x04, | |
94 | CMD_CODE_SET_MONITOR = 0x05, | |
95 | CMD_CODE_SAVE_MEAS = 0x06, | |
96 | CMD_CODE_GET_SAVED_MEAS = 0x07, | |
97 | CMD_CODE_GET_SAVED_COUNT = 0x08, | |
98 | CMD_CODE_DEL_SAVED_MEAS = 0x09, | |
99 | CMD_CODE_START_REC = 0x0a, | |
100 | CMD_CODE_STOP_REC = 0x0b, | |
101 | CMD_CODE_GET_REC_INFO = 0x0c, | |
102 | CMD_CODE_GET_REC_SAMPLES = 0x0d, | |
103 | CMD_CODE_GET_RECS_COUNT = 0x0e, | |
104 | CMD_CODE_BTN_PRESS = 0x12, | |
105 | }; | |
106 | ||
107 | enum ut181_rsp_type { | |
108 | RSP_TYPE_REPLY_CODE = 0x01, | |
109 | RSP_TYPE_MEASUREMENT = 0x02, | |
110 | RSP_TYPE_SAVE = 0x03, | |
111 | RSP_TYPE_REC_INFO = 0x04, | |
112 | RSP_TYPE_REC_DATA = 0x05, | |
113 | RSP_TYPE_REPLY_DATA = 0x72, /* 'r' */ | |
114 | }; | |
115 | ||
116 | /* | |
117 | * TODO | |
118 | * - See if there is a pattern to these number codes. | |
119 | * - [3:0] == 2 relative mode (when available) | |
120 | * - [7:4] == 3 peak mode aka max/min (when available) | |
121 | * (but there is command 4 set max/min on/off too) | |
122 | */ | |
123 | ||
124 | enum ut181a_mode_code { | |
125 | /* V AC */ | |
126 | MODE_V_AC = 0x1111, | |
127 | MODE_V_AC_REL = 0x1112, | |
128 | MODE_V_AC_Hz = 0x1121, | |
129 | MODE_V_AC_PEAK = 0x1131, | |
130 | MODE_V_AC_LOWPASS = 0x1141, | |
131 | MODE_V_AC_LOWPASS_REL = 0x1142, | |
132 | MODE_V_AC_dBV = 0x1151, | |
133 | MODE_V_AC_dBV_REL = 0x1152, | |
134 | MODE_V_AC_dBm = 0x1161, | |
135 | MODE_V_AC_dBm_REL = 0x1162, | |
136 | /* mV AC */ | |
137 | MODE_mV_AC = 0x2111, | |
138 | MODE_mV_AC_REL = 0x2112, | |
139 | MODE_mV_AC_Hz = 0x2121, | |
140 | MODE_mV_AC_PEAK = 0x2131, | |
141 | MODE_mV_AC_ACDC = 0x2141, | |
142 | MODE_mV_AC_ACDC_REL = 0x2142, | |
143 | /* V DC */ | |
144 | MODE_V_DC = 0x3111, | |
145 | MODE_V_DC_REL = 0x3112, | |
146 | MODE_V_DC_ACDC = 0x3121, | |
147 | MODE_V_DC_ACDC_REL = 0x3122, | |
148 | MODE_V_DC_PEAK = 0x3131, | |
149 | /* mV DC */ | |
150 | MODE_mV_DC = 0x4111, | |
151 | MODE_mV_DC_REL = 0x4112, | |
152 | MODE_mV_DC_PEAK = 0x4121, /* TODO Check number code, is it 0x4131? */ | |
153 | /* temperature Celsius */ | |
154 | MODE_TEMP_C_T1_and_T2 = 0x4211, | |
155 | MODE_TEMP_C_T1_and_T2_REL = 0x4212, | |
156 | MODE_TEMP_C_T2_and_T1 = 0x4221, | |
157 | MODE_TEMP_C_T2_and_T1_REL = 0x4222, | |
158 | MODE_TEMP_C_T1_minus_T2 = 0x4231, /* XXX exception, not PEAK */ | |
159 | MODE_TEMP_C_T2_minus_T1 = 0x4241, | |
160 | /* temperature Farenheit */ | |
161 | MODE_TEMP_F_T1_and_T2 = 0x4311, | |
162 | MODE_TEMP_F_T1_and_T2_REL = 0x4312, | |
163 | MODE_TEMP_F_T2_and_T1 = 0x4321, | |
164 | MODE_TEMP_F_T2_and_T1_REL = 0x4322, | |
165 | MODE_TEMP_F_T1_minus_T2 = 0x4331, | |
166 | MODE_TEMP_F_T2_minus_T1 = 0x4341, /* XXX exception, not PEAK */ | |
167 | /* resistance, continuity, conductivity */ | |
168 | MODE_RES = 0x5111, | |
169 | MODE_RES_REL = 0x5112, | |
170 | MODE_CONT_SHORT = 0x5211, | |
171 | MODE_CONT_OPEN = 0x5212, | |
172 | MODE_COND = 0x5311, | |
173 | MODE_COND_REL = 0x5312, | |
174 | /* diode, capacitance */ | |
175 | MODE_DIODE = 0x6111, | |
176 | MODE_DIODE_ALARM = 0x6112, /* XXX exception, not REL */ | |
177 | MODE_CAP = 0x6211, | |
178 | MODE_CAP_REL = 0x6212, | |
179 | /* frequency, duty cycle, pulse width */ | |
180 | MODE_FREQ = 0x7111, | |
181 | MODE_FREQ_REL = 0x7112, | |
182 | MODE_DUTY = 0x7211, | |
183 | MODE_DUTY_REL = 0x7212, | |
184 | MODE_PULSEWIDTH = 0x7311, | |
185 | MODE_PULSEWIDTH_REL = 0x7312, | |
186 | /* uA DC */ | |
187 | MODE_uA_DC = 0x8111, | |
188 | MODE_uA_DC_REL = 0x8112, | |
189 | MODE_uA_DC_ACDC = 0x8121, | |
190 | MODE_uA_DC_ACDC_REL = 0x8122, | |
191 | MODE_uA_DC_PEAK = 0x8131, | |
192 | /* uA AC */ | |
193 | MODE_uA_AC = 0x8211, | |
194 | MODE_uA_AC_REL = 0x8212, | |
195 | MODE_uA_AC_Hz = 0x8221, | |
196 | MODE_uA_AC_PEAK = 0x8231, | |
197 | /* mA DC */ | |
198 | MODE_mA_DC = 0x9111, | |
199 | MODE_mA_DC_REL = 0x9112, | |
200 | MODE_mA_DC_ACDC = 0x9121, | |
201 | MODE_mA_DC_ACDC_REL = 0x9122, | |
202 | MODE_mA_DC_ACDC_PEAK = 0x9131, | |
203 | /* mA AC */ | |
204 | MODE_mA_AC = 0x9211, | |
205 | MODE_mA_AC_REL = 0x9212, | |
206 | MODE_mA_AC_Hz = 0x9221, | |
207 | MODE_mA_AC_PEAK = 0x9231, | |
208 | /* A DC */ | |
209 | MODE_A_DC = 0xa111, | |
210 | MODE_A_DC_REL = 0xa112, | |
211 | MODE_A_DC_ACDC = 0xa121, | |
212 | MODE_A_DC_ACDC_REL = 0xa122, | |
213 | MODE_A_DC_PEAK = 0xa131, | |
214 | /* A AC */ | |
215 | MODE_A_AC = 0xa211, | |
216 | MODE_A_AC_REL = 0xa212, | |
217 | MODE_A_AC_Hz = 0xa221, | |
218 | MODE_A_AC_PEAK = 0xa231, | |
219 | }; | |
220 | ||
221 | /* Maximum number of UT181A modes which map to one MQ item. */ | |
222 | #define MODE_COUNT_PER_MQ_MQF 15 | |
223 | ||
224 | struct mqopt_item { | |
225 | enum sr_mq mq; | |
226 | enum sr_mqflag mqflags; | |
227 | enum ut181a_mode_code modes[MODE_COUNT_PER_MQ_MQF]; | |
228 | }; | |
229 | ||
230 | struct mq_scale_params { | |
231 | int scale; | |
232 | enum sr_mq mq; | |
233 | enum sr_mqflag mqflags; | |
234 | enum sr_unit unit; | |
235 | }; | |
236 | ||
237 | struct value_params { | |
238 | float value; | |
239 | int digits; | |
240 | gboolean ol_neg, ol_pos; | |
241 | }; | |
242 | ||
243 | struct feed_buffer { | |
244 | struct sr_datafeed_packet packet; | |
245 | struct sr_datafeed_analog analog; | |
246 | struct sr_analog_encoding encoding; | |
247 | struct sr_analog_meaning meaning; | |
248 | struct sr_analog_spec spec; | |
249 | int scale; | |
250 | float main_value; /* TODO double, for epoch timestamps */ | |
251 | }; | |
252 | ||
253 | struct ut181a_info { | |
254 | struct { | |
255 | enum ut181_rsp_type rsp_type; | |
256 | } rsp_head; | |
257 | struct { | |
258 | uint16_t code; | |
259 | gboolean ok; | |
260 | } reply_code; | |
261 | struct { | |
262 | uint32_t stamp; | |
263 | time_t epoch; | |
264 | } save_time; | |
265 | struct { | |
266 | uint8_t misc1, misc2, range; | |
267 | uint16_t mode; | |
268 | uint8_t is_type; | |
269 | gboolean is_norm, is_rel, is_minmax, is_peak; | |
270 | gboolean has_hold, has_aux1, has_aux2, has_bar; | |
271 | gboolean is_rec, is_comp, is_auto_range; | |
272 | gboolean has_lead_err, has_high_volt; | |
273 | } meas_head; | |
274 | union { | |
275 | struct { | |
276 | float main_value; | |
277 | uint8_t main_prec; | |
278 | char main_unit[8]; | |
279 | float aux1_value; | |
280 | uint8_t aux1_prec; | |
281 | char aux1_unit[8]; | |
282 | float aux2_value; | |
283 | uint8_t aux2_prec; | |
284 | char aux2_unit[8]; | |
285 | float bar_value; | |
286 | char bar_unit[8]; | |
287 | } norm; | |
288 | struct { | |
289 | enum { | |
290 | COMP_MODE_INNER = 0, | |
291 | COMP_MODE_OUTER = 1, | |
292 | COMP_MODE_BELOW = 2, | |
293 | COMP_MODE_ABOVE = 3, | |
294 | } mode; | |
295 | gboolean fail; | |
296 | int digits; | |
297 | float limit_high; | |
298 | float limit_low; | |
299 | } comp; | |
300 | struct { | |
301 | float rel_value; | |
302 | uint8_t rel_prec; | |
303 | char rel_unit[8]; | |
304 | float ref_value; | |
305 | uint8_t ref_prec; | |
306 | char ref_unit[8]; | |
307 | float abs_value; | |
308 | uint8_t abs_prec; | |
309 | char abs_unit[8]; | |
310 | float bar_value; | |
311 | char bar_unit[8]; | |
312 | } rel; | |
313 | struct { | |
314 | float curr_value; | |
315 | uint8_t curr_prec; | |
316 | float max_value; | |
317 | uint8_t max_prec; | |
318 | uint32_t max_stamp; | |
319 | float avg_value; | |
320 | uint8_t avg_prec; | |
321 | uint32_t avg_stamp; | |
322 | float min_value; | |
323 | uint8_t min_prec; | |
324 | uint32_t min_stamp; | |
325 | char all_unit[8]; | |
326 | } minmax; | |
327 | struct { | |
328 | float max_value; | |
329 | uint8_t max_prec; | |
330 | char max_unit[8]; | |
331 | float min_value; | |
332 | uint8_t min_prec; | |
333 | char min_unit[8]; | |
334 | } peak; | |
335 | } meas_data; | |
336 | struct { | |
337 | size_t save_idx; | |
338 | size_t save_count; | |
339 | } save_info; | |
340 | struct { | |
341 | size_t rec_count; | |
342 | size_t rec_idx; | |
343 | gboolean auto_feed; | |
344 | gboolean auto_next; | |
345 | char name[12]; | |
346 | char unit[8]; | |
347 | uint16_t interval; | |
348 | uint32_t duration; | |
349 | uint32_t samples; | |
350 | float max_value, avg_value, min_value; | |
351 | uint8_t max_prec, avg_prec, min_prec; | |
352 | uint32_t start_stamp; | |
353 | } rec_info; | |
354 | struct { | |
355 | size_t rec_idx; | |
356 | size_t samples_total; | |
357 | size_t samples_curr; | |
358 | uint8_t samples_chunk; | |
359 | } rec_data; | |
360 | struct { | |
361 | enum ut181_cmd_code code; | |
362 | uint16_t data; | |
363 | } reply_data; | |
364 | }; | |
365 | ||
366 | enum ut181a_data_source { | |
367 | DATA_SOURCE_LIVE, | |
368 | DATA_SOURCE_SAVE, | |
369 | DATA_SOURCE_REC_FIRST, | |
370 | DATA_SOURCE_MAX = DATA_SOURCE_REC_FIRST + MAX_REC_COUNT, | |
371 | }; | |
372 | ||
373 | struct dev_context { | |
374 | struct sr_sw_limits limits; | |
375 | enum ut181a_data_source data_source; | |
376 | size_t data_source_count; | |
377 | const char *data_source_names[DATA_SOURCE_MAX + 1]; | |
378 | size_t record_count; | |
379 | char record_names[MAX_REC_COUNT][MAX_REC_NAMELEN]; | |
380 | gboolean is_monitoring; | |
381 | gboolean is_recording; | |
382 | ||
383 | /* Reception of serial communication data. */ | |
384 | uint8_t recv_buff[RECV_BUFF_SIZE]; | |
385 | size_t recv_count; | |
386 | ||
387 | /* Meter's internal state tracking. */ | |
388 | int disable_feed; | |
389 | gboolean frame_started; | |
390 | struct ut181a_info info; | |
391 | ||
392 | /* Management for request/response pairs. */ | |
393 | struct wait_state { | |
394 | gboolean want_code, got_code; | |
395 | enum ut181_cmd_code want_data; gboolean got_data; | |
396 | enum ut181_rsp_type want_rsp_type; | |
397 | gboolean got_rsp_type; | |
398 | gboolean want_measure, got_measure; | |
399 | gboolean got_rec_count; | |
400 | gboolean got_save_count; | |
401 | gboolean got_sample_count; | |
402 | size_t response_count; | |
403 | gboolean code_ok; | |
404 | size_t data_value; | |
405 | } wait_state; | |
406 | struct { | |
407 | char unit_text[12]; | |
408 | } last_data; | |
409 | }; | |
410 | ||
411 | SR_PRIV const struct mqopt_item *ut181a_get_mqitem_from_mode(uint16_t mode); | |
412 | SR_PRIV uint16_t ut181a_get_mode_from_mq_flags(enum sr_mq mq, enum sr_mqflag mqflags); | |
413 | SR_PRIV GVariant *ut181a_get_mq_flags_list_item(enum sr_mq mq, enum sr_mqflag mqflag); | |
414 | SR_PRIV GVariant *ut181a_get_mq_flags_list(void); | |
415 | ||
416 | SR_PRIV int ut181a_send_cmd_monitor(struct sr_serial_dev_inst *serial, gboolean on); | |
417 | SR_PRIV int ut181a_send_cmd_setmode(struct sr_serial_dev_inst *serial, uint16_t mode); | |
418 | SR_PRIV int ut181a_send_cmd_setrange(struct sr_serial_dev_inst *serial, uint8_t range); | |
419 | SR_PRIV int ut181a_send_cmd_get_save_count(struct sr_serial_dev_inst *serial); | |
420 | SR_PRIV int ut181a_send_cmd_get_saved_value(struct sr_serial_dev_inst *serial, size_t idx); | |
421 | SR_PRIV int ut181a_send_cmd_get_recs_count(struct sr_serial_dev_inst *serial); | |
422 | SR_PRIV int ut181a_send_cmd_get_rec_info(struct sr_serial_dev_inst *serial, size_t idx); | |
423 | SR_PRIV int ut181a_send_cmd_get_rec_samples(struct sr_serial_dev_inst *serial, size_t idx, size_t off); | |
424 | ||
425 | SR_PRIV int ut181a_configure_waitfor(struct dev_context *devc, | |
426 | gboolean want_code, enum ut181_cmd_code want_data, | |
427 | enum ut181_rsp_type want_rsp_type, | |
428 | gboolean want_measure, gboolean want_rec_count, | |
429 | gboolean want_save_count, gboolean want_sample_count); | |
430 | SR_PRIV int ut181a_waitfor_response(const struct sr_dev_inst *sdi, int timeout_ms); | |
431 | ||
432 | SR_PRIV int ut181a_handle_events(int fd, int revents, void *cb_data); | |
433 | ||
434 | SR_PRIV GVariant *ut181a_get_ranges_list(void); | |
435 | SR_PRIV const char *ut181a_get_range_from_packet_bytes(struct dev_context *devc); | |
436 | SR_PRIV int ut181a_set_range_from_text(const struct sr_dev_inst *sdi, const char *text); | |
437 | ||
438 | #endif |