Quelltext /~heha/basteln/PC/Wetterstation/telemet.zip/linux/programme/l_tenki.cc

/* L_TENKI (jap. <Wetter>) liest Datenbytes vom Conrad-Telemetrie-Empfänger
 * an /dev/ttyS0 und gibt die Daten auf Standard-Ausgabe aus.
 *
 * Das Programm ist ein Standard-Linux-Programm, geschrieben in C++. 
 * Es basiert auf dem Windows-Programm tenki von h#s.
 *
 * Benoetigt werden vier Umrechnungstabellen festen Namens.
 * (diese sollten durchaus als Konstanten ins Programm eingebaut werden)
 *
 * tisc, 01/02

Ein Datenrahmen umfaßt 14 Bytes und ist wie folgt aufgebaut:

	Byte	Daten
	----	-----
	 1	8 Bit A/D-Wert vom Eingang A (A1)
	 2	8 Bit A/D-Wert vom Eingang B (A2) Regen
	 3	8 Bit A/D-Wert vom Eingang C (A3) Windrichtung [360°/256]
	 4	8 Bit A/D-Wert vom Eingang D (A4) Luftdruck [hPa(Tabelle)]
	 5	8 Bit A/D-Wert vom Eingang E (A5) Radioaktivität [100µSv/h]
	 6	8 Bit A/D-Wert vom Eingang F (A6) Licht [Lux(Tabelle)]
	 7	8 Bit A/D-Wert vom Eingang G (A7) Feuchte [%(Tabelle)]
	 8	8 Bit A/D-Wert vom Eingang H (A8) Temperatur [°C(Tabelle)]

	 9	8 Bits vom Digitalport

	10	High-Byte des Zähler-/Frequenzmesserwertes	Windgeschw.
	11	Low-Byte des Zähler-/Frequenzmesserwertes	[0.0179 m/s]

	12	Minuten-/Stundenwert der Stoppuhr
	13	Sekunden-/Minutenwert der Stoppuhr
	14	Hundertstel-/Sekundenwert der Stoppuhr

Die Zuordnung der A/D-Wandlerwerte (0...255) zu den physikalischen Meßgrößen
der von uns angebotenen Sensoren erfolgt in den meisten Fällen durch
Tabellendateien.
Die Tabellen berücksichtigen eventuelle Nichtlinearitäten der Sensorkennlinien
und nehmen Rundungen vor.

Byte 12 enthält im MSB das Stopflag (kennzeichnet den letzen Datenrahmen
und die Stoppzeit nach dem Low-High-Übergang am Triggereingang).

Byte 13 enthält im MSB das Zeitformatflag der Stoppuhr:

	0 = Minuten:Sekunden:Hundertstel
	1 = Stunden:Minuten:Sekunden

Läuft die Stoppuhr länger als eine Stunde, erfolgt automatisch das
Umschalten des Zeitformates. Läuft die Stoppuhr länger als 24 Stunden,
rollt der Stundenwert nach 23 auf 0. Dies kann zum Zählen von Tagen
genutzt werden.
*/

const char* default_device = "/dev/ttyS0"; /* = COM1 */
const long int timeout_sec = 10;
/* wir haben 10 Sekunden, um ein Paket zu empfangen */
const long int timeout_usec = 0;

/* Terminal-IO */
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>

/* open () */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/* select() */
#include <sys/time.h>

/* fuer Fehlermeldungen */
#include <errno.h>	// fuer Fehlermeldungen zu Fehlercodes
#include <string.h>	// fuer strerror() - macht Fehlermeldungen aus Fehlercodes

#include <errno.h>
#include <iostream>		
#include <iomanip>
#include <fstream>		
#include <string>

// Deklaration der Umrechnungstabellen - die sind am Dateiende der
// Uebersichtlichkeit halber
extern const float kty[256], hyg[256], lux[256], baro[256];

static void my_perror (const string& s)
{
	// erstmal die Fehlermeldung abholen
	const char *err_msg = strerror (errno);

	// C++ konform ausgeben
	cerr << s << ": " << err_msg << endl;
}


/*
static bool LiesTabelle(const string& dateiname, float *puffer) 
{
	//eine Tabelle (Datei) mit 256 float-Werten einlesen, muß neben der .EXE liegen
	ifstream datei (dateiname.c_str());

	if (datei)
	{
		for (int i = 0; i < 256; i++, puffer++)
		{
			datei >> *puffer;
		}
		return true;
	}

	return false;
}
*/

