|
|
@@ -0,0 +1,200 @@ |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <termio.h> |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/ioctl.h> |
|
|
|
#include <errno.h> |
|
|
|
#include <unistd.h> |
|
|
|
#include <getopt.h> |
|
|
|
#include <stdint.h> |
|
|
|
#include <string.h> |
|
|
|
#include <syslog.h> |
|
|
|
#include <fcntl.h> |
|
|
|
#include <err.h> |
|
|
|
#include <linux/serial.h> |
|
|
|
#include <sys/signal.h> |
|
|
|
|
|
|
|
int zoom, gpib; |
|
|
|
|
|
|
|
void calibrate(void); |
|
|
|
|
|
|
|
#define info(x...) fprintf(stderr,x) |
|
|
|
|
|
|
|
int quit = 0; |
|
|
|
void handle_sig(int sig) |
|
|
|
{ |
|
|
|
quit = 1; |
|
|
|
} |
|
|
|
|
|
|
|
int serial_open(const char *device, int rate) |
|
|
|
{ |
|
|
|
struct termios options; |
|
|
|
struct serial_struct serinfo; |
|
|
|
int fd; |
|
|
|
int speed = 0; |
|
|
|
|
|
|
|
/* Open and configure serial port */ |
|
|
|
if ((fd = open(device,O_RDWR|O_NOCTTY)) == -1) |
|
|
|
err(1, "%s", device); |
|
|
|
|
|
|
|
switch (rate) { |
|
|
|
case 9600: speed = B9600; break; |
|
|
|
case 115200: speed = B115200; break; |
|
|
|
} |
|
|
|
|
|
|
|
if (speed == 0) { |
|
|
|
serinfo.reserved_char[0] = 0; |
|
|
|
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) |
|
|
|
err(1, "%s: TIOCGSERIAL", device); |
|
|
|
serinfo.flags &= ~ASYNC_SPD_MASK; |
|
|
|
serinfo.flags |= ASYNC_SPD_CUST; |
|
|
|
serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate; |
|
|
|
if (serinfo.custom_divisor < 1) |
|
|
|
serinfo.custom_divisor = 1; |
|
|
|
if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0) |
|
|
|
err(1, "%s: TIOCSSERIAL", device); |
|
|
|
if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0) |
|
|
|
err(1, "%s: TIOCGSERIAL 2", device); |
|
|
|
if (serinfo.custom_divisor * rate != serinfo.baud_base) { |
|
|
|
warnx("actual baudrate is %d / %d = %f", |
|
|
|
serinfo.baud_base, serinfo.custom_divisor, |
|
|
|
(float)serinfo.baud_base / serinfo.custom_divisor); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fcntl(fd, F_SETFL, 0); |
|
|
|
tcgetattr(fd, &options); |
|
|
|
cfsetispeed(&options, speed ?: B38400); |
|
|
|
cfsetospeed(&options, speed ?: B38400); |
|
|
|
cfmakeraw(&options); |
|
|
|
options.c_cflag |= (CLOCAL | CREAD); |
|
|
|
options.c_cflag &= ~CRTSCTS; |
|
|
|
if (tcsetattr(fd, TCSANOW, &options) != 0) |
|
|
|
err(1, "TCSANOW"); |
|
|
|
|
|
|
|
return fd; |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char *argv[]) |
|
|
|
{ |
|
|
|
char *zoomdev=strdup("/dev/ttyUSB0"); |
|
|
|
char *gpibdev=strdup("/dev/ttyUSB1"); |
|
|
|
int getopt_index; |
|
|
|
int i; |
|
|
|
char buf[1024]; |
|
|
|
|
|
|
|
static struct option long_opts[] = { |
|
|
|
{ "zoom-device", required_argument, NULL, 'z' }, |
|
|
|
{ "gpib-device", required_argument, NULL, 'g' }, |
|
|
|
{ "help", no_argument, NULL, 'h' }, |
|
|
|
{ 0, 0, 0, 0 } |
|
|
|
}; |
|
|
|
int help=0; |
|
|
|
char c; |
|
|
|
|
|
|
|
while ((c = getopt_long(argc, argv, "z:g:h?", |
|
|
|
long_opts, &getopt_index)) != -1) { |
|
|
|
switch(c) |
|
|
|
{ |
|
|
|
case 'z': |
|
|
|
free(zoomdev); |
|
|
|
zoomdev = strdup(optarg); |
|
|
|
break; |
|
|
|
case 'g': |
|
|
|
free(gpibdev); |
|
|
|
gpibdev = strdup(optarg); |
|
|
|
break; |
|
|
|
case 'h': |
|
|
|
case '?': |
|
|
|
default: |
|
|
|
help = 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (help) { |
|
|
|
fprintf(stderr, "Zoom Nilm Calibration Tool\n"); |
|
|
|
fprintf(stderr, "usage: %s [options]\n\n", *argv); |
|
|
|
fprintf(stderr, " -z, --zoom-device %-14s zoom NILM serial port\n", zoomdev); |
|
|
|
fprintf(stderr, " -z, --gpib-device %-14s GPIB serial port\n", gpibdev); |
|
|
|
fprintf(stderr, " -h, --help this help\n"); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
if ((zoom = serial_open(zoomdev, 115200)) == -1) |
|
|
|
errx(1, "zoom open failed"); |
|
|
|
if ((gpib = serial_open(zoomdev, 9600)) == -1) |
|
|
|
errx(1, "gpib open failed"); |
|
|
|
|
|
|
|
signal(SIGTERM, handle_sig); |
|
|
|
calibrate(); |
|
|
|
|
|
|
|
close(zoom); |
|
|
|
close(gpib); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void gputs(char *s) |
|
|
|
{ |
|
|
|
if (write(gpib, s, strlen(s)) != strlen(s) || |
|
|
|
write(gpib, "\r", 1) != 1) |
|
|
|
err(1, "error writing GPIB string '%s'", s); |
|
|
|
} |
|
|
|
|
|
|
|
void keithley_on(void) |
|
|
|
{ |
|
|
|
gputs("++mode 1"); |
|
|
|
gputs("++mode 1"); |
|
|
|
gputs("++auto 0"); |
|
|
|
gputs("++eos 1"); |
|
|
|
gputs("++eoi 1"); |
|
|
|
gputs("++read_tmo_ms 4000"); |
|
|
|
gputs("++eot_enable 1"); |
|
|
|
gputs("++eot_char 13"); |
|
|
|
gputs("++addr 24"); |
|
|
|
gputs(":syst:beep:stat 0"); |
|
|
|
gputs(":sour:func:mode curr"); |
|
|
|
gputs(":sour:del 0"); |
|
|
|
gputs(":sour:curr 0"); |
|
|
|
gputs(":outp on"); |
|
|
|
} |
|
|
|
|
|
|
|
void keithley_current(int ma) |
|
|
|
{ |
|
|
|
char s[128]; |
|
|
|
sprintf(s, ":sour:curr %0.3f", ma / 1000.0); |
|
|
|
gputs(s); |
|
|
|
} |
|
|
|
|
|
|
|
void keithley_off(void) |
|
|
|
{ |
|
|
|
gputs(":outp off"); |
|
|
|
} |
|
|
|
|
|
|
|
void zputc(char ch) |
|
|
|
{ |
|
|
|
if (write(zoom, &ch, 1) != 1) |
|
|
|
err(1, "zoom write"); |
|
|
|
} |
|
|
|
|
|
|
|
void zero(void) |
|
|
|
{ |
|
|
|
zputc('z'); |
|
|
|
} |
|
|
|
|
|
|
|
void calibrate(void) |
|
|
|
{ |
|
|
|
int ma; |
|
|
|
|
|
|
|
info("Initializing Keithley"); |
|
|
|
keithley_on(); |
|
|
|
|
|
|
|
info("Sweep"); |
|
|
|
for (ma = -1000; ma <= 1000; ma += 10) { |
|
|
|
keithley_current(ma / 1000.0); |
|
|
|
sleep(1); |
|
|
|
if (quit) break; |
|
|
|
} |
|
|
|
|
|
|
|
keithley_off(); |
|
|
|
} |