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.
 
 
 

806 lines
19 KiB

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