218 lines
4.2 KiB
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;
|
|
}
|
|
|