Show vp2.c syntax highlighted
/*
* vp2.c
*
* Connects to davis weatherenvoy or vantage pro 2
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <libevent/event.h>
#include <link/link.h>
#include <emrun/emrun.h>
#include <sys/socket.h>
#include <termios.h>
#include <sys/uio.h>
#include "libmisc/misc.h"
#include "libdev/status_dev.h"
#include "timesync/sync.h"
#define READ_LEN 4096
#define SUMMARY_STATUS_DEV sim_path("/dev/davis-vp2/summary")
#define BUFLEN 99
g_event_t *request_timer = NULL;
typedef struct W {
float wind_spd;
int wind_direction;
float temperature;
int rh;
float soil_t;
float leaf_t;
struct timeval report_time;
} weather_t;
int baud;
g_event_t *serial = NULL;
char *device;
int serial_fd;
weather_t weather;
status_context_t *summary_ref = NULL;
char *clock_opt = NULL;
int clock_number = -1;
int test_mode = 0;
/*
* periodic request
*/
int timer_fired (void *data, int interval, g_event_t *event)
{
char buf[BUFLEN];
if (test_mode)
sprintf(buf, "TEST\n");
else
sprintf(buf, "LOOP 100\n");
write_to_fd(serial_fd, buf, strlen(buf));
elog(LOG_DEBUG(0), "write request string!");
return TIMER_RENEW;
}
/*
* Handle incoming data from serial port.
*/
static
int serial_data_ready(void *data, int fd, int cond, g_event_t *event)
{
static char buf[2*BUFLEN];
static int buf_len = 0;
/* the file descriptor is ready for reading... */
if (cond & FUSD_NOTIFY_INPUT) {
/* read into the buffer.. */
int status = read(fd, buf+buf_len, sizeof(buf) - buf_len);
/* error condition.. */
if (status < 0) {
if (errno == EINTR || errno == EAGAIN)
goto done;
elog(LOG_CRIT, "Read error from serial %s: %m", device);
exit(1);
}
/* got data.. */
if (status > 0) {
buf_len += status;
elog(LOG_DEBUG(5), "got %d bytes from serial.. pushing", status);
elog_raw(LOG_DEBUG(5), buf, buf_len);
retry:
while (buf_len > 0) {
if (buf[0] == 0x6)
goto trash_it_silently;
int check_max = buf_len;
if (check_max > 3) check_max = 3;
if (strncmp(buf, "LOO", check_max)) {
goto trash_it;
}
else break;
}
if (buf_len >= BUFLEN) {
if (buf[95]=='\n' && buf[96]=='\r') {
/* got a frame? */
gettimeofday(&weather.report_time, NULL);
if (clock_number >= 0) {
sync_id_t src = {
node: my_node_id,
comp: CPU
};
sync_id_t dest = {
node: my_node_id,
comp: clock_number
};
struct timeval src_tv = weather.report_time;
if (sync_convert_tv(&src, &src_tv, &dest, &weather.report_time) < 0) {
elog(LOG_WARNING, "couldn't convert from %s to %s: %m\n",
print_sync_id(&src), print_sync_id(&dest));
}
}
weather.wind_spd = (float)buf[14];
/* convert mph -> m/s */
weather.wind_spd *= 0.44704;
weather.wind_direction = buf[17];
weather.wind_direction *= 256;
weather.wind_direction += buf[16];
weather.temperature = buf[13];
weather.temperature *= 256;
weather.temperature += buf[12];
weather.temperature /= 10;
/* convert F -> C */
weather.temperature = ((weather.temperature - 32) * 5)/9;
weather.rh = buf[33];
weather.soil_t = buf[25] - 90;
weather.soil_t = ((weather.soil_t - 32) * 5)/9;
weather.leaf_t = buf[29] - 90;
weather.leaf_t = ((weather.leaf_t - 32) * 5)/9;
g_status_dev_notify(summary_ref);
buf_len -= BUFLEN;
memmove(buf, buf+BUFLEN, buf_len);
/* reset request timer */
g_event_destroy(request_timer);
g_timer_add(2000, timer_fired, NULL, NULL, &request_timer);
}
else {
goto trash_it;
}
}
}
done:
;
}
/* exceptions occur when the device disappears out from under or other
* unusual events.. */
if (cond & FUSD_NOTIFY_EXCEPT) {
elog(LOG_CRIT, "exception on serial port device: %m");
exit(1);
}
return EVENT_RENEW;
trash_it:
elog(LOG_WARNING, "dropping byte: %x", buf[0]);
trash_it_silently:
buf_len--;
memmove(buf, buf+1, buf_len);
goto retry;
}
/*
* Usage and initialization
*/
void usage(char *name)
{
misc_print_usage
(name,
"-d <device> [-b <baud>] [--clock <clock-name>]",
" --device <device>: specify device to expose\n"
" --baud <baud>: specify baud rate\n"
" --clock <clock-name>: clock in which to record data\n"
"\n"
"device, baud args are required\n"
);
exit(1);
}
static void vp2_shutdown(void *data)
{
elog(LOG_NOTICE, "vp2 device (connected to '%s'), shutting down...",
device);
exit(0);
}
int summary_status_print(status_context_t *info, buf_t *buf)
{
bufprintf(buf, "%ld.%06ld %.2f %d %.2f %d %.2f %.2f\n",
weather.report_time.tv_sec, weather.report_time.tv_usec,
weather.wind_spd, weather.wind_direction,
weather.temperature, weather.rh, weather.soil_t,
weather.leaf_t);
return STATUS_MSG_COMPLETE;
}
int main(int argc, char **argv)
{
misc_init(&argc, argv, CVSTAG);
/* parse args */
baud = 19200;
misc_parse_option_as_uint(&argc, argv, "baud", 'b', (uint*)&baud);
if ((device = misc_parse_out_option(&argc, argv, "device", 'd')) == NULL)
usage(argv[0]);
clock_opt = misc_parse_out_option(&argc, argv, "clock", 0);
if (misc_parse_out_switch(&argc, argv, "help", 'h'))
usage(argv[0]);
test_mode = misc_parse_out_switch(&argc, argv, "test", 0);
if (misc_args_remain(&argc, argv))
usage(argv[0]);
if (clock_opt) {
clock_number = sync_clock_no_create(clock_opt);
if (clock_number < 0) {
elog(LOG_WARNING, "No clock by the name of %s exists!\n", clock_opt);
}
}
/* Try to open the port */
if ((serial_fd = open(device, O_RDWR | O_NOCTTY)) < 0) {
elog(LOG_CRIT, "can't open %s: %m", device);
exit(1);
}
/* configure the serial port: raw, set baud, no rtscts */
misc_config_serial(serial_fd, baud, 0);
/* flush output */
if (tcflush(serial_fd, TCIFLUSH) < 0)
elog(LOG_WARNING, "can't tcflush serial port %s: %m", device);
/* Set this FD to be nonblocking */
set_nonblock(serial_fd, 1);
/* try to reset the device */
write(serial_fd, "\n", 1);
sleep(1);
write(serial_fd, "\n", 1);
sleep(1);
write(serial_fd, "\n", 1);
sleep(1);
write(serial_fd, "TEST\n", 5);
/* Add an event that fires when the serial port is readable */
if (g_event_add(serial_fd, FUSD_NOTIFY_INPUT | FUSD_NOTIFY_EXCEPT,
serial_data_ready, NULL, NULL, &serial) < 0) {
elog(LOG_CRIT, "can't create event for %s: %m", device);
exit(1);
}
elog(LOG_NOTICE, "Davis VantagePro2 (connected to '%s') starting...",
device);
status_dev_opts_t s_opts_summary = {
device: {
devname: SUMMARY_STATUS_DEV,
device_info: NULL
},
printable: summary_status_print
};
if (g_status_dev(&s_opts_summary, &summary_ref) < 0) {
elog(LOG_CRIT, "Unable to create status device: %m");
exit(1);
}
/* $$$ also create sensor devs!! */
/* $$$ sensorcat ... echos relative, streams back text formatted data! */
/* connect to emrun */
emrun_opts_t emrun_opts = {
shutdown: vp2_shutdown,
data: NULL
};
g_timer_add(2000, timer_fired, NULL, NULL, &request_timer);
emrun_init(&emrun_opts);
/* start event loop */
g_main();
return 1;
}
See more files for this project here