es51984.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. /*
  2. * Cyrustek ES 51984 digital multimeter
  3. * RS232 signal interpreter
  4. *
  5. * Copyright (C) 2009-2016 Michael Buesch <m@bues.ch>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include "es51984.h"
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. #include <stdint.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <unistd.h>
  24. #include <fcntl.h>
  25. #include <termios.h>
  26. #include <time.h>
  27. #include <sys/time.h>
  28. #include <math.h>
  29. #include <float.h>
  30. #include <assert.h>
  31. #define PFX "es51984: "
  32. struct es51984 {
  33. enum es51984_board_type board;
  34. const char *tty;
  35. int fd;
  36. int synced;
  37. unsigned char sample_buf[11];
  38. unsigned int sample_ptr;
  39. };
  40. enum es51984_voltage_range {
  41. ES51984_VOLTRANGE_4p000 = ES51984_PACK(0), /* 4.000 V */
  42. ES51984_VOLTRANGE_40p00 = ES51984_PACK(1), /* 40.00 V */
  43. ES51984_VOLTRANGE_400p0 = ES51984_PACK(2), /* 400.0 V */
  44. ES51984_VOLTRANGE_4000 = ES51984_PACK(3), /* 4000 V */
  45. ES51984_VOLTRANGE_400p0m = ES51984_PACK(4), /* 400.0 mV */
  46. };
  47. enum es51984_ma_range {
  48. ES51984_MARANGE_40p00 = ES51984_PACK(0), /* 40.00 mA */
  49. ES51984_MARANGE_400p0 = ES51984_PACK(1), /* 400.0 mA */
  50. };
  51. enum es51984_ua_range {
  52. ES51984_UARANGE_400p0 = ES51984_PACK(0), /* 400.0 uA */
  53. ES51984_UARANGE_4000 = ES51984_PACK(1), /* 4000 uA */
  54. };
  55. enum es51984_autoa_range {
  56. ES51984_AARANGE_4p000 = ES51984_PACK(0), /* 4.000 A */
  57. ES51984_AARANGE_40p00 = ES51984_PACK(1), /* 40.00 A */
  58. };
  59. enum es51984_ohm_range {
  60. ES51984_OHMRANGE_400p0 = ES51984_PACK(0), /* 400.0 Ohms */
  61. ES51984_OHMRANGE_4p000k = ES51984_PACK(1), /* 4.000 Kilo-Ohms */
  62. ES51984_OHMRANGE_40p00k = ES51984_PACK(2), /* 40.00 Kilo-Ohms */
  63. ES51984_OHMRANGE_400p0k = ES51984_PACK(3), /* 400.0 Kilo-Ohms */
  64. ES51984_OHMRANGE_4p000m = ES51984_PACK(4), /* 4.000 Mega-Ohms */
  65. ES51984_OHMRANGE_40p00m = ES51984_PACK(5), /* 40.00 Mega-Ohms */
  66. };
  67. enum es51984_freq_range {
  68. ES51984_FREQRANGE_4p000k = ES51984_PACK(0), /* 4.000 KHz */
  69. ES51984_FREQRANGE_40p00k = ES51984_PACK(1), /* 40.00 KHz */
  70. ES51984_FREQRANGE_400p0k = ES51984_PACK(2), /* 400.0 KHz */
  71. ES51984_FREQRANGE_4p000m = ES51984_PACK(3), /* 4.000 MHz */
  72. ES51984_FREQRANGE_40p00m = ES51984_PACK(4), /* 40.00 MHz */
  73. };
  74. enum es51984_cap_range {
  75. ES51984_CAPRANGE_4p000n = ES51984_PACK(0), /* 4.000 nF */
  76. ES51984_CAPRANGE_40p00n = ES51984_PACK(1), /* 40.00 nF */
  77. ES51984_CAPRANGE_400p0n = ES51984_PACK(2), /* 400.0 nF */
  78. ES51984_CAPRANGE_4p000u = ES51984_PACK(3), /* 4.000 uF */
  79. ES51984_CAPRANGE_40p00u = ES51984_PACK(4), /* 40.00 uF */
  80. ES51984_CAPRANGE_400p0u = ES51984_PACK(5), /* 400.0 uF */
  81. ES51984_CAPRANGE_4p000m = ES51984_PACK(6), /* 4.000 mF */
  82. };
  83. struct es51984_raw_sample {
  84. uint8_t range;
  85. uint8_t digit3;
  86. uint8_t digit2;
  87. uint8_t digit1;
  88. uint8_t digit0;
  89. uint8_t function;
  90. uint8_t status;
  91. uint8_t option1;
  92. uint8_t option2;
  93. uint8_t cr;
  94. uint8_t lf;
  95. } __attribute__((__packed__));
  96. #define ES51984_DIGIT_MASK 0x0F
  97. #define ES51984_STATUS_JUDGE 0x08
  98. #define ES51984_STATUS_SIGN 0x04
  99. #define ES51984_STATUS_BATT 0x02
  100. #define ES51984_STATUS_OL 0x01
  101. #define ES51984_OPT1_HOLD 0x08
  102. #define ES51984_OPT2_DC 0x08
  103. #define ES51984_OPT2_AC 0x04
  104. #define ES51984_OPT2_AUTO 0x02
  105. static void dump_raw_sample(const char *description,
  106. struct es51984_raw_sample *raw)
  107. {
  108. int valid_termination = (raw->cr == '\r' && raw->lf == '\n');
  109. printf("%s (%svalid termination):\n", description,
  110. valid_termination ? "" : "in");
  111. printf("Function: %02X\n", raw->function);
  112. printf("Status: %02X\n", raw->status);
  113. printf("Option1: %02X\n", raw->option1);
  114. printf("Option2: %02X\n", raw->option2);
  115. printf("Digits: %02X %02X %02X %02X\n",
  116. raw->digit3, raw->digit2, raw->digit1, raw->digit0);
  117. }
  118. static int set_blocking(struct es51984 *es, unsigned int block_chars)
  119. {
  120. struct termios ios;
  121. int err;
  122. err = tcgetattr(es->fd, &ios);
  123. if (err < 0) {
  124. fprintf(stderr, PFX "Failed to get tty attributes on %s: %s\n",
  125. es->tty, strerror(errno));
  126. return -EIO;
  127. }
  128. ios.c_cc[VMIN] = block_chars;
  129. err = tcsetattr(es->fd, TCSANOW, &ios);
  130. if (err < 0) {
  131. fprintf(stderr, PFX "Failed to set tty attributes on %s: %s\n",
  132. es->tty, strerror(errno));
  133. return -EIO;
  134. }
  135. return 0;
  136. }
  137. static int read_sample(struct es51984 *es,
  138. struct es51984_raw_sample **sample,
  139. int blocking)
  140. {
  141. struct timespec ts;
  142. ssize_t res;
  143. int err;
  144. assert(sizeof(es->sample_buf) == sizeof(struct es51984_raw_sample));
  145. err = set_blocking(es, blocking ? sizeof(struct es51984_raw_sample) : 0);
  146. if (err)
  147. return err;
  148. while (1) {
  149. res = read(es->fd, es->sample_buf + es->sample_ptr,
  150. sizeof(struct es51984_raw_sample) - es->sample_ptr);
  151. if (res < 0)
  152. return -EIO;
  153. if (res == 0) {
  154. if (!blocking)
  155. return -EAGAIN;
  156. ts.tv_sec = 0;
  157. ts.tv_nsec = 1000*1000;
  158. nanosleep(&ts, &ts);
  159. continue;
  160. }
  161. es->sample_ptr += res;
  162. if (es->sample_ptr >= sizeof(struct es51984_raw_sample)) {
  163. *sample = (void *)es->sample_buf;
  164. es->sample_ptr = 0;
  165. break;
  166. }
  167. if (!blocking)
  168. return -EAGAIN;
  169. }
  170. return 0;
  171. }
  172. static int digits_sanity_check(struct es51984_raw_sample *raw)
  173. {
  174. if ((raw->digit3 & 0xF0) != 0x30 ||
  175. (raw->digit2 & 0xF0) != 0x30 ||
  176. (raw->digit1 & 0xF0) != 0x30 ||
  177. (raw->digit0 & 0xF0) != 0x30)
  178. return 1;
  179. if ((raw->digit3 & ES51984_DIGIT_MASK) > 4 ||
  180. (raw->digit2 & ES51984_DIGIT_MASK) > 9 ||
  181. (raw->digit1 & ES51984_DIGIT_MASK) > 9 ||
  182. (raw->digit0 & ES51984_DIGIT_MASK) > 9)
  183. return 1;
  184. return 0; /* Digits are OK */
  185. }
  186. static void parse_4p000(struct es51984_raw_sample *raw,
  187. struct es51984_sample *sample)
  188. {
  189. sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK);
  190. sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) / 10.0l;
  191. sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) / 100.0l;
  192. sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 1000.0l;
  193. }
  194. static void parse_40p00(struct es51984_raw_sample *raw,
  195. struct es51984_sample *sample)
  196. {
  197. sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 10.0l;
  198. sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK);
  199. sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) / 10.0l;
  200. sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 100.0l;
  201. }
  202. static void parse_400p0(struct es51984_raw_sample *raw,
  203. struct es51984_sample *sample)
  204. {
  205. sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 100.0l;
  206. sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) * 10.0l;
  207. sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK);
  208. sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK) / 10.0l;
  209. }
  210. static void parse_4000(struct es51984_raw_sample *raw,
  211. struct es51984_sample *sample)
  212. {
  213. sample->value += (double)(raw->digit3 & ES51984_DIGIT_MASK) * 1000.0l;
  214. sample->value += (double)(raw->digit2 & ES51984_DIGIT_MASK) * 100.0l;
  215. sample->value += (double)(raw->digit1 & ES51984_DIGIT_MASK) * 10.0l;
  216. sample->value += (double)(raw->digit0 & ES51984_DIGIT_MASK);
  217. }
  218. static int parse_sample(struct es51984 *es,
  219. struct es51984_raw_sample *raw,
  220. struct es51984_sample *sample)
  221. {
  222. if (digits_sanity_check(raw)) {
  223. fprintf(stderr, PFX "Got invalid digits %02X %02X %02X %02X (func %02X)\n",
  224. raw->digit3, raw->digit2, raw->digit1, raw->digit0,
  225. raw->function);
  226. goto error;
  227. }
  228. switch (raw->function) {
  229. case ES51984_FUNC_VOLTAGE:
  230. switch (raw->range) {
  231. case ES51984_VOLTRANGE_4p000:
  232. parse_4p000(raw, sample);
  233. break;
  234. case ES51984_VOLTRANGE_40p00:
  235. parse_40p00(raw, sample);
  236. break;
  237. case ES51984_VOLTRANGE_400p0:
  238. parse_400p0(raw, sample);
  239. break;
  240. case ES51984_VOLTRANGE_4000:
  241. parse_4000(raw, sample);
  242. break;
  243. case ES51984_VOLTRANGE_400p0m:
  244. parse_400p0(raw, sample);
  245. sample->value /= 1000.0l;
  246. break;
  247. default:
  248. goto invalid_range;
  249. }
  250. break;
  251. case ES51984_FUNC_UA_CURRENT:
  252. switch (raw->range) {
  253. case ES51984_UARANGE_400p0:
  254. parse_400p0(raw, sample);
  255. break;
  256. case ES51984_UARANGE_4000:
  257. parse_4000(raw, sample);
  258. break;
  259. default:
  260. goto invalid_range;
  261. }
  262. break;
  263. case ES51984_FUNC_MA_CURRENT:
  264. switch (raw->range) {
  265. case ES51984_MARANGE_40p00:
  266. parse_40p00(raw, sample);
  267. break;
  268. case ES51984_MARANGE_400p0:
  269. parse_400p0(raw, sample);
  270. break;
  271. default:
  272. goto invalid_range;
  273. }
  274. break;
  275. case ES51984_FUNC_AUTO_CURRENT:
  276. switch (raw->range) {
  277. case ES51984_AARANGE_4p000:
  278. parse_4p000(raw, sample);
  279. break;
  280. case ES51984_AARANGE_40p00:
  281. parse_40p00(raw, sample);
  282. break;
  283. default:
  284. goto invalid_range;
  285. }
  286. break;
  287. case ES51984_FUNC_MAN_CURRENT:
  288. /* TODO: What range do we have here? */
  289. break;
  290. case ES51984_FUNC_OHMS:
  291. switch (raw->range) {
  292. case ES51984_OHMRANGE_400p0:
  293. parse_400p0(raw, sample);
  294. break;
  295. case ES51984_OHMRANGE_4p000k:
  296. parse_4p000(raw, sample);
  297. sample->value *= 1000.0l;
  298. break;
  299. case ES51984_OHMRANGE_40p00k:
  300. parse_40p00(raw, sample);
  301. sample->value *= 1000.0l;
  302. break;
  303. case ES51984_OHMRANGE_400p0k:
  304. parse_400p0(raw, sample);
  305. sample->value *= 1000.0l;
  306. break;
  307. case ES51984_OHMRANGE_4p000m:
  308. parse_4p000(raw, sample);
  309. sample->value *= 1000000.0l;
  310. break;
  311. case ES51984_OHMRANGE_40p00m:
  312. parse_40p00(raw, sample);
  313. sample->value *= 1000000.0l;
  314. break;
  315. default:
  316. goto invalid_range;
  317. }
  318. break;
  319. case ES51984_FUNC_CONT:
  320. parse_4000(raw, sample);
  321. break;
  322. case ES51984_FUNC_DIODE:
  323. parse_4p000(raw, sample);
  324. break;
  325. case ES51984_FUNC_FREQUENCY:
  326. switch (raw->range) {
  327. case ES51984_FREQRANGE_4p000k:
  328. parse_4p000(raw, sample);
  329. sample->value *= 1000.0l;
  330. break;
  331. case ES51984_FREQRANGE_40p00k:
  332. parse_40p00(raw, sample);
  333. sample->value *= 1000.0l;
  334. break;
  335. case ES51984_FREQRANGE_400p0k:
  336. parse_400p0(raw, sample);
  337. sample->value *= 1000.0l;
  338. break;
  339. case ES51984_FREQRANGE_4p000m:
  340. parse_4p000(raw, sample);
  341. sample->value *= 1000000.0l;
  342. break;
  343. case ES51984_FREQRANGE_40p00m:
  344. parse_40p00(raw, sample);
  345. sample->value *= 1000000.0l;
  346. break;
  347. default:
  348. goto invalid_range;
  349. }
  350. break;
  351. case ES51984_FUNC_CAPACITOR:
  352. switch (raw->range) {
  353. case ES51984_CAPRANGE_4p000n:
  354. parse_4p000(raw, sample);
  355. sample->value /= 1000000000.0l;
  356. break;
  357. case ES51984_CAPRANGE_40p00n:
  358. parse_40p00(raw, sample);
  359. sample->value /= 1000000000.0l;
  360. break;
  361. case ES51984_CAPRANGE_400p0n:
  362. parse_400p0(raw, sample);
  363. sample->value /= 1000000000.0l;
  364. break;
  365. case ES51984_CAPRANGE_4p000u:
  366. parse_4p000(raw, sample);
  367. sample->value /= 1000000.0l;
  368. break;
  369. case ES51984_CAPRANGE_40p00u:
  370. parse_40p00(raw, sample);
  371. sample->value /= 1000000.0l;
  372. break;
  373. case ES51984_CAPRANGE_400p0u:
  374. parse_400p0(raw, sample);
  375. sample->value /= 1000000.0l;
  376. break;
  377. case ES51984_CAPRANGE_4p000m:
  378. parse_4p000(raw, sample);
  379. sample->value /= 1000.0l;
  380. break;
  381. default:
  382. goto invalid_range;
  383. }
  384. break;
  385. case ES51984_FUNC_TEMP:
  386. /* TODO: What range do we have here? */
  387. break;
  388. case ES51984_FUNC_ADP0:
  389. switch (sample->board) {
  390. case ES51984_BOARD_UNKNOWN:
  391. sample->overflow = 1;
  392. sample->value = DBL_MAX;
  393. break;
  394. case ES51984_BOARD_AMPROBE_35XPA:
  395. parse_4000(raw, sample);
  396. break;
  397. }
  398. break;
  399. case ES51984_FUNC_ADP1:
  400. switch (sample->board) {
  401. case ES51984_BOARD_UNKNOWN:
  402. sample->overflow = 1;
  403. sample->value = DBL_MAX;
  404. break;
  405. case ES51984_BOARD_AMPROBE_35XPA:
  406. parse_400p0(raw, sample);
  407. break;
  408. }
  409. break;
  410. case ES51984_FUNC_ADP2:
  411. sample->overflow = 1;
  412. sample->value = DBL_MAX;
  413. break;
  414. case ES51984_FUNC_ADP3:
  415. sample->overflow = 1;
  416. sample->value = DBL_MAX;
  417. break;
  418. default:
  419. fprintf(stderr, PFX "Got invalid function code %02X\n",
  420. raw->function);
  421. goto error;
  422. }
  423. sample->function = raw->function;
  424. /* Parse status code */
  425. if ((raw->status & 0xF0) != 0x30) {
  426. fprintf(stderr, PFX "Got invalid status code %02X (func %02X)\n",
  427. raw->status, raw->function);
  428. goto error;
  429. }
  430. if (raw->function == ES51984_FUNC_TEMP) {
  431. if (raw->status & ES51984_STATUS_JUDGE)
  432. sample->degree = 1;
  433. else
  434. sample->degree = 0;
  435. }
  436. if (raw->status & ES51984_STATUS_OL) {
  437. sample->overflow = 1;
  438. sample->value = DBL_MAX;
  439. }
  440. if (raw->status & ES51984_STATUS_SIGN)
  441. sample->value = -(sample->value);
  442. if (raw->status & ES51984_STATUS_BATT)
  443. sample->batt_low = 1;
  444. /* Parse option1 code */
  445. if ((raw->option1 & 0xF0) != 0x30) {
  446. fprintf(stderr, PFX "Got invalid option1 code %02X (func %02X)\n",
  447. raw->option1, raw->function);
  448. goto error;
  449. }
  450. if (raw->option1 & ES51984_OPT1_HOLD)
  451. sample->hold = 1;
  452. /* Parse option2 code */
  453. if ((raw->option2 & 0xF0) != 0x30) {
  454. fprintf(stderr, PFX "Got invalid option2 code %02X (func %02X)\n",
  455. raw->option2, raw->function);
  456. goto error;
  457. }
  458. if (raw->option2 & ES51984_OPT2_DC)
  459. sample->dc_mode = 1;
  460. if (raw->option2 & ES51984_OPT2_AC)
  461. sample->dc_mode = 0;
  462. if (raw->option2 & ES51984_OPT2_AUTO)
  463. sample->auto_mode = 1;
  464. /* Verify CR/LF */
  465. if (raw->cr != '\r' || raw->lf != '\n') {
  466. fprintf(stderr, PFX "Got invalid packet termination %02X %02X\n",
  467. raw->cr, raw->lf);
  468. goto error;
  469. }
  470. return 0;
  471. invalid_range:
  472. fprintf(stderr, PFX "Got an invalid range code %02X (func %02X)\n",
  473. raw->range, raw->function);
  474. error:
  475. es->synced = 0; /* We lost synchronization */
  476. return -EPIPE;
  477. }
  478. int es51984_get_sample(struct es51984 *es,
  479. struct es51984_sample *sample,
  480. int blocking,
  481. int debug)
  482. {
  483. struct es51984_raw_sample *raw;
  484. int err;
  485. if (!es->synced)
  486. return -EPIPE; /* Must sync first! */
  487. memset(sample, 0, sizeof(*sample));
  488. sample->value = 0.0;
  489. sample->board = es->board;
  490. err = read_sample(es, &raw, blocking);
  491. if (err)
  492. return err;
  493. if (debug)
  494. dump_raw_sample("es51984 raw sample", raw);
  495. err = parse_sample(es, raw, sample);
  496. if (err)
  497. return err;
  498. return 0;
  499. }
  500. const char * es51984_get_units(const struct es51984_sample *sample)
  501. {
  502. switch (sample->function) {
  503. case ES51984_FUNC_VOLTAGE:
  504. return "V";
  505. case ES51984_FUNC_UA_CURRENT:
  506. return "uA";
  507. case ES51984_FUNC_MA_CURRENT:
  508. return "mA";
  509. case ES51984_FUNC_AUTO_CURRENT:
  510. return "A";
  511. case ES51984_FUNC_MAN_CURRENT:
  512. return "A";
  513. case ES51984_FUNC_OHMS:
  514. return "Ohms";
  515. case ES51984_FUNC_CONT:
  516. return "Ohms";
  517. case ES51984_FUNC_DIODE:
  518. return "V";
  519. case ES51984_FUNC_FREQUENCY:
  520. return "Hz";
  521. case ES51984_FUNC_CAPACITOR:
  522. return "F";
  523. case ES51984_FUNC_TEMP:
  524. if (sample->degree)
  525. return "C";
  526. return "F";
  527. case ES51984_FUNC_ADP0:
  528. switch (sample->board) {
  529. case ES51984_BOARD_UNKNOWN:
  530. break;
  531. case ES51984_BOARD_AMPROBE_35XPA:
  532. return "C/F";
  533. }
  534. return "ADP0";
  535. case ES51984_FUNC_ADP1:
  536. switch (sample->board) {
  537. case ES51984_BOARD_UNKNOWN:
  538. break;
  539. case ES51984_BOARD_AMPROBE_35XPA:
  540. return "C/F";
  541. }
  542. return "ADP1";
  543. case ES51984_FUNC_ADP2:
  544. return "ADP2";
  545. case ES51984_FUNC_ADP3:
  546. return "ADP3";
  547. }
  548. return "Unknown units";
  549. }
  550. int es51984_discard(struct es51984 *es)
  551. {
  552. struct es51984_sample sample;
  553. int err;
  554. if (!es->synced)
  555. return -EPIPE; /* Must sync first! */
  556. /* Read samples until the buffer is empty */
  557. while (1) {
  558. err = es51984_get_sample(es, &sample, 0, 0);
  559. if (err == -EAGAIN)
  560. break; /* No more samples */
  561. if (err)
  562. return err;
  563. }
  564. if (es->sample_ptr) {
  565. /* We have a partially received sample. Discard it.
  566. * Wait for the end of the sample. */
  567. err = es51984_sync(es);
  568. if (err)
  569. return err;
  570. }
  571. return 0;
  572. }
  573. static void tv_add_msec(struct timeval *tv, unsigned int msec)
  574. {
  575. tv->tv_usec += msec * 1000;
  576. while (tv->tv_usec > 1000000) {
  577. tv->tv_sec++;
  578. tv->tv_usec -= 1000000;
  579. }
  580. }
  581. static int tv_after(const struct timeval *a, const struct timeval *b)
  582. {
  583. if (a->tv_sec > b->tv_sec)
  584. return 1;
  585. if (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec)
  586. return 1;
  587. return 0;
  588. }
  589. int es51984_sync(struct es51984 *es)
  590. {
  591. ssize_t res;
  592. int err;
  593. unsigned char prev = 0, c;
  594. struct timeval to, tv;
  595. struct timespec ts;
  596. /* We sync to the final CR/LF sequence of the data stream. */
  597. err = gettimeofday(&to, NULL);
  598. if (err) {
  599. fprintf(stderr, PFX "Failed to get time of day: %s\n",
  600. strerror(errno));
  601. return -EIO;
  602. }
  603. switch (es->board) {
  604. case ES51984_BOARD_UNKNOWN:
  605. case ES51984_BOARD_AMPROBE_35XPA:
  606. tv_add_msec(&to, 3000); /* 3 seconds */
  607. break;
  608. }
  609. err = set_blocking(es, 0);
  610. if (err)
  611. return err;
  612. tcflush(es->fd, TCIFLUSH);
  613. while (1) {
  614. err = gettimeofday(&tv, NULL);
  615. if (err) {
  616. fprintf(stderr, PFX "Failed to get time of day: %s\n",
  617. strerror(errno));
  618. return -EIO;
  619. }
  620. if (tv_after(&tv, &to)) {
  621. fprintf(stderr, PFX "Sync: Timeout. Is the device connected?\n");
  622. return -ETIME;
  623. }
  624. res = read(es->fd, &c, 1);
  625. if (res == 0) {
  626. ts.tv_sec = 0;
  627. ts.tv_nsec = 1000*1000;
  628. nanosleep(&ts, &ts);
  629. continue;
  630. }
  631. if (res != 1) {
  632. fprintf(stderr, PFX "Sync: Read failed: %s\n",
  633. strerror(errno));
  634. return -EIO;
  635. }
  636. if (prev == '\r' && c == '\n') {
  637. /* Got it! */
  638. break;
  639. }
  640. prev = c;
  641. }
  642. es->synced = 1;
  643. es->sample_ptr = 0;
  644. return 0;
  645. }
  646. struct es51984 * es51984_init(enum es51984_board_type board,
  647. const char *tty)
  648. {
  649. struct es51984 *es;
  650. struct termios ios;
  651. int err;
  652. es = malloc(sizeof(*es));
  653. if (!es) {
  654. fprintf(stderr, "Out of memory\n");
  655. return NULL;
  656. }
  657. memset(es, 0, sizeof(*es));
  658. es->board = board;
  659. es->tty = tty;
  660. es->fd = open(tty, O_RDONLY | O_NOCTTY);
  661. if (es->fd < 0) {
  662. fprintf(stderr, PFX "Failed to open %s: %s\n",
  663. tty, strerror(errno));
  664. goto err_free;
  665. }
  666. err = tcgetattr(es->fd, &ios);
  667. if (err < 0) {
  668. fprintf(stderr, PFX "Failed to get tty attributes on %s: %s\n",
  669. tty, strerror(errno));
  670. goto err_close;
  671. }
  672. cfsetispeed(&ios, B19200);
  673. cfmakeraw(&ios);
  674. ios.c_cflag &= ~(CSIZE | CLOCAL | CREAD | CSTOPB | PARENB | PARODD);
  675. ios.c_cflag |= CS7 | CLOCAL | CREAD | PARENB | PARODD;
  676. ios.c_iflag &= ~(INPCK | PARMRK | IXON | IXOFF | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL | ISTRIP | IGNBRK | IGNPAR);
  677. ios.c_iflag |= IGNBRK;
  678. ios.c_lflag &= ~(NOFLSH | ECHO | ECHOE | ECHOK | ECHONL | XCASE | ECHOCTL | ECHOPRT | ECHOKE | PENDIN | ICANON | ISIG);
  679. ios.c_lflag |= 0;
  680. ios.c_cc[VMIN] = 0; /* non-blocking */
  681. err = tcsetattr(es->fd, TCSANOW, &ios);
  682. if (err < 0) {
  683. fprintf(stderr, PFX "Failed to set tty attributes on %s: %s\n",
  684. tty, strerror(errno));
  685. goto err_close;
  686. }
  687. err = tcflow(es->fd, TCION);
  688. if (err) {
  689. fprintf(stderr, PFX "Failed to enable input on %s: %s\n",
  690. tty, strerror(errno));
  691. goto err_close;
  692. }
  693. return es;
  694. err_close:
  695. close(es->fd);
  696. err_free:
  697. free(es);
  698. return NULL;
  699. }
  700. void es51984_exit(struct es51984 *es)
  701. {
  702. if (!es)
  703. return;
  704. close(es->fd);
  705. free(es);
  706. }