// Written by Sven Killig <sven@killig.de> 2010

#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ioctl.h>

const char* PORT="/dev/usb/tts/0";
const unsigned short int HOEHE_UE_NN=295;


die(const char *method) {
	printf("%s failed: %s\n", method, strerror(errno));
	exit(EXIT_FAILURE);
}


print_hex(const unsigned char *buf, int len) {
	unsigned int i;
	for(i=0; i<len; i++) {
		unsigned char c=buf[i];
	  printf("%i. %i 0x%02X\n", i, c, c);
	}
  printf("\n");
}


ssize_t write_or_exit(int fd, const unsigned char *buf) {
	ssize_t ret=write(fd, buf, strlen(buf));
	if (ret != strlen(buf)) die("write");
	return ret;
}


clearRts(int fd) {
  int temp;
  if(ioctl(fd, TIOCMGET, &temp) == -1) die("ioctl");
  temp &= ~TIOCM_RTS;
  if(ioctl(fd, TIOCMSET, &temp) == -1) die("ioctl");
}


float temperature(const unsigned char *buf, int pos) {
	unsigned char highbyte=buf[pos], lowbyte=buf[pos+1];
	float ret;
	if (highbyte == 255) ret=(float)lowbyte-256.0f;
	else ret=(float)highbyte*256.0f+(float)lowbyte;
	return ret/10;
}


unsigned char humidity(const unsigned char *buf, int pos) {
	unsigned char ret=buf[pos];
	return ret;
}


unsigned short int pressure(const unsigned char *buf, int pos) {
	unsigned short int ret=256*buf[pos]+buf[pos+1]+HOEHE_UE_NN/8;
	return ret;
}


int main(int argc, char *argv[]) {
  const unsigned short int BUFSIZE=80;
	static int fd=-1;
  struct termios portset;
  unsigned char in[BUFSIZE], in_unesc[BUFSIZE];
  unsigned short int i, j, offset=0;
  ssize_t ret;
  time_t rawtime;
  struct tm * ti;

	printf("content-type: text/plain\x0D\x0A");
	printf("\x0D\x0A");

  fd = open(PORT, O_RDWR | O_NOCTTY | O_NDELAY);
  if(fd == -1) die("open");

  if(tcgetattr(fd, &portset) == -1) die("tcgetattr");
  cfmakeraw(&portset);
  cfsetspeed(&portset, 19200);
	portset.c_cflag |= PARENB;
	portset.c_cflag &= ~PARODD;
	portset.c_cflag &= ~CSTOPB;
	portset.c_cflag &= ~CSIZE;
	portset.c_cflag |= CS8;
	portset.c_cflag &= ~CRTSCTS;
  if(tcsetattr(fd, TCSANOW, &portset) == -1) die("tcsetattr");

  clearRts(fd);
	usleep(250*1000);

  do {
		write_or_exit(fd, "\xFE\x33\xFC");
	  usleep(500*1000);
	  for(i=0; i<sizeof(in); i++) in[i]=0;
	  ret=read(fd, in, sizeof(in));
	} while(ret<40);
  if(in[0] == 0) offset=1;

  for(i=j=0; i<ret-1; i++, j++) {
  	if(in[i] == 0xF8) in_unesc[j]=in[++i]-1;
  	else in_unesc[j]=in[i];
  }
	if(argc>1) print_hex(in_unesc, ret-1);

  time(&rawtime);
  ti=localtime(&rawtime);

	printf("\x0D\x0A");
	printf("%.1f\x0D\x0A", temperature(in_unesc, offset+14));
	printf("%i\x0D\x0A",   humidity   (in_unesc, offset+16));
	printf("%i\x0D\x0A",   pressure   (in_unesc, offset+36));
	printf(" \x0D\x0A");  // Tagesniederschlagsmenge
	printf("-1\x0D\x0A"); // Windgeschwindigkeit
	printf(" \x0D\x0A");  // Windrichtung
	printf("%02i:%02i\x0D\x0A", ti->tm_hour, ti->tm_min);
	printf("%02i.%02i.%i\x0D\x0A", ti->tm_mday, ti->tm_mon+1, ti->tm_year+1900);
	printf(" \x0D\x0A");  // Aenderung des Luftdruckes in den letzen 6 Stunden
	printf(" \x0D\x0A");
	printf("%.1f\x0D\x0A", temperature(in_unesc, offset+33));
	printf("%i\x0D\x0A",   humidity   (in_unesc, offset+35));
}

