Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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