void Auswertung(unsigned char* incoming) 
{
	int windgeschw;
	static int letzte_windgeschw = 0;
	int h,m,s;	// vom Zeit-Diagramm

	const static char *richtung[16]=
	{	//Norden=0°, Uhrzeiger-Richtung
		"Nord","Nord-Nordost","Nordost","Ost-Nordost",
		"Ost","Ost-Südost","Südost","Süd-Südost",
		"Süd","Süd-Südwest","Südwest","West-Südwest",
		"West","West-Nordwest","Nordwest","Nord-Nordwest"
	};

	// Windgeschwindigkeit vorberechnen:
	// Leider hinterläßt der Sender bei stehendem Flügelrad
	// den letzten gemessenen Wert konstant, deshalb hier Extrawurst braten
	windgeschw = (((int)incoming[9]) << 8) + incoming[10];

	if ((windgeschw == letzte_windgeschw) && (windgeschw < 0x30))
	{
		windgeschw=0;
	}

	letzte_windgeschw=windgeschw;

	//Uhr des Senders auswerten:
	if (incoming[12] & 0x80) 
	{	//Stunden-Minuten-Sekunden
		h=incoming[11];
		m=incoming[12]&0x7F;
		s=incoming[13];
	}
	else
	{				//Minuten-Sekunden-Hundertstel
		h=0;
		m=incoming[11];
		s=incoming[12];
	}

	// Ergebnisse ausgeben
	//
	char timestr[256];
	time_t cur_time = time (0L);
	struct tm* local_time = localtime(&cur_time);
	strftime (timestr, 256, "%c", local_time);

	cout << "Uhrzeit (lokal): " << timestr << endl;

	ios::fmtflags old_flags = cout.flags();
	cout.setf (ios::fixed);

	cout << "Regen (letzte Stunde) in mm/h:" << (int)incoming[1] << endl;
	cout << "Windgeschwindigkeit in m/s:" << setprecision (2) << windgeschw*0.0179 << endl;
	cout << "Windrichtung (Grad):";

	if (windgeschw != 0) 
	{
		cout << (int)incoming[2]*360/256 << richtung[(incoming[2]+8) >> 4] << endl;
	}
	else
	{
		cout << "unbekannt (zu wenig Wind)" << endl;
	}
	cout << "Luftdruck in hPa:" << setprecision (0) << baro[incoming[3]] << endl;
	cout << "Radioaktivität in µSv/h:" << setprecision (2) << incoming[4]*(2.5/255) << endl;
	cout << "Lichtintensität in Lux:" << setprecision (0) << lux[incoming[5]] << endl;

	cout << "Luftfeuchte in %:" << setprecision (0) << hyg[incoming[6]] << endl;

	cout << "Temperatur in °C:" << setprecision (1) << kty[incoming[7]] << endl;
	cout << "Laufzeit:" << setw(2) << setfill ('0') << h << "." << m << ":" << s << endl;

	cout.flags (old_flags);
}

