/*
 * ultimeter.c - Peet Bros Ultimeter weather parsing functions
 *
 *   These functions were developed for APRS World.  
 *   Copyright 2002 David L Norris <dave@webaugur.com>
 *   This program serves as a simple testbed for these functions.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *  
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/


#include <string.h>
#include <stdio.h>
#include "metric.h"

// weather struct is simply copied from the APRSWorld sources.
struct weather {
	char source[10];	// AX.25 Source address
	int wind_direction;
	int wind_speed;	// Kilometers / hour
	int wind_gust;	// kilometers / hour
	int wind_sustained;	// kilometers / hour
	int temperature;	// celcius
	float rain_hour;	// centimeters
	float rain_calendar_day;	// centimeters
	float rain_24hour_day;	// centimeters
	int humidity;
	float barometer;	// milibars
	int luminosity;
};

// Declare Functions
void parse_peet_packet (struct weather *wx, char *p);
void parse_peet_datalog (struct weather *wx, char *p);
void parse_peet_complete (struct weather *wx, char *p);
int axtoi( const char *digits );
void substr (char *dest, char *src, int size) ;

// Functions start here
void substr (char *dest, char *src, int size) {
	strncpy (dest, src, (size_t) size);
	dest[size] = '\0';
}

// Parse Peet Bros Packet mode data.  Header is "$ULTW"
void
parse_peet_packet (struct weather *wx, char *p) {
	char temp[5];
	
	// Wind Peak Speed, Gust, Sustained.  Ultimeter only reports 5-min gust in Packet Mode.
	substr(temp, p+5, 4);
	wx->wind_speed = wx->wind_gust = wx->wind_sustained = 
		axtoi( temp ) * 0.1;  // Convert 1/10 KPH to KPH

	// Wind Peak Direction
	substr(temp, p+9, 4);
	wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	
	// Outdoor Temperature
	substr(temp, p+13, 4);
	wx->temperature = F_TO_C( axtoi( temp ) * 0.1 );  // Convert 1/10 F to C
	
	// Rain Total (since Ultimeter manual reset)
	substr(temp, p+17, 4);
	wx->rain_hour = wx->rain_calendar_day =	wx->rain_24hour_day =
		IN_TO_CM( axtoi( temp ) * 0.01 );  // Convert 1/100 IN to CM
	
	// Altimeter Pressure
	substr(temp, p+21, 4);
	wx->barometer = axtoi( temp ) * 0.1;  // Already in millibars

	// Percent Relative Humidity
	substr(temp, p+37, 4);
	wx->humidity = axtoi( temp ) * 0.1;  // Convert 1/10 rh to rh

	// No luminousity sensors
	wx->luminosity = 0;
}

// Parse peet bros data logging format.  Header is "!!"
void
parse_peet_datalog (struct weather *wx, char *p) {
	char temp[5];
	
	// Wind Peak Speed, Gust, Sustained.
	substr(temp, p+2, 4);
	wx->wind_speed = wx->wind_gust = wx->wind_sustained = 
		axtoi( temp ) * 0.1;  // Convert 1/10 KPH to KPH

	// Wind Peak Direction
	substr(temp, p+6, 4);
	wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	
	// Outdoor Temperature
	substr(temp, p+10, 4);
	wx->temperature = F_TO_C( axtoi( temp ) * 0.1 );  // Convert 1/10 F to C
	
	// Rain Total (since Ultimeter manual reset)
	substr(temp, p+14, 4);
	wx->rain_hour = wx->rain_calendar_day =	wx->rain_24hour_day =
		IN_TO_CM( axtoi( temp ) * 0.01 );  // Convert 1/100 IN to CM
	
	// Altimeter Pressure
	substr(temp, p+18, 4);
	wx->barometer = axtoi( temp ) * 0.1;  // Already in millibars

	// Percent Relative Humidity
	substr(temp, p+26, 4);
	wx->humidity = axtoi( temp ) * 0.1;  // Convert 1/10 rh to rh

	// No luminousity sensors
	wx->luminosity = 0;
}

// Parse Peet Bros complete record format.  Header is "&CR&"
void
parse_peet_complete (struct weather *wx, char *p) {
	char temp[5];
	unsigned int tempval;
	unsigned int wind1, wind2, wind3;
	
	// Wind Speed fields 1, 34, and 71.  Wind direction fields 2, 35, 72.
	substr(temp, p+4, 4); wind1 = axtoi(temp);
	substr(temp, p+136, 4); wind2 = axtoi(temp);
	substr(temp, p+284, 4); wind3 = axtoi(temp);
	
	// Select wind speed and direction based on which value is the highest.
	// Ugh, surely there's a way to make this pretty.
	if( wind1 >= wind2 && wind1 >= wind3 ){
		wx->wind_speed = wind1 * 0.1;  // Convert 1/10 KPH to KPH
		// Wind Direction. field 2.
		substr(temp, p+8, 4);
		wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	}
	else if( wind2 >= wind1 && wind2 >= wind3 ){
		wx->wind_speed = wind2 * 0.1;  // Convert 1/10 KPH to KPH
		// Wind Direction. field 35.
		substr(temp, p+140, 4);
		wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	}
	else if( wind3 >= wind2 && wind3 >= wind1 ){
		wx->wind_speed = wind3 * 0.1;  // Convert 1/10 KPH to KPH
		// Wind Direction. field 72.
		substr(temp, p+288, 4);
		wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	}
	else{   // Just default to the first value rather than burn more CPU time.
		wx->wind_speed = wind1 * 0.1;  // Convert 1/10 KPH to KPH
		// Wind Direction. field 2.
		substr(temp, p+8, 4);
		wx->wind_direction = axtoi( temp ) * 1.41176;  // Convert 1/255 into 1/360
	}

	// Wind Peak Speed. field 3. 5 minute peak speed
	substr(temp, p+12, 4);
	wx->wind_gust = axtoi( temp ) * 0.1;  // Convert 1/10 KPH to KPH
	
	// Wind Sustained. 1 minute average.  field 115 does not exist on some models.
	substr(temp, p+460, 4);
	tempval = axtoi( temp );
	if( ( tempval > 0 ) && ( tempval < 150 ) ){
		wx->wind_sustained = tempval * 0.1;  // Convert 1/10 KPH to KPH
	}
	else {
		wx->wind_sustained = wx->wind_speed;  // Convert 1/10 KPH to KPH
	}

	// Outdoor Temperature. field 6
	substr(temp, p+24, 4);
	wx->temperature = F_TO_C( axtoi( temp ) * 0.1 );  // Convert 1/10 F to C
	
	// Rain Total since midnight. field 7.  We can't determine hourly or 24-hourly without history.
	substr(temp, p+28, 4);
	wx->rain_hour = wx->rain_calendar_day =	wx->rain_24hour_day =
		IN_TO_CM( axtoi( temp ) * 0.01 );  // Convert 1/100 IN to CM
	
	// Altimeter Pressure. field 8
	substr(temp, p+32, 4);
	wx->barometer = axtoi( temp ) * 0.1;  // Already in millibars

	// Percent Relative Humidity.  field 13
	substr(temp, p+52, 4);
	wx->humidity = axtoi( temp ) * 0.1;  // Convert 1/10 rh to rh

	// No luminousity sensors
	wx->luminosity = 0;
}

// ASCII Hexadecimal to integer
// Similar to atoi() but assumes Hexadecimal (base-16)
int
axtoi( const char *digits ){
	unsigned int retval,i;
	
	// Initialize
	i = retval = 0;
	
	// While we have a digit 0-9 or A-F.  Meaning, we break on the first non-hexadecimal character just like atoi.
	while( (digits[i] >= '0' && digits[i] <= '9') || (digits[i] >= 'A' && digits[i] <= 'F') ){
		// Multiply value by 16. No effect if this is our first pass
		retval = retval * 16;

		// Convert ASCII into Integer by subtracting either 0x37 from A-F or 0x30 from 0-9
		retval += (unsigned int)( (digits[i] > '9') ? digits[i] - 0x37 : digits[i] - 0x30 );

		i++;
	}
	
	return retval;
}

// Here's a good example of how you would initialize the structure and call the functions.
int
main ( void ){
	char record[1024];
	struct weather wx = { -1, -1, -1, -1, 0, -1, -1, -1, 0, -1, -1 };
	
	while( fgets( record, 1024, stdin ) ){
		switch( record[0] ){
			case '$':
				printf("Peet Bros Packet Format\n");
				parse_peet_packet( &wx, record );
				break;
			case '!':
				printf("Peet Bros Data Logging Format\n");
				parse_peet_datalog( &wx, record );
				break;
			case '&':
				printf("Peet Bros Complete Record\n");
				parse_peet_complete( &wx, record );
				break;
			default:
				printf("Unknown data format!\n");
		}

		// Print out our values.
		printf("wind speed: %i\n", wx.wind_speed);
		printf("wind gusting: %i\n", wx.wind_gust);
		printf("wind sustain: %i\n", wx.wind_sustained);
		printf("wind direction: %i\n", wx.wind_direction);
		printf("temperature: %i\n", wx.temperature);
		printf("humidity: %i\n", wx.humidity);
		printf("rainfall: %f\n", wx.rain_hour);
		printf("barometer: %f\n", wx.barometer);
		printf("\n\n");

	}
return 0;	
}




