git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7298 ddd99763-3ecb-0310-9145-efcb8ce7c51ftags/ethstream-1.1
@@ -3,55 +3,83 @@ | |||
#include "compat.h" | |||
#include <windows.h> | |||
unsigned int sleep(unsigned int seconds) | |||
unsigned int | |||
sleep (unsigned int seconds) | |||
{ | |||
Sleep(seconds * 1000); | |||
return 0; | |||
Sleep (seconds * 1000); | |||
return 0; | |||
} | |||
static struct { | |||
int num; | |||
char *msg; | |||
} win32_error[] = { | |||
/* Errors that we might vaguely expect to see */ | |||
{ WSAEINTR, "Winsock: Interrupted system call" }, | |||
{ WSAEBADF, "Winsock: Bad file number" }, | |||
{ WSAEFAULT, "Winsock: Bad address" }, | |||
{ WSAEINVAL, "Winsock: Invalid argument" }, | |||
{ WSAEMFILE, "Winsock: Too many open files" }, | |||
{ WSAEWOULDBLOCK, "Winsock: Operation would block" }, | |||
{ WSAEINPROGRESS, "Winsock: Operation now in progress" }, | |||
{ WSAEALREADY, "Winsock: Operation already in progress" }, | |||
{ WSAENOTSOCK, "Winsock: Socket operation on nonsocket" }, | |||
{ WSAEADDRINUSE, "Winsock: Address already in use" }, | |||
{ WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address" }, | |||
{ WSAENETDOWN, "Winsock: Network is down" }, | |||
{ WSAENETUNREACH, "Winsock: Network is unreachable" }, | |||
{ WSAENETRESET, "Winsock: Network dropped connection on reset" }, | |||
{ WSAECONNABORTED, "Winsock: Software caused connection abort" }, | |||
{ WSAECONNRESET, "Winsock: Connection reset by peer" }, | |||
{ WSAETIMEDOUT, "Winsock: Connection timed out" }, | |||
{ WSAECONNREFUSED, "Winsock: Connection refused" }, | |||
{ WSAEHOSTDOWN, "Winsock: Host is down" }, | |||
{ WSAEHOSTUNREACH, "Winsock: No route to host" }, | |||
{ WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version" }, | |||
{ ETIMEDOUT, "Connection timed out" }, | |||
{ ENOTCONN, "Not connected" }, | |||
{ -1, NULL }, | |||
}; | |||
char *compat_strerror(int errnum) | |||
static struct | |||
{ | |||
int i; | |||
static char buf[128]; | |||
for (i = 0; win32_error[i].num != -1; i++) | |||
if (errnum == win32_error[i].num) | |||
return win32_error[i].msg; | |||
if (errnum >= 10000) { | |||
sprintf(buf, "Winsock: unknown error %d\n", errnum); | |||
return buf; | |||
} | |||
return strerror(errnum); | |||
int num; | |||
char *msg; | |||
} win32_error[] = | |||
{ | |||
/* Errors that we might vaguely expect to see */ | |||
{ | |||
WSAEINTR, "Winsock: Interrupted system call"}, | |||
{ | |||
WSAEBADF, "Winsock: Bad file number"}, | |||
{ | |||
WSAEFAULT, "Winsock: Bad address"}, | |||
{ | |||
WSAEINVAL, "Winsock: Invalid argument"}, | |||
{ | |||
WSAEMFILE, "Winsock: Too many open files"}, | |||
{ | |||
WSAEWOULDBLOCK, "Winsock: Operation would block"}, | |||
{ | |||
WSAEINPROGRESS, "Winsock: Operation now in progress"}, | |||
{ | |||
WSAEALREADY, "Winsock: Operation already in progress"}, | |||
{ | |||
WSAENOTSOCK, "Winsock: Socket operation on nonsocket"}, | |||
{ | |||
WSAEADDRINUSE, "Winsock: Address already in use"}, | |||
{ | |||
WSAEADDRNOTAVAIL, "Winsock: Cannot assign requested address"}, | |||
{ | |||
WSAENETDOWN, "Winsock: Network is down"}, | |||
{ | |||
WSAENETUNREACH, "Winsock: Network is unreachable"}, | |||
{ | |||
WSAENETRESET, "Winsock: Network dropped connection on reset"}, | |||
{ | |||
WSAECONNABORTED, "Winsock: Software caused connection abort"}, | |||
{ | |||
WSAECONNRESET, "Winsock: Connection reset by peer"}, | |||
{ | |||
WSAETIMEDOUT, "Winsock: Connection timed out"}, | |||
{ | |||
WSAECONNREFUSED, "Winsock: Connection refused"}, | |||
{ | |||
WSAEHOSTDOWN, "Winsock: Host is down"}, | |||
{ | |||
WSAEHOSTUNREACH, "Winsock: No route to host"}, | |||
{ | |||
WSAVERNOTSUPPORTED, "Winsock: Unsupported Winsock version"}, | |||
{ | |||
ETIMEDOUT, "Connection timed out"}, | |||
{ | |||
ENOTCONN, "Not connected"}, | |||
{ | |||
-1, NULL},}; | |||
char * | |||
compat_strerror (int errnum) | |||
{ | |||
int i; | |||
static char buf[128]; | |||
for (i = 0; win32_error[i].num != -1; i++) | |||
if (errnum == win32_error[i].num) | |||
return win32_error[i].msg; | |||
if (errnum >= 10000) | |||
{ | |||
sprintf (buf, "Winsock: unknown error %d\n", errnum); | |||
return buf; | |||
} | |||
return strerror (errnum); | |||
} | |||
#ifdef __WIN32__ | |||
@@ -80,4 +108,3 @@ char *compat_strerror(int errnum) | |||
} | |||
*/ | |||
#endif | |||
@@ -2,8 +2,8 @@ | |||
#define COMPAT_H | |||
#ifdef __WIN32__ | |||
unsigned int sleep(unsigned int seconds); | |||
char *compat_strerror(int errnum); | |||
unsigned int sleep (unsigned int seconds); | |||
char *compat_strerror (int errnum); | |||
//const char *inet_ntop(int af, void *src, const char *dst, socklen_t cnt); | |||
#define INET_ADDRSTRLEN 16 | |||
#define ETIMEDOUT 110 | |||
@@ -4,15 +4,15 @@ | |||
int verb_count = 0; | |||
int func_fprintf(const char *func, FILE *stream, const char *format, ...) | |||
int | |||
func_fprintf (const char *func, FILE * stream, const char *format, ...) | |||
{ | |||
va_list ap; | |||
int ret; | |||
va_list ap; | |||
int ret; | |||
fprintf(stream, "%s: ", func); | |||
va_start(ap, format); | |||
ret = vfprintf(stream, format, ap); | |||
va_end(ap); | |||
return ret; | |||
fprintf (stream, "%s: ", func); | |||
va_start (ap, format); | |||
ret = vfprintf (stream, format, ap); | |||
va_end (ap); | |||
return ret; | |||
} | |||
@@ -14,8 +14,8 @@ extern int verb_count; | |||
#include <stdio.h> | |||
int func_fprintf(const char *func, FILE *stream, const char *format, | |||
...) __attribute__ ((format (printf, 3, 4))); | |||
int func_fprintf (const char *func, FILE * stream, const char *format, | |||
...) __attribute__ ((format (printf, 3, 4))); | |||
#define debug(x...) ({ \ | |||
if(verb_count >= 2) \ | |||
@@ -25,74 +25,78 @@ | |||
#define UE9_COMMAND_PORT 52360 | |||
struct options opt[] = { | |||
{ 'a', "address", "string", "host/address of UE9 (192.168.1.209)" }, | |||
{ 'h', "help", NULL, "this help" }, | |||
{ 'v', "verbose", NULL, "be verbose" }, | |||
{ 'V', "version", NULL, "show version number and exit" }, | |||
{ 0, NULL, NULL, NULL } | |||
{'a', "address", "string", "host/address of UE9 (192.168.1.209)"}, | |||
{'h', "help", NULL, "this help"}, | |||
{'v', "verbose", NULL, "be verbose"}, | |||
{'V', "version", NULL, "show version number and exit"}, | |||
{0, NULL, NULL, NULL} | |||
}; | |||
int main(int argc, char *argv[]) | |||
int | |||
main (int argc, char *argv[]) | |||
{ | |||
int optind; | |||
char *optarg; | |||
char c; | |||
FILE *help = stderr; | |||
char *address = strdup(DEFAULT_HOST); | |||
int fd; | |||
int ret; | |||
int optind; | |||
char *optarg; | |||
char c; | |||
FILE *help = stderr; | |||
char *address = strdup (DEFAULT_HOST); | |||
int fd; | |||
int ret; | |||
/* Parse arguments */ | |||
opt_init(&optind); | |||
while ((c = opt_parse(argc, argv, &optind, &optarg, opt)) != 0) { | |||
switch (c) { | |||
case 'a': | |||
free(address); | |||
address = strdup(optarg); | |||
break; | |||
case 'v': | |||
verb_count++; | |||
break; | |||
case 'V': | |||
printf("ljconfig " VERSION "\n"); | |||
printf("Written by Jim Paris <jim@jtan.com>\n"); | |||
printf("This program comes with no warranty and is " | |||
"provided under the GPLv2.\n"); | |||
return 0; | |||
break; | |||
case 'h': | |||
help = stdout; | |||
default: | |||
printhelp: | |||
fprintf(help, "Usage: %s [options]\n", *argv); | |||
opt_help(opt, help); | |||
fprintf(help, "Displays/changes Labjack UE9 config.\n"); | |||
return (help == stdout) ? 0 : 1; | |||
} | |||
/* Parse arguments */ | |||
opt_init (&optind); | |||
while ((c = opt_parse (argc, argv, &optind, &optarg, opt)) != 0) | |||
{ | |||
switch (c) | |||
{ | |||
case 'a': | |||
free (address); | |||
address = strdup (optarg); | |||
break; | |||
case 'v': | |||
verb_count++; | |||
break; | |||
case 'V': | |||
printf ("ljconfig " VERSION "\n"); | |||
printf ("Written by Jim Paris <jim@jtan.com>\n"); | |||
printf ("This program comes with no warranty and is " | |||
"provided under the GPLv2.\n"); | |||
return 0; | |||
break; | |||
case 'h': | |||
help = stdout; | |||
default: | |||
printhelp: | |||
fprintf (help, "Usage: %s [options]\n", *argv); | |||
opt_help (opt, help); | |||
fprintf (help, "Displays/changes Labjack UE9 config.\n"); | |||
return (help == stdout) ? 0 : 1; | |||
} | |||
} | |||
if(optind<argc) { | |||
info("Error: too many arguments (%s)\n\n", argv[optind]); | |||
goto printhelp; | |||
} | |||
ret = 1; | |||
if (optind < argc) | |||
{ | |||
info ("Error: too many arguments (%s)\n\n", argv[optind]); | |||
goto printhelp; | |||
} | |||
/* Open */ | |||
fd = ue9_open(address, UE9_COMMAND_PORT); | |||
if (fd < 0) { | |||
info("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT); | |||
goto out0; | |||
} | |||
ret = 1; | |||
goto out1; | |||
ret = 0; | |||
out1: | |||
/* Close */ | |||
ue9_close(fd); | |||
out0: | |||
return ret; | |||
} | |||
/* Open */ | |||
fd = ue9_open (address, UE9_COMMAND_PORT); | |||
if (fd < 0) | |||
{ | |||
info ("Connect failed: %s:%d\n", address, UE9_COMMAND_PORT); | |||
goto out0; | |||
} | |||
goto out1; | |||
ret = 0; | |||
out1: | |||
/* Close */ | |||
ue9_close (fd); | |||
out0: | |||
return ret; | |||
} |
@@ -16,52 +16,53 @@ | |||
#include "ue9.h" | |||
#include "compat.h" | |||
int main(int argc, char *argv[]) | |||
int | |||
main (int argc, char *argv[]) | |||
{ | |||
int fd_cmd; | |||
struct ue9Calibration calib; | |||
int fd_cmd; | |||
struct ue9Calibration calib; | |||
verb_count = 2; | |||
verb_count = 2; | |||
fd_cmd = ue9_open("192.168.1.209", 52360); | |||
if (fd_cmd < 0) { | |||
fprintf(stderr, "ue9_open: %s\n", | |||
compat_strerror(errno)); | |||
return 1; | |||
} | |||
fd_cmd = ue9_open ("192.168.1.209", 52360); | |||
if (fd_cmd < 0) | |||
{ | |||
fprintf (stderr, "ue9_open: %s\n", compat_strerror (errno)); | |||
return 1; | |||
} | |||
if (ue9_get_calibration(fd_cmd, &calib) < 0) { | |||
fprintf(stderr, "ue9_get_calibration: %s\n", | |||
compat_strerror(errno)); | |||
return 1; | |||
} | |||
if (ue9_get_calibration (fd_cmd, &calib) < 0) | |||
{ | |||
fprintf (stderr, "ue9_get_calibration: %s\n", compat_strerror (errno)); | |||
return 1; | |||
} | |||
printf("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]); | |||
printf("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]); | |||
printf("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]); | |||
printf("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]); | |||
printf("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]); | |||
printf("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]); | |||
printf("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]); | |||
printf("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]); | |||
printf("double bipolarSlope = %lf\n", calib.bipolarSlope); | |||
printf("double bipolarOffset = %lf\n", calib.bipolarOffset); | |||
printf("double DACSlope[0] = %lf\n", calib.DACSlope[0]); | |||
printf("double DACSlope[1] = %lf\n", calib.DACSlope[1]); | |||
printf("double DACOffset[0] = %lf\n", calib.DACOffset[0]); | |||
printf("double DACOffset[1] = %lf\n", calib.DACOffset[1]); | |||
printf("double tempSlope = %lf\n", calib.tempSlope); | |||
printf("double tempSlopeLow = %lf\n", calib.tempSlopeLow); | |||
printf("double calTemp = %lf\n", calib.calTemp); | |||
printf("double Vref = %lf\n", calib.Vref); | |||
printf("double VrefDiv2 = %lf\n", calib.VrefDiv2); | |||
printf("double VsSlope = %lf\n", calib.VsSlope); | |||
printf("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope); | |||
printf("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset); | |||
printf("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope); | |||
printf("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset); | |||
printf ("double unipolarSlope[0] = %lf\n", calib.unipolarSlope[0]); | |||
printf ("double unipolarSlope[1] = %lf\n", calib.unipolarSlope[1]); | |||
printf ("double unipolarSlope[2] = %lf\n", calib.unipolarSlope[2]); | |||
printf ("double unipolarSlope[3] = %lf\n", calib.unipolarSlope[3]); | |||
printf ("double unipolarOffset[0] = %lf\n", calib.unipolarOffset[0]); | |||
printf ("double unipolarOffset[1] = %lf\n", calib.unipolarOffset[1]); | |||
printf ("double unipolarOffset[2] = %lf\n", calib.unipolarOffset[2]); | |||
printf ("double unipolarOffset[3] = %lf\n", calib.unipolarOffset[3]); | |||
printf ("double bipolarSlope = %lf\n", calib.bipolarSlope); | |||
printf ("double bipolarOffset = %lf\n", calib.bipolarOffset); | |||
printf ("double DACSlope[0] = %lf\n", calib.DACSlope[0]); | |||
printf ("double DACSlope[1] = %lf\n", calib.DACSlope[1]); | |||
printf ("double DACOffset[0] = %lf\n", calib.DACOffset[0]); | |||
printf ("double DACOffset[1] = %lf\n", calib.DACOffset[1]); | |||
printf ("double tempSlope = %lf\n", calib.tempSlope); | |||
printf ("double tempSlopeLow = %lf\n", calib.tempSlopeLow); | |||
printf ("double calTemp = %lf\n", calib.calTemp); | |||
printf ("double Vref = %lf\n", calib.Vref); | |||
printf ("double VrefDiv2 = %lf\n", calib.VrefDiv2); | |||
printf ("double VsSlope = %lf\n", calib.VsSlope); | |||
printf ("double hiResUnipolarSlope = %lf\n", calib.hiResUnipolarSlope); | |||
printf ("double hiResUnipolarOffset = %lf\n", calib.hiResUnipolarOffset); | |||
printf ("double hiResBipolarSlope = %lf\n", calib.hiResBipolarSlope); | |||
printf ("double hiResBipolarOffset = %lf\n", calib.hiResBipolarOffset); | |||
ue9_close(fd_cmd); | |||
ue9_close (fd_cmd); | |||
return 0; | |||
return 0; | |||
} |
@@ -25,464 +25,553 @@ | |||
#include "netutil.h" | |||
#include "ethstream.h" | |||
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */ | |||
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */ | |||
//Struct holding information about how channels should be reordered for output | |||
typedef struct { | |||
int numCopies; | |||
int * destlist; | |||
typedef struct | |||
{ | |||
int numCopies; | |||
int *destlist; | |||
} deststruct; | |||
typedef struct __attribute__((__packed__)) { | |||
unsigned char headerone; | |||
unsigned char headertwo; | |||
unsigned short packetNumber; | |||
unsigned long lwipmemoryused; | |||
unsigned short adcused; | |||
unsigned short packetsready; | |||
signed short data[NERDJACK_NUM_SAMPLES]; | |||
typedef struct __attribute__ ((__packed__)) | |||
{ | |||
unsigned char headerone; | |||
unsigned char headertwo; | |||
unsigned short packetNumber; | |||
unsigned long lwipmemoryused; | |||
unsigned short adcused; | |||
unsigned short packetsready; | |||
signed short data[NERDJACK_NUM_SAMPLES]; | |||
} dataPacket; | |||
/* Choose the best ScanConfig and ScanInterval parameters for the | |||
desired scanrate. Returns -1 if no valid config found */ | |||
int nerdjack_choose_scan(double desired_rate, double *actual_rate, unsigned long *period) | |||
int | |||
nerdjack_choose_scan (double desired_rate, double *actual_rate, | |||
unsigned long *period) | |||
{ | |||
//The ffffe is because of a silicon bug. The last bit is unusable in all | |||
//devices so far. It is worked around on the chip, but giving it exactly | |||
//0xfffff would cause the workaround code to roll over. | |||
*period = floor((double) NERDJACK_CLOCK_RATE / desired_rate); | |||
if(*period > 0x0ffffe) { | |||
info("Cannot sample that slowly\n"); | |||
*actual_rate = (double)NERDJACK_CLOCK_RATE / (double) 0x0ffffe; | |||
*period = 0x0ffffe; | |||
//info("Sampling at slowest rate:%f\n",*actual_rate); | |||
return -1; | |||
//The ffffe is because of a silicon bug. The last bit is unusable in all | |||
//devices so far. It is worked around on the chip, but giving it exactly | |||
//0xfffff would cause the workaround code to roll over. | |||
*period = floor ((double) NERDJACK_CLOCK_RATE / desired_rate); | |||
if (*period > 0x0ffffe) | |||
{ | |||
info ("Cannot sample that slowly\n"); | |||
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) 0x0ffffe; | |||
*period = 0x0ffffe; | |||
//info("Sampling at slowest rate:%f\n",*actual_rate); | |||
return -1; | |||
} | |||
//Period holds the period register for the NerdJack, so it needs to be right | |||
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period; | |||
if(*actual_rate != desired_rate) { | |||
//info("Sampling at nearest rate:%f\n",*actual_rate); | |||
return -1; | |||
} | |||
return 0; | |||
//Period holds the period register for the NerdJack, so it needs to be right | |||
*actual_rate = (double) NERDJACK_CLOCK_RATE / (double) *period; | |||
if (*actual_rate != desired_rate) | |||
{ | |||
//info("Sampling at nearest rate:%f\n",*actual_rate); | |||
return -1; | |||
} | |||
return 0; | |||
} | |||
int nerdjack_detect(char * ipAddress) { | |||
int32_t sock, receivesock; | |||
struct sockaddr_in sa, receiveaddr, sFromAddr; | |||
int bytes_sent, buffer_length; | |||
char buffer[200]; | |||
char incomingData[10]; | |||
unsigned int lFromLen; | |||
sprintf(buffer, "TEST"); | |||
buffer_length = strlen(buffer) + 1; | |||
net_init(); | |||
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | |||
receivesock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | |||
/* Set nonblocking */ | |||
if (soblock(sock, 0) < 0) { | |||
verb("can't set nonblocking\n"); | |||
int | |||
nerdjack_detect (char *ipAddress) | |||
{ | |||
int32_t sock, receivesock; | |||
struct sockaddr_in sa, receiveaddr, sFromAddr; | |||
int bytes_sent, buffer_length; | |||
char buffer[200]; | |||
char incomingData[10]; | |||
unsigned int lFromLen; | |||
sprintf (buffer, "TEST"); | |||
buffer_length = strlen (buffer) + 1; | |||
net_init (); | |||
sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); | |||
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); | |||
/* Set nonblocking */ | |||
if (soblock (sock, 0) < 0) | |||
{ | |||
verb ("can't set nonblocking\n"); | |||
return -1; | |||
} | |||
/* Set nonblocking */ | |||
if (soblock(receivesock, 0) < 0) { | |||
verb("can't set nonblocking\n"); | |||
} | |||
/* Set nonblocking */ | |||
if (soblock (receivesock, 0) < 0) | |||
{ | |||
verb ("can't set nonblocking\n"); | |||
return -1; | |||
} | |||
} | |||
int opt = 1; | |||
setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(void *) &opt,sizeof(int)); | |||
if((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */ | |||
{ | |||
verb("Error Creating Socket\n"); | |||
int opt = 1; | |||
setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (void *) &opt, sizeof (int)); | |||
if ((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */ | |||
{ | |||
verb ("Error Creating Socket\n"); | |||
return -1; | |||
} | |||
//Setup family for both sockets | |||
sa.sin_family = PF_INET; | |||
receiveaddr.sin_family = PF_INET; | |||
//Setup ports to send on DATA and receive on RECEIVE | |||
receiveaddr.sin_port = htons(NERDJACK_UDP_RECEIVE_PORT); | |||
sa.sin_port = htons(NERDJACK_DATA_PORT); | |||
//Receive from any IP address, Will send to broadcast | |||
receiveaddr.sin_addr.s_addr = INADDR_ANY; | |||
sa.sin_addr.s_addr = INADDR_BROADCAST; | |||
bind(receivesock,(struct sockaddr*) &receiveaddr, sizeof(struct sockaddr_in)); | |||
bytes_sent = sendto(sock, buffer, buffer_length, 0,(struct sockaddr*) &sa, sizeof(struct sockaddr_in) ); | |||
if(bytes_sent < 0) { | |||
info("Error sending packet: %s\n", strerror(errno) ); | |||
return -1; | |||
} | |||
} | |||
//Setup family for both sockets | |||
sa.sin_family = PF_INET; | |||
receiveaddr.sin_family = PF_INET; | |||
//Setup ports to send on DATA and receive on RECEIVE | |||
receiveaddr.sin_port = htons (NERDJACK_UDP_RECEIVE_PORT); | |||
sa.sin_port = htons (NERDJACK_DATA_PORT); | |||
//Receive from any IP address, Will send to broadcast | |||
receiveaddr.sin_addr.s_addr = INADDR_ANY; | |||
sa.sin_addr.s_addr = INADDR_BROADCAST; | |||
lFromLen = sizeof(sFromAddr); | |||
if(0 > recvfrom_timeout(receivesock, incomingData, sizeof(incomingData),0,(struct sockaddr *) &sFromAddr, &lFromLen, | |||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT })) { | |||
return -1; | |||
bind (receivesock, (struct sockaddr *) &receiveaddr, | |||
sizeof (struct sockaddr_in)); | |||
bytes_sent = | |||
sendto (sock, buffer, buffer_length, 0, (struct sockaddr *) &sa, | |||
sizeof (struct sockaddr_in)); | |||
if (bytes_sent < 0) | |||
{ | |||
info ("Error sending packet: %s\n", strerror (errno)); | |||
return -1; | |||
} | |||
ipAddress = malloc(INET_ADDRSTRLEN); | |||
//It isn't ipv6 friendly, but inet_ntop isn't on Windows... | |||
strcpy(ipAddress, inet_ntoa(sFromAddr.sin_addr)); | |||
close(sock); /* close the socket */ | |||
close(receivesock); | |||
return 0; | |||
lFromLen = sizeof (sFromAddr); | |||
if (0 > | |||
recvfrom_timeout (receivesock, incomingData, sizeof (incomingData), 0, | |||
(struct sockaddr *) &sFromAddr, &lFromLen, | |||
&(struct timeval) | |||
{ | |||
.tv_sec = NERDJACK_TIMEOUT})) | |||
{ | |||
return -1; | |||
} | |||
ipAddress = malloc (INET_ADDRSTRLEN); | |||
//It isn't ipv6 friendly, but inet_ntop isn't on Windows... | |||
strcpy (ipAddress, inet_ntoa (sFromAddr.sin_addr)); | |||
close (sock); /* close the socket */ | |||
close (receivesock); | |||
return 0; | |||
} | |||
int nerd_send_command(const char * address, void * command, int length) | |||
int | |||
nerd_send_command (const char *address, void *command, int length) | |||
{ | |||
int ret,fd_command; | |||
char buf[3]; | |||
fd_command = nerd_open(address, NERDJACK_COMMAND_PORT); | |||
if (fd_command < 0) { | |||
info("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT); | |||
return -2; | |||
int ret, fd_command; | |||
char buf[3]; | |||
fd_command = nerd_open (address, NERDJACK_COMMAND_PORT); | |||
if (fd_command < 0) | |||
{ | |||
info ("Connect failed: %s:%d\n", address, NERDJACK_COMMAND_PORT); | |||
return -2; | |||
} | |||
/* Send request */ | |||
ret = send_all_timeout(fd_command, command, length, 0, | |||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }); | |||
if (ret < 0 || ret != length) { | |||
verb("short send %d\n", (int)ret); | |||
return -1; | |||
} | |||
/* Send request */ | |||
ret = send_all_timeout (fd_command, command, length, 0, &(struct timeval) | |||
{ | |||
.tv_sec = NERDJACK_TIMEOUT}); | |||
if (ret < 0 || ret != length) | |||
{ | |||
verb ("short send %d\n", (int) ret); | |||
return -1; | |||
} | |||
ret = recv_all_timeout(fd_command,buf,3,0, | |||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }); | |||
ret = recv_all_timeout (fd_command, buf, 3, 0, &(struct timeval) | |||
{ | |||
.tv_sec = NERDJACK_TIMEOUT}); | |||
nerd_close_conn(fd_command); | |||
nerd_close_conn (fd_command); | |||
if (ret < 0 || ret != 3) { | |||
verb("Error receiving OK for command\n"); | |||
return -1; | |||
} | |||
if (ret < 0 || ret != 3) | |||
{ | |||
verb ("Error receiving OK for command\n"); | |||
return -1; | |||
} | |||
if (0 != strcmp("OK",buf)){ | |||
verb("Did not receive OK. Received %s\n",buf); | |||
return -3; | |||
if (0 != strcmp ("OK", buf)) | |||
{ | |||
verb ("Did not receive OK. Received %s\n", buf); | |||
return -3; | |||
} | |||
return 0; | |||
return 0; | |||
} | |||
//Initialize the channel structure to distill how data should be displayed | |||
static void nerd_init_channels(deststruct * destination, int numChannels, int numChannelsSampled, int *channel_list) { | |||
int channelprocessing = 0; | |||
int currentalign = 0; //Index into sampled channels | |||
int i; | |||
int tempdestlist[NERDJACK_CHANNELS]; | |||
//Clear out destination stuff | |||
for(i=0; i < numChannelsSampled;i++) { | |||
destination[i].numCopies = 0; | |||
static void | |||
nerd_init_channels (deststruct * destination, int numChannels, | |||
int numChannelsSampled, int *channel_list) | |||
{ | |||
int channelprocessing = 0; | |||
int currentalign = 0; //Index into sampled channels | |||
int i; | |||
int tempdestlist[NERDJACK_CHANNELS]; | |||
//Clear out destination stuff | |||
for (i = 0; i < numChannelsSampled; i++) | |||
{ | |||
destination[i].numCopies = 0; | |||
} | |||
for(channelprocessing = 0; channelprocessing < numChannelsSampled; channelprocessing++) { | |||
//Find out how many copies of each channel so we malloc the right things | |||
currentalign = 0; | |||
for(i = 0; i < numChannels; i++) { | |||
if(channelprocessing == channel_list[i]) { | |||
tempdestlist[currentalign] = i; | |||
currentalign++; | |||
} | |||
} | |||
//If this channel is wanted, set it up. | |||
if(currentalign > 0) { | |||
destination[channelprocessing].numCopies = currentalign; | |||
destination[channelprocessing].destlist = malloc( destination[channelprocessing].numCopies * sizeof(int) ); | |||
memcpy(destination[channelprocessing].destlist, tempdestlist, destination[channelprocessing].numCopies * sizeof(int) ); | |||
} | |||
for (channelprocessing = 0; channelprocessing < numChannelsSampled; | |||
channelprocessing++) | |||
{ | |||
//Find out how many copies of each channel so we malloc the right things | |||
currentalign = 0; | |||
for (i = 0; i < numChannels; i++) | |||
{ | |||
if (channelprocessing == channel_list[i]) | |||
{ | |||
tempdestlist[currentalign] = i; | |||
currentalign++; | |||
} | |||
} | |||
//If this channel is wanted, set it up. | |||
if (currentalign > 0) | |||
{ | |||
destination[channelprocessing].numCopies = currentalign; | |||
destination[channelprocessing].destlist = | |||
malloc (destination[channelprocessing].numCopies * sizeof (int)); | |||
memcpy (destination[channelprocessing].destlist, tempdestlist, | |||
destination[channelprocessing].numCopies * sizeof (int)); | |||
} | |||
} | |||
return; | |||
return; | |||
} | |||
int nerd_data_stream(int data_fd, int numChannels, int *channel_list, int precision, int convert, int lines, int showmem, unsigned short * currentcount, unsigned int period) | |||
int | |||
nerd_data_stream (int data_fd, int numChannels, int *channel_list, | |||
int precision, int convert, int lines, int showmem, | |||
unsigned short *currentcount, unsigned int period) | |||
{ | |||
//Variables that should persist across retries | |||
static dataPacket buf; | |||
static int linesleft = 0; | |||
static int linesdumped = 0; | |||
int index = 0; | |||
int charsprocessed = 0; | |||
int alignment = 0; | |||
signed short datapoint = 0; | |||
unsigned short dataline[NERDJACK_CHANNELS]; | |||
long double voltline[NERDJACK_CHANNELS]; | |||
int i; | |||
unsigned long memused = 0; | |||
unsigned short packetsready = 0; | |||
unsigned short adcused = 0; | |||
unsigned short tempshort = 0; | |||
int charsread = 0; | |||
int numgroups = 0; | |||
long double volts; | |||
unsigned int expectedtimeout = (period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 2; | |||
//Check to see if we're trying to resume | |||
//Don't blow away linesleft in that case | |||
if(lines != 0 && linesleft == 0) { | |||
linesleft = lines; | |||
//Variables that should persist across retries | |||
static dataPacket buf; | |||
static int linesleft = 0; | |||
static int linesdumped = 0; | |||
int index = 0; | |||
int charsprocessed = 0; | |||
int alignment = 0; | |||
signed short datapoint = 0; | |||
unsigned short dataline[NERDJACK_CHANNELS]; | |||
long double voltline[NERDJACK_CHANNELS]; | |||
int i; | |||
unsigned long memused = 0; | |||
unsigned short packetsready = 0; | |||
unsigned short adcused = 0; | |||
unsigned short tempshort = 0; | |||
int charsread = 0; | |||
int numgroups = 0; | |||
long double volts; | |||
unsigned int expectedtimeout = | |||
(period * NERDJACK_NUM_SAMPLES / NERDJACK_CLOCK_RATE) + 2; | |||
//Check to see if we're trying to resume | |||
//Don't blow away linesleft in that case | |||
if (lines != 0 && linesleft == 0) | |||
{ | |||
linesleft = lines; | |||
} | |||
int numChannelsSampled = channel_list[0] + 1; | |||
//The number sampled will be the highest channel requested plus 1 (i.e. channel 0 requested means 1 sampled) | |||
for(i = 0; i < numChannels; i++) { | |||
if (channel_list[i] + 1 > numChannelsSampled) | |||
numChannelsSampled = channel_list[i] + 1; | |||
int numChannelsSampled = channel_list[0] + 1; | |||
//The number sampled will be the highest channel requested plus 1 (i.e. channel 0 requested means 1 sampled) | |||
for (i = 0; i < numChannels; i++) | |||
{ | |||
if (channel_list[i] + 1 > numChannelsSampled) | |||
numChannelsSampled = channel_list[i] + 1; | |||
} | |||
deststruct destination[numChannelsSampled]; | |||
nerd_init_channels(destination,numChannels,numChannelsSampled, channel_list); | |||
//Now destination structure array is set as well as numDuplicates. | |||
deststruct destination[numChannelsSampled]; | |||
//int numChannelsSampled = numChannels - numDuplicates; | |||
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled; | |||
nerd_init_channels (destination, numChannels, numChannelsSampled, | |||
channel_list); | |||
//Loop forever to grab data | |||
while((charsread = recv_all_timeout(data_fd,&buf,NERDJACK_PACKET_SIZE,0, | |||
& (struct timeval) { .tv_sec = expectedtimeout }))){ | |||
//Now destination structure array is set as well as numDuplicates. | |||
//We want a complete packet, so take the chars so far and keep waiting | |||
if(charsread != NERDJACK_PACKET_SIZE) { | |||
//There was a problem getting data. Probably a closed | |||
//connection. | |||
info("Packet timed out or was too short\n"); | |||
return -2; | |||
} | |||
//int numChannelsSampled = numChannels - numDuplicates; | |||
int numGroups = NERDJACK_NUM_SAMPLES / numChannelsSampled; | |||
//First check the header info | |||
if(buf.headerone != 0xF0 || buf.headertwo != 0xAA) { | |||
info("No Header info\n"); | |||
return -1; | |||
} | |||
//Check counter info to make sure not out of order | |||
tempshort = ntohs(buf.packetNumber); | |||
//tempshort = (buf[2] << 8) | buf[3]; | |||
if(tempshort != *currentcount ){ | |||
info("Count wrong. Expected %hd but got %hd\n", *currentcount, tempshort); | |||
return -1; | |||
//Loop forever to grab data | |||
while ((charsread = | |||
recv_all_timeout (data_fd, &buf, NERDJACK_PACKET_SIZE, 0, | |||
&(struct timeval) | |||
{ | |||
.tv_sec = expectedtimeout}))) | |||
{ | |||
//We want a complete packet, so take the chars so far and keep waiting | |||
if (charsread != NERDJACK_PACKET_SIZE) | |||
{ | |||
//There was a problem getting data. Probably a closed | |||
//connection. | |||
info ("Packet timed out or was too short\n"); | |||
return -2; | |||
} | |||
//First check the header info | |||
if (buf.headerone != 0xF0 || buf.headertwo != 0xAA) | |||
{ | |||
info ("No Header info\n"); | |||
return -1; | |||
} | |||
//Check counter info to make sure not out of order | |||
tempshort = ntohs (buf.packetNumber); | |||
//tempshort = (buf[2] << 8) | buf[3]; | |||
if (tempshort != *currentcount) | |||
{ | |||
info ("Count wrong. Expected %hd but got %hd\n", *currentcount, | |||
tempshort); | |||
return -1; | |||
} | |||
//Increment number of packets received | |||
*currentcount = *currentcount + 1; | |||
//Process the rest of the header and update the index value to be pointing after it | |||
charsprocessed = 12; | |||
memused = ntohl (buf.lwipmemoryused); | |||
adcused = ntohs (buf.adcused); | |||
packetsready = ntohs (buf.packetsready); | |||
alignment = 0; | |||
numgroups = 0; | |||
if (showmem) | |||
{ | |||
printf ("%lX %hd %hd\n", memused, adcused, packetsready); | |||
continue; | |||
} | |||
index = 0; | |||
//While there is still more data in the packet, process it | |||
//use the destination structure to load the line before printing | |||
while (charsread > charsprocessed) | |||
{ | |||
datapoint = ntohs (buf.data[index]); | |||
if (destination[alignment].numCopies != 0) | |||
{ | |||
switch (convert) | |||
{ | |||
case CONVERT_VOLTS: | |||
if (alignment <= 5) | |||
{ | |||
volts = | |||
(long double) (datapoint / 32767.0) * | |||
((precision & 0x01) ? 5.0 : 10.0); | |||
} | |||
else | |||
{ | |||
volts = | |||
(long double) (datapoint / 32767.0) * | |||
((precision & 0x02) ? 5.0 : 10.0); | |||
} | |||
for (i = 0; i < destination[alignment].numCopies; i++) | |||
{ | |||
voltline[destination[alignment].destlist[i]] = volts; | |||
} | |||
break; | |||
default: | |||
case CONVERT_HEX: | |||
case CONVERT_DEC: | |||
for (i = 0; i < destination[alignment].numCopies; i++) | |||
{ | |||
dataline[destination[alignment].destlist[i]] = | |||
(unsigned short) (datapoint - INT16_MIN); | |||
} | |||
break; | |||
} | |||
//Increment number of packets received | |||
*currentcount = *currentcount + 1; | |||
//Process the rest of the header and update the index value to be pointing after it | |||
charsprocessed = 12; | |||
memused = ntohl(buf.lwipmemoryused); | |||
adcused = ntohs(buf.adcused); | |||
packetsready = ntohs(buf.packetsready); | |||
alignment = 0; | |||
numgroups = 0; | |||
if(showmem) { | |||
printf("%lX %hd %hd\n",memused, adcused, packetsready); | |||
continue; | |||
} | |||
index = 0; | |||
//While there is still more data in the packet, process it | |||
//use the destination structure to load the line before printing | |||
while(charsread > charsprocessed) { | |||
datapoint = ntohs(buf.data[index]); | |||
if(destination[alignment].numCopies != 0) { | |||
switch(convert) { | |||
case CONVERT_VOLTS: | |||
if(alignment <= 5) { | |||
volts = (long double) ( datapoint / 32767.0 ) * ((precision & 0x01) ? 5.0 : 10.0); | |||
} else { | |||
volts = (long double) (datapoint / 32767.0 ) * ((precision & 0x02) ? 5.0 : 10.0); | |||
} | |||
for(i = 0; i < destination[alignment].numCopies; i++) { | |||
voltline[destination[alignment].destlist[i]] = volts; | |||
} | |||
break; | |||
default: | |||
case CONVERT_HEX: | |||
case CONVERT_DEC: | |||
for(i = 0; i < destination[alignment].numCopies; i++) { | |||
dataline[destination[alignment].destlist[i]] = | |||
(unsigned short) (datapoint - INT16_MIN); | |||
} | |||
break; | |||
} | |||
//Each point is two bytes, so increment index and total bytes read | |||
charsprocessed++; | |||
charsprocessed++; | |||
index++; | |||
alignment++; | |||
//Since channel data is packed, we need to know when to insert a newline | |||
if (alignment == numChannelsSampled) | |||
{ | |||
if (linesdumped != 0) | |||
{ | |||
switch (convert) | |||
{ | |||
case CONVERT_VOLTS: | |||
for (i = 0; i < numChannels; i++) | |||
{ | |||
if (printf ("%Lf ", voltline[i]) < 0) | |||
goto bad; | |||
} | |||
break; | |||
case CONVERT_HEX: | |||
for (i = 0; i < numChannels; i++) | |||
{ | |||
if (printf ("%04hX", dataline[i]) < 0) | |||
goto bad; | |||
} | |||
} | |||
//Each point is two bytes, so increment index and total bytes read | |||
charsprocessed++; | |||
charsprocessed++; | |||
index++; | |||
alignment++; | |||
//Since channel data is packed, we need to know when to insert a newline | |||
if(alignment == numChannelsSampled){ | |||
if(linesdumped != 0){ | |||
switch(convert) { | |||
case CONVERT_VOLTS: | |||
for(i = 0; i < numChannels; i++) { | |||
if (printf("%Lf ",voltline[i]) < 0) | |||
goto bad; | |||
} | |||
break; | |||
case CONVERT_HEX: | |||
for(i = 0; i < numChannels; i++) { | |||
if (printf("%04hX",dataline[i]) < 0) | |||
goto bad; | |||
} | |||
break; | |||
default: | |||
case CONVERT_DEC: | |||
for(i = 0; i < numChannels; i++) { | |||
if (printf("%hu ",dataline[i]) < 0) | |||
goto bad; | |||
} | |||
break; | |||
} | |||
if(printf("\n") < 0) | |||
goto bad; | |||
} else { | |||
linesdumped = linesdumped + 1; | |||
if(lines != 0) { | |||
linesleft++; | |||
} | |||
} | |||
alignment = 0; | |||
numgroups++; | |||
if(lines != 0) { | |||
linesleft--; | |||
if(linesleft == 0) { | |||
return 0; | |||
} | |||
} | |||
//If numgroups so far is equal to the numGroups in a packet, this packet is done | |||
if(numgroups == numGroups) { | |||
break; | |||
} | |||
break; | |||
default: | |||
case CONVERT_DEC: | |||
for (i = 0; i < numChannels; i++) | |||
{ | |||
if (printf ("%hu ", dataline[i]) < 0) | |||
goto bad; | |||
} | |||
break; | |||
} | |||
if (printf ("\n") < 0) | |||
goto bad; | |||
} | |||
else | |||
{ | |||
linesdumped = linesdumped + 1; | |||
if (lines != 0) | |||
{ | |||
linesleft++; | |||
} | |||
} | |||
alignment = 0; | |||
numgroups++; | |||
if (lines != 0) | |||
{ | |||
linesleft--; | |||
if (linesleft == 0) | |||
{ | |||
return 0; | |||
} | |||
} | |||
index = 0; | |||
charsprocessed = 0; | |||
//If numgroups so far is equal to the numGroups in a packet, this packet is done | |||
if (numgroups == numGroups) | |||
{ | |||
break; | |||
} | |||
} | |||
} | |||
index = 0; | |||
charsprocessed = 0; | |||
} | |||
return 0; | |||
return 0; | |||
bad: | |||
info("Output error (disk full?)\n"); | |||
return -1; | |||
info ("Output error (disk full?)\n"); | |||
return -1; | |||
} | |||
int nerd_open(const char *address,int port) { | |||
struct hostent *he; | |||
net_init(); | |||
int32_t i32SocketFD = socket(PF_INET, SOCK_STREAM, 0); | |||
int | |||
nerd_open (const char *address, int port) | |||
{ | |||
if(-1 == i32SocketFD) | |||
struct hostent *he; | |||
net_init (); | |||
int32_t i32SocketFD = socket (PF_INET, SOCK_STREAM, 0); | |||
if (-1 == i32SocketFD) | |||
{ | |||
verb("cannot create socket"); | |||
verb ("cannot create socket"); | |||
return -1; | |||
} | |||
/* Set nonblocking */ | |||
if (soblock (i32SocketFD, 0) < 0) | |||
{ | |||
verb ("can't set nonblocking\n"); | |||
return -1; | |||
} | |||
/* Set nonblocking */ | |||
if (soblock(i32SocketFD, 0) < 0) { | |||
verb("can't set nonblocking\n"); | |||
return -1; | |||
} | |||
struct sockaddr_in stSockAddr; | |||
memset(&stSockAddr, 0, sizeof(stSockAddr)); | |||
struct sockaddr_in stSockAddr; | |||
memset (&stSockAddr, 0, sizeof (stSockAddr)); | |||
stSockAddr.sin_family = AF_INET; | |||
stSockAddr.sin_port = htons(port); | |||
he = gethostbyname(address); | |||
if (he == NULL) { | |||
verb("gethostbyname(\"%s\") failed\n", address); | |||
return -1; | |||
} | |||
stSockAddr.sin_addr = *((struct in_addr *) he->h_addr); | |||
debug("Resolved %s -> %s\n", address, inet_ntoa(stSockAddr.sin_addr)); | |||
/* Connect */ | |||
if (connect_timeout(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof(stSockAddr), | |||
& (struct timeval) { .tv_sec = NERDJACK_TIMEOUT }) < 0) { | |||
verb("connection to %s:%d failed: %s\n", | |||
inet_ntoa(stSockAddr.sin_addr), port, compat_strerror(errno)); | |||
return -1; | |||
} | |||
return i32SocketFD; | |||
stSockAddr.sin_family = AF_INET; | |||
stSockAddr.sin_port = htons (port); | |||
he = gethostbyname (address); | |||
if (he == NULL) | |||
{ | |||
verb ("gethostbyname(\"%s\") failed\n", address); | |||
return -1; | |||
} | |||
stSockAddr.sin_addr = *((struct in_addr *) he->h_addr); | |||
debug ("Resolved %s -> %s\n", address, inet_ntoa (stSockAddr.sin_addr)); | |||
/* Connect */ | |||
if (connect_timeout | |||
(i32SocketFD, (struct sockaddr *) &stSockAddr, sizeof (stSockAddr), | |||
&(struct timeval) | |||
{ | |||
.tv_sec = NERDJACK_TIMEOUT}) < 0) | |||
{ | |||
verb ("connection to %s:%d failed: %s\n", | |||
inet_ntoa (stSockAddr.sin_addr), port, compat_strerror (errno)); | |||
return -1; | |||
} | |||
return i32SocketFD; | |||
} | |||
//Generate an appropriate sample initiation command | |||
int nerd_generate_command(getPacket * command, int * channel_list, int channel_count, int precision, | |||
unsigned long period) { | |||
short channelbit = 0; | |||
int i; | |||
for( i = 0; i < channel_count; i++) { | |||
channelbit = channelbit | (0x1 << channel_list[i]); | |||
int | |||
nerd_generate_command (getPacket * command, int *channel_list, | |||
int channel_count, int precision, unsigned long period) | |||
{ | |||
short channelbit = 0; | |||
int i; | |||
for (i = 0; i < channel_count; i++) | |||
{ | |||
channelbit = channelbit | (0x1 << channel_list[i]); | |||
} | |||
//command->word = "GETD"; | |||
command->word[0] = 'G'; | |||
command->word[1] = 'E'; | |||
command->word[2] = 'T'; | |||
command->word[3] = 'D'; | |||
command->channelbit = htons(channelbit); | |||
command->precision = precision; | |||
command->period = htonl(period); | |||
command->prescaler = 0; | |||
//sprintf(command,"GETD%3.3X%d%5.5d", channelbit,precision,period); | |||
return 0; | |||
//command->word = "GETD"; | |||
command->word[0] = 'G'; | |||
command->word[1] = 'E'; | |||
command->word[2] = 'T'; | |||
command->word[3] = 'D'; | |||
command->channelbit = htons (channelbit); | |||
command->precision = precision; | |||
command->period = htonl (period); | |||
command->prescaler = 0; | |||
//sprintf(command,"GETD%3.3X%d%5.5d", channelbit,precision,period); | |||
return 0; | |||
} | |||
int nerd_close_conn(int data_fd) | |||
int | |||
nerd_close_conn (int data_fd) | |||
{ | |||
shutdown(data_fd, 2); | |||
close(data_fd); | |||
return 0; | |||
shutdown (data_fd, 2); | |||
close (data_fd); | |||
return 0; | |||
} |
@@ -24,33 +24,38 @@ | |||
#define NERDJACK_PACKET_SIZE 1460 | |||
#define NERDJACK_NUM_SAMPLES 724 | |||
typedef struct __attribute__((__packed__)) { | |||
char word[4]; | |||
unsigned short channelbit; | |||
unsigned char precision; | |||
unsigned long period; | |||
unsigned char prescaler; | |||
typedef struct __attribute__ ((__packed__)) | |||
{ | |||
char word[4]; | |||
unsigned short channelbit; | |||
unsigned char precision; | |||
unsigned long period; | |||
unsigned char prescaler; | |||
} getPacket; | |||
/* Open/close TCP/IP connection to the NerdJack */ | |||
int nerd_open(const char *address,int port); | |||
int nerd_close_conn(int data_fd); | |||
int nerd_open (const char *address, int port); | |||
int nerd_close_conn (int data_fd); | |||
/* Generate the command word for the NerdJack */ | |||
int nerd_generate_command(getPacket * command, int * channel_list, int channel_count, int precision, | |||
unsigned long period); | |||
int nerd_generate_command (getPacket * command, int *channel_list, | |||
int channel_count, int precision, | |||
unsigned long period); | |||
/* Send given command to NerdJack */ | |||
int nerd_send_command(const char * address, void * command, int length); | |||
int nerd_send_command (const char *address, void *command, int length); | |||
/* Stream data out of the NerdJack */ | |||
int nerd_data_stream(int data_fd, int numChannels, int * channel_list, int precision, int convert, int lines, int showmem, unsigned short * currentcount, unsigned int period); | |||
int nerd_data_stream (int data_fd, int numChannels, int *channel_list, | |||
int precision, int convert, int lines, int showmem, | |||
unsigned short *currentcount, unsigned int period); | |||
/* Detect the IP Address of the NerdJack and return in ipAddress */ | |||
int nerdjack_detect(char * ipAddress); | |||
int nerdjack_detect (char *ipAddress); | |||
/* Choose the best ScanConfig and ScanInterval parameters for the | |||
desired scanrate. Returns -1 if no valid config found */ | |||
int nerdjack_choose_scan(double desired_rate, double *actual_rate, unsigned long *period); | |||
int nerdjack_choose_scan (double desired_rate, double *actual_rate, | |||
unsigned long *period); | |||
#endif |
@@ -5,239 +5,262 @@ | |||
#include <stdio.h> | |||
/* Initialize networking */ | |||
void net_init(void) | |||
void | |||
net_init (void) | |||
{ | |||
#ifdef __WIN32__ | |||
WSADATA blah; | |||
WSAStartup(0x0101, &blah); | |||
WSADATA blah; | |||
WSAStartup (0x0101, &blah); | |||
#endif | |||
} | |||
/* Set socket blocking/nonblocking */ | |||
int soblock(int socket, int blocking) | |||
int | |||
soblock (int socket, int blocking) | |||
{ | |||
#ifdef __WIN32__ | |||
unsigned long arg = blocking ? 0 : 1; | |||
if (ioctlsocket(socket, FIONBIO, &arg) != 0) | |||
return -1; | |||
return 0; | |||
unsigned long arg = blocking ? 0 : 1; | |||
if (ioctlsocket (socket, FIONBIO, &arg) != 0) | |||
return -1; | |||
return 0; | |||
#else | |||
int sockopt; | |||
/* Get flags */ | |||
sockopt = fcntl(socket, F_GETFL); | |||
if (sockopt == -1) { | |||
return -1; | |||
} | |||
/* Modify */ | |||
if (blocking) | |||
sockopt &= ~O_NONBLOCK; | |||
else | |||
sockopt |= O_NONBLOCK; | |||
/* Set flags */ | |||
if (fcntl(socket, F_SETFL, sockopt) != 0) | |||
return -1; | |||
return 0; | |||
int sockopt; | |||
/* Get flags */ | |||
sockopt = fcntl (socket, F_GETFL); | |||
if (sockopt == -1) | |||
{ | |||
return -1; | |||
} | |||
/* Modify */ | |||
if (blocking) | |||
sockopt &= ~O_NONBLOCK; | |||
else | |||
sockopt |= O_NONBLOCK; | |||
/* Set flags */ | |||
if (fcntl (socket, F_SETFL, sockopt) != 0) | |||
return -1; | |||
return 0; | |||
#endif | |||
} | |||
/* Like connect(2), but with a timeout. Socket must be non-blocking. */ | |||
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen, | |||
struct timeval *timeout) | |||
int | |||
connect_timeout (int s, const struct sockaddr *serv_addr, socklen_t addrlen, | |||
struct timeval *timeout) | |||
{ | |||
int ret; | |||
fd_set writefds; | |||
fd_set exceptfds; | |||
int optval; | |||
socklen_t optlen; | |||
/* Start connect */ | |||
ret = connect(s, serv_addr, addrlen); | |||
if (ret == 0) { | |||
/* Success */ | |||
return 0; | |||
} | |||
/* Check for immediate failure */ | |||
int ret; | |||
fd_set writefds; | |||
fd_set exceptfds; | |||
int optval; | |||
socklen_t optlen; | |||
/* Start connect */ | |||
ret = connect (s, serv_addr, addrlen); | |||
if (ret == 0) | |||
{ | |||
/* Success */ | |||
return 0; | |||
} | |||
/* Check for immediate failure */ | |||
#ifdef __WIN32__ | |||
errno = WSAGetLastError(); | |||
if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL) | |||
return -1; | |||
errno = WSAGetLastError (); | |||
if (ret < 0 && errno != WSAEWOULDBLOCK && errno != WSAEINVAL) | |||
return -1; | |||
#else | |||
if (ret < 0 && errno != EINPROGRESS && errno != EALREADY) | |||
return -1; | |||
if (ret < 0 && errno != EINPROGRESS && errno != EALREADY) | |||
return -1; | |||
#endif | |||
/* In progress, wait for result. */ | |||
FD_ZERO(&writefds); | |||
FD_SET(s, &writefds); | |||
FD_ZERO(&exceptfds); | |||
FD_SET(s, &exceptfds); | |||
ret = select(s + 1, NULL, &writefds, &exceptfds, timeout); | |||
if (ret < 0) { | |||
/* Error */ | |||
return -1; | |||
} | |||
if (ret == 0) { | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
/* Check the socket state */ | |||
optlen = sizeof(optval); | |||
if (getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen) != 0) | |||
return -1; | |||
if (optval != 0) { | |||
/* Connection failed. */ | |||
errno = optval; | |||
return -1; | |||
} | |||
/* On Windows, SO_ERROR sometimes shows no error but the connection | |||
still failed. Sigh. */ | |||
if (FD_ISSET(s, &exceptfds) || !FD_ISSET(s, &writefds)) { | |||
errno = EIO; | |||
return -1; | |||
} | |||
/* Success */ | |||
return 0; | |||
/* In progress, wait for result. */ | |||
FD_ZERO (&writefds); | |||
FD_SET (s, &writefds); | |||
FD_ZERO (&exceptfds); | |||
FD_SET (s, &exceptfds); | |||
ret = select (s + 1, NULL, &writefds, &exceptfds, timeout); | |||
if (ret < 0) | |||
{ | |||
/* Error */ | |||
return -1; | |||
} | |||
if (ret == 0) | |||
{ | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
/* Check the socket state */ | |||
optlen = sizeof (optval); | |||
if (getsockopt (s, SOL_SOCKET, SO_ERROR, (void *) &optval, &optlen) != 0) | |||
return -1; | |||
if (optval != 0) | |||
{ | |||
/* Connection failed. */ | |||
errno = optval; | |||
return -1; | |||
} | |||
/* On Windows, SO_ERROR sometimes shows no error but the connection | |||
still failed. Sigh. */ | |||
if (FD_ISSET (s, &exceptfds) || !FD_ISSET (s, &writefds)) | |||
{ | |||
errno = EIO; | |||
return -1; | |||
} | |||
/* Success */ | |||
return 0; | |||
} | |||
/* Like send(2), but with a timeout. Socket must be non-blocking. | |||
The timeout only applies if no data at all is sent -- this function | |||
may still send less than requested. */ | |||
ssize_t send_timeout(int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout) | |||
ssize_t | |||
send_timeout (int s, const void *buf, size_t len, int flags, | |||
struct timeval * timeout) | |||
{ | |||
fd_set writefds; | |||
int ret; | |||
FD_ZERO(&writefds); | |||
FD_SET(s, &writefds); | |||
ret = select(s + 1, NULL, &writefds, NULL, timeout); | |||
if (ret == 0) { | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) { | |||
/* Error */ | |||
return -1; | |||
} | |||
return send(s, buf, len, flags); | |||
fd_set writefds; | |||
int ret; | |||
FD_ZERO (&writefds); | |||
FD_SET (s, &writefds); | |||
ret = select (s + 1, NULL, &writefds, NULL, timeout); | |||
if (ret == 0) | |||
{ | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) | |||
{ | |||
/* Error */ | |||
return -1; | |||
} | |||
return send (s, buf, len, flags); | |||
} | |||
/* Like recv(2), but with a timeout. Socket must be non-blocking. | |||
The timeout only applies if no data at all is received -- this | |||
function may still return less than requested. */ | |||
ssize_t recv_timeout(int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout) | |||
ssize_t | |||
recv_timeout (int s, void *buf, size_t len, int flags, | |||
struct timeval * timeout) | |||
{ | |||
fd_set readfds; | |||
int ret; | |||
FD_ZERO(&readfds); | |||
FD_SET(s, &readfds); | |||
ret = select(s + 1, &readfds, NULL, NULL, timeout); | |||
if (ret == 0) { | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) { | |||
/* Error */ | |||
return -1; | |||
} | |||
return recv(s, buf, len, flags); | |||
fd_set readfds; | |||
int ret; | |||
FD_ZERO (&readfds); | |||
FD_SET (s, &readfds); | |||
ret = select (s + 1, &readfds, NULL, NULL, timeout); | |||
if (ret == 0) | |||
{ | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) | |||
{ | |||
/* Error */ | |||
return -1; | |||
} | |||
return recv (s, buf, len, flags); | |||
} | |||
/* Like recvfrom(2), but with a timeout. Socket must be non-blocking. | |||
The timeout only applies if no data at all is received -- this | |||
function may still return less than requested. */ | |||
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len, | |||
struct timeval *timeout) | |||
ssize_t | |||
recvfrom_timeout (int s, void *buf, size_t len, int flags, | |||
struct sockaddr * address, socklen_t * address_len, | |||
struct timeval * timeout) | |||
{ | |||
fd_set readfds; | |||
int ret; | |||
FD_ZERO(&readfds); | |||
FD_SET(s, &readfds); | |||
ret = select(s + 1, &readfds, NULL, NULL, timeout); | |||
if (ret == 0) { | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) { | |||
/* Error */ | |||
return -1; | |||
} | |||
return recvfrom(s, buf, len, flags, address, address_len); | |||
fd_set readfds; | |||
int ret; | |||
FD_ZERO (&readfds); | |||
FD_SET (s, &readfds); | |||
ret = select (s + 1, &readfds, NULL, NULL, timeout); | |||
if (ret == 0) | |||
{ | |||
/* Timed out */ | |||
errno = ETIMEDOUT; | |||
return -1; | |||
} | |||
if (ret != 1) | |||
{ | |||
/* Error */ | |||
return -1; | |||
} | |||
return recvfrom (s, buf, len, flags, address, address_len); | |||
} | |||
/* Like send_timeout, but retries (with the same timeout) in case of | |||
partial transfers. This is a stronger attempt to send all | |||
requested data. */ | |||
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout) | |||
ssize_t | |||
send_all_timeout (int s, const void *buf, size_t len, int flags, | |||
struct timeval * timeout) | |||
{ | |||
struct timeval tv; | |||
size_t left = len; | |||
ssize_t ret; | |||
struct timeval tv; | |||
size_t left = len; | |||
ssize_t ret; | |||
while (left > 0) { | |||
tv.tv_sec = timeout->tv_sec; | |||
tv.tv_usec = timeout->tv_usec; | |||
ret = send_timeout(s, buf, left, flags, &tv); | |||
while (left > 0) | |||
{ | |||
tv.tv_sec = timeout->tv_sec; | |||
tv.tv_usec = timeout->tv_usec; | |||
ret = send_timeout (s, buf, left, flags, &tv); | |||
if (ret < 0) | |||
return ret; | |||
if (ret < 0) | |||
return ret; | |||
if (ret == 0) | |||
break; | |||
if (ret == 0) | |||
break; | |||
left -= ret; | |||
buf += ret; | |||
} | |||
left -= ret; | |||
buf += ret; | |||
} | |||
return len - left; | |||
return len - left; | |||
} | |||
/* Like recv_timeout, but retries (with the same timeout) in case of | |||
partial transfers. This is a stronger attempt to recv all | |||
requested data. */ | |||
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout) | |||
ssize_t | |||
recv_all_timeout (int s, void *buf, size_t len, int flags, | |||
struct timeval * timeout) | |||
{ | |||
struct timeval tv; | |||
size_t left = len; | |||
ssize_t ret; | |||
struct timeval tv; | |||
size_t left = len; | |||
ssize_t ret; | |||
while (left > 0) { | |||
tv.tv_sec = timeout->tv_sec; | |||
tv.tv_usec = timeout->tv_usec; | |||
ret = recv_timeout(s, buf, left, flags, &tv); | |||
while (left > 0) | |||
{ | |||
tv.tv_sec = timeout->tv_sec; | |||
tv.tv_usec = timeout->tv_usec; | |||
ret = recv_timeout (s, buf, left, flags, &tv); | |||
if (ret < 0) | |||
return ret; | |||
if (ret < 0) | |||
return ret; | |||
if (ret == 0) | |||
break; | |||
if (ret == 0) | |||
break; | |||
left -= ret; | |||
buf += ret; | |||
} | |||
left -= ret; | |||
buf += ret; | |||
} | |||
return len - left; | |||
return len - left; | |||
} |
@@ -19,27 +19,28 @@ | |||
#endif | |||
/* Initialize networking */ | |||
void net_init(void); | |||
void net_init (void); | |||
/* Set socket blocking/nonblocking */ | |||
int soblock(int socket, int blocking); | |||
int soblock (int socket, int blocking); | |||
/* Like send(2), recv(2), connect(2), but with timeouts. | |||
Socket must be O_NONBLOCK. */ | |||
int connect_timeout(int s, const struct sockaddr *serv_addr, socklen_t addrlen, | |||
struct timeval *timeout); | |||
ssize_t send_timeout(int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recv_timeout(int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recvfrom_timeout(int s, void *buf, size_t len, int flags, struct sockaddr *address, socklen_t *address_len, | |||
struct timeval *timeout); | |||
int connect_timeout (int s, const struct sockaddr *serv_addr, | |||
socklen_t addrlen, struct timeval *timeout); | |||
ssize_t send_timeout (int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recv_timeout (int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recvfrom_timeout (int s, void *buf, size_t len, int flags, | |||
struct sockaddr *address, socklen_t * address_len, | |||
struct timeval *timeout); | |||
/* Like send_timeout and recv_timeout, but they retry (with the same timeout) | |||
in case of partial transfers, in order to try to transfer all data. */ | |||
ssize_t send_all_timeout(int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recv_all_timeout(int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t send_all_timeout (int s, const void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
ssize_t recv_all_timeout (int s, void *buf, size_t len, int flags, | |||
struct timeval *timeout); | |||
#endif |
@@ -11,85 +11,98 @@ | |||
#include <string.h> | |||
#include "opt.h" | |||
void opt_init(int *optind) { | |||
*optind=0; | |||
void | |||
opt_init (int *optind) | |||
{ | |||
*optind = 0; | |||
} | |||
char opt_parse(int argc, char **argv, int *optind, char **optarg, | |||
struct options *opt) { | |||
char c; | |||
int i; | |||
(*optind)++; | |||
if(*optind>=argc) | |||
return 0; | |||
if(argv[*optind][0]=='-' && | |||
argv[*optind][1]!='-' && | |||
argv[*optind][1]!=0) { | |||
/* Short option (or a bunch of 'em) */ | |||
/* Save this and shift others over */ | |||
c=argv[*optind][1]; | |||
for(i=2;argv[*optind][i]!=0;i++) | |||
argv[*optind][i-1]=argv[*optind][i]; | |||
argv[*optind][i-1]=0; | |||
if(argv[*optind][1]!=0) | |||
(*optind)--; | |||
/* Now find it */ | |||
for(i=0;opt[i].shortopt!=0;i++) | |||
if(opt[i].shortopt==c) | |||
break; | |||
if(opt[i].shortopt==0) { | |||
fprintf(stderr,"Error: unknown option '-%c'\n",c); | |||
return '?'; | |||
} | |||
if(opt[i].arg==NULL) | |||
return c; | |||
(*optind)++; | |||
if(*optind>=argc || (argv[*optind][0]=='-' && | |||
argv[*optind][1]!=0)) { | |||
fprintf(stderr,"Error: option '-%c' requires an " | |||
"argument\n",c); | |||
return '?'; | |||
} | |||
(*optarg)=argv[*optind]; | |||
return c; | |||
} else if(argv[*optind][0]=='-' && | |||
argv[*optind][1]=='-' && | |||
argv[*optind][2]!=0) { | |||
/* Long option */ | |||
for(i=0;(c=opt[i].shortopt)!=0;i++) | |||
if(strcmp(opt[i].longopt,argv[*optind]+2)==0) | |||
break; | |||
if(opt[i].shortopt==0) { | |||
fprintf(stderr,"Error: unknown option '%s'\n", | |||
argv[*optind]); | |||
return '?'; | |||
} | |||
if(opt[i].arg==NULL) | |||
return c; | |||
(*optind)++; | |||
if(*optind>=argc || (argv[*optind][0]=='-' && | |||
argv[*optind][1]!=0)) { | |||
fprintf(stderr,"Error: option '%s' requires an " | |||
"argument\n",argv[*optind-1]); | |||
return '?'; | |||
} | |||
(*optarg)=argv[*optind]; | |||
return c; | |||
} else { | |||
/* End of options */ | |||
return 0; | |||
char | |||
opt_parse (int argc, char **argv, int *optind, char **optarg, | |||
struct options *opt) | |||
{ | |||
char c; | |||
int i; | |||
(*optind)++; | |||
if (*optind >= argc) | |||
return 0; | |||
if (argv[*optind][0] == '-' && | |||
argv[*optind][1] != '-' && argv[*optind][1] != 0) | |||
{ | |||
/* Short option (or a bunch of 'em) */ | |||
/* Save this and shift others over */ | |||
c = argv[*optind][1]; | |||
for (i = 2; argv[*optind][i] != 0; i++) | |||
argv[*optind][i - 1] = argv[*optind][i]; | |||
argv[*optind][i - 1] = 0; | |||
if (argv[*optind][1] != 0) | |||
(*optind)--; | |||
/* Now find it */ | |||
for (i = 0; opt[i].shortopt != 0; i++) | |||
if (opt[i].shortopt == c) | |||
break; | |||
if (opt[i].shortopt == 0) | |||
{ | |||
fprintf (stderr, "Error: unknown option '-%c'\n", c); | |||
return '?'; | |||
} | |||
if (opt[i].arg == NULL) | |||
return c; | |||
(*optind)++; | |||
if (*optind >= argc || (argv[*optind][0] == '-' && | |||
argv[*optind][1] != 0)) | |||
{ | |||
fprintf (stderr, "Error: option '-%c' requires an " | |||
"argument\n", c); | |||
return '?'; | |||
} | |||
(*optarg) = argv[*optind]; | |||
return c; | |||
} | |||
else if (argv[*optind][0] == '-' && | |||
argv[*optind][1] == '-' && argv[*optind][2] != 0) | |||
{ | |||
/* Long option */ | |||
for (i = 0; (c = opt[i].shortopt) != 0; i++) | |||
if (strcmp (opt[i].longopt, argv[*optind] + 2) == 0) | |||
break; | |||
if (opt[i].shortopt == 0) | |||
{ | |||
fprintf (stderr, "Error: unknown option '%s'\n", argv[*optind]); | |||
return '?'; | |||
} | |||
if (opt[i].arg == NULL) | |||
return c; | |||
(*optind)++; | |||
if (*optind >= argc || (argv[*optind][0] == '-' && | |||
argv[*optind][1] != 0)) | |||
{ | |||
fprintf (stderr, "Error: option '%s' requires an " | |||
"argument\n", argv[*optind - 1]); | |||
return '?'; | |||
} | |||
(*optarg) = argv[*optind]; | |||
return c; | |||
} | |||
else | |||
{ | |||
/* End of options */ | |||
return 0; | |||
} | |||
} | |||
void opt_help(struct options *opt, FILE *out) { | |||
int i; | |||
int printed; | |||
void | |||
opt_help (struct options *opt, FILE * out) | |||
{ | |||
int i; | |||
int printed; | |||
for(i=0;opt[i].shortopt!=0;i++) { | |||
fprintf(out," -%c, --%s%n",opt[i].shortopt, | |||
opt[i].longopt,&printed); | |||
fprintf(out," %-*s%s\n",30-printed, | |||
opt[i].arg?opt[i].arg:"",opt[i].help); | |||
} | |||
for (i = 0; opt[i].shortopt != 0; i++) | |||
{ | |||
fprintf (out, " -%c, --%s%n", opt[i].shortopt, | |||
opt[i].longopt, &printed); | |||
fprintf (out, " %-*s%s\n", 30 - printed, | |||
opt[i].arg ? opt[i].arg : "", opt[i].help); | |||
} | |||
} |
@@ -11,18 +11,19 @@ | |||
#include <stdlib.h> | |||
struct options { | |||
char shortopt; | |||
char *longopt; | |||
char *arg; | |||
char *help; | |||
struct options | |||
{ | |||
char shortopt; | |||
char *longopt; | |||
char *arg; | |||
char *help; | |||
}; | |||
void opt_init(int *optind); | |||
void opt_init (int *optind); | |||
char opt_parse(int argc, char **argv, int *optind, char **optarg, | |||
struct options *opt); | |||
char opt_parse (int argc, char **argv, int *optind, char **optarg, | |||
struct options *opt); | |||
void opt_help(struct options *opt, FILE *out); | |||
void opt_help (struct options *opt, FILE * out); | |||
#endif |
@@ -16,56 +16,59 @@ | |||
#include "netutil.h" | |||
/* Calibration data */ | |||
struct ue9Calibration { | |||