Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
617 rain-er 1
#!/usr/bin/perl
2
#!/usr/bin/perl -d:ptkdb
3
 
4
###############################################################################
5
#
6
# libmktime.pl -  MK Mission Cockpit - Timer for GUI Frontend
7
#
8
# Copyright (C) 2009  Rainer Walther  (rainerwalther-mail@web.de)
9
#
10
# Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
11
#
12
# Es ist Ihnen gestattet: 
13
#     * das Werk vervielfältigen, verbreiten und öffentlich zugänglich machen
14
#     * Abwandlungen bzw. Bearbeitungen des Inhaltes anfertigen
15
# 
16
# Zu den folgenden Bedingungen:
17
#     * Namensnennung.
18
#       Sie müssen den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen.
19
#     * Keine kommerzielle Nutzung.
20
#       Dieses Werk darf nicht für kommerzielle Zwecke verwendet werden.
21
#     * Weitergabe unter gleichen Bedingungen.
22
#       Wenn Sie den lizenzierten Inhalt bearbeiten oder in anderer Weise umgestalten,
23
#       verändern oder als Grundlage für einen anderen Inhalt verwenden,
24
#       dürfen Sie den neu entstandenen Inhalt nur unter Verwendung von Lizenzbedingungen
25
#       weitergeben, die mit denen dieses Lizenzvertrages identisch oder vergleichbar sind.
26
# 
27
# Im Falle einer Verbreitung müssen Sie anderen die Lizenzbedingungen, unter welche dieses
28
# Werk fällt, mitteilen. Am Einfachsten ist es, einen Link auf diese Seite einzubinden.
29
# 
30
# Jede der vorgenannten Bedingungen kann aufgehoben werden, sofern Sie die Einwilligung
31
# des Rechteinhabers dazu erhalten.
32
# 
33
# Diese Lizenz lässt die Urheberpersönlichkeitsrechte unberührt.
34
# 
35
# Weitere Details zur Lizenzbestimmung gibt es hier:
36
#   Kurzform: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
37
#   Komplett: http://creativecommons.org/licenses/by-nc-sa/3.0/de/legalcode
38
#
39
###############################################################################
40
# 2009-08-09 0.2.5 rw Timer moved from mkcockpit.pl
41
#                     Optional Player home-pos in map configuration
42
# 2009-08-23 0.2.6 rw Tracking-Antenna Icon
43
#                     POI heading control
44
#
45
###############################################################################
46
 
47
$Version{'libmktimer.pl'}  = "0.2.6 - 2009-08-23";
48
 
49
use Math::Trig;
50
 
51
#
52
# Timer: 5s
53
#
54
$main->repeat (5000, sub
55
    {
56
    if ( ! $MkSendWp )
57
        {
58
        # Abfragefrequenz OSD und Debug regelmäßig neu einstellen, falls Übertragungsfehler
59
        $MkSendQueue->enqueue( "o", "$AddrNC", pack ("C", 10) );   # Frequenz OSD Datensatz, * 10ms
60
        $MkSendQueue->enqueue( "d", "$AddrNC", pack ("C", 10) );   # Frequenz MK Debug Datensatz, * 10ms
61
        $MkSendQueue->enqueue( "v", "$AddrNC", "");   # Version
62
        $MkSendQueue->enqueue( "e", "$AddrNC", "");   # Error Text Request
63
        }
64
 
65
    lock (%MkOsd);              # until end of block
66
 
67
    # Draw Operation Radius Border
68
    $map_canvas->delete('Map-Border-OperatingRadius');
69
    if ( &HomePosIsValid() )
70
        {
71
        my $Radius = $MkOsd{'OperatingRadius'};
72
        my $H_Lat = $MkOsd{'HomePos_Lat'};
73
        my $H_Lon = $MkOsd{'HomePos_Lon'};
74
        my $Angel = &MapAngel();
75
 
76
        my ($T_Lat, $T_Lon) = &MapGpsAt ($H_Lat, $H_Lon, $Radius, $Angel -90);
77
        my ($R_Lat, $R_Lon) = &MapGpsAt ($H_Lat, $H_Lon, $Radius, $Angel);
78
        my ($B_Lat, $B_Lon) = &MapGpsAt ($H_Lat, $H_Lon, $Radius, $Angel + 90);
79
        my ($L_Lat, $L_Lon) = &MapGpsAt ($H_Lat, $H_Lon, $Radius, $Angel + 180);
80
 
81
        my ($T_x, $T_y) = &MapGps2XY ($T_Lat, $T_Lon);
82
        my ($R_x, $R_y) = &MapGps2XY ($R_Lat, $R_Lon);
83
        my ($B_x, $B_y) = &MapGps2XY ($B_Lat, $B_Lon);
84
        my ($L_x, $L_y) = &MapGps2XY ($L_Lat, $L_Lon);
85
 
86
        $map_canvas->createArc ( $L_x, $B_y, $R_x, $T_y,
87
                                 '-tags' => 'Map-Border-OperatingRadius',
88
                                 '-extent' => '359',
89
                                 '-start' => '0',
90
                                 '-style' => 'chord',
91
                                 '-outline' => $Cfg->{'mkcockpit'}->{'ColorAirfield'},
92
                                 '-width' => '1',
93
                               );
94
        $map_canvas->raise('Map-Border-OperatingRadius', 'Map');  # Border above Map
95
        }
96
 
97
    });
