You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. /*
  2. * Labjack Tools
  3. * Copyright (c) 2003-2007 Jim Paris <jim@jtan.com>
  4. *
  5. * This is free software; you can redistribute it and/or modify it and
  6. * it is provided under the terms of version 2 of the GNU General Public
  7. * License as published by the Free Software Foundation; see COPYING.
  8. */
  9. #include <errno.h>
  10. #include <stdint.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include <math.h>
  17. #include "netutil.h"
  18. #include "compat.h"
  19. #include "debug.h"
  20. #include "ue9.h"
  21. #include "ue9error.h"
  22. #include "util.h"
  23. #include "netutil.h"
  24. #include "ethstream.h"
  25. /* Fill checksums in data buffers, with "normal" checksum format */
  26. void ue9_checksum_normal(uint8_t * buffer, size_t len)
  27. {
  28. uint16_t sum = 0;
  29. if (len < 1) {
  30. fprintf(stderr, "ue9_checksum_normal: len too short\n");
  31. exit(1);
  32. }
  33. while (--len >= 1)
  34. sum += (uint16_t) buffer[len];
  35. sum = (sum / 256) + (sum % 256);
  36. sum = (sum / 256) + (sum % 256);
  37. buffer[0] = (uint8_t) sum;
  38. }
  39. /* Fill checksums in data buffers, with "extended" checksum format */
  40. void ue9_checksum_extended(uint8_t * buffer, size_t len)
  41. {
  42. uint16_t sum = 0;
  43. if (len < 6) {
  44. fprintf(stderr, "ue9_checksum_extended: len too short\n");
  45. exit(1);
  46. }
  47. /* 16-bit extended checksum */
  48. while (--len >= 6)
  49. sum += (uint16_t) buffer[len];
  50. buffer[4] = (uint8_t) (sum & 0xff);
  51. buffer[5] = (uint8_t) (sum >> 8);
  52. /* 8-bit normal checksum over first 6 bytes */
  53. ue9_checksum_normal(buffer, 6);
  54. }
  55. /* Verify checksums in data buffers, with "normal" checksum format. */
  56. int ue9_verify_normal(uint8_t * buffer, size_t len)
  57. {
  58. uint8_t saved, new;
  59. if (len < 1) {
  60. fprintf(stderr, "ue9_verify_normal: len too short\n");
  61. exit(1);
  62. }
  63. saved = buffer[0];
  64. ue9_checksum_normal(buffer, len);
  65. new = buffer[0];
  66. buffer[0] = saved;
  67. if (new != saved) {
  68. verb("got %02x, expected %02x\n", saved, new);
  69. return 0;
  70. }
  71. return 1;
  72. }
  73. /* Verify checksums in data buffers, with "extended" checksum format. */
  74. int ue9_verify_extended(uint8_t * buffer, size_t len)
  75. {
  76. uint8_t saved[3], new[3];
  77. if (len < 6) {
  78. fprintf(stderr, "ue9_verify_extended: len too short\n");
  79. exit(1);
  80. }
  81. saved[0] = buffer[0];
  82. saved[1] = buffer[4];
  83. saved[2] = buffer[5];
  84. ue9_checksum_extended(buffer, len);
  85. new[0] = buffer[0];
  86. new[1] = buffer[4];
  87. new[2] = buffer[5];
  88. buffer[0] = saved[0];
  89. buffer[4] = saved[1];
  90. buffer[5] = saved[2];
  91. if (saved[0] != new[0] || saved[1] != new[1] || saved[2] != new[2]) {
  92. verb("got %02x %02x %02x, expected %02x %02x %02x\n",
  93. saved[0], saved[1], saved[2], new[0], new[1], new[2]);
  94. return 0;
  95. }
  96. return 1;
  97. }
  98. /* Temperature conversion. If calib is NULL, use uncalibrated conversions. */
  99. double ue9_binary_to_temperature(struct ue9Calibration *calib, uint16_t data)
  100. {
  101. double slope;
  102. if (calib == NULL) {
  103. slope = 0.012683;
  104. } else {
  105. slope = calib->tempSlope;
  106. }
  107. return data * slope; /* output is in Kelvin */
  108. }
  109. /* Data conversion. If calib is NULL, use uncalibrated conversions. */
  110. double
  111. ue9_binary_to_analog(struct ue9Calibration *calib,
  112. int gain, uint8_t resolution, uint16_t data)
  113. {
  114. double slope = 0, offset;
  115. if (calib == NULL) {
  116. double uncal[9] = { 5.08, 2.54, 1.27, 0.63, 0, 0, 0, 0, 10.25 };
  117. if (gain >= ARRAY_SIZE(uncal) || uncal[gain] == 0) {
  118. fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
  119. exit(1);
  120. }
  121. return data * uncal[gain] / 65536.0;
  122. }
  123. if (resolution < 18) {
  124. switch (gain) {
  125. case 1:
  126. slope = calib->unipolarSlope[0];
  127. offset = calib->unipolarOffset[0];
  128. break;
  129. case 2:
  130. slope = calib->unipolarSlope[1];
  131. offset = calib->unipolarOffset[1];
  132. break;
  133. case 4:
  134. slope = calib->unipolarSlope[2];
  135. offset = calib->unipolarOffset[2];
  136. break;
  137. case 8:
  138. slope = calib->unipolarSlope[3];
  139. offset = calib->unipolarOffset[3];
  140. break;
  141. default:
  142. slope = calib->bipolarSlope;
  143. offset = calib->bipolarOffset;
  144. }
  145. } else {
  146. if (gain == 0) {
  147. slope = calib->hiResUnipolarSlope;
  148. offset = calib->hiResUnipolarOffset;
  149. } else if (gain == 8) {
  150. slope = calib->hiResBipolarSlope;
  151. offset = calib->hiResBipolarOffset;
  152. }
  153. }
  154. if (slope == 0) {
  155. fprintf(stderr, "ue9_binary_to_analog: bad gain\n");
  156. exit(1);
  157. }
  158. return data * slope + offset;
  159. }
  160. /* Execute a command on the UE9. Returns -1 on error. Fills the
  161. checksums on the outgoing packets, and verifies them on the
  162. incoming packets. Data in "out" is transmitted, data in "in" is
  163. received. */
  164. int ue9_command(int fd, uint8_t * out, uint8_t * in, int inlen)
  165. {
  166. int extended = 0, outlen;
  167. uint8_t saved_1, saved_3;
  168. ssize_t ret;
  169. if ((out[1] & 0x78) == 0x78)
  170. extended = 1;
  171. /* Figure out length of data payload, and fill checksums. */
  172. if (extended) {
  173. outlen = 6 + (out[2]) * 2;
  174. ue9_checksum_extended(out, outlen);
  175. } else {
  176. outlen = 2 + (out[1] & 7) * 2;
  177. ue9_checksum_normal(out, outlen);
  178. }
  179. /* Send request */
  180. ret = send_all_timeout(fd, out, outlen, 0, &(struct timeval) {
  181. .tv_sec = TIMEOUT});
  182. if (ret < 0 || ret != outlen) {
  183. verb("short send %d\n", (int)ret);
  184. return -1;
  185. }
  186. /* Save a few bytes that we'll want to compare against later,
  187. in case the caller passed the same buffer twice. */
  188. saved_1 = out[1];
  189. if (extended)
  190. saved_3 = out[3];
  191. /* Receive result */
  192. ret = recv_all_timeout(fd, in, inlen, 0, &(struct timeval) {
  193. .tv_sec = TIMEOUT});
  194. if (ret < 0 || ret != inlen) {
  195. verb("short recv %d\n", (int)ret);
  196. return -1;
  197. }
  198. /* Verify it */
  199. if ((in[1] & 0xF8) != (saved_1 & 0xF8))
  200. verb("returned command doesn't match\n");
  201. else if (extended && (in[3] != saved_3))
  202. verb("extended command doesn't match\n");
  203. else if (extended && (inlen != (6 + (in[2]) * 2)))
  204. verb("returned extended data is the wrong len\n");
  205. else if (!extended && (inlen != (2 + (in[1] & 7) * 2)))
  206. verb("returned data is the wrong len\n");
  207. else if (extended && !ue9_verify_extended(in, inlen))
  208. verb("extended checksum is invalid\n");
  209. else if (!ue9_verify_normal(in, extended ? 6 : inlen))
  210. verb("normal checksum is invalid\n");
  211. else
  212. return 0; /* looks good */
  213. return -1;
  214. }
  215. /* Read a memory block from the device. Returns -1 on error. */
  216. int ue9_memory_read(int fd, int blocknum, uint8_t * buffer, int len)
  217. {
  218. uint8_t sendbuf[8], recvbuf[136];
  219. if (len != 128) {
  220. fprintf(stderr, "ue9_memory_read: buffer length must be 128\n");
  221. exit(1);
  222. }
  223. /* Request memory block */
  224. sendbuf[1] = 0xf8;
  225. sendbuf[2] = 0x01;
  226. sendbuf[3] = 0x2a;
  227. sendbuf[6] = 0x00;
  228. sendbuf[7] = blocknum;
  229. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  230. verb("command failed\n");
  231. return -1;
  232. }
  233. /* Got it */
  234. memcpy(buffer, recvbuf + 8, len);
  235. return 0;
  236. }
  237. /* Convert 64-bit fixed point to double type */
  238. double ue9_fp64_to_double(uint8_t * data)
  239. {
  240. int32_t a;
  241. uint32_t b;
  242. a = (data[7] << 24) | (data[6] << 16) | (data[5] << 8) | data[4];
  243. b = (data[3] << 24) | (data[2] << 16) | (data[1] << 8) | data[0];
  244. return (double)a + (double)b / (double)4294967296.0L;
  245. }
  246. /* Retrieve calibration data from the device. Returns -1 on error. */
  247. int ue9_get_calibration(int fd, struct ue9Calibration *calib)
  248. {
  249. uint8_t buf[128];
  250. /* Block 0 */
  251. if (ue9_memory_read(fd, 0, buf, 128) < 0)
  252. return -1;
  253. calib->unipolarSlope[0] = ue9_fp64_to_double(buf + 0);
  254. calib->unipolarOffset[0] = ue9_fp64_to_double(buf + 8);
  255. calib->unipolarSlope[1] = ue9_fp64_to_double(buf + 16);
  256. calib->unipolarOffset[1] = ue9_fp64_to_double(buf + 24);
  257. calib->unipolarSlope[2] = ue9_fp64_to_double(buf + 32);
  258. calib->unipolarOffset[2] = ue9_fp64_to_double(buf + 40);
  259. calib->unipolarSlope[3] = ue9_fp64_to_double(buf + 48);
  260. calib->unipolarOffset[3] = ue9_fp64_to_double(buf + 56);
  261. /* Block 1 */
  262. if (ue9_memory_read(fd, 1, buf, 128) < 0)
  263. return -1;
  264. calib->bipolarSlope = ue9_fp64_to_double(buf + 0);
  265. calib->bipolarOffset = ue9_fp64_to_double(buf + 8);
  266. /* Block 2 */
  267. if (ue9_memory_read(fd, 2, buf, 128) < 0)
  268. return -1;
  269. calib->DACSlope[0] = ue9_fp64_to_double(buf + 0);
  270. calib->DACOffset[0] = ue9_fp64_to_double(buf + 8);
  271. calib->DACSlope[1] = ue9_fp64_to_double(buf + 16);
  272. calib->DACOffset[1] = ue9_fp64_to_double(buf + 24);
  273. calib->tempSlope = ue9_fp64_to_double(buf + 32);
  274. calib->tempSlopeLow = ue9_fp64_to_double(buf + 48);
  275. calib->calTemp = ue9_fp64_to_double(buf + 64);
  276. calib->Vref = ue9_fp64_to_double(buf + 72);
  277. calib->VrefDiv2 = ue9_fp64_to_double(buf + 88);
  278. calib->VsSlope = ue9_fp64_to_double(buf + 96);
  279. /* Block 3 */
  280. if (ue9_memory_read(fd, 3, buf, 128) < 0)
  281. return -1;
  282. calib->hiResUnipolarSlope = ue9_fp64_to_double(buf + 0);
  283. calib->hiResUnipolarOffset = ue9_fp64_to_double(buf + 8);
  284. /* Block 4 */
  285. if (ue9_memory_read(fd, 4, buf, 128) < 0)
  286. return -1;
  287. calib->hiResBipolarSlope = ue9_fp64_to_double(buf + 0);
  288. calib->hiResBipolarOffset = ue9_fp64_to_double(buf + 8);
  289. /* All done */
  290. return 1;
  291. }
  292. /* Retrieve comm config, returns -1 on error */
  293. int ue9_get_comm_config(int fd, struct ue9CommConfig *config)
  294. {
  295. uint8_t sendbuf[18];
  296. uint8_t recvbuf[24];
  297. memset(sendbuf, 0, sizeof(sendbuf));
  298. memset(config, 0, sizeof(struct ue9CommConfig));
  299. sendbuf[1] = 0xf8;
  300. sendbuf[2] = 0x09;
  301. sendbuf[3] = 0x08;
  302. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  303. verb("command failed\n");
  304. return -1;
  305. }
  306. verb("todo\n");
  307. return -1;
  308. }
  309. /* Retrieve control config, returns -1 on error */
  310. int ue9_get_control_config(int fd, struct ue9ControlConfig *config)
  311. {
  312. uint8_t sendbuf[18];
  313. uint8_t recvbuf[24];
  314. memset(sendbuf, 0, sizeof(sendbuf));
  315. memset(config, 0, sizeof(struct ue9ControlConfig));
  316. sendbuf[1] = 0xf8;
  317. sendbuf[2] = 0x06;
  318. sendbuf[3] = 0x08;
  319. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  320. verb("command failed\n");
  321. return -1;
  322. }
  323. verb("todo\n");
  324. return -1;
  325. }
  326. /* Open TCP/IP connection to the UE9 */
  327. int ue9_open(const char *host, int port)
  328. {
  329. int fd;
  330. struct sockaddr_in address;
  331. struct hostent *he;
  332. int window_size = 128 * 1024;
  333. net_init();
  334. /* Create socket */
  335. fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  336. if (fd < 0) {
  337. verb("socket returned %d\n", fd);
  338. return -1;
  339. }
  340. /* Set nonblocking */
  341. if (soblock(fd, 0) < 0) {
  342. verb("can't set nonblocking\n");
  343. close(fd);
  344. return -1;
  345. }
  346. /* Set initial window size hint to workaround LabJack firmware bug */
  347. setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&window_size,
  348. sizeof(window_size));
  349. setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&window_size,
  350. sizeof(window_size));
  351. /* Resolve host */
  352. address.sin_family = AF_INET;
  353. address.sin_port = htons(port);
  354. he = gethostbyname(host);
  355. if (he == NULL) {
  356. verb("gethostbyname(\"%s\") failed\n", host);
  357. close(fd);
  358. return -1;
  359. }
  360. address.sin_addr = *((struct in_addr *)he->h_addr);
  361. debug("Resolved %s -> %s\n", host, inet_ntoa(address.sin_addr));
  362. /* Connect */
  363. if (connect_timeout(fd, (struct sockaddr *)&address, sizeof(address),
  364. &(struct timeval) {
  365. .tv_sec = TIMEOUT}) < 0) {
  366. verb("connection to %s:%d failed: %s\n",
  367. inet_ntoa(address.sin_addr), port, compat_strerror(errno));
  368. close(fd);
  369. return -1;
  370. }
  371. debug("Connected to port %d\n", port);
  372. return fd;
  373. }
  374. /* Close connection to the UE9 */
  375. void ue9_close(int fd)
  376. {
  377. /* does anyone actually call shutdown these days? */
  378. shutdown(fd, 2 /* SHUT_RDWR */ );
  379. close(fd);
  380. }
  381. /* Compute scanrate based on the provided values. */
  382. double ue9_compute_rate(uint8_t scanconfig, uint16_t scaninterval)
  383. {
  384. double clock;
  385. /* A "scan" is across all channels. Each scan is triggered at
  386. a fixed rate, and not affected by the number of channels.
  387. Channels are scanned as quickly as possible. */
  388. switch ((scanconfig >> 3) & 3) {
  389. case 0:
  390. clock = 4e6;
  391. break;
  392. case 1:
  393. clock = 48e6;
  394. break;
  395. case 2:
  396. clock = 750e3;
  397. break;
  398. case 3:
  399. clock = 24e6;
  400. break;
  401. }
  402. if (scanconfig & 0x2)
  403. clock /= 256;
  404. if (scaninterval == 0)
  405. return 0;
  406. return clock / scaninterval;
  407. }
  408. /* Choose the best ScanConfig and ScanInterval parameters for the
  409. desired scanrate. Returns -1 if no valid config found */
  410. int
  411. ue9_choose_scan(double desired_rate, double *actual_rate,
  412. uint8_t * scanconfig, uint16_t * scaninterval)
  413. {
  414. int i;
  415. struct {
  416. double clock;
  417. uint8_t config;
  418. } valid[] = {
  419. {
  420. 48e6, 0x08}, {
  421. 24e6, 0x18}, {
  422. 4e6, 0x00}, {
  423. 750e3, 0x10}, {
  424. 48e6 / 256, 0x0a}, {
  425. 24e6 / 256, 0x1a}, {
  426. 4e6 / 256, 0x02}, {
  427. 750e3 / 256, 0x12}, {
  428. 0, 0}};
  429. /* Start with the fastest clock frequency. If the
  430. scaninterval would be too large, knock it down until it
  431. fits. */
  432. for (i = 0; valid[i].clock != 0; i++) {
  433. double interval = valid[i].clock / desired_rate;
  434. debug("Considering clock %lf (interval %lf)\n",
  435. valid[i].clock, interval);
  436. if (interval >= 0.5 && interval < 65535.5) {
  437. *scaninterval = floor(interval + 0.5);
  438. *scanconfig = valid[i].config;
  439. *actual_rate =
  440. ue9_compute_rate(*scanconfig, *scaninterval);
  441. debug("Config 0x%02x, desired %lf, actual %lf\n",
  442. *scanconfig, desired_rate, *actual_rate);
  443. return 0;
  444. }
  445. }
  446. return -1;
  447. }
  448. /* Flush data buffers */
  449. void ue9_buffer_flush(int fd)
  450. {
  451. uint8_t sendbuf[2], recvbuf[2];
  452. sendbuf[1] = 0x08; /* FlushBuffer */
  453. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  454. verb("command failed\n");
  455. }
  456. }
  457. /* Stop stream. Returns < 0 on failure. */
  458. int ue9_stream_stop(int fd)
  459. {
  460. uint8_t sendbuf[2], recvbuf[4];
  461. sendbuf[1] = 0xB0;
  462. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  463. verb("command failed\n");
  464. return -1;
  465. }
  466. if (recvbuf[2] == STREAM_NOT_RUNNING || recvbuf[2] == 0)
  467. return 0;
  468. debug("error %s\n", ue9_error(recvbuf[2]));
  469. return -recvbuf[2];
  470. }
  471. /* Start stream. Returns < 0 on failure. */
  472. int ue9_stream_start(int fd)
  473. {
  474. uint8_t sendbuf[2], recvbuf[4];
  475. sendbuf[1] = 0xA8;
  476. if (ue9_command(fd, sendbuf, recvbuf, sizeof(recvbuf)) < 0) {
  477. verb("command failed\n");
  478. return -1;
  479. }
  480. if (recvbuf[2] == 0)
  481. return 0;
  482. debug("error %s\n", ue9_error(recvbuf[2]));
  483. return -recvbuf[2];
  484. }
  485. /* "Simple" stream configuration, assumes the channels are all
  486. configured with the same gain. */
  487. int
  488. ue9_streamconfig_simple(int fd, int *channel_list, int channel_count,
  489. uint8_t scanconfig, uint16_t scaninterval, uint8_t gain)
  490. {
  491. int i;
  492. uint8_t buf[256];
  493. /* Set up StreamConfig command with channels and scan options */
  494. buf[1] = 0xF8; /* Extended command */
  495. buf[2] = channel_count + 3; /* Command data words */
  496. buf[3] = 0x11; /* StreamConfig */
  497. buf[6] = channel_count; /* Number of channels */
  498. buf[7] = 12; /* Bit resolution */
  499. buf[8] = 0; /* Extra settling time */
  500. buf[9] = scanconfig;
  501. buf[10] = scaninterval & 0xff;
  502. buf[11] = scaninterval >> 8;
  503. for (i = 0; i < channel_count; i++) {
  504. buf[12 + 2 * i] = channel_list[i]; /* Channel number */
  505. buf[13 + 2 * i] = gain; /* Gain/bipolar setup */
  506. }
  507. /* Send StreamConfig */
  508. if (ue9_command(fd, buf, buf, 8) < 0) {
  509. debug("command failed\n");
  510. return -1;
  511. }
  512. if (buf[6] != 0) {
  513. verb("returned error %s\n", ue9_error(buf[6]));
  514. return -1;
  515. }
  516. return 0;
  517. }
  518. /* Stream configuration, each Analog Input channel can have its own gain. */
  519. int
  520. ue9_streamconfig(int fd, int *channel_list, int channel_count,
  521. uint8_t scanconfig, uint16_t scaninterval, int *gain_list, int gain_count)
  522. {
  523. int i;
  524. uint8_t buf[256];
  525. /* Set up StreamConfig command with channels and scan options */
  526. buf[1] = 0xF8; /* Extended command */
  527. buf[2] = channel_count + 3; /* Command data words */
  528. buf[3] = 0x11; /* StreamConfig */
  529. buf[6] = channel_count; /* Number of channels */
  530. buf[7] = 12; /* Bit resolution */
  531. buf[8] = 0; /* Extra settling time */
  532. buf[9] = scanconfig;
  533. buf[10] = scaninterval & 0xff;
  534. buf[11] = scaninterval >> 8;
  535. for (i = 0; i < channel_count; i++) {
  536. buf[12 + 2 * i] = channel_list[i]; /* Channel number */
  537. if (i < gain_count) {
  538. switch (gain_list[i]) {
  539. case 0:
  540. buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
  541. break;
  542. case 1:
  543. buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN1;
  544. break;
  545. case 2:
  546. buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN2;
  547. break;
  548. case 4:
  549. buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN4;
  550. break;
  551. case 8:
  552. buf[13 + 2 * i] = UE9_UNIPOLAR_GAIN8;
  553. break;
  554. default:
  555. buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
  556. }
  557. }
  558. else
  559. {
  560. buf[13 + 2 * i] = UE9_BIPOLAR_GAIN1;
  561. }
  562. }
  563. /* Send StreamConfig */
  564. if (ue9_command(fd, buf, buf, 8) < 0) {
  565. debug("command failed\n");
  566. return -1;
  567. }
  568. if (buf[6] != 0) {
  569. verb("returned error %s\n", ue9_error(buf[6]));
  570. return -1;
  571. }
  572. return 0;
  573. }
  574. /* Timer configuration */
  575. int ue9_timer_config(int fd, int *mode_list, int *value_list, int count, int divisor)
  576. {
  577. int i;
  578. uint8_t buf[256];
  579. if (count < 0 || count > 6) {
  580. verb("invalid count\n");
  581. return -1;
  582. }
  583. /* Set up TimerConfig command */
  584. buf[1] = 0xF8; /* Extended command */
  585. buf[2] = 0x0C; /* Command data words */
  586. buf[3] = 0x18; /* TimerConfig */
  587. buf[6] = divisor; /* TimerClockDivisor */
  588. buf[7] = 0x80 | count; /* Number of timers enabled, UpdateConfig=1 */
  589. buf[8] = 0x01; /* TimerClockBase = System 48MHz */
  590. buf[9] = 0x00; /* Don't reset */
  591. for (i = 0; i < 6; i++) {
  592. if (i < count) {
  593. buf[10 + 3 * i] = mode_list[i];
  594. buf[11 + 3 * i] = value_list[i] & 0xff;
  595. buf[12 + 3 * i] = value_list[i] >> 8;
  596. }
  597. else {
  598. buf[10 + 3 * i] = 0;
  599. buf[11 + 3 * i] = 0;
  600. buf[12 + 3 * i] = 0;
  601. }
  602. }
  603. buf[28] = 0;
  604. buf[29] = 0;
  605. /* Send StreamConfig */
  606. if (ue9_command(fd, buf, buf, 40) < 0) {
  607. debug("command failed\n");
  608. return -1;
  609. }
  610. if (buf[6] != 0) {
  611. verb("returned error %s\n", ue9_error(buf[6]));
  612. return -1;
  613. }
  614. debug("timer EnableStatus=0x%02x\n", buf[7]);
  615. return 0;
  616. }
  617. /* Stream data and pass it to the data callback. If callback returns
  618. negative, stops reading and returns 0. Returns < 0 on error. */
  619. int
  620. ue9_stream_data(int fd, int channels, int *channel_list, int gain_count, int *gain_list, ue9_stream_cb_t callback, void *context)
  621. {
  622. int ret;
  623. uint8_t buf[46];
  624. uint8_t packet = 0;
  625. int channel = 0;
  626. int i;
  627. uint16_t data[channels];
  628. for (;;) {
  629. /* Receive data */
  630. ret = recv_all_timeout(fd, buf, 46, 0, &(struct timeval) {
  631. .tv_sec = TIMEOUT});
  632. /* Verify packet format */
  633. if (ret != 46) {
  634. verb("short recv %d\n", (int)ret);
  635. return -1;
  636. }
  637. if (!ue9_verify_extended(buf, 46) || !ue9_verify_normal(buf, 6)) {
  638. verb("bad checksum\n");
  639. return -2;
  640. }
  641. if (buf[1] != 0xF9 || buf[2] != 0x14 || buf[3] != 0xC0) {
  642. verb("bad command bytes\n");
  643. return -3;
  644. }
  645. if (buf[11] != 0) {
  646. verb("stream error: %s\n", ue9_error(buf[11]));
  647. return -4;
  648. }
  649. /* Check for dropped packets. */
  650. if (buf[10] != packet) {
  651. verb("expected packet %d, but received packet %d\n",
  652. packet, buf[10]);
  653. return -5;
  654. }
  655. packet++;
  656. /* Check comm processor backlog (up to 512 kB) */
  657. if (buf[45] & 0x80) {
  658. verb("buffer overflow in CommBacklog, aborting\n");
  659. return -6;
  660. }
  661. if ((buf[45] & 0x7f) > 112)
  662. debug("warning: CommBacklog is high (%d bytes)\n",
  663. (buf[45] & 0x7f) * 4096);
  664. /* Check control processor backlog (up to 256 bytes). */
  665. if (buf[44] == 255) {
  666. verb("ControlBacklog is maxed out, aborting\n");
  667. return -7;
  668. }
  669. if (buf[44] > 224)
  670. debug("warning: ControlBacklog is high (%d bytes)\n",
  671. buf[44]);
  672. /* Read samples from the buffer */
  673. for (i = 12; i <= 42; i += 2) {
  674. data[channel++] = buf[i] + (buf[i + 1] << 8);
  675. if (channel < channels)
  676. continue;
  677. /* Received a full scan, send to callback */
  678. channel = 0;
  679. if ((*callback) (channels, channel_list, gain_count, gain_list, data, context) < 0) {
  680. /* We're done */
  681. return 0;
  682. }
  683. }
  684. }
  685. }
  686. /*
  687. Local variables:
  688. c-basic-offset: 8
  689. End:
  690. */