USB Serial Interface
Overview
Davis VantagePro2 stations come in two varieties; wireless or wired. In this case I'm using the wireless version because it's more flexible. The outdoor sensors (ISS) transmit a wireless signal to a receiver. A receiver can be either a console with a display or an Envoy without a display. Consoles and Envoys only listen to what the ISS transmits so you can have multimple consoles associated with a single ISS if necessary.
In this configuration I've setup the console to log the station data in Davis format and report to CWOP via WeatherLink. For the resources I donate to CWOP, I recieve valuable QC information that helps to validate the data from the station. I've added a second Envoy to provide the same data stream to the Linux daemon via USB.
Davis also offers an IP data logger and that's certainly another option. For simplicity I chose to use a serial connection. From ISS, to Envoy, to Linux, opening and closing a serial connection in GCC is relatively straightfoward if you have any experience in C. If not, the suite and standard libraries come with extensive documentation.
Declarations
To start, we need to include some standard C headers and define shared variables for the file handle and receive buffer.
#include <errno.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <termios.h>#include "usbserial.h"#define BUFFER_SIZE (255) int fd; char buf[BUFFER_SIZE];
To send and receive data via USB we only need a few basic functions.
Opening and closing the USB port
Since the port won't be changing, I'll just hard code ttyUSB0 and the default serial port parameters. If the port is opened sucessfully, this function stores the file handle and returns 0 to indicate success. Otherwise it returns (-1).
int usb_open() {
struct termios port;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
fcntl(fd, F_SETFL, 0);
if (fd != -1) {
memset (&port, 0, sizeof(port));
// Serial control options
port.c_cflag &= ~PARENB;
port.c_cflag &= ~CSTOPB;
port.c_cflag &= ~CSIZE;
port.c_cflag |= CS8;
port.c_cflag |= CREAD;
port.c_cflag &= ~HUPCL;
port.c_cflag |= CLOCAL;
port.c_cflag |= CRTSCTS;
cfsetispeed (&port, B19200);
cfsetospeed (&port, B19200);
// Serial local options
port.c_lflag = 0;
// Serial input options
port.c_iflag = IGNBRK|IGNPAR;
// Serial output options
port.c_oflag &= ~OPOST;
port.c_cc[VTIME] = 1; // timer 1s
port.c_cc[VMIN] = 0;// blocking read until 1 char
tcsetattr (fd, TCSANOW, &port);
tcflush(fd, TCIOFLUSH);
}
return (int) (fd != -1) ? 0 : -1;
}
void usb_close() {
if (fd != -1) close(fd);
}
Reading and writing from and to the USB port
We'll also include a function to write a string to the port.
int usb_puts(char *buf) {
return (int) (write(fd, buf, strlen(buf)) == strlen(buf)) ? (0) : (-1);
}
For convenience, we'll add one more function to send a command to the console and collect the result. Remember, this is binary input so we can't rely on a null termination at the end of the buffer (we'll throw one in anyway just to be neat). This function returns 0 if there's an error or the length of the received data packet if the request was successful.
int usb_read(char *cmd) {
int n, err;
char *ptr;
for (err = -1 ; err ; err++) {
if (usb_puts(cmd))
break;
ptr = buf;
while ((n = read(fd, ptr, buf + sizeof(buf) - ptr - 1)) != 0)
ptr += n;
*ptr = '\0';
}
return (int) (err ? 0 : (ptr - buf));
}
Finally, we could expose the buffer to the code that implements the Davis protocol but just to keep things neat, let's offer a pointer to it instead.
char *usb_buffer(void) {
return (buf);
}