int main(int argc, char**argv) 
{
	const string program_name = argv[0];

	/*
	const string basedir = string (program_name, 0, program_name.rfind ('/'));

	LiesTabelle (basedir + "kty.tab", kty);
	LiesTabelle (basedir + "hyg.tab", hyg);
	LiesTabelle (basedir + "lux.tab", lux);
	LiesTabelle (basedir + "baro.tab", baro);
	*/

	// Schnittstelle oeffnen: lesen+schreiben, wird nicht unser
	// "controlling tty", nicht-blockierend
	int port_fd = open (default_device, O_RDWR | O_NOCTTY | O_NONBLOCK);

	if (port_fd == -1)
	{
		my_perror ("Fehler beim Oeffnen des seriellen Ports");
		return 1;
	}

	// Platz fuer Einstellungen des seriellen Ports
	struct termios saved_settings, our_settings;

	// aktuelle Einstellungen des Ports abfragen
	if (tcgetattr (port_fd, &saved_settings) != 0)
	{
		my_perror ("Fehler beim Abfragen der Portparameter");
		return 1;
	}

	// Einstellungen kopieren
	our_settings = saved_settings;

	// Eingabe-Geschwindigkeit setzen
	cfsetispeed (&our_settings, B2400);
	// Ausgabe-Geschwindigkeit setzen (ist das notwendig?)
	cfsetospeed (&our_settings, B2400);
	// raw-Modus anschalten -> 8Bit, keine Paritaet, 1 Stopbit, keine
	// Flusskontrolle, keine Verarbeitung spezieller Zeichen
	cfmakeraw (&our_settings);
	// Einstellungen uebernehmen, jetzt!
	if (tcsetattr (port_fd, TCSANOW, &our_settings) != 0)
	{
		my_perror ("Fehler beim Setzen der Portparameter");
		return 1;
	}

	// jetzt wollen wir noch den DTR anmachen
	int port_status;

	if (ioctl (port_fd, TIOCMGET, &port_status) != 0)
	{
		my_perror ("Fehler beim Abfragen des Portstatus");
		return 1;
	}
	// DTR setzen, falls noch nicht gesetzt
	if ((port_status | TIOCM_DTR) == 0)
	{
		// FIXME: Geht nicht, ich bekomme "bad address"
		// zum Glueck ist DTR an...
		if (ioctl (port_fd, TIOCMSET, port_status|TIOCM_DTR) != 0)
		{
			my_perror ("Fehler beim Setzen des Portstatus");
			//cerr << hex << "alter Status: " << port_status << ", neuer: " << (port_status | TIOCM_DTR) << endl;
			return 1;
		}
	}

	struct timeval timeout;

	timeout.tv_sec = timeout_sec;
	timeout.tv_usec = timeout_usec;

	/* Eingangs-Puffer */
	unsigned char incoming[14];
	int inpos = 0;

	for (inpos = 0; inpos < 14; inpos++)
	{
		fd_set	read_set;
		FD_ZERO (&read_set);
		FD_SET (port_fd, &read_set);

		// warten auf Daten, mit Timeout
		// Achtung: Die Struktur timeout wird modifiziert und enthaelt
		// nach dem Aufruf die Rest-Zeit. Das ist nicht portabel auf
		// andere Unices.
		int status = select (port_fd+1, &read_set, 0L, 0L, &timeout);

		if (status == -1)
		{
			my_perror ("Fehler beim Warten auf Daten");
			return 1;
		}

		if (status == 0)
		{
			cerr << "Timeout beim Warten auf Daten. Breche ab." << endl;
			break;
		}

		// Daten sind da -> lesen wir sie, bis max. Pufferende
		ssize_t bytes_read = read (port_fd, incoming, 14-inpos);

		if (bytes_read == -1)
		{
			my_perror ("Fehler beim Lesen der Daten");
			return 1;
		}

		inpos += bytes_read;
	}

	// Puffer wurde gelesen
	if (inpos >= 14)
	{
		Auswertung (incoming);
	}
	else
	{
		cout << inpos << endl;
	}

	// Alte Einstellungen wiederherstellen
	/* FIXME: Geht nicht, ich bekomme "bad address"
	if (ioctl (port_fd, TIOCMSET, port_status) != 0)
	{
		my_perror ("Fehler beim Wiederherstellen des Portstatus");
		return 1;
	}
	*/
	if (tcsetattr (port_fd, TCSANOW, &saved_settings) != 0)
	{
		my_perror ("Fehler beim Wiederherstellen der Portparameter");
		return 1;
	}
	close (port_fd);

	return 0;
}

