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.
 
 
 

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