98
 
99
 
100
 
101
#       
102
# Timer: 0.1s - Map Overlay aktualisieren
103
#
104
$frame_map_top->repeat (100, sub
105
    {
106
 
107
    # Clear old messages from this timer
108
    &MkMessageInit ("Timer-MapOverlay");
109
 
110
    lock (%MkOsd);              # until end of block
111
 
112
    # Aktuell gültige Karte
113
    %Map = %{$Maps{'Current'}};
114
 
115
    if ( &MkOsdIsValid() )
116
        {
117
        # Gueltige OSD Daten
118
 
119
        # Operation Mode
120
        $OperationMode = "";
121
        if ( &MkIsWptMode() )         { $OperationMode = "WPT"; }
122
        if ( $PlayerMode eq "Play" )  { $OperationMode = "Play"; }
123
        if ( $PlayerMode eq "Pause" ) { $OperationMode = "Paus"; }
124
        if ( $PlayerMode eq "Home" )  { $OperationMode = "Home"; }
125
        if ( &MkIsPhMode() )          { $OperationMode = "PH"; }
126
        if ( &MkIsFreeMode() )        { $OperationMode = "Free"; }
127
 
128
        my $SatsInUse = $MkOsd{'SatsInUse'};
129
        if ( &CurPosIsValid()  and  &HomePosIsValid() )
130
            {
131
            # ausreichender GPS Empfang
132
 
133
            # get x,y map coords of current position
134
            my ($C_x, $C_y, $C_Angel) = &MapGps2XY($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'}, $MkOsd{'CompassHeading'});
135
            $MkPos_x = $C_x;
136
            $MkPos_y = $C_y;
137
 
138
            # rotate MK arrow
139
            my $dy = sin (deg2rad $C_Angel) * ($MapMkLen/2);
140
            my $dx = cos (deg2rad $C_Angel) * ($MapMkLen/2);
141
            my $x0 = $C_x - $dx;
142
            my $y0 = $C_y - $dy;
143
            my $x1 = $C_x + $dx;
144
            my $y1 = $C_y + $dy;
145
            $map_canvas->coords ('MK-Arrow', $x0, $y0, $x1, $y1);
146
 
147
            # Update speed vector
148
            my $MapAngel = &MapAngel();   # North to Map-Horizont
149
            my $GpsSpeedNorth = $MkNcDebug{'Analog_21'};
150
            my $GpsSpeedEast  = $MkNcDebug{'Analog_22'};
151
            my $PhiGpsSpeed = rad2deg atan2 ( $GpsSpeedEast, $GpsSpeedNorth );
152
            $PhiMapSpeed = $PhiGpsSpeed - $MapAngel;
153
 
154
            # 555 cm/s ~ 20 km/h -> Zeigerlänge = $MkSpeedLen bei 20 km/h
155
            my $dy = sin (deg2rad $PhiMapSpeed) * $MapMkSpeedLen * $MkOsd{'GroundSpeed'} / 555;
156
            my $dx = cos (deg2rad $PhiMapSpeed) * $MapMkSpeedLen * $MkOsd{'GroundSpeed'} / 555;
157
            my $x0 = $C_x;
158
            my $y0 = $C_y;
159
            my $x1 = $C_x + $dx;
160
            my $y1 = $C_y + $dy;
161
            $map_canvas->coords ('MK-Speed', $x0, $y0, $x1, $y1);
162
 
163
            # Update Line between Home and MK
164
            my ($H_x, $H_y) = &MapGps2XY($MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'});
165
            $map_canvas->coords ('MK-Home-Line', $H_x, $H_y, $C_x, $C_y);
166
 
167
            # Update Distance between Home and MK
168
            my ($Dist, $Bearing) = &MapGpsTo($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'},
169
                                                    $MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'} );
170
            my $x = ($C_x - $H_x) / 2 + $H_x + 8;
171
            my $y = ($C_y - $H_y) / 2 + $H_y + 8;
172
            $map_canvas->coords ('MK-Home-Dist', $x, $y);
173
            $map_canvas->itemconfigure ('MK-Home-Dist',
174
                                        '-text' => sprintf ("%4d m", int ($Dist + 0.5) ),
175
                                       );
176
 
177
            # Update OSD - Sat dependent values
178
            $map_canvas->itemconfigure ('MK-OSD-Spd-Value', '-text' => sprintf ("%3d km/h", $MkOsd{'GroundSpeed'} * 0.036) );
179
 
180
            # Alt = average Luftdruck und Sat
181
            my $Alt = int ( ($MkOsd{'Altimeter'} / $Cfg->{'mkcockpit'}->{'AltFactor'} +
182
                             $MkOsd{'CurPos_Alt'} - $MkOsd{'HomePos_Alt'} ) / 2 + 0.5 );
183
            $System{'Alt'} = $Alt;
184
            $map_canvas->itemconfigure ('MK-OSD-Alt-Value', '-text' => sprintf ("%3d m", $Alt) );
185
 
186
            if ( &TargetIsValid() )
187
                {
188
                # Valid Target
189
 
190
                # Update Line between Target and MK
191
                my ($T_x, $T_y) = &MapGps2XY($MkOsd{'TargetPos_Lat'}, $MkOsd{'TargetPos_Lon'});
192
                $map_canvas->coords ('MK-Target-Line', $C_x, $C_y, $T_x, $T_y);
193
 
194
                # Update Distance between Target and MK
195
                my ($Dist, $Bearing) = &MapGpsTo($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'},
196
                                                         $MkOsd{'TargetPos_Lat'}, $MkOsd{'TargetPos_Lon'} );
197
                if ( $Dist >= 25 )  
198
                    {
199
                    my $x = ($C_x - $T_x) / 2 + $T_x - 8;
200
                    my $y = ($C_y - $T_y) / 2 + $T_y + 8;
201
                    $map_canvas->coords ('MK-Target-Dist', $x, $y);
202
                    $map_canvas->itemconfigure ('MK-Target-Dist',
203
                                                '-text' => sprintf ("%4d m", int ($Dist + 0.5) ),
204
                                               );
205
                    }
206
                else
207
                    {
208
                    # Don't show distance < 25m
209
                    $map_canvas->coords ('MK-Target-Dist', 0, -100);
210
                    }
211
 
212
                # show target icon
213
                my $IconHeight = 48;
214
                my $IconWidth = 48;
215
                $map_canvas->coords('Target', $T_x - $IconWidth/2, $T_y - $IconHeight );
216
 
217
                $System{'CrossingBorder'} = 0;
218
                if ( &MkIsFlying()  and  &IsCrossingBorder($MkPos_x, $MkPos_y, $T_x, $T_y) )
219
                    {
220
                    # only, if MK is flying
221
                    $System{'CrossingBorder'} = 1;
222
                    &MkMessage ($Translate{'MsgCrossingBorder'}, "Timer-MapOverlay");
223
                    }
224
                }
225
            else
226
                {
227
                # No valid Target, move target line out of sight/canvas
228
                $map_canvas->coords ('MK-Target-Line', 0, -100, 0, -100);
229
                $map_canvas->coords ('MK-Target-Dist', 0, -100);
230
 
231
                # hide target icon
232
                $map_canvas->coords('Target', 0, -100, );
233
                }
234
 
235
            # Update Line between MK and POI
236
            if ( $PoiMode )
237
                {
238
                my ($P_x, $P_y) = &MapGps2XY($Poi_Lat, $Poi_Lon);
239
                $map_canvas->coords ('MK-POI-Line', $P_x, $P_y, $C_x, $C_y);
240
                }
241
            else
242
                {
243
                $map_canvas->coords ('MK-POI-Line', 0, -200, 0, -200);
244
                }
245
            }
246
        else
247
            {
248
            # kein ausreichender Sat-Empfang
249
            $map_canvas->itemconfigure ('MK-OSD-Spd-Value', '-text' => sprintf ("%3d km/h", 0 ) );
250
            }
251
 
252
        # Update OSD - non Sat dependent values
253
        $map_canvas->itemconfigure ('MK-OSD-Odo-Value', '-text' => sprintf ("%3.3f km", $OdoMeter / 1000) );
254
        $map_canvas->itemconfigure ('MK-OSD-Tim-Value', '-text' => sprintf ("%02d:%02d", $MkFlyingTime / 60, $MkFlyingTime % 60) );
255
        $map_canvas->itemconfigure ('MK-OSD-Sat-Value', '-text' => $MkOsd{'SatsInUse'} );
256
 
257
        # battery - OSD and warning
258
        my $UBat = sprintf ("%3.1f", $MkOsd{'UBat'});
259
        $System{'UBat'} = $UBat;
260
        $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-text' => "$UBat V" );
261
 
262
        $System{'BatWarning'} = 0;
263
        $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'});
264
        if ( $MkOsd{'UBat'}  <  $Cfg->{'mkcockpit'}->{'UBatWarning'} )
265
            {
266
            if ( time %2 )
267
                {
268
                $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-fill' => 'red');
269
                }
270
 
271
            &MkMessage ($Translate{'MsgBatWarning'}, "Timer-MapOverlay");
272
            $System{'BatWarning'} = 1;
273
            }
274
 
275
 
276
        # Display Operation Mode
277
        my $DisplayMode = $OperationMode;
278
        if ( &MkIsWptMode()  and  $OperationMode eq "Play" )
279
            {
280
            my %ModeMatrix =
281
               (
282
               "KML-STD" => "Play KML",
283
               "KML-RND" => "Play KML",
284
               "KML-MAP" => "Play KML",
285
               "WPT-STD" => "Play WPT",
286
               "WPT-RND" => "Rand WPT",
287
               "WPT-MAP" => "Rand MAP",
288
               );
289
            my $Key = "${PlayerWptKmlMode}-${PlayerRandomMode}";
290
            $DisplayMode = $ModeMatrix{$Key};
291
            }
292
 
293
        $System{'RangeWarning'} = 0;
294
        if ( &MkRangeLimit() )
295
            {
296
            $DisplayMode  = "$DisplayMode" . " !!";   # Range Warning
297
            $System{'RangeWarning'} = 1;
298
            }
299
        $map_canvas->itemconfigure ('MK-OSD-Mode-Value', '-text' => $DisplayMode );
300
 
301
 
302
        # Waypoints abhaengig vom Modus NC/Player
303
        my $WpValue = "-- / --";
304
        if ( $MkOsd{'WaypointNumber'} > 0)
305
            {
306
            $WpValue = sprintf ("%d / %d", $MkOsd{'WaypointIndex'} + 1, $MkOsd{'WaypointNumber'});
307
            }
308
        if ($PlayerMode ne "Stop" and $PlayerWptKmlMode eq "WPT")
309
            {
310
            $WpValue = sprintf ("%d / %d", $WpPlayerIndex +1, scalar @Waypoints);
311
            }
312
        if ($PlayerMode ne "Stop" and $PlayerWptKmlMode eq "KML" )
313
            {
314
            my $KmlTimeBase = $Cfg->{'waypoint'}->{'KmlTimeBase'} || 1.0;
315
            my $CurrTime = int ($KmlPlayerIndex * $KmlTimeBase + 0.5);
316
            my $TotTime = int (scalar @KmlTargets * $KmlTimeBase + 0.5);
317
            $WpValue = sprintf ("%02d:%02d / %02d:%02d", $CurrTime / 60, $CurrTime % 60, $TotTime / 60, $TotTime % 60);
318
            }
319
        $map_canvas->itemconfigure ('MK-OSD-Wp-Value',  '-text' => "$WpValue");
320
 
321
        # Recording Mode
322
        my $RecordText = "";
323
        if ( $PlayerRecordMode =~ /REC/i )
324
            {
325
            my $KmlTimeBase = $Cfg->{'waypoint'}->{'KmlTimeBase'} || 1.0;
326
            my $TotTime = int (scalar @KmlTargets * $KmlTimeBase + 0.5);
327
            $RecordText = sprintf ("Recording %02d:%02d", $TotTime / 60, $TotTime % 60);
328
            }
329
        $map_canvas->itemconfigure ('MK-OSD-Rec-Value', '-text' => $RecordText );
330
 
331
 
332
        # Farbe MK-Zeiger abhängig vom GPS Empfang
333
        my $MkCol= $Cfg->{'mkcockpit'}->{'ColorMkSatNo'};
334
        if ( $SatsInUse >= 1 ) { $MkCol = $Cfg->{'mkcockpit'}->{'ColorMkSatLow'} ; }
335
        if ( $SatsInUse >= 6 ) { $MkCol = $Cfg->{'mkcockpit'}->{'ColorMkSatGood'}; }
336
        $map_canvas->itemconfigure ('MK-Arrow', '-fill' => $MkCol);
337
 
338
 
339
        # Show/Hide SatFix Icon
340
        if ($SatsInUse >= 6 )
341
            {
342
            $map_canvas->coords('Satellite', $MapSizeX-300, 10, );
343
            }
344
        else
345
            {
346
            # move icon out of sight
347
            $map_canvas->coords('Satellite', 0, -100, );
348
            }
349
 
350
 
351
        # Variometer Pointer
352
        my $dy = -$MkOsd{'Variometer'} * 10;
353
        $map_canvas->coords('Map-Variometer-Pointer', 5, $MapSizeY/2+$dy, 20, $MapSizeY/2+10+$dy, 20, $MapSizeY/2-10+$dy);
354
 
355
        #
356
        # System checks
357
        #
358
 
359
        if ( ! &MkIsMotorOn() )      { &MkMessage ($Translate{'MsgMotorOff'}, "Timer-MapOverlay"); }
360
        if ( ! &MkIsFlying() )       { &MkMessage ($Translate{'MsgNotFlying'}, "Timer-MapOverlay"); }
361
        if ( &MkIsCalibrating() )    { &MkMessage ($Translate{'MsgCalibrate'}, "Timer-MapOverlay"); }
362
        if ( &MkIsMotorStarting() )  { &MkMessage ($Translate{'MsgStart'}, "Timer-MapOverlay") }
363
        if ( &MkEmergencyLanding() ) { &MkMessage ($Translate{'MsgEmergencyLanding'}, "Timer-MapOverlay"); }
364
        if ( &MkRangeLimit() )       { &MkMessage ($Translate{'MsgRangeLimit'}, "Timer-MapOverlay"); }
365
 
366
        # RC range check
367
        my $RcQuality = $MkOsd{'RC_Quality'};
368
        $System{'RCQuality'} = "";
369
 
370
        if ( $RcQuality < 100 )
371
            {
372
            $System{'RCQuality'} = "NO";
373
            &MkMessage ($Translate{'MsgRcError'}, "Timer-MapOverlay");
374
            }
375
        elsif ( $RcQuality < 150 )
376
            {
377
            $System{'RCQuality'} = "WEAK";
378
            &MkMessage ($Translate{'MsgRcWarning'}, "Timer-MapOverlay");
379
            }
380
 
381
        # Sat reception quality
382
        if ( $SatsInUse == 0 )
383
            {
384
            &MkMessage ($Translate{'MsgNoSatReception'}, "Timer-MapOverlay");
385
            }
386
        elsif ( $SatsInUse > 0  and $SatsInUse < 6 )
387
            {
388
            &MkMessage ($Translate{'MsgWeakSatReception'}, "Timer-MapOverlay");
389
            }
390
 
391
        # MK Border check
392
        $System{'OutsideBorder'} = "0";
393
        if ( &MkIsFlying() and ! &IsInsideBorder($MkPos_x, $MkPos_y) )
394
            {
395
            # only, if MK is flying
396
            $System{'OutsideBorder'} = "1";
397
            &MkMessage ($Translate{'MsgOutsideBorder'}, "Timer-MapOverlay");
398
            }
399
 
400
        # Show Balloon, when aproaching Target
401
        &TargetMessageShow();
402
 
403
        }
404
    else
405
        {
406
        # keine aktuellen OSD Daten vom MK verfügbar
407
        &MkMessage ($Translate{'MsgNoData'}, "Timer-MapOverlay");
408
        }
409
 
410
 
411
    # Wp-Number input from keyboard
412
    $KbTimer++;
413
    if ( $CbPlayerKey ne "" )
414
        {
415
        # Key pressed
416
        $KbNum = "$KbNum" . "$CbPlayerKey";
417
 
418
        $CbPlayerKey = "";
419
        $KbTimer = 0;
420
        }
421
    if ( $KbTimer > 7  and $KbNum ne "" )
422
        {
423
        # number complete, set target
424
        my $WpIndex = sprintf ("%d", $KbNum);
425
        &WpTargetSet ($WpIndex - 1);
426
 
427
        # prepare for next number
428
        $KbNum = "";
429
        }
430
 
431
 
432
    # Show System Messages
433
    &MkMessageShow();
434
 
435
    });
436
 
437
#       
438
# Timer: 0.1s - Tracking Anzeige aktualisieren
439
#
440
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
441
    {
442
    $frame_map_top->repeat (100, sub
443
        {
444
        # Clear old messages from this timer
445
        &MkMessageInit ("Timer-Tracking");    
446
 
447
        lock (%MkOsd);              # until end of block
448
        lock (%MkTrack);            # until end of block
449
 
450
        # Aktuell gültige Karte
451
        %Map = %{$Maps{'Current'}};
452
 
453
        # Zeiger neu zeichnen
454
        my $ServoPan = @ServoPos[$MkTrack{'ServoPan'}];
455
        if ( $ServoPan ne ""  )
456
            {
457
            my $x0 = $TrackSizeX/2;    
458
            my $y0 = $TrackSizeY - 0 - $TrackOffY;
459
            my $x1 = $TrackSizeX/2 - ($TrackPtrLen-22) * cos( deg2rad $ServoPan);
460
            my $y1 = $TrackSizeY   - ($TrackPtrLen-22) * sin (deg2rad $ServoPan) - $TrackOffY;
461
            $track_canvas->coords ('Track-Ptr', $x0, $y0, $x1, $y1);
462
            }
463
 
464
        # Farbe Zeiger abhängig vom GPS Empfang
465
        my $SatsInUse = $MkOsd{'SatsInUse'};
466
        my $TrackPtrCol= 'red';
467
        if ( $SatsInUse >= 1 ) { $TrackPtrCol = 'orange'; }
468
        if ( $SatsInUse >= 6 ) { $TrackPtrCol = 'green'; }
469
        $track_canvas->itemconfigure ('Track-Ptr', '-fill' => $TrackPtrCol);
470
        });
471
    }
472
 
473
 
474
#       
475
# Timer: 0.5s - Waypoint Player
476
#
477
$frame_map_top->repeat (500, sub
478
    {
479
    # Clear old messages from this timer
480
    &MkMessageInit ("Timer-Player");        
481
 
482
    lock (%MkOsd);              # until end of block
483
 
484
    if ( &MkIsWptMode() )
485
        {
486
        # NC is in WPT Mode 
487
 
488
        my $PoiHeading = $Cfg->{'waypoint'}->{'DefaultHeading'};
489
        if ( &CurPosIsValid()  and  $PoiMode )
490
            {
491
            $PoiHeading = &MapGpsTo ( $MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'},
492
                                      $Poi_Lat,  $Poi_Lon );
493
            }
494
 
495
        if ( $PlayerMode eq "Pause" )
496
            {
497
            if ( $PlayerPause_Lat ne ""  and  $PlayerPause_Lon ne "" )
498
                {
499
                # Gespeicherte Pausen-Pos senden
500
                &MkFlyTo ( '-lat'  => $PlayerPause_Lat,
501
                           '-lon'  => $PlayerPause_Lon,
502
                           '-holdtime' => "60",
503
                           '-heading' => $PoiHeading,
504
                           '-mode' => "Target",
505
                         );
506
                }
507
            }
508
 
509
        if ( $PlayerMode eq "Home" and &HomePosIsValid() )
510
            {
511
            # Gespeicherte oder eingestellte Home-Pos senden
512
 
513
            my $Home_Lat = $Map{'Home_Lat'} || $MkOsd{'HomePos_Lat'};
514
            my $Home_Lon = $Map{'Home_Lon'} || $MkOsd{'HomePos_Lon'};
515
 
516
            &MkFlyTo ( '-lat'  => $Home_Lat,
517
                       '-lon'  => $Home_Lon,
518
                       '-holdtime' => "60",
519
                       '-heading' => $PoiHeading,
520
                       '-mode' => "Target",
521
                     );
522
            }
523
 
524
 
525
        if ( $PlayerWptKmlMode ne 'WPT' )
526
            {
527
            # not in Wp mode
528
            return;
529
            }
530
 
531
 
532
        if ( $PlayerMode eq "Play"  )
533
            {
534
 
535
            if ( $PlayerRandomMode =~ /RND/i  or $PlayerRandomMode =~ /STD/i )
536
                {
537
                my $WpCnt = scalar @Waypoints;
538
                if ( $WpCnt > 0  and  $WpPlayerIndex < $WpCnt )
539
                    {
540
                    # Target WP-Pos senden
541
                    my $Wp = $Waypoints[$WpPlayerIndex];
542
                    my $Wp_Lon = $Wp->{'Pos_Lon'};
543
                    my $Wp_Lat = $Wp->{'Pos_Lat'};
544
                    if ( $Wp_Lat ne ""  and  $Wp_Lon ne "" )
545
                        {
546
                        &MkFlyTo ( '-lat'  => $Wp_Lat,
547
                                   '-lon'  => $Wp_Lon,
548
                                   '-holdtime' => "60",
549
                                   '-heading' => $PoiHeading,
550
                                   '-mode' => "Target",
551
                                 );
552
                        }
553
                    }
554
                }
555
 
556
            if ( $PlayerRandomMode =~ /MAP/i )
557
                {
558
                # Target Map-Pos senden
559
                &MkFlyTo ( '-x'  => $RandomTarget_x ,
560
                           '-y'  => $RandomTarget_y ,
561
                           '-holdtime' => "60",
562
                           '-heading' => $PoiHeading,
563
                           '-mode' => "Target",
564
                         );
565
                }
566
 
567
            # Ziel erreicht?
568
            if ( &WpCheckTargetReached() )
569
                {
570
                &WpTargetNext();
571
                }
572
            }
573
        }
574
 
575
    # WP Player Holdtime count down
576
    if ( $WpPlayerHoldtime > 0  )
577
        {
578
        $WpPlayerHoldtime --;
579
        }
580
    });
581
 
582
 
583
#       
584
# Timer: variabel - KML Player
585
#
586
my $KmlTimeBase = $Cfg->{'waypoint'}->{'KmlTimeBase'} || 1.0;
587
$KmlTimeBase *= 1000;
588
 
589
$frame_map_top->repeat ($KmlTimeBase, sub
590
    {
591
 
592
    # Clear old messages from this timer
593
    &MkMessageInit ("Timer-KMLPlayer");    
594
 
595
    lock (%MkOsd);              # until end of block
596
 
597
    if ( &CurPosIsValid() and $PlayerRecordMode =~ /REC/i )
598
        {
599
        # record current position
600
        push @KmlTargets, {
601
                          'Lat' => $MkOsd{'CurPos_Lat'},
602
                          'Lon' => $MkOsd{'CurPos_Lon'},
603
                          'Alt' => $MkOsd{'CurPos_Alt'},
604
                          };
605
        }
606
 
607
 
608
    if ( &MkIsWptMode() and  $PlayerMode eq "Play"  and  $PlayerWptKmlMode eq 'KML')
609
        {
610
        # Play KML
611
 
612
        # Pause, Home is handled in WPT-Timer
613
 
614
        my $KmlCnt = scalar @KmlTargets;
615
        if ( $KmlCnt > 0  and  $KmlPlayerIndex < $KmlCnt )
616
            {
617
            my $Lat = $KmlTargets[$KmlPlayerIndex]->{'Lat'};
618
            my $Lon = $KmlTargets[$KmlPlayerIndex]->{'Lon'};
619
            my $Alt = $KmlTargets[$KmlPlayerIndex]->{'Alt'};
620
 
621
            &MkFlyTo ( '-lat'             => $Lat,
622
                       '-lon'             => $Lon,
623
                       '-alt'             => $Alt,
624
                       '-holdtime'        => "60",
625
                       '-mode'            => "Target",
626
                     );
627
 
628
            # proceed to next Target
629
            $KmlPlayerIndex ++;
630
            if ( $KmlPlayerIndex >= $KmlCnt )
631
                {
632
                $KmlPlayerIndex = 0;
633
                }
634
            }
635
        }
636
 
637
    });
638
 
639
 
640
#       
641
# Timer: 1s
642
#
643
$frame_map_top->repeat (1000, sub
644
    {
645
    # Clear old messages from this timer
646
    &MkMessageInit ("Timer-Misc-1s");    
647
 
648
    lock (%MkOsd);              # until end of block
649
 
650
    # Aktuell gültige Karte
651
    %Map = %{$Maps{'Current'}};
652
 
653
    if ( &MkOsdIsValid() )
654
        {
655
 
656
        # Heartbeat MK Datenübertragung
657
        if ( time %2 )
658
            {
659
            $map_canvas->itemconfigure('Heartbeat', '-image' => 'HeartbeatLarge', );
660
            }
661
        else
662
            {
663
            $map_canvas->itemconfigure('Heartbeat', '-image' => 'HeartbeatSmall', );
664
            }
665
 
666
        # Flugzeit aktualisieren
667
        # Flugzeit selber mitzählen, da $MkOsd{'FlyingTime'} immer 0 (0.14b)
668
        if ( &MkIsFlying() )
669
            {
670
            $MkFlyingTime += 1;
671
            }
672
 
673
        # Update ODO-Meter
674
        if ( &CurPosIsValid() )
675
            {
676
            my $C_Lat = $MkOsd{'CurPos_Lat'};
677
            my $C_Lon = $MkOsd{'CurPos_Lon'};
678
 
679
            if ( $OdoFirst ne "" )
680
                {
681
                my ($Dist, $Bearing) = &MapGpsTo($C_Lat, $C_Lon, $OdoPos_Lat, $OdoPos_Lon );
682
                $OdoMeter += $Dist;
683
                }
684
            $OdoPos_Lat = $C_Lat;
685
            $OdoPos_Lon = $C_Lon;
686
            $OdoFirst = "1";
687
            }
688
 
689
        # Bat capacity
690
        my $Capacity = 100.0;
691
        my $CapacityText = "";
692
        if ( &MkIsFlying() )
693
            {
694
            if ( $UBatAverage eq "" )
695
                {
696
                $UBatAverage = $MkOsd{'UBat'};
697
                }
698
            $UBatAverage = (9.0 * $UBatAverage + $MkOsd{'UBat'}) / 10.0;
699
            $Capacity = &BatCapacity($UBatAverage);
700
            $CapacityText = sprintf ("(%d %)", int ($Capacity + 0.5) );
701
            }
702
        $map_canvas->itemconfigure ('MK-OSD-Bat-Level', '-text' => $CapacityText );
703
 
704
 
705
        # # Estimate remaining flight time
706
        # my $TextTimeLeft = "";
707
        # if ( &MkIsFlying()  and  $Capacity <= 90 )
708
        #     {
709
        #     my $MaxTime = 100.0 / (100.0 - $Capacity) * $MkFlyingTime;
710
        #     my $TimeLeft = $MaxTime - $MkFlyingTime;
711
        #     $TextTimeLeft = sprintf ("(%d min)", int ($TimeLeft / 60.0 + 0.8) );
712
        #     }
713
        # $map_canvas->itemconfigure ('MK-OSD-Tim-Left', '-text' => $TextTimeLeft );
714
 
715
 
716
        # Footprint
717
        if ( $Cfg->{'mkcockpit'}->{'FootprintLength'} > 0 )
718
            {
719
            if ( &CurPosIsValid() )
720
                {
721
                # neuen Footprint hinten anhaengen
722
                my ($x, $y) = &MapGps2XY($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'});
723
                push @Footprint, $x, $y;
724
                }
725
 
726
            while ( $#Footprint / 2  >  $Cfg->{'mkcockpit'}->{'FootprintLength'} )
727
                {
728
                # alte Footprints entfernen
729
                splice @Footprint, 0, 2;
730
                }
731
 
732
            &FootprintRedraw();
733
            }
734
 
735
 
736
        # start tracking antenne
737
        lock (%MkTrack);            # until end of block
738
        if ( &MkIsMotorOn()  and  ! $MkTrack{'IsRunning'} and
739
             $Cfg->{'track'}->{'Active'} =~ /y/i )
740
            {
741
            # start track at 1st motor start
742
            $track_thr = threads->create (\&TrackAntennaGps)->detach();
743
            }
744
 
745
 
746
        # show tracking antenna icon
747
        if ( $MkTrack{'HomePos_Lat'} ne ""  and  $MkTrack{'HomePos_Lon'} ne ""  )
748
            {
749
            # show antenna icon
750
            my ($x, $y) = &MapGps2XY($MkTrack{'HomePos_Lat'}, $MkTrack{'HomePos_Lon'});
751
 
752
            my $IconHeight = 48;
753
            my $IconWidth = 48;
754
            $map_canvas->coords('Track-Antenna', $x - $IconWidth/2, $y - $IconHeight );
755
            }
756
        else
757
            {
758
            # move icon out of sight
759
            $map_canvas->coords('Track-Antenna', 0, -50 );
760
            }
761
 
762
 
763
        # fun :-)
764
        if ( int rand (100) == 43 )
765
            {
766
            &TtsSpeak ('LOW', $Translate{'TtsFun'});
767
            }
768
        }
769
 
770
    });
771
 
772
 
773
#       
774
# Timer: 1s - TTS Sprachausgabe
775
#
776
$frame_map_top->repeat (1000, sub
777
    {
778
    # Aktuell gültige Karte
779
    %Map = %{$Maps{'Current'}};
780
 
781
    lock (%MkOsd);              # until end of block
782
 
783
    my $StatusInterval = $Cfg->{'tts'}->{'StatusInterval'}  || "30";  
784
    $SpeechTimer ++;
785
    my @TtsMsg;
786
 
787
    if ( &MkOsdIsValid() )
788
        {
789
        # Gueltige OSD Daten
790
 
791
        if ( $SpeechTimer % $StatusInterval == 0 )
792
            {
793
            #
794
            # give system status, low prio messages
795
            #
796
 
797
            # clear old low prio messages
798
            &TtsClear('LOW');
799
 
800
            # Flight time
801
            my $Min = int ( ($MkFlyingTime +1) / 60);
802
            my $Sec = int ( ($MkFlyingTime +1) % 60);
803
            my $Text = sprintf ("$Translate{'TtsFlightTimeMinSec'}", $Min, $Sec);
804
            if ( $Min == 0 )
805
                {
806
                $Text = sprintf ("$Translate{'TtsFlightTimeSec'}", $Sec);
807
                }
808
            &TtsSpeak ('LOW', "$Text");
809
 
810
            # Battery
811
            my ($Volt, $Tenth) = split '\.', $System{'UBat'};
812
            &TtsSpeak ('LOW', sprintf ("$Translate{'TtsBattery'}", $Volt, $Tenth));
813
 
814
            # Altitude
815
            if ( $System{'Alt'} < 0 )
816
                {
817
                &TtsSpeak ('LOW', sprintf ("$Translate{'TtsAltitudeNegative'}", abs($System{'Alt'}) ) );
818
                }
819
            else
820
                {
821
                &TtsSpeak ('LOW', sprintf ("$Translate{'TtsAltitude'}", $System{'Alt'} ) );
822
                }
823
 
824
            # Satellites
825
            &TtsSpeak ('LOW', sprintf ("$Translate{'TtsSatellite'}",  $MkOsd{'SatsInUse'}) );
826
            }
827
 
828
       # high prio messages
829
       if ( $SpeechTimer % 5 == 0 )
830
            {
831
            if ( $System{'BatWarning'} )          { push @TtsMsg, $Translate{'TtsBatteryWarning'}; }
832
            if ( $System{'RCQuality'} eq "WEAK" ) { push @TtsMsg, $Translate{'TtsRcWeak'}; }
833
            if ( $System{'RCQuality'} eq "NO" )   { push @TtsMsg, $Translate{'TtsRcNo'}; }
834
            if ( $System{'CrossingBorder'} )      { push @TtsMsg, $Translate{'TtsCrossingBorder'}; }
835
            if ( $System{'OutsideBorder'} )       { push @TtsMsg, $Translate{'TtsOutsideAirfield'}; }
836
            if ( $System{'RangeWarning'} )        { push @TtsMsg, $Translate{'TtsRange'}; }
837
            }
838
        }
839
    else
840
        {
841
        # no data link
842
        if ( $SpeechTimer % 5 == 0 )
843
            {
844
            push @TtsMsg, $Translate{'TtsNoDataLink'};
845
            }
846
        }
847
 
848
    # speak high prio messages 
849
    if ( scalar @TtsMsg > 0 )
850
        {
851
        # Clear pending messsages
852
        &TtsClear('HIGH');
853
 
854
        # Speak collected messages
855
        foreach $Msg (@TtsMsg)
856
            {
857
            &TtsSpeak ('HIGH', $Msg);
858
            }
859
        }
860
    });
861
 
862
 
863
__END__