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.
 
 
 

697 lines
16 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 <math.h>
  16. #include "netutil.h"
  17. #include "compat.h"
  18. #include "debug.h"
  19. #include "nerdjack.h"
  20. #include "util.h"
  21. #include "netutil.h"
  22. #include "ethstream.h"
  23. #define NERD_HEADER_SIZE 8
  24. #define MAX_SOCKETS 32
  25. typedef struct __attribute__ ((__packed__)) {
  26. unsigned char headerone;
  27. unsigned char headertwo;
  28. unsigned short packetNumber;
  29. unsigned short adcused;
  30. unsigned short packetsready;
  31. signed short data[NERDJACK_NUM_SAMPLES];
  32. } dataPacket;
  33. struct discovered_socket {
  34. int sock;
  35. uint32_t local_ip;
  36. uint32_t subnet_mask;
  37. };
  38. struct discover_t {
  39. struct discovered_socket socks[MAX_SOCKETS];
  40. unsigned int sock_count;
  41. };
  42. /* Choose the best ScanConfig and ScanInterval parameters for the
  43. desired scanrate. Returns -1 if no valid config found */
  44. int
  45. nerdjack_choose_scan(double desired_rate, double *actual_rate,
  46. unsigned long *period)
  47. {
  48. //The ffffe is because of a silicon bug. The last bit is unusable in all
  49. //devices so far. It is worked around on the chip, but giving it exactly
  50. //0xfffff would cause the workaround code to roll over.
  51. *period = floor((double)NERDJACK_CLOCK_RATE / desired_rate);
  52. if (*period > 0x0ffffe) {
  53. info("Cannot sample that slowly\n");
  54. *actual_rate = (double)NERDJACK_CLOCK_RATE / (double)0x0ffffe;
  55. *period = 0x0ffffe;
  56. return -1;
  57. }
  58. //Period holds the period register for the NerdJack, so it needs to be right
  59. *actual_rate = (double)NERDJACK_CLOCK_RATE / (double)*period;
  60. if (*actual_rate != desired_rate) {
  61. return -1;
  62. }
  63. return 0;
  64. }
  65. /**
  66. * Create a discovered socket and add it to the socket list structure.
  67. * All sockets in the structure should be created, bound, and ready for broadcasting
  68. */
  69. static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip,
  70. uint32_t subnet_mask)
  71. {
  72. if (ds->sock_count >= MAX_SOCKETS) {
  73. return 0;
  74. }
  75. /* Create socket. */
  76. int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
  77. if (sock == -1) {
  78. return 0;
  79. }
  80. /* Allow broadcast. */
  81. int sock_opt = 1;
  82. setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt,
  83. sizeof(sock_opt));
  84. /* Set nonblocking */
  85. if (soblock(sock, 0) < 0) {
  86. verb("can't set nonblocking\n");
  87. return 0;
  88. }
  89. /* Bind socket. */
  90. struct sockaddr_in sock_addr;
  91. memset(&sock_addr, 0, sizeof(sock_addr));
  92. sock_addr.sin_family = AF_INET;
  93. sock_addr.sin_addr.s_addr = htonl(local_ip);
  94. sock_addr.sin_port = htons(0);
  95. if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
  96. close(sock);
  97. return 0;
  98. }
  99. /* Write sock entry. */
  100. struct discovered_socket *dss = &ds->socks[ds->sock_count++];
  101. dss->sock = sock;
  102. dss->local_ip = local_ip;
  103. dss->subnet_mask = subnet_mask;
  104. return 1;
  105. }
  106. /**
  107. * Enumerate all interfaces we can find and open sockets on each
  108. */
  109. #if defined(USE_IPHLPAPI)
  110. static void enumerate_interfaces(struct discover_t *ds)
  111. {
  112. PIP_ADAPTER_INFO pAdapterInfo =
  113. (IP_ADAPTER_INFO *) malloc(sizeof(IP_ADAPTER_INFO));
  114. ULONG ulOutBufLen = sizeof(IP_ADAPTER_INFO);
  115. DWORD Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
  116. if (Ret != NO_ERROR) {
  117. free(pAdapterInfo);
  118. if (Ret != ERROR_BUFFER_OVERFLOW) {
  119. return;
  120. }
  121. pAdapterInfo = (IP_ADAPTER_INFO *) malloc(ulOutBufLen);
  122. Ret = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
  123. if (Ret != NO_ERROR) {
  124. free(pAdapterInfo);
  125. return;
  126. }
  127. }
  128. PIP_ADAPTER_INFO pAdapter = pAdapterInfo;
  129. while (pAdapter) {
  130. IP_ADDR_STRING *pIPAddr = &pAdapter->IpAddressList;
  131. while (pIPAddr) {
  132. uint32_t local_ip =
  133. ntohl(inet_addr(pIPAddr->IpAddress.String));
  134. uint32_t mask =
  135. ntohl(inet_addr(pIPAddr->IpMask.String));
  136. if (local_ip == 0) {
  137. pIPAddr = pIPAddr->Next;
  138. continue;
  139. }
  140. discovered_sock_create(ds, local_ip, mask);
  141. pIPAddr = pIPAddr->Next;
  142. }
  143. pAdapter = pAdapter->Next;
  144. }
  145. free(pAdapterInfo);
  146. }
  147. #else
  148. static void enumerate_interfaces(struct discover_t *ds)
  149. {
  150. int fd = socket(AF_INET, SOCK_DGRAM, 0);
  151. if (fd == -1) {
  152. return;
  153. }
  154. struct ifconf ifc;
  155. uint8_t buf[8192];
  156. ifc.ifc_len = sizeof(buf);
  157. ifc.ifc_buf = (char *)buf;
  158. memset(buf, 0, sizeof(buf));
  159. if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
  160. close(fd);
  161. return;
  162. }
  163. uint8_t *ptr = (uint8_t *) ifc.ifc_req;
  164. uint8_t *end = (uint8_t *) & ifc.ifc_buf[ifc.ifc_len];
  165. while (ptr <= end) {
  166. struct ifreq *ifr = (struct ifreq *)ptr;
  167. ptr += _SIZEOF_ADDR_IFREQ(*ifr);
  168. if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
  169. continue;
  170. }
  171. struct sockaddr_in *addr_in =
  172. (struct sockaddr_in *)&(ifr->ifr_addr);
  173. uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
  174. if (local_ip == 0) {
  175. continue;
  176. }
  177. if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
  178. continue;
  179. }
  180. struct sockaddr_in *mask_in =
  181. (struct sockaddr_in *)&(ifr->ifr_addr);
  182. uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
  183. discovered_sock_create(ds, local_ip, mask);
  184. }
  185. }
  186. #endif
  187. /**
  188. * Close all sockets previously enumerated and free the struct
  189. */
  190. static void destroy_socks(struct discover_t *ds)
  191. {
  192. unsigned int i;
  193. for (i = 0; i < ds->sock_count; i++) {
  194. struct discovered_socket *dss = &ds->socks[i];
  195. close(dss->sock);
  196. }
  197. free(ds);
  198. }
  199. /* Perform autodetection. Returns 0 on success, -1 on error
  200. * Sets ipAddress to the detected address
  201. */
  202. int nerdjack_detect(char *ipAddress)
  203. {
  204. int32_t receivesock;
  205. struct sockaddr_in sa, receiveaddr, sFromAddr;
  206. int buffer_length;
  207. char buffer[200];
  208. char incomingData[10];
  209. socklen_t lFromLen;
  210. sprintf(buffer, "TEST");
  211. buffer_length = strlen(buffer) + 1;
  212. net_init();
  213. receivesock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  214. /* Set nonblocking */
  215. if (soblock(receivesock, 0) < 0) {
  216. verb("can't set nonblocking\n");
  217. return -1;
  218. }
  219. if (-1 == receivesock) { /* if socket failed to initialize, exit */
  220. verb("Error Creating Socket\n");
  221. return -1;
  222. }
  223. //Setup family for both sockets
  224. sa.sin_family = PF_INET;
  225. receiveaddr.sin_family = PF_INET;
  226. //Setup ports to send on DATA and receive on RECEIVE
  227. receiveaddr.sin_port = htons(NERDJACK_UDP_RECEIVE_PORT);
  228. sa.sin_port = htons(NERDJACK_DATA_PORT);
  229. //Receive from any IP address
  230. receiveaddr.sin_addr.s_addr = INADDR_ANY;
  231. bind(receivesock, (struct sockaddr *)&receiveaddr,
  232. sizeof(struct sockaddr_in));
  233. struct discover_t *ds =
  234. (struct discover_t *)calloc(1, sizeof(struct discover_t));
  235. if (!ds) {
  236. return -1;
  237. }
  238. /* Create a routable broadcast socket. */
  239. if (!discovered_sock_create(ds, 0, 0)) {
  240. free(ds);
  241. return -1;
  242. }
  243. /* Detect & create local sockets. */
  244. enumerate_interfaces(ds);
  245. /*
  246. * Send subnet broadcast using each local ip socket.
  247. * This will work with multiple separate 169.254.x.x interfaces.
  248. */
  249. unsigned int i;
  250. for (i = 0; i < ds->sock_count; i++) {
  251. struct discovered_socket *dss = &ds->socks[i];
  252. uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
  253. sa.sin_addr.s_addr = htonl(target_ip);
  254. sendto(dss->sock, buffer, buffer_length, 0,
  255. (struct sockaddr *)&sa, sizeof(struct sockaddr_in));
  256. }
  257. destroy_socks(ds);
  258. lFromLen = sizeof(sFromAddr);
  259. if (0 >
  260. recvfrom_timeout(receivesock, incomingData, sizeof(incomingData), 0,
  261. (struct sockaddr *)&sFromAddr, &lFromLen,
  262. &(struct timeval) {
  263. .tv_sec = TIMEOUT})) {
  264. close(receivesock);
  265. return -1;
  266. }
  267. ipAddress = malloc(INET_ADDRSTRLEN);
  268. //It isn't ipv6 friendly, but inet_ntop isn't on Windows...
  269. strcpy(ipAddress, inet_ntoa(sFromAddr.sin_addr));
  270. close(receivesock);
  271. return 0;
  272. }
  273. /*
  274. * Get the NerdJack version string and print it
  275. */
  276. int nerd_get_version(const char *address)
  277. {
  278. int ret, fd_command;
  279. char buf[200];
  280. fd_command = nerd_open(address, NERDJACK_COMMAND_PORT);
  281. if (fd_command < 0) {
  282. info("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
  283. return -2;
  284. }
  285. /* Send request */
  286. ret = send_all_timeout(fd_command, "VERS", 4, 0, &(struct timeval) {
  287. .tv_sec = TIMEOUT});
  288. if (ret < 0) {
  289. verb("short send %d\n", (int)ret);
  290. return -1;
  291. }
  292. ret = recv_all_timeout(fd_command, buf, 200, 0, &(struct timeval) {
  293. .tv_sec = TIMEOUT});
  294. nerd_close_conn(fd_command);
  295. if (ret < 0) {
  296. verb("Error receiving command\n");
  297. return -1;
  298. }
  299. //Slice off the "OK" from the string
  300. buf[strlen(buf) - 2] = '\0';
  301. printf("%s\n", buf);
  302. return 0;
  303. }
  304. /* Send the given command to address. The command should be something
  305. * of the specified length. This expects the NerdJack to reply with OK
  306. * or NO
  307. */
  308. int nerd_send_command(const char *address, void *command, int length)
  309. {
  310. int ret, fd_command;
  311. char buf[3];
  312. fd_command = nerd_open(address, NERDJACK_COMMAND_PORT);
  313. if (fd_command < 0) {
  314. info("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT);
  315. return -2;
  316. }
  317. /* Send request */
  318. ret = send_all_timeout(fd_command, command, length, 0, &(struct timeval) {
  319. .tv_sec = TIMEOUT});
  320. if (ret < 0 || ret != length) {
  321. verb("short send %d\n", (int)ret);
  322. return -1;
  323. }
  324. ret = recv_all_timeout(fd_command, buf, 3, 0, &(struct timeval) {
  325. .tv_sec = TIMEOUT});
  326. nerd_close_conn(fd_command);
  327. if (ret < 0 || ret != 3) {
  328. verb("Error receiving OK for command\n");
  329. return -1;
  330. }
  331. if (0 != strcmp("OK", buf)) {
  332. verb("Did not receive OK. Received %s\n", buf);
  333. return -4;
  334. }
  335. return 0;
  336. }
  337. int
  338. nerd_data_stream(int data_fd, int numChannels, int *channel_list,
  339. int precision, int convert, int lines, int showmem,
  340. unsigned short *currentcount, unsigned int period,
  341. int wasreset)
  342. {
  343. //Variables that should persist across retries
  344. static dataPacket buf;
  345. static int linesleft = 0;
  346. static int linesdumped = 0;
  347. //Variables essential to packet processing
  348. signed short datapoint = 0;
  349. int i;
  350. int numChannelsSampled = channel_list[0] + 1;
  351. //The number sampled will be the highest channel requested plus 1
  352. //(i.e. channel 0 requested means 1 sampled)
  353. for (i = 0; i < numChannels; i++) {
  354. if (channel_list[i] + 1 > numChannelsSampled)
  355. numChannelsSampled = channel_list[i] + 1;
  356. }
  357. double voltline[numChannels];
  358. unsigned short dataline[numChannels];
  359. unsigned short packetsready = 0;
  360. unsigned short adcused = 0;
  361. unsigned short tempshort = 0;
  362. int charsread = 0;
  363. int numgroupsProcessed = 0;
  364. double volts;
  365. //The timeout should be the expected time plus 60 seconds
  366. //This permits slower speeds to work properly
  367. unsigned int expectedtimeout =
  368. (period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 60;
  369. //Check to see if we're trying to resume
  370. //Don't blow away linesleft in that case
  371. if (lines != 0 && linesleft == 0) {
  372. linesleft = lines;
  373. }
  374. //If there was a reset, we still need to dump a line because of faulty PDCA start
  375. if (wasreset) {
  376. linesdumped = 0;
  377. }
  378. //If this is the first time called, warn the user if we're too fast
  379. if (linesdumped == 0) {
  380. if (period < (numChannelsSampled * 200 + 600)) {
  381. info("You are sampling close to the limit of NerdJack\n");
  382. info("Sample fewer channels or sample slower\n");
  383. }
  384. }
  385. //Now destination structure array is set as well as numDuplicates.
  386. int totalGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled;
  387. //Loop forever to grab data
  388. while ((charsread =
  389. recv_all_timeout(data_fd, &buf, NERDJACK_PACKET_SIZE, 0,
  390. &(struct timeval) {
  391. .tv_sec = expectedtimeout}))) {
  392. if (charsread != NERDJACK_PACKET_SIZE) {
  393. //There was a problem getting data. Probably a closed
  394. //connection.
  395. info("Packet timed out or was too short\n");
  396. return -2;
  397. }
  398. //First check the header info
  399. if (buf.headerone != 0xF0 || buf.headertwo != 0xAA) {
  400. info("No Header info\n");
  401. return -1;
  402. }
  403. //Check counter info to make sure not out of order
  404. tempshort = ntohs(buf.packetNumber);
  405. if (tempshort != *currentcount) {
  406. info("Count wrong. Expected %hd but got %hd\n",
  407. *currentcount, tempshort);
  408. return -1;
  409. }
  410. //Increment number of packets received
  411. *currentcount = *currentcount + 1;
  412. adcused = ntohs(buf.adcused);
  413. packetsready = ntohs(buf.packetsready);
  414. numgroupsProcessed = 0;
  415. if (showmem) {
  416. printf("%hd %hd\n", adcused, packetsready);
  417. continue;
  418. }
  419. //While there is still more data in the packet, process it
  420. while (numgroupsProcessed < totalGroups) {
  421. //Poison the data structure
  422. switch (convert) {
  423. case CONVERT_VOLTS:
  424. memset(voltline, 0,
  425. numChannels * sizeof(double));
  426. break;
  427. default:
  428. case CONVERT_HEX:
  429. case CONVERT_DEC:
  430. memset(dataline, 0,
  431. numChannels * sizeof(unsigned char));
  432. }
  433. //Read in each group
  434. for (i = 0; i < numChannels; i++) {
  435. //Get the datapoint associated with the desired channel
  436. datapoint =
  437. ntohs(buf.data[channel_list[i] +
  438. numgroupsProcessed *
  439. numChannelsSampled]);
  440. //Place it into the line
  441. switch (convert) {
  442. case CONVERT_VOLTS:
  443. if (channel_list[i] <= 5) {
  444. volts =
  445. (double)(datapoint /
  446. 32767.0) *
  447. ((precision & 0x01) ? 5.0 :
  448. 10.0);
  449. } else {
  450. volts =
  451. (double)(datapoint /
  452. 32767.0) *
  453. ((precision & 0x02) ? 5.0 :
  454. 10.0);
  455. }
  456. voltline[i] = volts;
  457. break;
  458. default:
  459. case CONVERT_HEX:
  460. case CONVERT_DEC:
  461. dataline[i] =
  462. (unsigned short)(datapoint -
  463. INT16_MIN);
  464. break;
  465. }
  466. }
  467. //We want to dump the first line because it's usually spurious
  468. if (linesdumped != 0) {
  469. //Now print the group
  470. switch (convert) {
  471. case CONVERT_VOLTS:
  472. for (i = 0; i < numChannels; i++) {
  473. if (printf("%lf ", voltline[i])
  474. < 0)
  475. goto bad;
  476. }
  477. break;
  478. case CONVERT_HEX:
  479. for (i = 0; i < numChannels; i++) {
  480. if (printf("%04hX", dataline[i])
  481. < 0)
  482. goto bad;
  483. }
  484. break;
  485. default:
  486. case CONVERT_DEC:
  487. for (i = 0; i < numChannels; i++) {
  488. if (printf("%hu ", dataline[i])
  489. < 0)
  490. goto bad;
  491. }
  492. break;
  493. }
  494. if (printf("\n") < 0)
  495. goto bad;
  496. //If we're counting lines, decrement them
  497. if (lines != 0) {
  498. linesleft--;
  499. if (linesleft == 0) {
  500. return 0;
  501. }
  502. }
  503. } else {
  504. linesdumped = linesdumped + 1;
  505. }
  506. //We've processed this group, so advance the counter
  507. numgroupsProcessed++;
  508. }
  509. }
  510. return 0;
  511. bad:
  512. info("Output error (disk full?)\n");
  513. return -3;
  514. }
  515. /* Open a connection to the NerdJack */
  516. int nerd_open(const char *address, int port)
  517. {
  518. struct hostent *he;
  519. net_init();
  520. int32_t i32SocketFD = socket(PF_INET, SOCK_STREAM, 0);
  521. if (-1 == i32SocketFD) {
  522. verb("cannot create socket");
  523. return -1;
  524. }
  525. /* Set nonblocking */
  526. if (soblock(i32SocketFD, 0) < 0) {
  527. verb("can't set nonblocking\n");
  528. return -1;
  529. }
  530. struct sockaddr_in stSockAddr;
  531. memset(&stSockAddr, 0, sizeof(stSockAddr));
  532. stSockAddr.sin_family = AF_INET;
  533. stSockAddr.sin_port = htons(port);
  534. he = gethostbyname(address);
  535. if (he == NULL) {
  536. verb("gethostbyname(\"%s\") failed\n", address);
  537. return -1;
  538. }
  539. stSockAddr.sin_addr = *((struct in_addr *)he->h_addr);
  540. debug("Resolved %s -> %s\n", address, inet_ntoa(stSockAddr.sin_addr));
  541. /* Connect */
  542. if (connect_timeout
  543. (i32SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr),
  544. &(struct timeval) {
  545. .tv_sec = 3}) < 0) {
  546. verb("connection to %s:%d failed: %s\n",
  547. inet_ntoa(stSockAddr.sin_addr), port,
  548. compat_strerror(errno));
  549. return -1;
  550. }
  551. return i32SocketFD;
  552. }
  553. //Generate an appropriate sample initiation command
  554. int
  555. nerd_generate_command(getPacket * command, int *channel_list,
  556. int channel_count, int precision, unsigned long period)
  557. {
  558. short channelbit = 0;
  559. int i;
  560. int highestchannel = 0;
  561. for (i = 0; i < channel_count; i++) {
  562. if (channel_list[i] > highestchannel) {
  563. highestchannel = channel_list[i];
  564. }
  565. //channelbit = channelbit | (0x1 << channel_list[i]);
  566. }
  567. for (i = 0; i <= highestchannel; i++) {
  568. channelbit = channelbit | (0x01 << i);
  569. }
  570. command->word[0] = 'G';
  571. command->word[1] = 'E';
  572. command->word[2] = 'T';
  573. command->word[3] = 'D';
  574. command->channelbit = htons(channelbit);
  575. command->precision = precision;
  576. command->period = htonl(period);
  577. command->prescaler = 0;
  578. return 0;
  579. }
  580. int nerd_close_conn(int data_fd)
  581. {
  582. shutdown(data_fd, 2);
  583. close(data_fd);
  584. return 0;
  585. }