|
|
@@ -15,13 +15,14 @@ |
|
|
|
#include "zoom.h" |
|
|
|
#include "math.h" |
|
|
|
#include <pthread.h> |
|
|
|
#include <ctype.h> |
|
|
|
|
|
|
|
#define info(x...) fprintf(stderr,x) |
|
|
|
|
|
|
|
void dctest(int zoom, int gpib); |
|
|
|
static void dctest(int zoom, int gpib); |
|
|
|
|
|
|
|
int g_quit = 0; |
|
|
|
void handle_sig(int sig) { g_quit = 1; } |
|
|
|
static void handle_sig(int sig) { g_quit = 1; } |
|
|
|
|
|
|
|
int main(int argc, char *argv[]) |
|
|
|
{ |
|
|
@@ -95,72 +96,204 @@ int main(int argc, char *argv[]) |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
struct keithley_t { |
|
|
|
pthread_mutex_t mutex; |
|
|
|
double desired; |
|
|
|
double actual; |
|
|
|
int stable; |
|
|
|
}; |
|
|
|
|
|
|
|
struct threadinfo_t { |
|
|
|
int quit_flag; |
|
|
|
int fd; |
|
|
|
float calibration; |
|
|
|
struct keithley_t k; |
|
|
|
}; |
|
|
|
|
|
|
|
void *read_data(void *arg) |
|
|
|
int process_adc_dac(const uint8_t *buf, struct threadinfo_t *ti) |
|
|
|
{ |
|
|
|
uint16_t dac, tmp; |
|
|
|
int16_t adc; |
|
|
|
int overflow; |
|
|
|
double idesired, iactual; |
|
|
|
int stable; |
|
|
|
|
|
|
|
/* data OK? */ |
|
|
|
if ((buf[0] & 0xC0) != 0) return 0; |
|
|
|
|
|
|
|
/* extract */ |
|
|
|
overflow = (buf[0] & 0x10) ? 1 : 0; |
|
|
|
tmp = ((buf[0] & 0x0F) << 8) | buf[1]; |
|
|
|
|
|
|
|
/* sign-extend ADC value */ |
|
|
|
if (tmp & 0x0800) |
|
|
|
tmp |= 0xF000; |
|
|
|
else |
|
|
|
tmp &= ~0xF000; |
|
|
|
adc = (int16_t)tmp; |
|
|
|
|
|
|
|
dac = (buf[2] << 8) | buf[3]; |
|
|
|
|
|
|
|
/* get keithley data */ |
|
|
|
pthread_mutex_lock(&ti->k.mutex); |
|
|
|
idesired = ti->k.desired; |
|
|
|
iactual = ti->k.actual; |
|
|
|
stable = ti->k.stable; |
|
|
|
pthread_mutex_unlock(&ti->k.mutex); |
|
|
|
|
|
|
|
/* write it out */ |
|
|
|
printf("%d %.8f %.8f %.8f %5d %5d %d\n", |
|
|
|
stable, |
|
|
|
idesired, |
|
|
|
iactual, |
|
|
|
ti->calibration, |
|
|
|
dac, |
|
|
|
adc, |
|
|
|
overflow); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int process_calibration(const uint8_t *buf, struct threadinfo_t *ti) |
|
|
|
{ |
|
|
|
float f = *(float *)buf; |
|
|
|
ti->calibration = f; |
|
|
|
info("new calibration value: %.8f\n", ti->calibration); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
static int process(const uint8_t *buf, int len, struct threadinfo_t *ti) |
|
|
|
{ |
|
|
|
int n = 0; |
|
|
|
|
|
|
|
/* Process blocks */ |
|
|
|
retry: |
|
|
|
for (; (n + 5) <= len; buf += 5, n += 5) { |
|
|
|
int ok = 0; |
|
|
|
switch (buf[0]) { |
|
|
|
case 0xA0: |
|
|
|
if (process_adc_dac(buf + 1, ti)) ok = 1; |
|
|
|
break; |
|
|
|
case 0xA1: |
|
|
|
if (process_calibration(buf + 1, ti)) ok = 1; |
|
|
|
break; |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
if (!ok) { |
|
|
|
/* badly formed data; eat one byte and retry */ |
|
|
|
info("throwing away 0x%02x '%c'\n", buf[0], isprint(buf[0]) ? buf[0] : '.'); |
|
|
|
buf++; |
|
|
|
n++; |
|
|
|
goto retry; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return n; |
|
|
|
} |
|
|
|
|
|
|
|
static void *read_data(void *arg) |
|
|
|
{ |
|
|
|
struct threadinfo_t *ti = (struct threadinfo_t *)arg; |
|
|
|
char buf[1024]; |
|
|
|
int len; |
|
|
|
|
|
|
|
printf("ti->fd=%d\n", ti->fd); |
|
|
|
/* read data in a loop. Use saferead_timeout here so we can |
|
|
|
notice quit_flag before too long. */ |
|
|
|
len = 0; |
|
|
|
while (!ti->quit_flag) { |
|
|
|
printf("thread sleeping\n"); |
|
|
|
sleep(1); |
|
|
|
int processed, n; |
|
|
|
n = saferead_timeout(ti->fd, |
|
|
|
buf + len, |
|
|
|
sizeof(buf) - len, |
|
|
|
1000); |
|
|
|
if (n < 0) |
|
|
|
err(1, "read"); |
|
|
|
if (n == 0) |
|
|
|
continue; |
|
|
|
len += n; |
|
|
|
processed = process((uint8_t *) buf, len, ti); |
|
|
|
memmove(buf, buf + processed, len - processed); |
|
|
|
len -= processed; |
|
|
|
} |
|
|
|
printf("thread quitting\n"); |
|
|
|
info("read thread quitting\n"); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
void dctest(int zoom, int gpib) |
|
|
|
/* change keithley and update keithley_t structure with locking */ |
|
|
|
static int keithley_change(int gpib, double desired, struct keithley_t *k) |
|
|
|
{ |
|
|
|
double actual; |
|
|
|
|
|
|
|
pthread_mutex_lock(&k->mutex); |
|
|
|
k->stable = 0; |
|
|
|
k->desired = desired; |
|
|
|
pthread_mutex_unlock(&k->mutex); |
|
|
|
|
|
|
|
if (keithley_current(gpib, desired) < 0) |
|
|
|
return -1; |
|
|
|
|
|
|
|
actual = keithley_read(gpib); |
|
|
|
if (isnan(actual)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
pthread_mutex_lock(&k->mutex); |
|
|
|
k->actual = actual; |
|
|
|
pthread_mutex_unlock(&k->mutex); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void dctest(int zoom, int gpib) |
|
|
|
{ |
|
|
|
// double idesired, iactual; |
|
|
|
// int i; |
|
|
|
// int zero; |
|
|
|
// int dac[ZOOM_SWEEP_COUNT]; |
|
|
|
// int adc[ZOOM_SWEEP_COUNT]; |
|
|
|
pthread_t thread; |
|
|
|
struct threadinfo_t threadinfo; |
|
|
|
struct threadinfo_t ti; |
|
|
|
|
|
|
|
/* Do a calibration with Keithley off */ |
|
|
|
info("Triggering calibration\n"); |
|
|
|
zoomrun_trigger_calibrate(zoom); |
|
|
|
usleep(500000); |
|
|
|
usleep(1000000); |
|
|
|
|
|
|
|
printf("zoom=%d gpib=%d\n", zoom,gpib); |
|
|
|
|
|
|
|
/* Init Keithley */ |
|
|
|
info("Initializing GPIB\n"); |
|
|
|
// if (gpib_init(gpib) < 0) { info("failed\n"); goto out1; } |
|
|
|
if (gpib_init(gpib) < 0) { info("failed\n"); goto out1; } |
|
|
|
|
|
|
|
info("Initializing Keithley\n"); |
|
|
|
// if (gpib_addr(gpib, 24) < 0) { info("failed\n"); goto out1; } |
|
|
|
// if (keithley_init(gpib) < 0) { info("failed\n"); goto out2; } |
|
|
|
// if (keithley_current(gpib, 0) < 0) { info("failed\n"); goto out2; } |
|
|
|
// if (isnan(keithley_read(gpib))) { info("failed\n"); goto out2; } |
|
|
|
if (gpib_addr(gpib, 24) < 0) { info("failed\n"); goto out1; } |
|
|
|
if (keithley_init(gpib) < 0) { info("failed\n"); goto out2; } |
|
|
|
if (keithley_current(gpib, 0) < 0) { info("failed\n"); goto out2; } |
|
|
|
if (isnan(keithley_read(gpib))) { info("failed\n"); goto out2; } |
|
|
|
|
|
|
|
/* Start the thread that reads and dumps data */ |
|
|
|
info("Spawning thread\n"); |
|
|
|
threadinfo.quit_flag = 0; |
|
|
|
threadinfo.fd = zoom; |
|
|
|
if (pthread_create(&thread, NULL, read_data, &threadinfo) != 0) { |
|
|
|
if (pthread_mutex_init(&ti.k.mutex, NULL) != 0) { |
|
|
|
info("failed\n"); |
|
|
|
goto out2; |
|
|
|
} |
|
|
|
ti.calibration = 1.0; |
|
|
|
ti.k.desired = 0; |
|
|
|
ti.k.actual = 0; |
|
|
|
ti.k.stable = 0; |
|
|
|
ti.quit_flag = 0; |
|
|
|
ti.fd = zoom; |
|
|
|
if (pthread_create(&thread, NULL, read_data, &ti) != 0) { |
|
|
|
info("failed\n"); |
|
|
|
goto out2; |
|
|
|
} |
|
|
|
|
|
|
|
/* Do another calibration now */ |
|
|
|
info("Triggering calibration\n"); |
|
|
|
if (keithley_change(gpib, 0.0, &ti.k) < 0) { info("failed\n"); goto out3; } |
|
|
|
zoomrun_trigger_calibrate(zoom); |
|
|
|
usleep(1000000); |
|
|
|
|
|
|
|
/* Change Keithley values */ |
|
|
|
while (!g_quit) { |
|
|
|
info("sleeping\n"); |
|
|
|
sleep(1); |
|
|
|
} |
|
|
|
printf("quitting\n"); |
|
|
|
printf("main thread quitting\n"); |
|
|
|
|
|
|
|
threadinfo.quit_flag = 1; |
|
|
|
out3: |
|
|
|
ti.quit_flag = 1; |
|
|
|
pthread_join(thread, NULL); |
|
|
|
out2: |
|
|
|
keithley_off(gpib); |
|
|
|