const float kty[256] =  {
	-27.5, -27.0, -26.0, -25.5, -24.5, -24.0, -23.5, -22.5, 
	-22.0, -21.5, -20.5, -20.0, -19.5, -18.5, -18.0, -17.5, 
	-17.0, -16.0, -15.5, -15.0, -14.0, -13.5, -13.0, -12.5, 
	-11.5, -11.0, -10.5, -9.5, -9.0, -8.5, -8.0, -7.5,
	-6.5, -6.0, -5.5, -5.0, -4.0, -3.5, -3.0, -2.5,
	-2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0, 2.5,
	3.0, 3.5, 4.0, 4.5, 5.5, 6.0, 6.5, 7.0,
	7.5, 8.0, 8.5, 9.5, 10.0, 10.5, 11.0, 11.5,
	12.0, 12.5, 13.0, 14.0, 14.5, 15.0, 15.5, 16.0,
	16.5, 17.0, 17.5, 18.0, 18.5, 19.0, 20.0, 20.5,
	21.0, 21.5, 22.0, 22.5, 23.0, 23.5, 24.0, 24.5,
	25.0, 25.5, 26.0, 26.5, 27.0, 27.5, 28.0, 28.5,
	29.5, 30.0, 30.5, 31.0, 31.5, 32.0, 32.5, 33.0,
	33.5, 34.0, 34.5, 35.0, 35.5, 36.0, 36.5, 37.0,
	37.5, 38.0, 38.5, 39.0, 39.5, 40.0, 40.5, 41.0,
	41.5, 42.0, 42.5, 43.0, 43.5, 43.5, 44.0, 44.5,
	45.0, 45.5, 46.0, 46.5, 47.0, 47.5, 48.0, 48.5,
	49.0, 49.5, 50.0, 50.5, 51.0, 51.5, 52.0, 52.5,
	53.0, 53.5, 53.5, 54.0, 54.5, 55.0, 55.5, 56.0,
	56.5, 57.0, 57.5, 58.0, 58.5, 59.0, 59.0, 59.5,
	60.0, 60.5, 61.0, 61.5, 62.0, 62.5, 63.0, 63.5,
	64.0, 64.0, 64.5, 65.0, 65.5, 66.0, 66.5, 67.0,
	67.5, 68.0, 68.0, 68.5, 69.0, 69.5, 70.0, 70.5,
	71.0, 71.0, 71.5, 72.0, 72.5, 73.0, 73.5, 74.0,
	74.5, 74.5, 75.0, 75.5, 76.0, 76.5, 77.0, 77.5,
	77.5, 78.0, 78.5, 79.0, 79.5, 80.0, 80.0, 80.5,
	81.0, 81.5, 82.0, 82.5, 82.5, 83.0, 83.5, 84.0,
	84.5, 85.0, 85.0, 85.5, 86.0, 86.5, 87.0, 87.0,
	87.5, 88.0, 88.5, 89.0, 89.5, 89.5, 90.0, 90.5,
	91.0, 91.5, 91.5, 92.0, 92.5, 93.0, 93.5, 93.5,
	94.0, 94.5, 95.0, 95.5, 95.5, 96.0, 96.5, 97.0,
	97.5, 97.5, 98.0, 98.5, 99.0, 99.0, 99.5, 100.0 
};


const float hyg[256] = {
	 100, 100, 100, 100, 100, 100, 100, 100,
	 100, 100, 100, 100, 100, 100, 100, 100,
	 100, 100, 100, 100, 100, 100, 100, 100,
	 100, 100, 100, 100, 100, 100, 100, 100,
	 100, 99, 99, 99, 98, 98, 98, 97,
	 97, 96, 96, 96, 95, 95, 95, 94,
	 94, 94, 93, 93, 92, 92, 92, 91,
	 91, 91, 90, 90, 89, 89, 89, 88,
	 88, 88, 87, 87, 86, 86, 86, 85,
	 85, 85, 84, 84, 83, 83, 83, 82,
	 82, 81, 81, 81, 80, 80, 79, 79,
	 79, 78, 78, 77, 77, 77, 76, 76,
	 75, 75, 75, 74, 74, 73, 73, 72,
	 72, 72, 71, 71, 70, 70, 69, 69,
	 69, 68, 68, 67, 67, 66, 66, 66,
	 65, 65, 64, 64, 63, 63, 62, 62,
	 62, 61, 61, 60, 60, 59, 59, 58,
	 58, 57, 57, 57, 56, 56, 55, 55,
	 54, 54, 53, 53, 52, 52, 51, 51,
	 50, 50, 49, 49, 48, 48, 47, 47,
	 46, 46, 45, 45, 44, 44, 43, 43,
	 42, 42, 41, 41, 40, 40, 39, 39,
	 38, 37, 37, 36, 36, 35, 35, 34,
	 34, 33, 32, 32, 31, 31, 30, 30,
	 29, 28, 28, 27, 27, 26, 25, 25,
	 24, 24, 23, 22, 22, 21, 20, 20,
	 19, 18, 18, 17, 16, 16, 15, 15,
	 14, 13, 12, 12, 11, 10, 10, 9,
	 8, 7, 7, 6, 5, 5, 4, 3,
	 2, 1, 1, 0, 0, 0, 0, 0,
	 0, 0, 0, 0, 0, 0, 0, 0,
	 0, 0, 0, 0, 0, 0, 0, 0
};

