#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <locale.h>
#include <iostream>
#include <iomanip>
#include <set>
#include <string>
#include <sstream>
/* global variables */
static int verbose = 0;
static int server_port = 8783; // "WS" - Wetterstation
const char* default_device = "/dev/ttyS0"; /* = COM1 */
// Status des seriellen Ports wird gespeichert
struct termios saved_settings;
/* Mindest-Abstand zwischen zwei Paketen -> Wenn Daten in groesserem
* Abstand eintreffen, wird angenommen, dass sie zu verschiedenen Paketen
* gehoeren.
*/
static const struct timeval packet_gap = { 5, 0 };
// Paketfrequenz von der Anlage
static const struct timeval packet_frequency = { 10, 0 };
// Wie oft (=wie lange) soll versucht werden, Pakete von der Station
// zu empfangen? (Nur bei (Re-)Synchronisierung.)
const int synchronize_retry_count = 50;
// Wir definieren fuer das Protokoll: Neue Zeile durch \n.
const std::string new_line = "\n";
const std::string next_str = "NEXT:NEXT";
static void display_help ();
static int prepare_server_socket (int sockfd);
static int run_server (int listen_fd, int serial_fd, unsigned char* first_packet);
static int open_serial_port (unsigned char* first_packet);
static int synchronize (int port_fd, unsigned char* received_packet);
static std::string evaluate_packet (unsigned char* packet);
static std::string get_current_time ();
int main (int argc, char **argv)
{
int c; /* return value from getopt_long */
int *longindex = NULL;
int listen_sockfd, serial_fd;
/* parse command line options */
c = EOF+1;
while (c != EOF)
{
static struct option cmd_options[] = {
{"--help", 0, NULL, 'h' },
{"--verbose", 0, NULL, 'v' },
{"--port", 1, NULL, 'p' }
};
c = getopt_long (argc, argv, "hvp:", cmd_options, longindex);
switch (c) {
case 'h':
display_help ();
exit (0);
break;
case 'v':
verbose++;
break;
case 'p':
{
char* endptr = 0L;
if (strlen (optarg) <= 0)
{
std::cerr << "Fehlendes Argument für -p" << std::endl;
display_help ();
exit (1);
}
/* convert port to number */
server_port = strtol (optarg, &endptr, 10);
if ((endptr == 0L) || (*endptr != 0L))
{
std::cerr << "Ungültige Portnummer: " << optarg << std::endl;
display_help ();
exit (1);
}
break;
}
case '?':
case ':':
display_help ();
exit (1);
break;
}
} /* end of option parsing loop */
if (optind < argc)
{
std::cerr << "Zu viele Parameter." << std::endl;
exit (1);
}
/* open socket, Internet, TCP */
listen_sockfd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listen_sockfd == -1)
{
std::cerr << "Fehler beim Socket Erzeugen: " << strerror (errno) << std::endl;
return 1;
}
else
{
/* ease debugging: allow reusage of same address */
int x = 1;
if (setsockopt (listen_sockfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)) == -1)
{
std::cerr << "setsockopt (...SO_REUSEADDR...) fehlgeschlagen: " << strerror (errno) << std::endl;
return 1;
}
}
if (prepare_server_socket (listen_sockfd) != 0)
{
return 1;
}
// open serial port etc.
unsigned char first_packet[32];
if ((serial_fd = open_serial_port (first_packet)) < 0)
{
std::cerr << "Fehler beim Öffnen des seriellen Ports." << std::endl;
return 1;
}
// Signale blockieren: SIGPIPE - wir bekommen das mit, wenn wir versuchen,
// auf die Sockets zu schreiben und brauchen uns deshalb nicht auf das
// gefaehrliche Gebiet der Signal-handler zu wagen.
sigset_t sigs;
sigemptyset (&sigs);
sigaddset (&sigs, SIGPIPE);
sigprocmask (SIG_BLOCK, &sigs, NULL);
run_server (listen_sockfd, serial_fd, first_packet);
}
// end main()
static void display_help ()
{
std::cerr <<
"Syntax: l_tenki_d [-d] [-p port] [-v]" << std::endl <<
std::endl <<
"Optionen:" << std::endl <<
"-d, --daemon Daemon-Modus" << std::endl <<
"-p, --port Zu verwendenden Port setzen" << std::endl <<
"-v, --verbose Mehr erzählen" << std::endl <<
"-h, --help Diese Hilfe" << std::endl;
}
static int prepare_server_socket (int sockfd)
/* sockfd is an TCP/IP-Socket ready for bind()ing */
{
struct sockaddr_in localaddr;
if (verbose)
{
std::cerr << "Schalte non-blocking I/O ein" << std::endl;
}
if (fcntl (sockfd, F_SETFL, fcntl (sockfd, F_GETFL, 0) | O_NONBLOCK) != 0)
{
std::cerr << "Fehler beim Aktivieren der non-blocking I/O auf Server Socket: " << strerror (errno) << std::endl;
return 0;
}
if (verbose)
{
std::cerr << "bind() auf Server Socket" << std::endl;
}
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons (server_port);
// wir lauschen ueberall
localaddr.sin_addr.s_addr = htonl (INADDR_ANY);
if (bind (sockfd, (struct sockaddr *) &localaddr, sizeof (localaddr)) != 0)
{
std::cerr << "Error bei bind(): " << strerror (errno) << std::endl;
return 1;
}
return 0;
}
static void my_perror (const char *fmt,...) {
// sollte reichen, auch fuer grosse Fehlermeldungen
char error_message[2048];
// erstmal die Fehlermeldung abholen
va_list arguments;
va_start (arguments, fmt);
vsnprintf(error_message,2048,fmt,arguments);
va_end (arguments);
std::cerr << error_message << strerror (errno) << std::endl;
}
static int open_serial_port (unsigned char *first_packet)
{
if (verbose)
{
std::cerr << "Öffne seriellen Port" << std::endl;
}
// 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 port_fd;
}
// Platz fuer Einstellungen des seriellen Ports
struct termios 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 Aktivieren von DTR");
//cerr << hex << "alter Status: " << port_status << ", neuer: " << (port_status | TIOCM_DTR) << endl;
return -1;
}
}
synchronize (port_fd, first_packet);
return port_fd;
}
static int synchronize (int port_fd, unsigned char* received_packet)
// received_packet muss Platz fuer 32 Byte haben!
{
if (verbose)
{
std::cerr << get_current_time () << ": Synchronisiere..." << std::endl;
}
bool synchronized = false;
int retry_count = synchronize_retry_count;
fd_set orgreadset;
FD_ZERO (&orgreadset);
FD_SET (port_fd, &orgreadset);
if (tcflush (port_fd, TCIFLUSH) != 0)
{
my_perror ("tcflush() fehlgeschlagen: ");
return -1;
}
// Synchronisieren wir mal mit der Station:
// 1. alles wegwerfen
// 2. warten auf Daten
// 3. Bis zu 1 Sekunde warten, dass 14 Byte vollwerden
// 4. Wenn nicht erfolgreich, gehe zu 1.
while (! synchronized)
{
fd_set readset = orgreadset;
if (verbose > 1)
{
std::cerr << get_current_time () << ": Warte auf Daten..." << std::endl;
}
struct timeval timeout = packet_frequency;
// schlagen wir mal 1 Sekunde drauf.
timeout.tv_sec++;
// erstmal auf irgendwelche Daten warten
int select_result = select (port_fd+1, &readset, NULL, NULL, &timeout);
if (select_result == -1)
{
my_perror ("Fehler beim Synchronisieren: ");
return -1;
}
if (select_result == 0)
{
retry_count--;
if (retry_count == 0)
{
std::cerr << "Fehler beim Synchronisieren mit der Station. Abbruch nach " << synchronize_retry_count << " Versuchen." << std::endl;
return -1;
}
continue;
}
// struct timeval packet_timeout = packet_gap;
timeout = packet_gap;
int bytes_received = 0;
bool packet_complete = false;
if (verbose > 1)
{
std::cerr << get_current_time () << ": neues Paket?" << std::endl;
}
while (! packet_complete)
{
readset = orgreadset;
int select_result = select (port_fd+1, &readset, NULL, NULL, &timeout);
if (select_result == -1)
{
my_perror ("Fehler beim Synchronisieren: ");
return -1;
}
if (select_result == 0)
break;
int read_result = read (port_fd, &received_packet[bytes_received], 32-bytes_received);
if (read_result == -1)
{
my_perror ("Fehler beim Synchronisieren: ");
return -1;
}
bytes_received += read_result;
if (verbose > 1)
{
std::cerr << get_current_time () << ": " << read_result << " Bytes gelesen (insgesamt: " << bytes_received << ")." << std::endl;
}
if (bytes_received == 14)
packet_complete = true;
}
synchronized = packet_complete;
}
if (verbose)
{
std::cerr << "Synchronisation erfolgreich." << std::endl;
}
return 0;
}
static int run_server (int server_fd, int serial_fd, unsigned char* first_packet)
{
// auf eingehende Verbindungen warten
if (verbose)
{
std::cerr << "Server bereit." << std::endl;
}
// eingehende Verbindungen werden am Socket listen_fd signalisiert durch
// "readable" - siehe accept(2)
if (listen (server_fd, 0) != 0)
{
std::cerr << "Fehler bei listen(): " << strerror (errno) << std::endl;
return 1;
}
fd_set orgrset;
int highest_fd = 0;
FD_ZERO (&orgrset);
FD_SET (server_fd, &orgrset);
if (server_fd > highest_fd) highest_fd = server_fd;
// wir warten auch auf Daten am seriellen Port
FD_SET (serial_fd, &orgrset);
if (serial_fd > highest_fd) highest_fd = serial_fd;
std::set<int> connected_clients;
std::string last_dataset;
last_dataset = evaluate_packet (first_packet) + next_str + new_line;
//last_dataset = "FEHLER:Noch keine Daten empfangen" + new_line + next_str + new_line;
unsigned char incoming_packet[32];
struct timeval packet_start_time, current_time;
int invalid_packet_count = 0;
int packet_pos = 0;
while (1)
{
// select modifiziert readset dann um anzuzeigen, wo sich was tut
fd_set readset = orgrset;
// wir warten, bis irgendwas passiert:
// - neue Daten
// - neue Verbindung geht ein
int select_result = select (highest_fd+1, &readset, NULL, NULL, NULL);
if (verbose > 1)
{
std::cerr << "select() lieferte " << select_result << std::endl;
}
if (select_result == -1)
{
if (errno != EINTR)
{
std::cerr << "Fehler bei select(): " << strerror (errno) << std::endl;
return 1;
}
// FIXME: sollen wir bei EINTR (z.B. bei CTRL-C) stoppen oder ignorieren?
if (verbose)
{
std::cerr << "Ende." << std::endl;
}
break;
}
// was auch immer da los war - wir probieren's nochmal
if (select_result == 0)
{
std::cerr << "select() lieferte 0" << std::endl;
continue;
}
// Was zum Lesen da?
if (FD_ISSET (serial_fd, &readset))
{
gettimeofday (¤t_time, NULL);
if (packet_pos == 0) // neues Paket?
{
// Startzeit des Pakets merken
packet_start_time.tv_sec = current_time.tv_sec;
packet_start_time.tv_usec = current_time.tv_usec;
}
else
{
// Nachsehen, ob mehr als 9 Sekunden vergangen seit Paketstart
long sekunden = current_time.tv_sec - packet_start_time.tv_sec;
if (sekunden >= 9)
{
std::cerr << get_current_time() << ": letztes Paket unvollstaendig (nur " << packet_pos << " Bytes empfangen)." << std::endl;
packet_pos = 0;
packet_start_time.tv_sec = current_time.tv_sec;
packet_start_time.tv_usec = current_time.tv_usec;
#if 0
invalid_packet_count++;
if (invalid_packet_count > 3)
{
if (synchronize (serial_fd, incoming_packet) == 0)
{
last_dataset = evaluate_packet (incoming_packet) + next_str + new_line;
}
invalid_packet_count = 0;
continue;
}
#endif
}
}
// wir lesen u.U. mehr als notwendig
ssize_t read_result = read (serial_fd, &incoming_packet[packet_pos], 32-packet_pos);
if (read_result == -1)
{
std::cerr << "Fehler beim Lesen der Daten: " << strerror (errno) << std::endl;
continue;
}
packet_pos += read_result;
if (verbose)
{
std::cerr << get_current_time() << ": " << read_result << " Byte gelesen. Paketgroesse: " << packet_pos << std::endl;
}
if (packet_pos > 14)
{
if (verbose > 1)
std::cerr << "Mehr als 14 Byte gelesen: insgesamt " << read_result + packet_pos << std::endl;
tcflush (serial_fd, TCIFLUSH);
// einfach alles wegwerfen, + 1 Sekunde warten
// und da auch alles wegwerfen
fd_set orgwait_readset;
FD_ZERO (&orgwait_readset);
FD_SET (serial_fd, &orgwait_readset);
struct timeval timeout = packet_gap;
int r = 1, bytes_skipped = packet_pos;
while (r != 0)
{
fd_set wait_readset = orgwait_readset;
r = select (highest_fd+1, &wait_readset, NULL, NULL, &timeout);
if (r == -1)
{
std::cerr << "Fehler bei select(): " << strerror (errno) << std::endl;
break;
}
if (r != 0)
{
char buf;
bytes_skipped += read (serial_fd, &buf, 1);
}
}
if (verbose)
{
std::cerr << bytes_skipped << " Bytes verworfen." << std::endl;
}
packet_pos = 0;
}
if (packet_pos == 14)
{
invalid_packet_count = 0;
packet_pos = 0;
last_dataset = evaluate_packet (incoming_packet) + next_str + new_line;
if (verbose > 2)
{
std::cerr << "Neuer Datensatz:" << std::endl << last_dataset;
}
const char* last_dataset_buf = last_dataset.c_str();
const int last_dataset_size = last_dataset.size();
std::set<int> still_connected_clients;
// alle Clients abklappern und Daten hinschicken
for (std::set<int>::const_iterator it = connected_clients.begin (),
end_it = connected_clients.end ();
it != end_it;
++it)
{
ssize_t write_result = write (*it, last_dataset_buf, last_dataset_size);
// wir ignorieren genau 2 Fehler: EAGAIN und EINTR
// FIXME: teilweise geschriebene Daten noch nachschieben?
// -> gibt Probleme: Zeugs kann sich stauen...
if ((write_result >= 0) || ((write_result == -1) && ((errno == EAGAIN) || (errno == EINTR))))
{
if (verbose > 1)
std::cerr << "Schreiben auf FD " << *it << " erfolgreich: " << write_result << " Bytes" << std::endl;
still_connected_clients.insert (*it);
}
else
{
if (verbose > 1)
{
std::cerr << "Schliesse FD " << *it << " wegen: " << strerror (errno) << std::endl;
}
// -> diesen FD schliessen
close (*it);
} // Fehler beim Schreiben zu Client
} // Clients mit Daten versorgen
connected_clients = still_connected_clients;
} // Paket war vollstaendig
} // neue Daten gelesen
// neue Verbindungsanfrage?
if (FD_ISSET (server_fd, &readset))
{
struct sockaddr_in remoteaddr;
socklen_t remoteaddrlen = sizeof (remoteaddr);
// Verbindung annehmen -> neuer Socket
int new_fd = accept (server_fd, (sockaddr*)&remoteaddr, &remoteaddrlen);
if (new_fd < 0) // Fehler
{
// EAGAIN und EWOULDBLOCK stufen wir mal als nicht-kritisch ein
if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
{
if (verbose)
std::cerr << "accept() lieferte: " << strerror (errno) << std::endl;
}
else
{
std::cerr << "Fehler bei accept(): " << strerror (errno) << std::endl;
break;
}
}
else
{
// Verbindung ging gut
if (verbose)
{ // mal anzeigen, wer da ist
std::cerr << "Verbindungsanahme von " << inet_ntoa (remoteaddr.sin_addr) << ':' << ntohs (remoteaddr.sin_port) << " auf FD " << new_fd << std::endl;
}
if (fcntl (new_fd, F_SETFL, fcntl (new_fd, F_GETFL, 0) | O_NONBLOCK) != 0)
{
std::cerr << "Fehler beim Setzen von non-blocking I/O: " << strerror (errno) << std::endl;
}
else
{
connected_clients.insert (new_fd);
if (verbose)
{
std::cerr << "Schicke letzten Datensatz nach FD " << new_fd << std::endl;
}
// einfach Daten rausschreiben und vergessen
// FIXME: evtl. noch Fehlerbehandlung?
if (write (new_fd, last_dataset.c_str(), last_dataset.size()) < 0)
{
std::cerr << "Fehler beim Schreiben auf FD " << new_fd << ": " << strerror (errno) << std::endl;
// wir ignorieren das einfach mal...
// beim naechsten Schreiben fliegt der fd dann wieder weg
}
}
}
} // neue Verbindung angenommen
} // while(1)
// TODO: Aufraeumen
return 0;
}
static std::string get_current_time ()
{
struct timeval tv;
gettimeofday (&tv, NULL);
std::stringstream result;
result << tv.tv_sec << "." << tv.tv_usec;
return result.str();
}
extern const float kty[256], hyg[256], lux[256], baro[256];
static std::string evaluate_packet (unsigned char* incoming)
{
std::stringstream ergebnis;
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
setlocale (LC_TIME, "de_DE");
char timestr[256];
time_t cur_time = time (0L);
struct tm* local_time = localtime(&cur_time);
strftime (timestr, 256, "%a, %d. %B, %X", local_time);
ergebnis << "Uhrzeit (lokal): " << timestr << new_line;
ios::fmtflags old_flags = cout.flags();
ergebnis.setf (ios::fixed);
ergebnis << "Regen (letzte Stunde) in mm/h:" << (int)incoming[1] << new_line;
ergebnis << "Windgeschwindigkeit in m/s:" << setprecision (2) << windgeschw*0.0179 << new_line;
ergebnis << "Windrichtung (Grad):";
if (windgeschw != 0)
{
ergebnis << (int)incoming[2]*360/256 << " " << richtung[(incoming[2]+8) >> 4] << new_line;
}
else
{
ergebnis << "unbekannt (zu wenig Wind)" << new_line;
}
ergebnis << "Luftdruck in hPa:" << setprecision (0) << baro[incoming[3]] << new_line;
ergebnis << "Radioaktivität in µSv/h:" << setprecision (2) << incoming[4]*(2.5/255) << new_line;
ergebnis << "Lichtintensität in Lux:" << setprecision (0) << lux[incoming[5]] << new_line;
ergebnis << "Luftfeuchte in %:" << setprecision (0) << hyg[incoming[6]] << new_line;
ergebnis << "Temperatur in °C:" << setprecision (1) << kty[incoming[7]] << new_line;
ergebnis << "Laufzeit:" << setw(2) << setfill ('0') << h << "." << m << ":" << s << new_line;
ergebnis.flags (old_flags);
return ergebnis.str();
}
// Tabellen-Variablen
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:smartindent:ts=4
*/
Detected encoding: ANSI (CP1252) | 4
|
|