#!/usr/bin/perl
#!/usr/bin/perl -d:ptkdb

###############################################################################
#
# logging.pl -  CSV, KLM, GPS Logging
#
# Copyright (C) 2009  Rainer Walther  (rainerwalther-mail@web.de)
#
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
#
# Es ist Ihnen gestattet: 
#     * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
#     * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
# 
# Zu den folgenden Bedingungen:
#     * Namensnennung.
#       Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
#     * Keine kommerzielle Nutzung.
#       Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
#     * Weitergabe unter gleichen Bedingungen.
#       Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
#       verändern oder als Grundlage für einen anderen Inhalt verwenden,
#       dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
#       weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
# 
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
# 
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
# des Rechteinhabers dazu erhalten.
# 
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
# 
# Weitere Details zur Lizenzbestimmung gibt es hier:
#   Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
#   Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
#
###############################################################################
#
# 2009-02-23 0.0.1 rw created
# 2009-04-01 0.1.0 rw RC1
# 2009-05-01 0.1.1 rw configurable logging interval
# 2009-05-17 0.1.7 rw _Timestamp timeout von 2s auf 10s erhoeht
#
###############################################################################

$Version{'logging.pl'} = "0.1.0 - 2009-04-01";

#
# Parameter
#

my $LoopTime = $Cfg->{'logging'}->{'Intervall'} || 1;  # in s
$LoopTime *= 1000000;      # in us

# Packages
use threads;
use threads::shared;
use Time::HiRes qw(usleep);

require "mkcomm.pl";     # MK communication
require "geserver.pl";   # Google Earth Server
require "translate.pl";  # Übersetzungstable

#
# Signal handler
#

$SIG{'INT'}  = 'LogSigHandler';
$SIG{'KILL'} = 'LogSigHandler';

sub SigHandler()
    {
    if ( defined threads->self() )
        {
        threads->exit();
        }
    exit;
    }

	
my $LogCsvIsOpen = 0;
my $LogKmlIsOpen = 0;
my $LogGpxIsOpen = 0;
my $GeServerIsRunning = 0;

#
# CSV
#

# Open CSV logfile
sub LogCsvOpen()
    {
    if ( ! $LogCsvIsOpen )
        {	
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
        my $Filename = sprintf ("mk-%04d%02d%02d-%02d%02d%02d.csv", $year+1900, $mon+1, $mday, $hour, $min, $sec);
        open LOGCSV, ">$Cfg->{'logging'}->{'CsvLogDir'}/$Filename";

        $LogCsvIsOpen = 1;

        # print labes at first line
	
        # NC OSD
        my $Sep = "";
        foreach $Label (sort keys %MkOsd)
            {
            if ( $Translate{$Label} ne "" )
                {
                $Label = $Translate{$Label};
                }
            print LOGCSV "$Sep" . "$Label";
            $Sep = ",";
            }
	
        # NC Debug
        foreach $Label (sort keys %MkNcDebug)
            {
            if ( $Translate{$Label} ne "" )
                {
                $Label = $Translate{$Label};
                }
	    print LOGCSV "$Sep" . "$Label";
            }
        print LOGCSV "\n";
        }

    return 0;
    }


# Close CSV
sub LogCsvClose()
    {
    if ( $LogCsvIsOpen )
        {
        close LOGCSV;
        $LogCsvIsOpen = 0;
        }
	
    return 0;
    }	
	
# Log CSV
sub LogCsv()
    {
    lock %MkOsd;      # until end of Block
    lock %MkNcDebug;  # until end of Block

    if ( $MkOsd{'_Timestamp'} >= time-10 )
        {
        # active connection to MK
        &LogCsvOpen();
	
        # NC OSD
        my $Sep = "";
        foreach $Label (sort keys %MkOsd)
            {
            print LOGCSV "$Sep" . "$MkOsd{$Label}";
            $Sep = ",";
            }
	
        # NC Debug
        foreach $Label (sort keys %MkNcDebug)
            {
            print LOGCSV "$Sep" . "$MkNcDebug{$Label}";
            }
        print LOGCSV "\n";
        }
    else
        {
        # connection to MK lost, close Logfile
        &LogCsvClose();
        }

    return 0;
    }

	
