zoom/pc/read.c

218 lines
4.2 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <stdint.h>
#include <syslog.h>
#include <err.h>
#include <linux/serial.h>
#include "serial-util.h"
#include <string.h>
#include <ctype.h>
int hex = 0;
int dec = 0;
int screen = 0;
int unprocessed = 0;
int process(const uint8_t *buf, int len);
int main(int argc, char *argv[])
{
char *device=strdup("/dev/serial/by-id/usb-FTDI_FT232R_"
"USB_UART_A6007wc5-if00-port0");
int rate=500000;
int fd;
int getopt_index;
char buf[1024];
int len;
int calibrate = 1;
static struct option long_opts[] = {
{ "device", required_argument, NULL, 'd' },
{ "rate", required_argument, NULL, 'r' },
{ "hex", no_argument, NULL, 'x' },
{ "dec", no_argument, NULL, 'D' },
{ "unprocessed", no_argument, NULL, 'u' },
{ "no-calibrate", no_argument, NULL, 'n' },
{ "screen", no_argument, NULL, 's' },
{ "help", no_argument, NULL, 'h' },
{ 0, 0, 0, 0 }
};
int help=0;
char c;
while ((c = getopt_long(argc, argv, "d:r:xDunsh?",
long_opts, &getopt_index)) != -1) {
switch(c)
{
case 'd':
free(device);
device = strdup(optarg);
break;
case 'r':
rate = atoi(optarg);
if(rate == 0)
errx(1, "invalid rate: %s",optarg);
break;
case 'x':
hex = 1;
break;
case 'D':
dec = 1;
break;
case 'u':
unprocessed = 1;
break;
case 'n':
calibrate = 0;
break;
case 's':
screen = 1;
break;
case 'h':
case '?':
default:
help = 1;
break;
}
}
if (help) {
fprintf(stderr, "Zoom Nilm Client\n");
fprintf(stderr, "usage: %s [options]\n\n", *argv);
fprintf(stderr, " -d, --device %-14s serial port\n", device);
fprintf(stderr, " -r, --rate %-16d baud rate\n", rate);
fprintf(stderr, " -x, --hex hex out\n");
fprintf(stderr, " -D, --dec dec out\n");
fprintf(stderr, " -u, --unprocessed "
"dump raw unprocessed data\n");
fprintf(stderr, " -n, --no-calibrate "
"skip calibration routine\n");
fprintf(stderr, " -s, --screen "
"send \\r instead of \\n\n");
fprintf(stderr, " -h, --help this cruft\n");
return 1;
}
if ((fd = serial_open(device, rate)) == -1)
err(1, "serial_open failed for %s", device);
if (calibrate) {
fprintf(stderr, "performing calibration\n");
char c = 'c';
write(fd, &c, 1);
drain(fd);
}
len = 0;
while (1) {
int processed, n;
n = read(fd, buf + len, sizeof(buf) - len);
if (n <= 0)
err(1, "read");
len += n;
processed = process((uint8_t *) buf, len);
memmove(buf, buf + processed, len - processed);
len -= processed;
}
return 1;
}
int process_adc_dac(const uint8_t *buf)
{
uint16_t dac, tmp;
int16_t adc;
int overflow;
/* data OK? */
if ((buf[0] & 0xC0) != 0)
return 0;
/* extract */
if (buf[0] & 0x10)
overflow = 1;
else
overflow = 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];
/* send it out */
if (hex) {
printf("%04x %03x", dac, adc & 0x0FFF);
} else if (dec) {
printf("%d %d", dac, adc);
} else {
printf("DAC: %5d ADC: % 5d Total: xxx", dac, adc);
if (overflow)
printf(" **** adc may have clamped");
}
if (screen)
printf("\033[K\r");
else
printf("\n");
return 1;
}
int process_calibration(const uint8_t *buf)
{
float f = *(float *)buf;
fprintf(stderr, "got calibration value: %f\n", f);
return 1;
}
int process(const uint8_t *buf, int len)
{
int n = 0;
if (unprocessed) {
n = write(fileno(stdout), buf, len);
if (n >= 0)
return n;
return 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)) ok = 1;
break;
case 0xA1:
if (process_calibration(buf + 1)) ok = 1;
break;
default:
break;
}
if (!ok) {
/* badly formed data; eat one byte and retry */
fprintf(stderr,"throwing away 0x%02x '%c'\n",
buf[0], isprint(buf[0]) ? buf[0] : '.');
buf++;
n++;
goto retry;
}
}
return n;
}