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.
 
 
 

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