#
# GPX
# http://www.topografix.com/gpx_manual.asp
#

# Open GPX logfile
sub LogGpxOpen()
    {
    if ( ! $LogGpxIsOpen )
        {
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
        my $TimeStamp = sprintf ("%04d%02d%02d-%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
        my $Filename = "mk-" . $TimeStamp . ".gpx";
        open LOGGPX, ">$Cfg->{'logging'}->{'GpxLogDir'}/$Filename";
        $LogGpxIsOpen = 1;

        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
        my $UtcTimeStamp = sprintf ("%04d-%02d-%02dT%02d:%02d:%02dZ", $year+1900, $mon+1, $mday, $hour, $min, $sec);
	
        # print GPX-Header
        print LOGGPX <<EOF;
<?xml version="1.0" encoding="UTF-8"?>
<gpx
  version="1.0"
  creator="MK Mission Cockpit"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/0"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
  <time>${UtcTimeStamp}</time>
  <trk>
    <name>Mikrokopter GPS logging</name>
	<desc>Flight ${TimeStamp}</desc>
    <trkseg>
EOF
        }
		
    return 0;
    }	

	
# Close GPX
sub LogGpxClose()
    {
    if ( $LogGpxIsOpen )
        {
        # print GPX-Trailer
        print LOGGPX <<EOF;
    </trkseg>
  </trk>
</gpx>
EOF
        close LOGGPX;
        $LogGpxIsOpen = 0;
        }
	
    return 0;
    }	


# Log GPX
sub LogGpx()
    {
    lock %MkOsd;   # until end of Block

    if ( $MkOsd{'_Timestamp'} >= time-10  and
         $MkOsd{'MKFlags'} & 0x02  and  $MkOsd{'CurPos_Stat'} == 1 )
        {
        # active connection to MK, MK is flying, valid GPS
        &LogGpxOpen();

        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
        my $UtcTimeStamp = sprintf ("%04d-%02d-%02dT%02d:%02d:%02dZ", $year+1900, $mon+1, $mday, $hour, $min, $sec);

        my $Speed = $MkOsd{'GroundSpeed'} / 100;  # m/s
        printf LOGGPX <<EOF;
      <trkpt lat="$MkOsd{'CurPos_Lat'}" lon="$MkOsd{'CurPos_Lon'}">
        <ele>$MkOsd{'CurPos_Alt'}</ele>
        <time>${UtcTimeStamp}</time>
        <sat>$MkOsd{'SatsInUse'}</sat>
        <course>$MkOsd{'CompassHeading'}</course>
        <speed>$Speed</speed>
        <extensions>
          <Target-Lat>$MkOsd{'TargetPos_Lat'}</Target-Lat>
          <Target-Lon>$MkOsd{'TargetPos_Lon'}</Target-Lon>
          <Target-Alt>$MkOsd{'TargetPos_Alt'}</Target-Alt>
          <Target-Bearing>$MkOsd{'TargetPosDev_Bearing'}</Target-Bearing>
          <Target-Dist>$MkOsd{'TargetPosDev_Dist'}</Target-Dist>
          <Waypoint>$MkOsd{'WaypointIndex'} / $MkOsd{'WaypointNumber'}</Waypoint>
          <Altimeter>$MkOsd{'Altimeter'}</Altimeter>
          <Variometer>$MkOsd{'Variometer'}</Variometer>
          <UBat>$MkOsd{'UBat'}</UBat>
          <AngleNick>$MkOsd{'AngleNick'}</AngleNick>
          <AngleRoll>$MkOsd{'AngleRoll'}</AngleRoll>
          <MKFlags>$MkOsd{'MKFlags'}</MKFlags>
          <NCFlags>$MkOsd{'NCFlags'}</NCFlags>
        </extensions>
      </trkpt>		
EOF
        }
    else
        {
        &LogGpxClose();
        }
    }

#
# KML
# http://code.google.com/intl/de-DE/apis/kml/documentation/kml_tut.html
#

# Open KML logfile
sub LogKmlOpen()
    {
    if ( ! $LogKmlIsOpen )
        {	
        my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
        my $TimeStamp = sprintf ("%04d%02d%02d-%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
        my $Filename = "mk-" . $TimeStamp . ".kml";
        open LOGKML, ">$Cfg->{'logging'}->{'KmlLogDir'}/$Filename";
        $LogKmlIsOpen = 1;

        # print KML-Header
        print LOGKML <<EOF;
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
  <Document>
    <name>Mikrokopter GPS logging</name>
    <Style id="MK_gps-style">
      <LineStyle>
        <color>ff0000ff</color>
        <width>2</width>
      </LineStyle>
    </Style>
    <Placemark>
      <name>Flight ${TimeStamp}</name>
      <styleUrl>MK_gps-style</styleUrl>
      <LineString>
        <tessellate>1</tessellate>
        <altitudeMode>relativeToGround</altitudeMode>
        <coordinates>
EOF
        }
		
    return 0;
    }	

	
# Close KML
sub LogKmlClose()
    {
    if ( $LogKmlIsOpen )
        {
        # print KML-Trailer
        print LOGKML <<EOF;
        </coordinates>
      </LineString>
    </Placemark>
  </Document>
</kml>
EOF
        close LOGKML;
        $LogKmlIsOpen = 0;
        }
	
    return 0;
    }	


# Log KML
sub LogKml()
    {
    lock %MkOsd;   # until end of Block

    if ( $MkOsd{'_Timestamp'} >= time-10  and
         $MkOsd{'MKFlags'} & 0x02  and  $MkOsd{'CurPos_Stat'} == 1 )
        {
        # active connection to MK, MK is flying, valid GPS
        &LogKmlOpen();
	
        my $AltRel = $MkOsd{'CurPos_Alt'} - $MkOsd{'HomePos_Alt'};
        if ( $AltRel < 0 ) { $AltRel = 0; }
        printf LOGKML "          %f, %f, %f\n", $MkOsd{'CurPos_Lon'}, $MkOsd{'CurPos_Lat'}, $AltRel;
        }
    else
        {
        &LogKmlClose();
        }
    }


# Send Coords to GoogleEarth server
sub Send2GeServer()
    {
    lock %MkOsd;   # until end of Block

    if ( $MkOsd{'_Timestamp'} >= time-10  and
         $MkOsd{'MKFlags'} & 0x02  and  $MkOsd{'CurPos_Stat'} == 1 )
        {
        # active connection to MK, MK is flying, valid GPS

        my $AltRel = $MkOsd{'CurPos_Alt'} - $MkOsd{'HomePos_Alt'};
        if ( $AltRel < 0 ) { $AltRel = 0; }

        push @GeCoords, sprintf "%f, %f, %f", $MkOsd{'CurPos_Lon'}, $MkOsd{'CurPos_Lat'}, $AltRel;
        }
    }

	
sub MkLogLoop()
    {
    while (1)
        {
        &LogCsv();
        &LogKml();
        &LogGpx();

        &Send2GeServer();  # Google Earth

        # kurz schlafen legen
        usleep $LoopTime;
        }
    }
	
#
# Hauptprgramm
#	

if ( $0 =~ /logging.pl$/i )
    {
    # Program wurde direkt aufgerufen
	
    # Kommunikation zum MK herstellen
    $mk_thr = threads->create (\&MkCommLoop) -> detach();
    
    &MkLogLoop();
 
    # should never exit
    }

1;

__END__