const float lux[256] = {
	  0, 0, 10, 30, 50, 80, 100, 100,
	 100, 100, 110, 110, 110, 120, 130, 140,
	 150, 160, 170, 180, 190, 200, 200, 220,
	 230, 240, 250, 270, 290, 300, 330, 350,
	 380, 400, 430, 450, 470, 490, 510, 530,
	 550, 570, 590, 610, 630, 700, 750, 850,
	 980, 1150, 1300, 1500, 1700, 1900, 2600, 3200,
	 4100, 4500, 4700, 5200, 5700, 6400, 7300, 8000,
	 8400, 8900, 9300, 9700, 10000, 10500, 10800, 11000,
	 11200, 11400, 11700, 11900, 12300, 12400, 12600, 12800,
	 13100, 13700, 14300, 14900, 15300, 15900, 16600, 17000,
	 17500, 18000, 18500, 19000, 19600, 20100, 20800, 21400,
	 22000, 22700, 23300, 23900, 24500, 25100, 25900, 26500,
	27000, 27600, 28200, 28800, 29400, 30000, 30600, 31200,
	31800, 32500, 33100, 33700, 34300, 35000, 35600, 36200,
	36800, 37500, 38100, 38700, 39300, 40000, 40500, 41000,
	41500, 42000, 42500, 43000, 43500, 44000, 44500, 45000,
	45500, 46000, 46500, 47000, 47500, 48000, 48500, 49000,
	49500, 50000, 50300, 50600, 50900, 51200, 51500, 51800,
	52100, 52400, 52700, 53000, 53300, 53600, 53900, 54200,
	54500, 54800, 55100, 55400, 55700, 56000, 56300, 56600,
	56900, 57200, 57500, 57800, 58100, 58400, 58700, 59000,
	59300, 59600, 59900, 60200, 60500, 60800, 61100, 61400,
	61700, 62000, 62300, 62600, 62900, 63200, 63500, 63800,
	64100, 64400, 64700, 65000, 65300, 65600, 65900, 66200,
	66500, 66800, 67100, 67400, 67700, 68000, 68300, 68600,
	68900, 69200, 69500, 69800, 70100, 70400, 70700, 71000,
	71300, 71600, 71600, 71900, 72200, 72500, 72800, 73100,
	73400, 73700, 74000, 74000, 74300, 74600, 74900, 75200,
	75500, 75800, 76100, 76400, 76700, 77000, 77300, 77600,
	77900, 78200, 78500, 78800, 79100, 79400, 79700, 80000,
	80300, 80600, 80900, 81200, 81500, 81800, 82100, 85000
};

const float baro[256] = {
	 815, 816, 817, 818, 819, 820, 821, 822,
	 823, 824, 825, 826, 827, 828, 829, 830,
	 831, 832, 833, 834, 835, 836, 837, 838,
	 839, 840, 841, 842, 843, 844, 845, 846,
	 847, 848, 849, 850, 851, 852, 853, 854,
	 855, 856, 857, 858, 859, 860, 861, 862,
	 863, 864, 865, 866, 867, 868, 869, 870,
	 871, 872, 873, 874, 875, 876, 877, 878,
	 879, 880, 881, 882, 883, 884, 885, 886,
	 887, 888, 889, 890, 891, 892, 893, 894,
	 895, 896, 897, 898, 899, 900, 901, 902,
	 903, 904, 905, 906, 907, 908, 909, 910,
	 911, 912, 913, 914, 915, 916, 917, 918,
	 919, 920, 921, 922, 923, 924, 925, 926,
	 927, 928, 929, 930, 931, 932, 933, 934,
	 935, 936, 937, 938, 939, 940, 941, 942,
	 943, 944, 945, 946, 947, 948, 949, 950,
	 951, 952, 953, 954, 955, 956, 957, 958,
	 959, 960, 961, 962, 963, 964, 965, 966,
	 967, 968, 969, 970, 971, 972, 973, 974,
	 975, 976, 977, 978, 979, 980, 981, 982,
	 983, 984, 985, 986, 987, 988, 989, 990,
	 991, 992, 993, 994, 995, 996, 997, 998,
	 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006,
	 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014,
	 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022,
	 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030,
	 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038,
	 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046,
	 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054,
	 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062,
	 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070
};

/* vim:ts=4:sw=4:ai:si:nocindent
*/
Vorgefundene Kodierung: UTF-80