Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
533 rain-er 1
#!/usr/bin/perl
2
#!/usr/bin/perl -d:ptkdb
3
 
4
###############################################################################
5
#
6
# mkcockpit.pl -  MK Mission Cockpit - GUI
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-02-20 0.0.1 rw created
41
# 2009-04-01 0.1.0 rw RC1
42
# 2009-04-16 0.1.1 rw Bugfix, ALT= average of airsensor and Sat
43
# 2009-05-14 0.2.0 rw Waypoint Player
44
# 2009-05-17 0.2.1 rw Cursor-Steuerung fuer WP-Player. Cmdline-Parameter "-geometry"
45
# 2009-07-18 0.2.2 rw DE/EN multinational
46
#                     Target-Balloon with Distance, Tolerance and Holdtime
47
#                     Fix footprint "Ausreiser"
48
#                     JPEG and PNG maps supported
49
#                     Player for KML Files
50
# 2009-07-26 0.2.3 rw System Messages Balloon
51
#  
52
#
53
###############################################################################
54
 
55
$Version = "0.2.3 - 2009-07-26";
56
 
57
use threads;            # http://search.cpan.org/~jdhedden/threads-1.72/threads.pm
58
                        # http://perldoc.perl.org/threads.html
59
use threads::shared;    # http://search.cpan.org/~jdhedden/threads-shared-1.28/shared.pm
60
use Thread::Queue;      # http://search.cpan.org/dist/Thread-Queue-2.11/lib/Thread/Queue.pm
61
use Tk;
62
use Tk::Balloon;
63
use Tk::Dialog;
64
use Tk::Notebook;
65
use Tk::JPEG;           # http://search.cpan.org/~srezic/Tk-804.028/JPEG/JPEG.pm
66
use Tk::PNG;            # http://search.cpan.org/~srezic/Tk-804.028/PNG/PNG.pm
67
use Math::Trig;
68
use Time::HiRes qw(usleep);  # http://search.cpan.org/~jhi/Time-HiRes-1.9719/HiRes.pm
69
use XML::Simple;             # http://search.cpan.org/dist/XML-Simple-2.18/lib/XML/Simple.pm
70
 
71
# change working directory to program path
72
my $Cwd = substr ($0, 0, rindex ($0, "mkcockpit.pl"));
73
chdir $Cwd;
74
 
75
# set path for local Perl libs
76
push @INC, $Cwd . "perl/lib", $Cwd . "perl/site/lib";
77
 
78
# Version setting
79
share (%Version);
80
$Version{'mkcockpit.pl'}  = $Version;
81
 
82
# Read configuration
83
 
84
$XmlConfigFile = "mkcockpit.xml";
85
$Cfg = XMLin($XmlConfigFile);
86
 
87
require "track.pl";     # Tracking antenna
88
require "mkcomm.pl";    # MK communication
89
require "logging.pl";   # CSV and GPX Logging
90
require "geserver.pl";  # Google Earth Server
91
require "$Cfg->{'map'}->{'MapDir'}/map.pl";   # Landkarte
92
require "libmap.pl";    # map subs
93
require "translate.pl"; # Übersetzungstable
94
 
95
# Commandline parameter
96
my %CmdLine = @ARGV;
97
 
98
# Thread fuer Kommunikation mit MK starten
99
# Output: %MkOsd, %MkTarget, %MkNcDebug, %Mk
100
# Input:  Thread-Queue: $MkSendQueue
101
$mk_thr = threads->create (\&MkCommLoop) -> detach();
102
 
103
# Start Logging Thread
104
$log_thr = threads->create (\&MkLogLoop) -> detach();
105
 
106
# Start GoogleEarth Thread
107
$ge_thr = threads->create (\&GeServer) -> detach();
108
 
109
# Aktuell gültige Karte
110
my %Map = %{$Maps{'Current'}};
111
 
112
# Hauptfenster
113
my $main = new MainWindow;
114
$main->title ("MK Mission Cockpit - Version $Version");
115
 
116
if ( $CmdLine{'-geometry'} ne "" )
117
    {
118
    $main->geometry( "$CmdLine{'-geometry'}" );
119
    }
120
 
121
#-----------------------------------------------------------------
122
# Menu
123
#-----------------------------------------------------------------
124
 
125
# Menu bar
126
my $menu_bar = $main->Menu;
127
$main->optionAdd("*tearOff", "false");
128
$main->configure ('-menu' => $menu_bar);
129
 
130
my $menu_file = $menu_bar->cascade('-label' => $Translate{'File'});
131
    $menu_file->command('-label' => $Translate{'Preferences'},
132
                        '-command' => [\&Configure],
133
                       );
134
    $menu_file->separator;                                     
135
    $menu_file->command('-label' => $Translate{'Exit'},
136
                        '-command' => sub{exit(0)},
137
                        );
138
 
139
my $menu_debug = $menu_bar->cascade(-label => $Translate{'Debug'});
140
    $menu_debug->command('-label' => $Translate{'NcOsdDataset'},
141
                         '-command' => [\&DisplayHash, \%MkOsd, $Translate{'NcOsdDataset'}, "Display Refresh Heartbeat"],
142
                        );
143
    $menu_debug->command('-label' => $Translate{'NcTargetDataset'},
144
                         '-command' => [\&DisplayHash, \%MkTarget, $Translate{'NcTargetDataset'}, "Display Refresh Heartbeat"],
145
                        );
146
    $menu_debug->command('-label' => $Translate{'NcDebugDataset'},
147
                         '-command' => [\&DisplayHash, \%MkNcDebug, $Translate{'NcDebugDataset'}, "Display Refresh Heartbeat"],
148
                                        );             
149
    $menu_debug->command('-label' => $Translate{'NcOther'},
150
                         '-command' => [\&DisplayHash, \%Mk, $Translate{'NcOther'}, "Display Refresh Heartbeat"],
151
                                        );
152
    $menu_debug->separator;                                    
153
    $menu_debug->command('-label' => $Translate{'TrackingDebugDataset'},
154
                         '-command' => [\&DisplayHash, \%MkTrack, $Translate{'TrackingDebugDataset'}, "Display Refresh Heartbeat"],
155
                        );
156
 
157
my $menu_help = $menu_bar->cascade(-label => $Translate{'Help'});
158
    $menu_help->command('-label' => 'Version',
159
                        '-command' => [\&DisplayHash, \%Version, $Translate{'Version'}, "Display"],
160
                       );
161
    $menu_help->separator;
162
    $menu_help->command('-label' => $Translate{'About'},
163
                        '-command' => sub
164
        {
165
        my $License = <<EOF;
166
Copyright (C) 2009  Rainer Walther (rainerwalther-mail\@web.de)
167
 
168
Creative Commons Lizenz mit den Zusaetzen (by, nc, sa)
169
 
170
See LICENSE.TXT
171
EOF
172
 
173
        my $DlgAbout = $frame_map->Dialog('-title' => $Translate{'AboutMissionCockpit'},
174
                                          '-text' => "$License",
175
                                          '-buttons' => ['OK'],
176
                                          '-bitmap' => 'info',
177
                                         );
178
        $DlgAbout->Show;
179
        });  
180
 
181
 
182
# Hauptfenster Statuszeile
183
$frame_status = $main->Frame( '-background' => 'lightgray',
184
                         ) -> pack('-side' => 'bottom',
185
                                   '-anchor' => 'w',
186
                                   '-fill' => 'none',
187
                                   '-expand' => 'y',
188
                                    );
189
$status_line = $frame_status->Label ('-text' => $Translate{'StatusLine'},
190
                                    ) -> pack ('-side' => 'bottom',
191
                                               );
192
 
193
 
194
#-----------------------------------------------------------------
195
# Frames
196
#-----------------------------------------------------------------                        
197
 
198
#
199
# Frame: Map
200
#
201
 
202
$frame_map = $main->Frame( '-background' => 'lightgray',
203
                           '-relief' => 'sunken',
204
                           '-borderwidth' => 5,
205
                          ) -> pack('-side' => 'top',
206
                                    '-fill' => 'x',
207
                                    );
208
 
209
# Map Überschrift
210
$frame_map_top = $frame_map->Frame() -> pack( '-side' => 'top',
211
                                              '-expand' => 'x',
212
                                              '-anchor' => 'w',
213
                                            );
214
 
215
$frame_map_top->Label ('-text' => "$Translate{'Map'}: $Map{'Name'} ($Map{'File'})",
216
                       '-background' => 'lightgray',
217
                       '-relief' => 'flat',
218
                       ) -> pack( '-side' => 'left' );
219
 
220
# Map Statuszeile
221
$map_status = $frame_map->Frame( '-background' => 'lightgray',
222
                               ) -> pack('-side' => 'bottom',
223
                                         '-anchor' => 'w',
224
                                         '-fill' => 'none',
225
                                         '-expand' => 'y',
226
                                        );
227
$map_status_line = $map_status->Label ( '-text' => $Translate{'StatusLine'},
228
                                        '-background' => 'lightgray',
229
                                       ) -> pack ('-side' => 'bottom',);
230
 
231
# Map Canvas
232
 
233
# Canvas size
234
$MapSizeX  = $Map{'Size_X'};
235
$MapSizeY  = $Map{'Size_Y'};
236
 
237
$map_canvas = $frame_map->Canvas( '-width'  => $MapSizeX,
238
                                  '-height' => $MapSizeY,
239
                                  '-cursor' => 'cross',
240
                                ) -> pack();
241
 
242
# load Map photo
243
$map_canvas->Photo( 'Map',
244
                    '-file' => "$Cfg->{'map'}->{'MapDir'}/$Map{'File'}",
245
                  );
246
 
247
$map_canvas->createImage( 0, 0,
248
                          '-tags' => 'Map',
249
                          '-anchor' => 'nw',
250
                          '-image'  => 'Map',
251
                        );             
252
 
253
# border polygon
254
$map_canvas->createPolygon( @Map{'Border'},
255
                           '-tags' => 'Map-Border',
256
                           '-fill' => '',
257
                           '-outline' => $Cfg->{'mkcockpit'}->{'ColorAirfield'}, '-width' => 2,
258
                          );
259
 
260
# load Heartbeat icon
261
$map_canvas->Photo( 'HeartbeatSmall',
262
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconHeartSmall'}",
263
                  );
264
$map_canvas->Photo( 'HeartbeatLarge',
265
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconHeartLarge'}",
266
                  );
267
$map_canvas->createImage( $MapSizeX/4, 10,
268
                          '-tags' => 'Heartbeat',
269
                          '-anchor' => 'nw',
270
                          '-image'  => 'HeartbeatSmall',
271
                        );
272
 
273
# load Satellite icon
274
$map_canvas->Photo( 'Satellite-Photo',
275
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconSatellite'}",
276
                               );
277
$map_canvas->createImage($MapSizeX-290, -100,   # hide photo 
278
                         '-tags' => 'Satellite',
279
                         '-anchor' => 'nw',
280
                         '-image'  => 'Satellite-Photo',
281
                        );
282
 
283
# load Waypoint icon
284
$map_canvas->Photo( 'Waypoint-Photo',
285
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconWaypoint'}",
286
                  );
287
# load Target icon
288
$map_canvas->Photo( 'Target-Photo',
289
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconTarget'}",
290
                  );
291
 
292
$map_canvas->createImage(0, -100,   # hide photo 
293
                         '-tags' => 'Target',
294
                         '-anchor' => 'nw',
295
                         '-image'  => 'Target-Photo',
296
                        );
297
 
298
# load Fox icon
299
$map_canvas->Photo( 'Fox-Photo',
300
                    '-file' => "$Cfg->{'mkcockpit'}->{'IconFox'}",
301
                  );
302
$map_canvas->createImage($MapSizeX/2-100, $MapSizeY/2,
303
                         '-tags' => 'Fox',
304
                         '-anchor' => 'nw',
305
                         '-image'  => 'Fox-Photo',
306
                        );
307
 
308
# load WP-Player icons
309
$map_canvas->Photo( 'WpPlay-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconPlay'}");
310
$map_canvas->Photo( 'WpStop-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconStop'}");
311
$map_canvas->Photo( 'WpPause-Foto', '-file' => "$Cfg->{'waypoint'}->{'IconPause'}");
312
$map_canvas->Photo( 'WpNext-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconNext'}");
313
$map_canvas->Photo( 'WpPrev-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconPrev'}");
314
$map_canvas->Photo( 'WpFirst-Foto', '-file' => "$Cfg->{'waypoint'}->{'IconFirst'}");
315
$map_canvas->Photo( 'WpLast-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconLast'}");
316
$map_canvas->Photo( 'WpHome-Foto',  '-file' => "$Cfg->{'waypoint'}->{'IconHome'}");
317
$map_canvas->Photo( 'WpWpt-Foto',   '-file' => "$Cfg->{'waypoint'}->{'IconWpt'}");
318
$map_canvas->Photo( 'WpKml-Foto',   '-file' => "$Cfg->{'waypoint'}->{'IconKml'}");
319
 
320
$map_canvas->createImage($MapSizeX/2+100, $MapSizeY-48,
321
                         '-tags' => 'Wp-PlayPause',
322
                         '-anchor' => 'nw',
323
                         '-image'  => 'WpPlay-Foto',
324
                        );
325
$map_canvas->createImage($MapSizeX/2+150, $MapSizeY-48,
326
                         '-tags' => 'Wp-Stop',
327
                         '-anchor' => 'nw',
328
                         '-image'  => 'WpStop-Foto',
329
                        );
330
$map_canvas->createImage($MapSizeX/2, $MapSizeY-48,
331
                         '-tags' => 'Wp-Next',
332
                         '-anchor' => 'nw',
333
                         '-image'  => 'WpNext-Foto',
334
                        );
335
$map_canvas->createImage($MapSizeX/2-50, $MapSizeY-48,
336
                         '-tags' => 'Wp-Prev',
337
                         '-anchor' => 'nw',
338
                         '-image'  => 'WpPrev-Foto',
339
                        );
340
$map_canvas->createImage($MapSizeX/2-100, $MapSizeY-48,
341
                         '-tags' => 'Wp-First',
342
                         '-anchor' => 'nw',
343
                         '-image'  => 'WpFirst-Foto',
344
                        );
345
$map_canvas->createImage($MapSizeX/2+50, $MapSizeY-48,
346
                         '-tags' => 'Wp-Last',
347
                         '-anchor' => 'nw',
348
                         '-image'  => 'WpLast-Foto',
349
                        );
350
$map_canvas->createImage($MapSizeX/2-150, $MapSizeY-48,
351
                         '-tags' => 'Wp-Home',
352
                         '-anchor' => 'nw',
353
                         '-image'  => 'WpHome-Foto',
354
                        );
355
$map_canvas->createImage($MapSizeX/2-200, $MapSizeY-48,
356
                         '-tags' => 'Wp-WptKml',
357
                         '-anchor' => 'nw',
358
                         '-image'  => 'WpWpt-Foto',
359
                        );
360
 
361
 
362
 
363
# Balloon attached to Canvas
364
$map_balloon = $frame_map->Balloon('-statusbar' => $status_line, );
365
$map_balloon->attach($map_canvas,
366
                     '-balloonposition' => 'mouse',
367
                     '-state' => 'balloon',
368
                     '-msg' => { 'MK-Arrow'               => $Translate{'Balloon-MK-Arrow'},
369
                                 'MK-Home-Line'           => $Translate{'Balloon-MK-Home-Line'},
370
                                 'MK-Home-Dist'           => $Translate{'Balloon-MK-Home-Dist'},
371
                                 'MK-Target-Line'         => $Translate{'Balloon-MK-Target-Line' },
372
                                 'MK-Target-Dist'         => $Translate{'Balloon-MK-Target-Dist'},
373
                                 'MK-Speed'               => $Translate{'Balloon-MK-Speed'},
374
                                 'Map-Variometer'         => $Translate{'Balloon-Map-Variometer' },
375
                                 'Map-Variometer-Pointer' => $Translate{'Balloon-Map-Variometer-Pointer'},
376
                                 'Map-Variometer-Skala'   => $Translate{'Balloon-Map-Variometer-Pointer'},
377
                                 'Fox'                    => $Translate{'Balloon-Fox'},
378
                                 'Heartbeat'              => $Translate{'Balloon-Heartbeat'},
379
                                 'Satellite'              => $Translate{'Balloon-Satellite'},
380
                                 'Waypoint'               => $Translate{'Balloon-Waypoint'},
381
                                 'Map-Border'             => $Translate{'Balloon-Map-Border'},
382
                                 'Waypoint-Connector'     => $Translate{'Balloon-Waypoint-Connector'},
383
                                 'Wp-PlayPause'           => $Translate{'Balloon-Wp-PlayPause'},
384
                                 'Wp-Stop'                => $Translate{'Balloon-Wp-Stop'},
385
                                 'Wp-First'               => $Translate{'Balloon-Wp-First'},
386
                                 'Wp-Last'                => $Translate{'Balloon-Wp-Last'},
387
                                 'Wp-Next'                => $Translate{'Balloon-Wp-Next'},
388
                                 'Wp-Prev'                => $Translate{'Balloon-Wp-Prev'},
389
                                 'Wp-Home'                => $Translate{'Balloon-Wp-Home'},
390
                                 'Wp-WptKml'              => $Translate{'Balloon-Wp-WptKml'},
391
                               },
392
                    );
393
 
394
#
395
# Mouse buttons
396
#
397
 
398
# general Mouse button 1
399
$map_canvas->CanvasBind("<Button-1>", sub
400
    {
401
    # print coords in status line
402
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
403
    my ($Lat, $Lon) = &MapXY2Gps($x, $y);
404
    $map_status_line->configure ('-text' => "Lat: $Lat  Lon: $Lon     x: $x  y: $y");
405
    });
406
 
407
# Mouse button 1 for Fox
408
my $FoxOldx = 0;
409
my $FoxOldy = 0;
410
 
411
# Pick Fox
412
$map_canvas->bind('Fox' => '<Button-1>' => sub
413
    {
414
    # prepare to move Fox
415
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
416
    $FoxOldx = $x;
417
    $FoxOldy = $y;
418
    $FoxTime = time;
419
    });
420
 
421
# Move Fox
422
$map_canvas->bind('Fox' => '<Button1-Motion>' => sub
423
    {
424
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
425
    my $id      = $map_canvas->find('withtag', 'current');
426
 
427
    $map_canvas->move($id => $x - $FoxOldx, $y - $FoxOldy);
428
    $FoxOldx = $x;
429
    $FoxOldy = $y;
430
 
431
    if ( time > $FoxTime )
432
        {
433
          # wenn in Bewegung Koordinaten nur 1/s senden
434
        my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
435
        $x = $x0 + ($x1 - $x0)/2;
436
        $y = $y1;
437
 
438
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
439
        &MkFlyTo ( '-lat' => $Lat,
440
                   '-lon' => $Lon,
441
                   '-mode' => "Target",
442
                 );
443
        $FoxTime = time;
444
 
445
        $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $Lat  Lon: $Lon     x: $x  y: $y");
446
        }
447
    });
448
 
449
# Release Fox
450
$map_canvas->bind('Fox' => '<Button1-ButtonRelease>' => sub
451
    {
452
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
453
    my $id      = $map_canvas->find('withtag', 'current');
454
 
455
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
456
    $x = $x0 + ($x1 - $x0)/2;
457
    $y = $y1;
458
 
459
    my ($Lat, $Lon) = &MapXY2Gps($x, $y);
460
    &MkFlyTo ( '-lat' => $Lat,
461
               '-lon' => $Lon,
462
               '-mode' => "Target",
463
             );
464
 
465
    # Show user that Waypoints in MK are cleared
466
    $WaypointsModified = 1;
467
    &WpRedrawLines();
468
 
469
    $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $Lat  Lon: $Lon     x: $x  y: $y");
470
    });
471
 
472
# Pick Waypoint
473
$map_canvas->bind('Waypoint' => '<Button-1>' => sub
474
    {
475
    # prepare to move
476
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
477
    $WpOldx = $x;
478
    $WpOldy = $y;
479
    });
480
 
481
# Move Waypoint
482
$map_canvas->bind('Waypoint' => '<Button1-Motion>' => sub
483
    {
484
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
485
    my $id      = $map_canvas->find('withtag', 'current');
486
 
487
    # move icon and Wp-Number
488
    my $WpIndex = &WpGetIndexFromId($id);
489
    if ( $WpIndex >= 0 )
490
        {
491
        my $Tag = $Waypoints[$WpIndex]{'Tag'};
492
        $map_canvas->move($Tag => $x - $WpOldx, $y - $WpOldy);
493
        }
494
 
495
    $WpOldx = $x;
496
    $WpOldy = $y;
497
    });
498
 
499
# Release Wp
500
$map_canvas->bind('Waypoint' => '<Button1-ButtonRelease>' => sub
501
    {
502
    my ($x, $y) = ($Tk::event->x, $Tk::event->y);
503
    my $id      = $map_canvas->find('withtag', 'current');
504
 
505
    # take coords from lower/middle icon position
506
    my ($x0, $y0, $x1, $y1) = $map_canvas->bbox ($id);
507
    $x = $x0 + ($x1 - $x0)/2;
508
    $y = $y1;
509
 
510
    # update Waypoint-Array
511
    my $WpIndex = &WpGetIndexFromId($id);
512
    if ( $WpIndex >= 0 )
513
            {
514
        # got it: set new coords
515
 
516
        my ($Lat, $Lon) = &MapXY2Gps($x, $y);
517
        my $Wp = $Waypoints[$WpIndex];
518
        $Wp->{'MapX'} = $x;
519
        $Wp->{'MapY'} = $y;
520
        $Wp->{'Pos_Lat'} = $Lat;
521
        $Wp->{'Pos_Lon'} = $Lon;
522
 
523
        # redraw connector-lines
524
        &WpRedrawLines();
525
 
526
        # red connectors: Wp still have to be sent to MK
527
        $map_canvas->itemconfigure('Waypoint-Connector',
528
                                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpResend'},
529
                                  );
530
        $WaypointsModified = 1;
531
 
532
        my $WpNum = $WpIndex + 1;
533
        $map_status_line->configure ('-text' => "$Translate{'WpMoved'}: $WpNum -> Lat: $Lat  Lon: $Lon     x: $x  y: $y");
534
        }
535
    });
536
 
537
 
538
#
539
# Player:
540
#    Waypoint-List:   @Waypoints
541
#    KML-Target-List: @KmlTargets
542
#
543
 
544
# Player state machine
545
$PlayerMode = 'Stop';     # Start, Stop, Pause, Home ...
546
$WpPlayerIndex = 0;
547
$WpPlayerHoldtime = -1;
548
$KmlPlayerIndex = 0;
549
$WptKmlMode = 'WPT';      # WPT, KML
550
 
551
# Mouse bindings
552
$map_canvas->bind('Wp-PlayPause' => '<Button-1>' => \&CbPlayerPlayPause );
553
$map_canvas->bind('Wp-Next'      => '<Button-1>' => \&CbPlayerNext );
554
$map_canvas->bind('Wp-Prev'      => '<Button-1>' => \&CbPlayerPrev );
555
$map_canvas->bind('Wp-First'     => '<Button-1>' => \&CbPlayerFirst );
556
$map_canvas->bind('Wp-Last'      => '<Button-1>' => \&CbPlayerLast );
557
$map_canvas->bind('Wp-Home'      => '<Button-1>' => \&CbPlayerHome );
558
$map_canvas->bind('Wp-Stop'      => '<Button-1>' => \&CbPlayerStop );
559
$map_canvas->bind('Wp-WptKml'    => '<Button-1>' => \&CbPlayerWptKml );
560
 
561
 
562
# Focus Canvas, if any key pressed. Needed for the following key-bindings
563
$main->bind('<Any-Enter>' => sub { $map_canvas->Tk::focus });
564
 
565
# Disable default arrow-key bindings on canvas
566
$main->bind('Tk::Canvas',"<$_>",undef)for qw /Left Right Up Down/;
567
 
568
# keyboard bindings
569
$map_canvas->Tk::bind( '<Key-space>' , \&CbPlayerPlayPause );
570
$map_canvas->Tk::bind( '<Key-n>'     , \&CbPlayerNext );
571
$map_canvas->Tk::bind( '<Key-p>'     , \&CbPlayerPrev );
572
$map_canvas->Tk::bind( '<Key-f>'     , \&CbPlayerFirst );
573
$map_canvas->Tk::bind( '<Key-l>'     , \&CbPlayerLast );
574
$map_canvas->Tk::bind( '<Key-h>'     , \&CbPlayerHome );
575
$map_canvas->Tk::bind( '<Key-s>'     , \&CbPlayerStop );
576
$map_canvas->Tk::bind( '<Key-w>'     , \&CbPlayerWptKml );
577
$map_canvas->Tk::bind( '<Key-k>'     , \&CbPlayerWptKml );
578
$map_canvas->Tk::bind( '<Key-Left>'  , [\&CbPlayerMove, -1,  0] );
579
$map_canvas->Tk::bind( '<Key-Right>' , [\&CbPlayerMove,  1,  0] );
580
$map_canvas->Tk::bind( '<Key-Up>'    , [\&CbPlayerMove,  0,  1] );
581
$map_canvas->Tk::bind( '<Key-Down>'  , [\&CbPlayerMove,  0, -1] );
582
$map_canvas->Tk::bind( '<Key-Escape>', sub { exit; } );
583
 
584
 
585
 
586
# Mouse button 3 context menu
587
my $map_menu = $map_canvas->Menu('-tearoff' => 0,
588
                                 '-title' =>'None',
589
                                 '-menuitems' =>
590
    [
591
     [Button => $Translate{'WpAddAndSend'},  -command => sub
592
        {
593
 
594
        # send Wp to MK         
595
        ($Lat, $Lon) = &MapXY2Gps($MapCanvasX, $MapCanvasY);
596
        &MkFlyTo ( '-lat' => $Lat,
597
                   '-lon' => $Lon,
598
                   '-mode' => "Waypoint"
599
                 );
600
 
601
        # save Wp-Hash in Waypoint-Array
602
        my $Wp = {};        
603
        my $Tag = sprintf "Waypoint-%d.%d", time, int (rand(9)) ;   # kind of unique Tag for this Wp
604
        $Wp->{'Tag'} = $Tag;
605
        $Wp->{'MapX'} = $MapCanvasX;
606
        $Wp->{'MapY'} = $MapCanvasY;
607
        $Wp->{'Pos_Lat'} = $Lat;
608
        $Wp->{'Pos_Lon'} = $Lon;
609
        $Wp->{'Pos_Alt'} = $MkOsd{'CurPos_Alt'};
610
        $Wp->{'Heading'}         = $Cfg->{'waypoint'}->{'DefaultHeading'};
611
        $Wp->{'ToleranceRadius'} = $Cfg->{'waypoint'}->{'DefaultToleranceRadius'};
612
        $Wp->{'Holdtime'}        = $Cfg->{'waypoint'}->{'DefaultHoldtime'};
613
        $Wp->{'Event_Flag'}      = $Cfg->{'waypoint'}->{'DefaultEventFlag'};
614
        push @Waypoints, $Wp;
615
 
616
        # switch player to Wp mode and redraw waypoints
617
        &WptKmlSwitch ('WPT');  
618
 
619
        $map_status_line->configure ('-text' => "$Translate{'WpSavedAndSent'} -> Lat: $Lat Lon: $Lon");
620
        }],
621
 
622
 
623
     [Button => $Translate{'WpProperties'},  -command => sub
624
        {
625
        # find Wp-Hash for selected icon/tag
626
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
627
        if ( $WpIndex >= 0 )
628
            {
629
            my $Wp = $Waypoints[$WpIndex];
630
            my $WpNum = $WpIndex + 1;
631
 
632
            &DisplayHash ($Wp, "$Translate{'WpProperties'} $WpNum", "Edit Waypoint Refresh");
633
 
634
            $map_status_line->configure ('-text' => "$Translate{'WpProperties'} $WpNum");
635
            }
636
        }],
637
 
638
     [Button => $Translate{'WpResendAll'},  -command => sub
639
        {
640
        &WpSendAll();
641
 
642
        $map_status_line->configure ('-text' => $Translate{'WpAllSent'});
643
        }],
644
 
645
      '',   # Separator
646
 
647
     [Button => $Translate{'WpLoadAndSend'},  -command => sub
648
        {
649
        $WpFile = $main->getOpenFile('-defaultextension' => ".xml",
650
                                     '-filetypes'        =>
651
                                         [['Waypoints',     '.xml' ],
652
                                          ['All Files',     '*', ],
653
                                         ],
654
                                     '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
655
                                     '-title' => $Translate{'WpLoad'},
656
                                    );
657
        if ( -f $WpFile )
658
            {
659
            # XML in Hash-Ref lesen
660
            my $Wp = XMLin($WpFile, ForceArray => 1);
661
 
662
            # XML Hash-Ref in Wp-Array umkopieren
663
            undef @Waypoints;
664
            foreach $key (sort keys %$Wp)
665
                {
666
                my $Point = $Wp->{$key}->[0];
667
 
668
                # relative Pixelkoordinaten auf Bildgroesse umrechnen
669
                if ( $Point->{'MapX'} <= 1  and  $Point->{'MapY'} <= 1 )
670
                    {
671
                    $Point->{'MapX'} = int ( $Point->{'MapX'} * $MapSizeX + 0.5 );
672
                    $Point->{'MapY'} = int ( $Point->{'MapY'} * $MapSizeY + 0.5 );
673
                    }
674
 
675
                # GPS Koordinaten für die aktuelle Karte neu aus Map x/y berechnen
676
                my ($Lat, $Lon) = &MapXY2Gps($Point->{'MapX'}, $Point->{'MapY'});
677
                $Point->{'Pos_Lat'} = $Lat;
678
                $Point->{'Pos_Lon'} = $Lon;
679
 
680
                push @Waypoints, $Point;
681
                }
682
 
683
            # send all Wp to MK
684
            &WpSendAll();
685
 
686
            # switch player to Wp mode and redraw waypoints
687
            &WptKmlSwitch ('WPT');
688
 
689
            $map_status_line->configure ('-text' => "$Translate{'WpLoadedAndSent'}: $WpFile");
690
            }
691
        }],    
692
 
693
     [Button => $Translate{'WpSave'},  -command => sub
694
        {
695
        $WpFile = $main->getSaveFile('-defaultextension' => ".xml",
696
                                     '-filetypes'        =>
697
                                       [['Waypoints',     '.xml' ],
698
                                        ['All Files',     '*', ],
699
                                       ],
700
                                     '-initialdir' => $Cfg->{'waypoint'}->{'WpDir'},
701
                                     '-title' => $Translate{'WpSave'},
702
                                    );
703
 
704
        # Waypoint-Array in Hash umkopieren
705
        my %Wp;
706
        for  $i ( 0 .. $#Waypoints )
707
            {
708
 
709
            my $key = sprintf ("WP-%04d", $i);
710
            $Wp{$key} = $Waypoints[$i];
711
 
712
            # Pixelkoordinaten relativ zur Bildgroesse speichern
713
            $Wp{$key}{'MapX'} /= $MapSizeX;
714
            $Wp{$key}{'MapY'} /= $MapSizeY;
715
            }
716
 
717
        # WP-Hash als XML speichern
718
        &XMLout (\%Wp,
719
                 'OutputFile' => $WpFile,
720
                 'AttrIndent' => '1',
721
                 'RootName' => 'Waypoints',
722
                );
723
 
724
        $map_status_line->configure ('-text' => "$Translate{'WpSaved'}: $WpFile");
725
        }],
726
 
727
     '',   # Separator
728
 
729
     [Button => $Translate{'WpDelete'},  -command => sub
730
        {
731
        # find Wp-Hash for selected icon/tag
732
        my $WpIndex = &WpGetIndexFromId($MapCanvasId);
733
        if ( $WpIndex >= 0 )
734
            {
735
            my $Wp = $Waypoints[$WpIndex];
736
 
737
            # remove icon and Wp-Number on canvas;
738
            $map_canvas->delete($Wp->{'Tag'});
739
 
740
            # delete Wp in Waypoint-Array
741
            splice @Waypoints, $WpIndex, 1;
742
 
743
            # redraw connector-lines
744
            $WaypointsModified = 1;
745
            &WpRedrawLines();  
746
            &WpRedrawIcons();  # wg. Wp-Nummern
747
 
748
            $WpNum = $WpIndex + 1;
749
            $map_status_line->configure ('-text' => "$Translate{'WpDeleted'}: $WpNum");
750
            }
751
        }],
752
 
753
     [Button => $Translate{'WpAllDeleteAndSend'},  -command => sub
754
        {
755
        undef @Waypoints;
756
        $WpPlayerIndex = 0;
757
        $WpPlayerHoldtime = -1;
758
 
759
        # remove all Wp-Icons and Wp-Number on canvas
760
        &WpHide();
761
 
762
        &WpSendAll();
763
 
764
        $map_status_line->configure ('-text' => "$Translate{'WpAllDeleted'}: $WpIndex");
765
        }],
766
 
767
    '',   # Separator
768
 
769
     [Button => $Translate{'KmlLoadAndPlay'},  -command => sub
770
        {
771
        $KmlFile = $main->getOpenFile('-defaultextension' => ".kml",
772
                                     '-filetypes'        =>
773
                                         [['KML',           '.kml' ],
774
                                          ['All Files',     '*', ],
775
                                         ],
776
                                     '-initialdir' => $Cfg->{'waypoint'}->{'KmlDir'},
777
                                     '-title' => $Translate{'KmlLoad'},
778
                                    );
779
        if ( -f $KmlFile )
780
            {
781
            # XML in Hash-Ref lesen
782
            my $Kml = XMLin($KmlFile);
783
 
784
            # init state maschine
785
            undef @KmlTargets;
786
            $KmlPlayerIndex = 0;
787
 
788
            my $Coordinates = $Kml->{Document}->{Placemark}->{LineString}->{coordinates};
789
            foreach $Line (split "\n", $Coordinates)
790
                {
791
                chomp $Line;
792
                $Line =~ s/\s//g;       # remove white space
793
                if ( $Line ne "" )
794
                    {
795
                    my ($Lon, $Lat, $Alt) = split ",", $Line;
796
                    $Lon = sprintf ("%f", $Lon);
797
                    $Lat = sprintf ("%f", $Lat);
798
                    $Alt = sprintf ("%f", $Alt);
799
 
800
                    push @KmlTargets, {'Lat' => $Lat,
801
                                       'Lon' => $Lon,
802
                                       'Alt' => $Alt,
803
                                      };
804
                    }
805
                }
806
 
807
            # switch player to KML mode and redraw track
808
            &WptKmlSwitch ('KML');
809
 
810
            $map_status_line->configure ('-text' => "$Translate{'KmlLoaded'}: $KmlFile" );
811
            }
812
 
813
        }],
814
 
815
    '',   # Separator
816
 
817
     [Button => $Translate{'WpFlyImmediately'},  -command => sub
818
        {
819
        &MkFlyTo ( '-x' => $MapCanvasX,
820
                   '-y' => $MapCanvasY,
821
                   '-mode' => "Target"
822
                 );
823
 
824
        # redraw connector-lines
825
        $WaypointsModified = 1;
826
        &WpRedrawLines();  
827
 
828
        $map_status_line->configure ('-text' => "$Translate{'TargetCoordSent'} -> Lat: $Lat  Lon: $Lon     x: $MapCanvasX  y: $MapCanvasY");
829
        }],
830
    ]
831
                                    );
832
$map_canvas->CanvasBind("<Button-3>" => [ sub
833
    {
834
    $map_canvas->focus;
835
    my($w, $x, $y) = @_;
836
    ($MapCanvasX, $MapCanvasY) = ($Tk::event->x, $Tk::event->y);
837
    $MapCanvasId = $map_canvas->find('withtag', 'current');
838
    $map_menu->post($x, $y);
839
    }, Ev('X'), Ev('Y') ] );
840
 
841
 
842
#
843
# Objects on canvas
844
#
845
 
846
# Line from MK to Home
847
$map_canvas->createLine ( $MapSizeX/2, $MapSizeY/2, $MapSizeX/2, $MapSizeY/2,
848
                          '-tags' => 'MK-Home-Line',
849
                          '-arrow' => 'none',
850
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeLine'},
851
                          '-width' => 3,
852
                         );
853
 
854
# Text Entfernung positioniert an der Home-Linie
855
$map_canvas->createText ( $MapSizeX/2 + 8, $MapSizeY/2 - 8,
856
                          '-tags' => 'MK-Home-Dist',
857
                          '-text' => '0 m',
858
                          '-anchor' => 'w',
859
                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
860
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorHomeDist'},
861
                          );
862
 
863
# Line from MK to Target, draw invisible out of sight
864
$map_canvas->createLine ( 0, -100, 0, -100,
865
                          '-tags' => 'MK-Target-Line',
866
                          '-arrow' => 'none',
867
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetLine'},
868
                          '-width' => 3,
869
                         );
870
 
871
# Text Entfernung positioniert an der Target-Linie
872
$map_canvas->createText ( 0, -100,
873
                          '-tags' => 'MK-Target-Dist',
874
                          '-text' => '0 m',
875
                          '-anchor' => 'w',
876
                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
877
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorTargetDist'},
878
                          );
879
 
880
# MK Geschwindigkeits-Vektor
881
$MapMkSpeedLen = 60;    # Länge Speed-Zeiger
882
my $x0 = $MapSizeX/2;
883
my $y0 = $MapSizeY/2;
884
my $x1 = $MapSizeX/2;
885
my $y1 = $MapSizeY/2 - $MapMkSpeedLen;
886
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
887
                          '-tags' => 'MK-Speed',
888
                          '-arrow' => 'last',
889
                          '-arrowshape' => [10, 10, 3 ],
890
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorSpeedVector'},
891
                          '-width' => 4,
892
                         );
893
 
894
# MK als Pfeilspitze einer Linie darstellen
895
$MapMkLen = 25;
896
my $x0 = $MapSizeX/2;
897
my $y0 = $MapSizeY/2 + $MapMkLen/2;
898
my $x1 = $MapSizeX/2;
899
my $y1 = $MapSizeY/2 - $MapMkLen/2;
900
$map_canvas->createLine ( $x0, $y0, $x1, $y1,
901
                          '-tags' => 'MK-Arrow',
902
                          '-arrow' => 'last',
903
                          '-arrowshape' => [25, 30, 10 ],
904
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorMkSatNo'},
905
                          '-width' => 1
906
                         );
907
$MkPos_x = $MapSizeX/2;
908
$MkPos_y = $MapSizeY/2;
909
 
910
 
911
 
912
# OSD Daten auf Karte anzeigen
913
 
914
# Flugzeit
915
$map_canvas->createText ( $MapSizeX/2 - 40, 20,
916
                          '-tags' => 'MK-OSD-Tim-Label',
917
                          '-text' => 'TIM',
918
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
919
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
920
                          '-anchor' => 'w',
921
                         );
922
 
923
$map_canvas->createText ( $MapSizeX/2, 20,
924
                          '-tags' => 'MK-OSD-Tim-Value',
925
                          '-text' => $MkFlyingTime,            # $MkOsd{'FlyingTime'},
926
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
927
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
928
                          '-anchor' => 'w',
929
                         );
930
 
931
# Batterie Spannung
932
$map_canvas->createText ( $MapSizeX/2 - 40, 50,
933
                          '-tags' => 'MK-OSD-Bat-Label',
934
                          '-text' => 'BAT',
935
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
936
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
937
                          '-anchor' => 'w',
938
                         );
939
 
940
$map_canvas->createText ( $MapSizeX/2, 50,
941
                          '-tags' => 'MK-OSD-Bat-Value',
942
                          '-text' => sprintf ("%3.1f V", $MkOsd{'UBat'}),
943
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
944
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
945
                          '-anchor' => 'w',
946
                         );
947
 
948
# Ground speed
949
$map_canvas->createText ( 10,  20,
950
                          '-tags' => 'MK-OSD-Spd-Label',
951
                          '-text' => 'SPD',
952
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
953
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
954
                          '-anchor' => 'w',
955
                         );
956
 
957
$map_canvas->createText ( 50,  20,
958
                          '-tags' => 'MK-OSD-Spd-Value',
959
                          '-text' => sprintf ("%3d km/h", $MkOsd{'GroundSpeed'} * 0.036),
960
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
961
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
962
                          '-anchor' => 'w',
963
                         );
964
 
965
# Hoehe (Luftdruck)
966
$map_canvas->createText ( 10,  50,
967
                          '-tags' => 'MK-OSD-Alt-Label',
968
                          '-text' => 'ALT',
969
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
970
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
971
                          '-anchor' => 'w',
972
                         );
973
 
974
$map_canvas->createText ( 50,  50,
975
                          '-tags' => 'MK-OSD-Alt-Value',
976
                          '-text' => sprintf ("%3d m", $MkOsd{'Altimeter'}/$Cfg->{'mkcockpit'}->{'AltFactor'}),
977
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
978
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
979
                          '-anchor' => 'w',
980
                         );
981
 
982
# Variometer 
983
$map_canvas->createText ( 10,  80,
984
                          '-tags' => 'MK-OSD-Vsi-Label',
985
                          '-text' => 'VSI',
986
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
987
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
988
                          '-anchor' => 'w',
989
                         );
990
 
991
$map_canvas->createText ( 50,  80,
992
                          '-tags' => 'MK-OSD-Vsi-Value',
993
                          '-text' => sprintf ("%3d", $MkOsd{'Variometer'}),
994
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
995
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
996
                          '-anchor' => 'w',
997
                         );
998
 
999
# Anzahl Satelitten
1000
$map_canvas->createText ( $MapSizeX - 220, 20,
1001
                          '-tags' => 'MK-OSD-Sat-Label',
1002
                          '-text' => 'SAT',
1003
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
1004
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1005
                          '-anchor' => 'w',
1006
                         );
1007
 
1008
$map_canvas->createText ( $MapSizeX - 170, 20,
1009
                          '-tags' => 'MK-OSD-Sat-Value',
1010
                          '-text' => "$MkOsd{'SatsInUse'}",
1011
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
1012
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1013
                          '-anchor' => 'w',
1014
                         );
1015
 
1016
# Wegpunkte
1017
$map_canvas->createText ( $MapSizeX - 220, 50,
1018
                          '-tags' => 'MK-OSD-Wp-Label',
1019
                          '-text' => 'WPT',
1020
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
1021
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1022
                          '-anchor' => 'w',
1023
                         );
1024
 
1025
$map_canvas->createText ( $MapSizeX - 170, 50,
1026
                          '-tags' => 'MK-OSD-Wp-Value',
1027
                          '-text' => $MkOsd{'WaypointIndex'} . "/" . $MkOsd{'WaypointNumber'} ,
1028
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
1029
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1030
                          '-anchor' => 'w',
1031
                         );
1032
# Navigation Mode
1033
$map_canvas->createText ( $MapSizeX - 220, 80,
1034
                          '-tags' => 'MK-OSD-Mode-Label',
1035
                          '-text' => 'MOD',
1036
                          '-font' => '-*-Arial-Bold-R-Normal--*-150-*',
1037
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1038
                          '-anchor' => 'w',
1039
                         );
1040
 
1041
$map_canvas->createText ( $MapSizeX - 170, 80,
1042
                          '-tags' => 'MK-OSD-Mode-Value',
1043
                          '-text' => '' ,
1044
                          '-font' => '-*-Arial-Bold-R-Normal--*-270-*',
1045
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'},
1046
                          '-anchor' => 'w',
1047
                         );              
1048
 
1049
# Variometer on canvas
1050
my @Polygon;
1051
for ( $y = -100; $y <= 100; $y += 10)
1052
    {
1053
    my $Len = 5;
1054
    if ( ($y % 50) == 0 )
1055
        {
1056
        $Len = 10;
1057
        $map_canvas->createText ( $Len+5, $MapSizeY/2 + $y,
1058
                                  '-tags' => 'Map-Variometer-Skala',
1059
                                  '-text' => sprintf ("%3d", -$y / 10),
1060
                                  '-anchor' => 'w',
1061
                                  '-font' => '-*-Arial-Normal-R-Normal--*-150-*',
1062
                          '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
1063
                          );
1064
        }
1065
    push @Polygon, (   0, $MapSizeY/2 + $y);
1066
    push @Polygon, ($Len, $MapSizeY/2 + $y);
1067
    push @Polygon, (   0, $MapSizeY/2 + $y);
1068
    }
1069
 
1070
$map_canvas->createLine(@Polygon,
1071
                        '-tags' => 'Map-Variometer',
1072
                        '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometer'},
1073
                        '-width' => 2,
1074
                        '-arrow' => 'none',
1075
                       );
1076
# Vario Pointer
1077
$map_canvas->createPolygon( 5, $MapSizeY/2, 20, $MapSizeY/2+10, 20, $MapSizeY/2-10,
1078
                           '-tags' => 'Map-Variometer-Pointer',
1079
                           '-fill' => $Cfg->{'mkcockpit'}->{'ColorVariometerPointer'},
1080
                           '-outline' => 'black', '-width' => 1,
1081
                          );
1082
 
1083
# Tracking Canvas
1084
 
1085
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
1086
    {
1087
    # Canvas size
1088
    $TrackSizeX  = 125;
1089
    $TrackSizeY  = 100;
1090
    $TrackOffY   = $TrackSizeY - $MapSizeY + 20;
1091
    $TrackPtrLen = 50;    # Länge Zeiger
1092
 
1093
    # draw in map-canvas
1094
    $track_canvas = $map_canvas;
1095
 
1096
    # Ziffernblatt
1097
    my $x0 = $TrackSizeX/2 - $TrackPtrLen;
1098
    my $y0 = $TrackSizeY + $TrackPtrLen - $TrackOffY;
1099
    my $x1 = $TrackSizeX/2 + $TrackPtrLen;
1100
    my $y1 = $TrackSizeY   - $TrackPtrLen - $TrackOffY;
1101
    $track_canvas->createArc ( $x0, $y0, $x1, $y1,
1102
                               '-extent' => '200',
1103
                               '-start' => '-10',
1104
                               '-style' => 'chord',
1105
                               '-outline' => 'gray', '-width' => '1',
1106
                             );
1107
 
1108
    # Skala Ziffernblatt
1109
    for ($i=0; $i<=180; $i+=15)
1110
        {
1111
        my $pi = 3.14159265358979;
1112
        my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 20) * cos($i / 180 * $pi);
1113
        my $y0 = $TrackSizeY   - ($TrackPtrLen - 20) * sin($i / 180 * $pi) - $TrackOffY;
1114
        my $x1 = $TrackSizeX/2 - ($TrackPtrLen - 28) * cos($i / 180 * $pi);
1115
        my $y1 = $TrackSizeY   - ($TrackPtrLen - 28) * sin($i / 180 * $pi) - $TrackOffY;
1116
        $track_canvas->createLine ( $x0, $y0, $x1, $y1,
1117
                                   '-fill' => 'white',
1118
                                   '-width' => 1,
1119
                                  );
1120
        }
1121
 
1122
    # Skala Beschriftung Ziffernblatt
1123
    for ($i=0; $i<=180; $i+=45)
1124
        {
1125
        my $pi = 3.14159265358979;
1126
        my $x0 = $TrackSizeX/2 - ($TrackPtrLen - 12) * cos($i / 180 * $pi);
1127
        my $y0 = $TrackSizeY   - ($TrackPtrLen - 12) * sin($i / 180 * $pi) - $TrackOffY;
1128
        $track_canvas->createText ( $x0, $y0,
1129
                                   '-text' => $i - 90,
1130
                                   '-fill' => 'white',
1131
                                  );
1132
        }
1133
 
1134
    # Ziffernblatt Beschriftung Einheit
1135
    my $x0 = $TrackSizeX/2;
1136
    my $y0 = $MapSizeY -6;
1137
    $track_canvas->createText ( $x0, $y0,
1138
                                '-text' => "Antenne Winkel",
1139
                                '-justify' => 'center',
1140
                                '-fill' => 'white',
1141
                                );
1142
 
1143
    # Zeiger
1144
    my $x0 = $TrackSizeX/2;
1145
    my $y0 = $TrackSizeY - 0 - $TrackOffY;
1146
    my $x1 = $TrackSizeX/2;
1147
    my $y1 = $TrackSizeY - ($TrackPtrLen - 22) - $TrackOffY;
1148
    $track_ptr_id= $track_canvas->createLine ( $x0, $y0, $x1, $y1,
1149
                                               '-tags' => 'Track-Ptr',
1150
                                               '-arrow' => 'last',
1151
                                               '-arrowshape' => [20, 30, 5 ],
1152
                                               '-fill' => 'red',
1153
                                               '-width' => 8,
1154
                                              );
1155
    # Zeiger Center
1156
    my $Dia = 7;
1157
    my $x0 = $TrackSizeX/2 - $Dia;
1158
    my $y0 = $TrackSizeY + $Dia - $TrackOffY;
1159
    my $x1 = $TrackSizeX/2 + $Dia;
1160
    my $y1 = $TrackSizeY   - $Dia - $TrackOffY;
1161
    $track_canvas->createArc ( $x0, $y0, $x1, $y1,
1162
                               '-extent' => '359',
1163
                               '-outline' => 'gray', '-width' => 1,
1164
                               '-fill' => 'gray',
1165
                             );
1166
    }
1167
 
1168
#-----------------------------------------------------------------
1169
# Timer
1170
#-----------------------------------------------------------------                        
1171
 
1172
#
1173
# Timer: 5s
1174
#
1175
$main->repeat (5000, sub
1176
    {
1177
    if ( ! $MkSendWp )
1178
        {
1179
        # Abfragefrequenz OSD und Debug regelmäßig neu einstellen, falls Übertragungsfehler
1180
        $MkSendQueue->enqueue( "o", "$AddrNC", pack ("C", 10) );   # Frequenz OSD Datensatz, * 10ms
1181
        $MkSendQueue->enqueue( "d", "$AddrNC", pack ("C", 10) );   # Frequenz MK Debug Datensatz, * 10ms
1182
        $MkSendQueue->enqueue( "v", "$AddrNC", "");   # Version
1183
        $MkSendQueue->enqueue( "e", "$AddrNC", "");   # Error Text Request
1184
        }
1185
    });
1186
 
1187
#       
1188
# Timer: 0.1s - Map Overlay aktualisieren
1189
#
1190
$frame_map_top->repeat (100, sub
1191
    {
1192
 
1193
    # Clear old messages from this timer
1194
    &MkMessageInit ("Timer-MapOverlay");
1195
 
1196
    lock (%MkOsd);              # until end of block
1197
 
1198
    # Aktuell gültige Karte
1199
    my %Map = %{$Maps{'Current'}};
1200
 
1201
    if ( $MkOsd{'_Timestamp'} >= time-2 )
1202
        {
1203
        # Gueltige OSD Daten
1204
        my $SatsInUse = $MkOsd{'SatsInUse'};
1205
        if ( $SatsInUse > 0  and  $MkOsd{'CurPos_Stat'} == 1 and $MkOsd{'HomePos_Stat'} == 1 )
1206
            {
1207
            # ausreichender GPS Empfang
1208
 
1209
            # get x,y map coords of current position
1210
            my ($C_x, $C_y, $C_Angel) = &MapGps2XY($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'}, $MkOsd{'CompassHeading'});
1211
 
1212
            # rotate MK arrow
1213
            my $dy = sin (deg2rad $C_Angel) * ($MapMkLen/2);
1214
            my $dx = cos (deg2rad $C_Angel) * ($MapMkLen/2);
1215
            my $x0 = $C_x - $dx;
1216
            my $y0 = $C_y - $dy;
1217
            my $x1 = $C_x + $dx;
1218
            my $y1 = $C_y + $dy;
1219
            $map_canvas->coords ('MK-Arrow', $x0, $y0, $x1, $y1);
1220
            $MkPos_x = $C_x;
1221
            $MkPos_y = $C_y;
1222
 
1223
            # Update speed vector
1224
            my $MapAngel = &MapAngel();   # Norh to Map-Horizont
1225
            my $GpsSpeedNorth = $MkNcDebug{'Analog_21'};
1226
            my $GpsSpeedEast  = $MkNcDebug{'Analog_22'};
1227
            my $PhiGpsSpeed = rad2deg atan2 ( $GpsSpeedEast, $GpsSpeedNorth );
1228
            $PhiMapSpeed = $PhiGpsSpeed - $MapAngel;
1229
 
1230
            # 555 cm/s ~ 20 km/h -> Zeigerlänge = $MkSpeedLen bei 20 km/h
1231
            my $dy = sin (deg2rad $PhiMapSpeed) * $MapMkSpeedLen * $MkOsd{'GroundSpeed'} / 555;
1232
            my $dx = cos (deg2rad $PhiMapSpeed) * $MapMkSpeedLen * $MkOsd{'GroundSpeed'} / 555;
1233
            my $x0 = $C_x;
1234
            my $y0 = $C_y;
1235
            my $x1 = $C_x + $dx;
1236
            my $y1 = $C_y + $dy;
1237
            $map_canvas->coords ('MK-Speed', $x0, $y0, $x1, $y1);
1238
 
1239
            # Update Line between Home and MK
1240
            my ($H_x, $H_y) = &MapGps2XY($MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'});
1241
            $map_canvas->coords ('MK-Home-Line', $H_x, $H_y, $C_x, $C_y);
1242
 
1243
            # Update Distance between Home and MK
1244
            my ($Dist, $Bearing) = MapGpsTo($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'},
1245
                                                   $MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'} );
1246
            my $x = ($C_x - $H_x) / 2 + $H_x + 8;
1247
            my $y = ($C_y - $H_y) / 2 + $H_y + 8;
1248
            $map_canvas->coords ('MK-Home-Dist', $x, $y);
1249
            $map_canvas->itemconfigure ('MK-Home-Dist',
1250
                                        '-text' => sprintf ("%4d m", int ($Dist + 0.5) ),
1251
                                       );
1252
 
1253
            # Update OSD - Sat dependent values
1254
            $map_canvas->itemconfigure ('MK-OSD-Spd-Value', '-text' => sprintf ("%3d km/h", $MkOsd{'GroundSpeed'} * 0.036) );
1255
 
1256
            # Alt = average Luftdruck und Sat
1257
            my $Alt = int ( ($MkOsd{'Altimeter'} / $Cfg->{'mkcockpit'}->{'AltFactor'} +
1258
                             $MkOsd{'CurPos_Alt'} - $MkOsd{'HomePos_Alt'} + 0.5) / 2 );
1259
            $map_canvas->itemconfigure ('MK-OSD-Alt-Value', '-text' => sprintf ("%d m", $Alt) );
1260
 
1261
            if ( $MkOsd{'TargetPos_Stat'} == 1 )
1262
                {
1263
                # Valid Target
1264
                # Update Line between Target and MK
1265
                my ($T_x, $T_y) = &MapGps2XY($MkOsd{'TargetPos_Lat'}, $MkOsd{'TargetPos_Lon'});
1266
                $map_canvas->coords ('MK-Target-Line', $C_x, $C_y, $T_x, $T_y);
1267
 
1268
                # Update Distance between Target and MK
1269
                my ($Dist, $Bearing) = MapGpsTo($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'},
1270
                                                        $MkOsd{'TargetPos_Lat'}, $MkOsd{'TargetPos_Lon'} );
1271
 
1272
                if ( $Dist >= 25 )  
1273
                    {
1274
                    my $x = ($C_x - $T_x) / 2 + $T_x - 8;
1275
                    my $y = ($C_y - $T_y) / 2 + $T_y + 8;
1276
                    $map_canvas->coords ('MK-Target-Dist', $x, $y);
1277
                    $map_canvas->itemconfigure ('MK-Target-Dist',
1278
                                                '-text' => sprintf ("%4d m", int ($Dist + 0.5) ),
1279
                                               );
1280
                    }
1281
                else
1282
                    {
1283
                    # Don't show distance < 25m
1284
                    $map_canvas->coords ('MK-Target-Dist', 0, -100);
1285
                    }
1286
 
1287
                # show target icon
1288
                my $IconHeight = 48;
1289
                my $IconWidth = 48;
1290
                $map_canvas->coords('Target', $T_x - $IconWidth/2, $T_y - $IconHeight );
1291
                }
1292
            else
1293
                {
1294
                # No valid Target, move target line out of sight/canvas
1295
                $map_canvas->coords ('MK-Target-Line', 0, -100, 0, -100);
1296
                $map_canvas->coords ('MK-Target-Dist', 0, -100);
1297
 
1298
                # hide target icon
1299
                $map_canvas->coords('Target', 0, -100, );
1300
                }
1301
            }
1302
        else
1303
            {
1304
            # kein ausreichender Sat-Empfang
1305
            $map_canvas->itemconfigure ('MK-OSD-Spd-Value', '-text' => sprintf ("%3d km/h", 0 ) );
1306
            }
1307
 
1308
        # Update OSD - non Sat dependent values
1309
        $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-text' => sprintf ("%3.1f V", $MkOsd{'UBat'}) );
1310
        $map_canvas->itemconfigure ('MK-OSD-Vsi-Value', '-text' => sprintf ("%3d", $MkOsd{'Variometer'}) );
1311
        $map_canvas->itemconfigure ('MK-OSD-Tim-Value', '-text' => sprintf ("%02d:%02d", $MkFlyingTime / 60, $MkFlyingTime % 60) );
1312
        $map_canvas->itemconfigure ('MK-OSD-Sat-Value', '-text' => $MkOsd{'SatsInUse'} );
1313
 
1314
        # Waypoints abhaengig vom Modus NC/Player
1315
        my $WpValue = "--/--";
1316
        if ( $MkOsd{'WaypointNumber'} > 0)
1317
            {
1318
            $WpValue = sprintf ("%d / %d", $MkOsd{'WaypointIndex'} + 1, $MkOsd{'WaypointNumber'});
1319
            }
1320
        if ($PlayerMode ne "Stop" and $WptKmlMode eq "WPT" )
1321
            {
1322
            $WpValue = sprintf ("%d / %d", $WpPlayerIndex +1, scalar @Waypoints);
1323
            }
1324
        if ($PlayerMode ne "Stop" and $WptKmlMode eq "KML" )
1325
            {
1326
            my $KmlTimeBase = $Cfg->{'waypoint'}->{'KmlTimeBase'} || 1.0;
1327
            my $CurrTime = int ($KmlPlayerIndex * $KmlTimeBase + 0.5);
1328
            my $TotTime = int (scalar @KmlTargets * $KmlTimeBase + 0.5);
1329
            $WpValue = sprintf ("%02d:%02d / %02d:%02d", $CurrTime / 60, $CurrTime % 60, $TotTime / 60, $TotTime % 60);
1330
            }
1331
        $map_canvas->itemconfigure ('MK-OSD-Wp-Value',  '-text' => "$WpValue");
1332
 
1333
        # blink battery warning
1334
        $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-fill' => $Cfg->{'mkcockpit'}->{'ColorOsd'});
1335
        if ( $MkOsd{'UBat'}  <  $Cfg->{'mkcockpit'}->{'UBatWarning'} )
1336
            {
1337
            &MkMessage ($Translate{'MsgBatWarning'}, "Timer-MapOverlay");
1338
 
1339
            if ( time %2 )
1340
                {
1341
                $map_canvas->itemconfigure ('MK-OSD-Bat-Value', '-fill' => 'red');
1342
                }
1343
            }
1344
 
1345
 
1346
        my $Mode = "";
1347
        my $Extension = "";
1348
        if ($MkOsd{'NCFlags'} & 0x04) { $Mode = "WPT"};
1349
        if ($PlayerMode eq "Play")    { $Mode = "Play"};
1350
        if ($PlayerMode eq "Pause")   { $Mode = "Paus" };
1351
        if ($PlayerMode eq "Home")    { $Mode = "Home" };
1352
        if ($MkOsd{'NCFlags'} & 0x01) { $Mode = "Free"};
1353
        if ($MkOsd{'NCFlags'} & 0x02) { $Mode = "PH"};
1354
        if ($Mode eq "Play")          { $Extension = $WptKmlMode};
1355
        $map_canvas->itemconfigure ('MK-OSD-Mode-Value', '-text' => "$Mode $Extension" );
1356
 
1357
 
1358
        # Farbe MK-Zeiger abhängig vom GPS Empfang
1359
        my $MkCol= $Cfg->{'mkcockpit'}->{'ColorMkSatNo'};
1360
        if ( $SatsInUse >= 1 ) { $MkCol = $Cfg->{'mkcockpit'}->{'ColorMkSatLow'} ; }
1361
        if ( $SatsInUse >= 6 ) { $MkCol = $Cfg->{'mkcockpit'}->{'ColorMkSatGood'}; }
1362
        $map_canvas->itemconfigure ('MK-Arrow', '-fill' => $MkCol);
1363
 
1364
        # Show/Hide SatFix Icon
1365
        if ($SatsInUse >= 6 )
1366
            {
1367
            $map_canvas->coords('Satellite', $MapSizeX-290, 10, );
1368
            }
1369
        else
1370
            {
1371
            # move icon out of sight
1372
            $map_canvas->coords('Satellite', 0, -100, );
1373
            }
1374
 
1375
        if ( $SatsInUse == 0 )
1376
            {
1377
            &MkMessage ($Translate{'MsgNoSatReception'}, "Timer-MapOverlay");
1378
            }
1379
        elsif ( $SatsInUse > 0  and $SatsInUse < 6 )
1380
            {
1381
            &MkMessage ($Translate{'MsgWeakSatReception'}, "Timer-MapOverlay");
1382
            }
1383
 
1384
        # Variometer Pointer
1385
        my $dy = -$MkOsd{'Variometer'} * 10;
1386
        $map_canvas->coords('Map-Variometer-Pointer', 5, $MapSizeY/2+$dy, 20, $MapSizeY/2+10+$dy, 20, $MapSizeY/2-10+$dy);
1387
 
1388
        #
1389
        # System checks
1390
        #
1391
 
1392
        # RC range check
1393
        my $RcQuality = $MkOsd{'RC_Quality'};
1394
        if ( $RcQuality < 100 )
1395
            {
1396
            &MkMessage ($Translate{'MsgRcError'}, "Timer-MapOverlay");
1397
            }
1398
        elsif ( $RcQuality < 150 )
1399
            {
1400
            &MkMessage ($Translate{'MsgRcWarning'}, "Timer-MapOverlay");
1401
            }
1402
 
1403
        if (($MkOsd{'MKFlags'} & 0x01) == 0) { &MkMessage ($Translate{'MsgMototOff'}, "Timer-MapOverlay"); }
1404
        if (($MkOsd{'MKFlags'} & 0x02) == 0) { &MkMessage ($Translate{'MsgNotFlying'}, "Timer-MapOverlay"); }
1405
        if ($MkOsd{'MKFlags'} & 0x04 )       { &MkMessage ($Translate{'MsgCalibrate'}, "Timer-MapOverlay"); }
1406
        if ($MkOsd{'MKFlags'} & 0x08 )       { &MkMessage ($Translate{'MsgStart'}, "Timer-MapOverlay") }
1407
        if ($MkOsd{'MKFlags'} & 0x10 )       { &MkMessage ($Translate{'MsgEmergencyLanding'}, "Timer-MapOverlay"); }
1408
        if ($MkOsd{'NCFlags'} & 0x08)        { &MkMessage ($Translate{'MsgRangeLimit'}, "Timer-MapOverlay"); }
1409
 
1410
        #
1411
        # Show Balloon, when aproaching Target
1412
        #
1413
 
1414
        $map_canvas->delete('Target-Balloon');  # delete old Balloon
1415
 
1416
        my ($T_x, $T_y) = &MapGps2XY($MkOsd{'TargetPos_Lat'}, $MkOsd{'TargetPos_Lon'});
1417
 
1418
        if ( $Mode ne "Free" and $MkOsd{'TargetPos_Stat'} == 1  and $MkOsd{'TargetPosDev_Dist'} /10 < 25 )
1419
            {
1420
 
1421
            my $BalloonLines = 1;
1422
            $ColorBalloon = "blue";
1423
 
1424
            # Holdtime Wp-Player Mode
1425
            if ( $WpPlayerHoldtime >= 0 )
1426
                {
1427
                # Holdtime
1428
                $ColorBalloon = 'red';
1429
                my $HoldTime = sprintf ("%5s %3d s", "HLD:", int ($WpPlayerHoldtime / 2  + 0.5) );
1430
                $map_canvas->createText ( $T_x + 25, $T_y - 40,
1431
                                          '-tags' => ['Target-Balloon', 'Target-BalloonText'],
1432
                                          '-text' => $HoldTime,
1433
                                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1434
                                          '-fill' => $ColorBalloon,
1435
                                          '-anchor' => 'w',
1436
                                        );
1437
                $BalloonLines ++;
1438
                }
1439
 
1440
 
1441
            # Holdtime WPT-Mode
1442
            if ( $MkOsd{'NCFlags'} & 0x20  and  $Mode eq "WPT" )
1443
                {
1444
                # Holdtime
1445
                $ColorBalloon = 'red';
1446
                my $HoldTime = sprintf ("%5s %3d s", "HLD:", int ($MkOsd{'TargetHoldTime'} + 0.5) );
1447
                $map_canvas->createText ( $T_x + 25, $T_y - 40,
1448
                                          '-tags' => ['Target-Balloon', 'Target-BalloonText'],
1449
                                          '-text' => $HoldTime,
1450
                                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1451
                                          '-fill' => $ColorBalloon,
1452
                                          '-anchor' => 'w',
1453
                                        );
1454
                $BalloonLines ++;
1455
                }
1456
 
1457
 
1458
            # Tolerance Radius Player Mode
1459
            if ( $MkOsd{'NCFlags'} & 0x04  and  $Mode eq "Play" and $WptKmlMode eq "WPT" )
1460
                {
1461
                my $WpTolerance  = sprintf ("%5s %3d m", "TOL:", $Waypoints[$WpPlayerIndex]{'ToleranceRadius'});
1462
                $map_canvas->createText ( $T_x + 25, $T_y - 60,
1463
                                          '-tags' => ['Target-Balloon', 'Target-BalloonText'],
1464
                                          '-text' => $WpTolerance,
1465
                                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1466
                                          '-fill' => $ColorBalloon,
1467
                                          '-anchor' => 'w',
1468
                                        );
1469
                $BalloonLines ++;
1470
                }
1471
 
1472
 
1473
            # Tolerance WPT-Mode
1474
            if ( $MkOsd{'NCFlags'} & 0x04  and  $Mode eq "WPT" )
1475
                {
1476
                my $WpTolerance  = sprintf ("%5s %3d m", "TOL:", $Waypoints[$MkOsd{'WaypointIndex'}]{'ToleranceRadius'} );
1477
                $map_canvas->createText ( $T_x + 25, $T_y - 60,
1478
                                          '-tags' => ['Target-Balloon', 'Target-BalloonText'],
1479
                                          '-text' => $WpTolerance,
1480
                                          '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1481
                                          '-fill' => $ColorBalloon,
1482
                                          '-anchor' => 'w',
1483
                                        );
1484
                $BalloonLines ++;
1485
                }
1486
 
1487
 
1488
            # Distance to Target
1489
            my $Dist = int ($MkOsd{'TargetPosDev_Dist'} /10 + 0.5);
1490
            $map_canvas->createText ( $T_x + 25, $T_y - 80,
1491
                                      '-tags' => ['Target-Balloon', 'Target-BalloonText'],
1492
                                      '-text' => sprintf ("%5s %3d m", "DST:", $Dist) ,
1493
                                      '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
1494
                                      '-fill' => $ColorBalloon,
1495
                                      '-anchor' => 'w',
1496
                                    );
1497
 
1498
            if ( $BalloonLines >= 1 )
1499
                {
1500
                # draw Balloon
1501
                my @TargetBalloon = ( $T_x ,      $T_y,
1502
                                      $T_x + 30,  $T_y - (3 - $BalloonLines) * 20 -27,
1503
                                      $T_x + 150, $T_y - (3 - $BalloonLines) * 20 -27 ,
1504
                                      $T_x + 150, $T_y - 93,
1505
                                      $T_x + 20,  $T_y - 93,
1506
                                      $T_x + 20,  $T_y - (3 - $BalloonLines) * 20 -27,
1507
                                      $T_x,       $T_y,
1508
                                    );
1509
 
1510
                $map_canvas->createPolygon( @TargetBalloon,
1511
                                           '-tags' => ['Target-Balloon', 'Target-BalloonBubble'],
1512
                                           '-fill' => 'lightgray',
1513
                                           '-outline' => 'yellow',
1514
                                           '-width' => 1,
1515
                                          );
1516
                }
1517
 
1518
 
1519
            $map_canvas->lower('Target-Balloon', 'MK-Home-Line');
1520
            $map_canvas->lower('Target-BalloonBubble', 'Target-BalloonText');
1521
            }
1522
 
1523
        }
1524
    else
1525
        {
1526
        # keine aktuellen OSD Daten vom MK verfügbar
1527
        &MkMessage ($Translate{'MsgNoData'}, "Timer-MapOverlay");
1528
        }
1529
 
1530
    # Show System Messages
1531
    &MkMessageShow();
1532
 
1533
    });
1534
 
1535
#       
1536
# Timer: 0.1s - Tracking Anzeige aktualisieren
1537
#
1538
if ( $Cfg->{'track'}->{'Active'} =~ /y/i )
1539
    {
1540
    $frame_map_top->repeat (100, sub
1541
        {
1542
        # Clear old messages from this timer
1543
        &MkMessageInit ("Timer-Tracking");    
1544
 
1545
        lock (%MkOsd);              # until end of block
1546
 
1547
        # Aktuell gültige Karte
1548
        my %Map = %{$Maps{'Current'}};
1549
 
1550
        # Zeiger neu zeichnen
1551
        my $ServoPan = @ServoPos[$MkTrack{'ServoPan'}];
1552
        if ( $ServoPan ne ""  )
1553
            {
1554
            my $x0 = $TrackSizeX/2;    
1555
            my $y0 = $TrackSizeY - 0 - $TrackOffY;
1556
            my $x1 = $TrackSizeX/2 - ($TrackPtrLen-22) * cos( deg2rad $ServoPan);
1557
            my $y1 = $TrackSizeY   - ($TrackPtrLen-22) * sin (deg2rad $ServoPan) - $TrackOffY;
1558
            $track_canvas->coords ('Track-Ptr', $x0, $y0, $x1, $y1);
1559
            }
1560
 
1561
        # Farbe Zeiger abhängig vom GPS Empfang
1562
        my $SatsInUse = $MkOsd{'SatsInUse'};
1563
        my $TrackPtrCol= 'red';
1564
        if ( $SatsInUse >= 1 ) { $TrackPtrCol = 'orange'; }
1565
        if ( $SatsInUse >= 6 ) { $TrackPtrCol = 'green'; }
1566
        $track_canvas->itemconfigure ('Track-Ptr', '-fill' => $TrackPtrCol);
1567
        });
1568
    }
1569
 
1570
 
1571
#       
1572
# Timer: 0.5s - Waypoint Player
1573
#
1574
$frame_map_top->repeat (500, sub
1575
    {
1576
    # Clear old messages from this timer
1577
    &MkMessageInit ("Timer-Player");        
1578
 
1579
    lock (%MkOsd);              # until end of block
1580
 
1581
    if ($MkOsd{'NCFlags'} & 0x04)
1582
        {
1583
        # NC is in WPT Mode 
1584
 
1585
        if ( $PlayerMode eq "Pause" )
1586
            {
1587
            if ( $PlayerPause_Lat ne ""  and  $PlayerPause_Lon ne "" )
1588
                {
1589
                # Gespeicherte Pausen-Pos senden
1590
                &MkFlyTo ( '-lat'  => $PlayerPause_Lat,
1591
                           '-lon'  => $PlayerPause_Lon,
1592
                           '-holdtime' => "60",
1593
                           '-mode' => "Target",
1594
                         );
1595
                }
1596
            }
1597
 
1598
        if ( $PlayerMode eq "Home" )
1599
            {
1600
            if ( $MkOsd{'HomePos_Stat'} == 1 )
1601
                {
1602
                &MkFlyTo ( '-lat'  => $MkOsd{'HomePos_Lat'},
1603
                           '-lon'  => $MkOsd{'HomePos_Lon'},
1604
                           '-holdtime' => "60",
1605
                           '-mode' => "Target",
1606
                         );
1607
                }
1608
            }
1609
 
1610
 
1611
        if ( $WptKmlMode ne 'WPT' )
1612
            {
1613
            # not in Wp mode
1614
            return;
1615
            }
1616
 
1617
 
1618
        my $WpCnt = scalar @Waypoints;
1619
        if ( $PlayerMode eq "Play"  and  $WpCnt > 0  and  $WpPlayerIndex < $WpCnt )
1620
            {
1621
            # Target WP-Pos senden
1622
            my $Wp_Lon = $Waypoints[$WpPlayerIndex]{'Pos_Lon'};
1623
            my $Wp_Lat = $Waypoints[$WpPlayerIndex]{'Pos_Lat'};
1624
            if ( $Wp_Lat ne ""  and  $Wp_Lon ne "" )
1625
                {
1626
                &MkFlyTo ( '-lat'  => $Wp_Lat,
1627
                           '-lon'  => $Wp_Lon,
1628
                           '-holdtime' => "60",
1629
                           '-mode' => "Target",
1630
                         );
1631
                }
1632
            }
1633
 
1634
        if ( $PlayerMode eq "Play" )
1635
            {
1636
            # Ziel erreicht?
1637
            if ( &WpCheckTargetReached() )
1638
                {
1639
                &WpTargetNext();
1640
                }
1641
            }
1642
        }
1643
 
1644
    # WP Player Holdtime count down
1645
    if ( $WpPlayerHoldtime > 0  )
1646
        {
1647
        $WpPlayerHoldtime --;
1648
        }
1649
    });
1650
 
1651
 
1652
#       
1653
# Timer: variabel - KML Player
1654
#
1655
my $KmlTimeBase = $Cfg->{'waypoint'}->{'KmlTimeBase'} || 1.0;
1656
$KmlTimeBase *= 1000;
1657
 
1658
$frame_map_top->repeat ($KmlTimeBase, sub
1659
    {
1660
 
1661
    # Clear old messages from this timer
1662
    &MkMessageInit ("Timer-KMLPlayer");    
1663
 
1664
    if ( $WptKmlMode ne 'KML' )
1665
        {
1666
        # not in KML mode
1667
        return;
1668
        }
1669
 
1670
    lock (%MkOsd);              # until end of block
1671
 
1672
    if ($MkOsd{'NCFlags'} & 0x04)
1673
        {
1674
        # NC is in WPT Mode 
1675
 
1676
        # Pause, Home is handled in WPT-Timer
1677
 
1678
        my $KmlCnt = scalar @KmlTargets;
1679
            if ( $PlayerMode eq "Play"  and  $KmlCnt > 0  and  $KmlPlayerIndex < $KmlCnt )
1680
            {
1681
 
1682
            my $Lat = $KmlTargets[$KmlPlayerIndex]->{'Lat'};
1683
            my $Lon = $KmlTargets[$KmlPlayerIndex]->{'Lon'};
1684
            my $Alt = $KmlTargets[$KmlPlayerIndex]->{'Alt'};
1685
 
1686
            &MkFlyTo ( '-lat'             => $Lat,
1687
                       '-lon'             => $Lon,
1688
                       '-alt'             => $Alt,
1689
                       '-holdtime'        => "60",
1690
                       '-mode'            => "Target",
1691
                     );
1692
 
1693
            # next Target
1694
            $KmlPlayerIndex ++;
1695
            if ( $KmlPlayerIndex >= scalar @KmlTargets )
1696
                {
1697
                $KmlPlayerIndex = 0;
1698
                }
1699
            }
1700
        }
1701
    });
1702
 
1703
 
1704
#       
1705
# Timer: 1s
1706
#
1707
$frame_map_top->repeat (1000, sub
1708
    {
1709
    # Clear old messages from this timer
1710
    &MkMessageInit ("Timer-Misc-1s");    
1711
 
1712
    lock (%MkOsd);              # until end of block
1713
 
1714
    # Aktuell gültige Karte
1715
    my %Map = %{$Maps{'Current'}};
1716
 
1717
    if ( $MkOsd{'_Timestamp'} >= time -2 )
1718
        {
1719
 
1720
        # Heartbeat MK Datenübertragung
1721
        if ( time %2 )
1722
            {
1723
            $map_canvas->itemconfigure('Heartbeat', '-image' => 'HeartbeatLarge', );
1724
            }
1725
        else
1726
            {
1727
            $map_canvas->itemconfigure('Heartbeat', '-image' => 'HeartbeatSmall', );
1728
            }
1729
 
1730
        # Flugzeit aktualisieren
1731
        # Flugzeit selber mitzählen, da $MkOsd{'FlyingTime'} immer 0 (0.14b)
1732
        if ( $MkOsd{'MKFlags'} & 0x02 )
1733
            {
1734
            $MkFlyingTime += 1;
1735
            }
1736
 
1737
        # Footprint
1738
        if ( $Cfg->{'mkcockpit'}->{'FootprintLength'} > 0 )
1739
            {
1740
            if ( $MkOsd{'SatsInUse'} > 0  and  $MkOsd{'CurPos_Stat'} == 1 )
1741
                {
1742
                # neuen Footprint hinten anhaengen
1743
                my ($x, $y) = &MapGps2XY($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'});
1744
                push @Footprint, $x, $y;
1745
                }
1746
 
1747
            while ( $#Footprint / 2  >  $Cfg->{'mkcockpit'}->{'FootprintLength'} )
1748
                {
1749
                # alte Footprints entfernen
1750
                splice @Footprint, 0, 2;
1751
                }
1752
 
1753
            &FootprintRedraw();
1754
            }
1755
 
1756
 
1757
        # tracking antenne
1758
        if ( $MkOsd{'MKFlags'} & 0x01  and  ! $MkTrack{'IsRunning'} and
1759
             $Cfg->{'track'}->{'Active'} =~ /y/i )
1760
            {
1761
            # start track at 1st motor start
1762
            $track_thr = threads->create (\&TrackAntennaGps)->detach();
1763
            $MkTrack{'IsRunning'} = "Running";
1764
            }
1765
        }
1766
 
1767
    });
1768
 
1769
 
1770
MainLoop();   # should never end
1771
 
1772
 
1773
#-----------------------------------------------------------------
1774
# Subroutines
1775
#-----------------------------------------------------------------                        
1776
 
1777
# Get Wp Index from Canvas Id
1778
sub WpGetIndexFromId()
1779
    {
1780
    my ($id) = @_;
1781
 
1782
    my @Tags = $map_canvas->gettags($id);
1783
    my $WpTag = $Tags[1];
1784
 
1785
    for $i (0 .. $#Waypoints)
1786
        {
1787
        my $Wp = $Waypoints[$i];
1788
        if ( $Wp->{'Tag'} eq $WpTag )
1789
            {
1790
            # got it
1791
            return $i;
1792
            }
1793
        }
1794
    return -1;
1795
    }
1796
 
1797
 
1798
# Resend all Waypoints to MK
1799
sub WpSendAll()
1800
    {
1801
    # OSD/Debug Abfragefrequenz verringern, sonst kommen nicht alle Wp im MK an
1802
    # Sicherheitshalber doppelt senden
1803
    $MkSendWp = 1;       # verhindert ueberschreiben im Timer
1804
    $MkSendQueue->enqueue( "o", "$AddrNC", pack ("C", 1000) );   # Frequenz OSD Datensatz, * 10ms
1805
    $MkSendQueue->enqueue( "d", "$AddrNC", pack ("C", 1000) );   # Frequenz MK Debug Datensatz, * 10ms
1806
    usleep (200000);
1807
    $MkSendQueue->enqueue( "o", "$AddrNC", pack ("C", 1000) );   # Frequenz OSD Datensatz, * 10ms
1808
    $MkSendQueue->enqueue( "d", "$AddrNC", pack ("C", 1000) );   # Frequenz MK Debug Datensatz, * 10ms
1809
    usleep (200000);
1810
 
1811
    # Alte WP-Liste im MK löschen
1812
    my $Wp = $Waypoints[0];
1813
    &MkFlyTo ( '-lat'  => $Wp->{'Pos_Lat'},
1814
               '-lon'  => Wp->{'Pos_Lon'},
1815
               '-mode' => "Waypoint Delete"
1816
             );
1817
 
1818
    for $i (0 .. $#Waypoints)
1819
        {
1820
        my $Wp = $Waypoints[$i];
1821
        &MkFlyTo ( '-lat'             => $Wp->{'Pos_Lat'},
1822
                   '-lon'             => $Wp->{'Pos_Lon'},
1823
                   '-alt'             => $Wp->{'Pos_Alt'},
1824
                   '-heading'         => $Wp->{'Heading'},
1825
                   '-toleranceradius' => $Wp->{'ToleranceRadius'},
1826
                   '-holdtime'        => $Wp->{'Holdtime'},
1827
                   '-eventflag'       => $Wp->{'Event_Flag'},
1828
                   '-mode'            => "Waypoint"
1829
                 );
1830
 
1831
        usleep (150000)  # NC Zeit zum Verarbeiten geben
1832
        }
1833
 
1834
    $MkSendWp = 0;  # normale OSD/Debug Abfragefrequenz wird automatisch im 5s Timer wieder eingestellt
1835
 
1836
    # gray connectors: Wp are sent to MK
1837
    $map_canvas->itemconfigure('Waypoint-Connector',
1838
                               '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpConnector'},
1839
                              );
1840
 
1841
    # MK ist nun synchron mit @Waypoints
1842
    $WaypointsModified = 0;
1843
    }          
1844
 
1845
 
1846
# Redraw Waypoint Icons
1847
sub WpRedrawIcons()
1848
    {
1849
    if ( $WptKmlMode =~ /WPT/i )
1850
        {
1851
 
1852
        # delete old icons and Wp-Number from canvas
1853
        $map_canvas->delete('Waypoint');
1854
        $map_canvas->delete('WaypointNumber');
1855
 
1856
        # create new icons
1857
        for $i (0 .. $#Waypoints)
1858
           {
1859
            my $Wp = $Waypoints[$i];
1860
            my $x = $Wp->{'MapX'};
1861
            my $y = $Wp->{'MapY'};
1862
            my $Tag = $Wp->{'Tag'};
1863
 
1864
            # Waypoint Icon
1865
            my $IconHeight = 48;
1866
            my $IconWidth = 48;
1867
            $map_canvas->createImage($x-$IconWidth/2, $y-$IconHeight,
1868
                                     '-tags' => ['Waypoint', $Tag],
1869
                                     '-anchor' => 'nw',
1870
                                     '-image'  => 'Waypoint-Photo',
1871
                                    );
1872
            # Waypoint Number
1873
            my $WpNumber = $i + 1;
1874
            $map_canvas->createText ( $x+3, $y-$IconHeight/2+12,
1875
                                      '-tags' => ['WaypointNumber', $Tag],
1876
                                      '-text' => $WpNumber,
1877
                                      '-font' => '-*-Arial-Bold-R-Normal--*-100-*',
1878
                                      '-fill' => $Cfg->{'mkcockpit'}->{'ColorWpNumber'},
1879
                                      '-anchor' => 'w',
1880
                                     );
1881
 
1882
            }  
1883
        $map_canvas->lower('Waypoint', 'Fox');              # waypoint below Fox
1884
        $map_canvas->lower('WaypointNumber', 'Waypoint');   # waypoint-number below waypoint
1885
        }
1886
    }
1887
 
1888
 
1889
# Redraw Waypoint connectors
1890
sub WpRedrawLines()
1891
    {
1892
    if ( $WptKmlMode =~ /WPT/i )
1893
        {
1894
        # delete old connectors from canvas
1895
        $map_canvas->delete('Waypoint-Connector');  
1896
 
1897
        my $Color = $Cfg->{'mkcockpit'}->{'ColorWpConnector'};
1898
        if ( $WaypointsModified )
1899
            {
1900
            $Color = $Cfg->{'mkcockpit'}->{'ColorWpResend'};
1901
            }
1902
 
1903
        my $Wp = $Waypoints[0];
1904
        my $x_last = $Wp->{'MapX'};
1905
        my $y_last = $Wp->{'MapY'};
1906
        for $i (1 .. $#Waypoints)
1907
            {
1908
            my $Wp = $Waypoints[$i];
1909
            my $x = $Wp->{'MapX'};
1910
            my $y = $Wp->{'MapY'};
1911
 
1912
            $map_canvas->createLine ( $x_last, $y_last, $x, $y,
1913
                                      '-tags' => 'Waypoint-Connector',
1914
                                      '-arrow' => 'last',
1915
                                      '-arrowshape' => [10, 10, 3 ],
1916
                                      '-fill' => $Color,
1917
                                      '-width' => 1,
1918
                                    );                                           
1919
            $x_last = $x;
1920
            $y_last = $y;
1921
            }
1922
 
1923
        $map_canvas->lower('Waypoint-Connector', 'Waypoint');   # connector below waypoint
1924
        }
1925
    }
1926
 
1927
 
1928
# Hide Waypoints on Canvas
1929
sub WpHide()
1930
   {
1931
   $map_canvas->delete('Waypoint');
1932
   $map_canvas->delete('WaypointNumber');
1933
   $map_canvas->delete('Waypoint-Connector');
1934
   }
1935
 
1936
 
1937
 
1938
# Redraw Footprint
1939
sub FootprintRedraw()
1940
    {
1941
    # delete old Footprint from canvas
1942
    $map_canvas->delete('Footprint');  
1943
 
1944
    if ( scalar @Footprint >= 4 )  # at least 2 Koordinaten-Paare
1945
        {
1946
        $map_canvas->createLine ( @Footprint,
1947
                                  '-tags' => 'Footprint',
1948
                                  '-fill' => $Cfg->{'mkcockpit'}->{'ColorFootprint'},
1949
                                  '-width' => 1,
1950
                                );       
1951
        }
1952
 
1953
    $map_canvas->lower('Footprint', 'Fox');
1954
    }
1955
 
1956
 
1957
# Redraw KML track
1958
sub KmlRedraw()
1959
    {
1960
 
1961
    # delete old Track from canvas
1962
    $map_canvas->delete('KML-Track');
1963
 
1964
    my @Track;
1965
 
1966
    foreach $Target ( @KmlTargets )
1967
        {
1968
        my $Lat = $Target->{'Lat'};
1969
        my $Lon = $Target->{'Lon'};
1970
        my $Alt = $Target->{'Alt'};
1971
        my ($x, $y) = &MapGps2XY($Lat, $Lon);
1972
        push @Track, $x, $y;
1973
        }
1974
 
1975
    if ( scalar @Track >= 4 )  # at least 2 Koordinaten-Paare
1976
        {
1977
        $map_canvas->createLine ( @Track,
1978
                                  '-tags' => 'KML-Track',
1979
                                  '-fill' => $Cfg->{'mkcockpit'}->{'ColorKmlTrack'},
1980
                                  '-width' => 1,
1981
                                );       
1982
 
1983
        $map_canvas->lower('KML-Track', 'Target');        # Track below Target
1984
        }
1985
    }
1986
 
1987
 
1988
# Hide Kml-Track on Canvas
1989
sub KmlHide()
1990
   {
1991
   $map_canvas->delete('KML-Track');
1992
   }
1993
 
1994
 
1995
# Switch player between WPT and KML
1996
sub WptKmlSwitch()
1997
    {
1998
    my ($Mode) = @_;
1999
 
2000
    # Wpt/Kml-Player-Icon loeschen und neu anzeigen
2001
    $map_canvas->delete('Wp-WptKml');
2002
 
2003
    if ( $Mode =~ /KML/i )
2004
        {
2005
        $WptKmlMode = 'KML';
2006
 
2007
        # set player button to KML
2008
        $map_canvas->createImage($MapSizeX/2-200, $MapSizeY-48,
2009
                                 '-tags' => 'Wp-WptKml',
2010
                                 '-anchor' => 'nw',
2011
                                 '-image'  => 'WpKml-Foto',
2012
                                 );
2013
 
2014
        # delete Waypoints from canvas
2015
        &WpHide();
2016
 
2017
        # show KML Track
2018
        &KmlRedraw();
2019
        }
2020
 
2021
    if ( $Mode =~ /WPT/i )
2022
        {
2023
        $WptKmlMode = 'WPT';
2024
 
2025
        # set player button to WPT
2026
        $map_canvas->createImage($MapSizeX/2-200, $MapSizeY-48,
2027
                                 '-tags' => 'Wp-WptKml',
2028
                                 '-anchor' => 'nw',
2029
                                 '-image'  => 'WpWpt-Foto',
2030
                                 );
2031
 
2032
        # delete Kml-Track from canvas
2033
        &KmlHide();
2034
 
2035
        # Show waypoints
2036
        &WpRedrawIcons()
2037
        &WpRedrawLines()
2038
        }
2039
    }
2040
 
2041
 
2042
# Display or Modify Hash
2043
sub DisplayHash()
2044
    {
2045
    my ($hrefData, $Titel, $Mode) = @_;
2046
 
2047
    # $Mode: Display, Edit, Waypoint, Refresh
2048
 
2049
    my %Id;
2050
    my $Label;
2051
    my $Value;
2052
 
2053
    # Neues Fenster aufmachen
2054
    my $popup = $main->Toplevel();
2055
    $popup->title($Titel);
2056
 
2057
    # Buttons
2058
    my $popup_button = $popup->Frame() -> pack('-side' => 'bottom',
2059
                                               '-expand' => 'y',
2060
                                               '-anchor' => 's',
2061
                                               '-padx' => 5,
2062
                                               '-pady' => 5,
2063
                                               );
2064
    $popup_button->Button('-text'    => 'Schließen',
2065
                          '-command' => sub
2066
        {
2067
        if ( $Mode =~ /edit/i  and  $Mode =~ /waypoint/i )
2068
            {
2069
            $WaypointsModified = 1;            
2070
            &WpRedrawLines();
2071
            &WpRedrawIcons();
2072
            }
2073
 
2074
        $popup->destroy()
2075
        })->pack;
2076
 
2077
    # Frame mit den Labels
2078
    my $popup_label = $popup->Frame() -> pack('-side' => 'left',
2079
                                              '-expand' => 'y',
2080
                                              '-anchor' => 'w',
2081
                                              '-padx' => 10,
2082
                                              '-pady' => 10,
2083
                                              );
2084
    # Labels anzeigen                    
2085
    foreach $Label ( sort keys %{$hrefData})
2086
        {
2087
        if ( $Translate{$Label} ne "" )
2088
            {
2089
            $Label = $Translate{$Label};
2090
            }
2091
 
2092
        $popup_label->Label ('-text' => $Label,
2093
                             '-width' => 25,
2094
                             '-anchor' => 'w',
2095
                             ) -> pack();
2096
        }
2097
 
2098
    # Frame mit den Daten
2099
    my $popup_values = $popup->Frame() -> pack('-side' => 'left',
2100
                                               '-expand' => 'y',
2101
                                               '-anchor' => 'w',
2102
                                               '-padx' => 10,
2103
                                               '-pady' => 10,
2104
                                               );
2105
    # Daten anzeigen
2106
    foreach $Value ( sort keys %{$hrefData})
2107
        {                              
2108
        if ( $Mode =~ /display/i )
2109
            {
2110
            # Display
2111
            $Id{$Value} = $popup_values->Label ('-text' => ${$hrefData}{$Value},
2112
                                                '-width' => 20,
2113
                                                '-anchor' => 'e',
2114
                                                '-relief' => 'sunken',
2115
                                                ) -> pack();
2116
            }
2117
        if ( $Mode =~ /edit/i )
2118
            {
2119
            # Edit
2120
            $Id{$Value} = $popup_values->Entry ('-textvariable' => \${$hrefData}{$Value},
2121
                                                '-exportselection' => '1',
2122
                                                '-width' => 20,
2123
                                                '-relief' => 'sunken',
2124
                                               ) -> pack();
2125
            if ( $Mode =~ /waypoint/i )
2126
                {
2127
                # einige Waypoint-Felder nicht aenderbar einstellen
2128
                if ( "MapX MapY Pos_Lat Pos_Lon Tag" =~ /$Value/i )
2129
                    {
2130
                    $Id{$Value}->configure('-state' => 'disabled', );
2131
                    }
2132
                }      
2133
            }
2134
        }
2135
 
2136
    if ( $Mode =~ /refresh/i )
2137
        {
2138
        # Timer: 0.1s
2139
        $popup_values->repeat (100, sub
2140
            {
2141
            # Datenfelder alle 100ms aktualisieren
2142
 
2143
            my $BgColor = 'white';
2144
            if ( $Mode =~ /heartbeat/i )
2145
                {
2146
                $BgColor = 'red';
2147
                if ( $MkOsd{'_Timestamp'} >= time-2 )
2148
                    {
2149
                    # gültige daten vom MK
2150
                    $BgColor = 'white';
2151
                    }
2152
                }
2153
 
2154
            foreach $Value ( sort keys %{$hrefData} )
2155
                {
2156
                # Eingebbare Waypoint-Felder nicht aktualisieren
2157
                if ( ! ($Mode =~ /waypoint/i  and
2158
                        "Event_Flag Heading ToleranceRadius HoldTime Pos_Alt" =~ /$Value/i) )
2159
                    {                
2160
                    $Id{$Value}->configure('-text' => ${$hrefData}{$Value},
2161
                                           '-background' => "$BgColor",
2162
                                          );
2163
                    }
2164
                }
2165
            });
2166
        }
2167
 
2168
    return 0;
2169
    }
2170
 
2171
 
2172
 
2173
# Konfigurationsdatei mkcockpit.xml im Popup-Fenster editieren
2174
sub Configure()
2175
    {
2176
 
2177
    # Copy Cfg-Hash for editing
2178
    my $CfgEdit = {%{$Cfg}};
2179
    foreach $key (keys %{$Cfg})
2180
        {
2181
        if ( ref $Cfg->{$key} )
2182
            {
2183
            $CfgEdit->{$key} = {%{$Cfg->{$key}}};
2184
            }
2185
        }
2186
 
2187
    # Neues Fenster aufmachen
2188
    my $popup = $main->Toplevel();
2189
    $popup->title("Einstellungen - $XmlConfigFile");
2190
 
2191
    # jede Sektion in einem Tab anzeigen
2192
    my $book = $popup->NoteBook()->pack( -fill=>'both', -expand=>1 );
2193
    foreach $key (sort keys %{$CfgEdit})
2194
        {    
2195
        if ( ! ref $CfgEdit->{$key} )
2196
            {
2197
            next;
2198
            }
2199
 
2200
        my $TabLabel = "$key";
2201
        if ( $Translate{$key} ne "" )
2202
                {
2203
                $TabLabel = $Translate{$key};
2204
                }
2205
 
2206
        my $Tab = $book->add( "$key", -label=>"$TabLabel", );
2207
 
2208
        # Frame fuer Buttons
2209
        my $book_button = $Tab->Frame() -> pack('-side' => 'bottom',
2210
                                                '-expand' => 'y',
2211
                                                '-anchor' => 's',
2212
                                                '-padx' => 5,
2213
                                                '-pady' => 5,
2214
                                                );
2215
 
2216
        $book_button->Button('-text'    => 'OK',
2217
                             '-width' => '10',
2218
                             '-command' => sub
2219
            {
2220
            # Copy back CfgEdit-Hash
2221
            $Cfg = {%{$CfgEdit}};
2222
            foreach $key (keys %{$CfgEdit})
2223
                {
2224
                if ( ref $CfgEdit->{$key} )
2225
                    {
2226
                    $Cfg->{$key} = {%{$CfgEdit->{$key}}};
2227
                    }
2228
                }
2229
 
2230
            # set new timestamp
2231
            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
2232
            my $TimeStamp = sprintf ("%04d%02d%02d-%02d%02d%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
2233
            $Cfg->{'CreationDate'} = $TimeStamp;
2234
 
2235
            # Cfg in mkcockpit.xml speichern
2236
            &XMLout ($Cfg,
2237
                     'OutputFile' => $XmlConfigFile,
2238
                     'AttrIndent' => '1',
2239
                     'RootName' => 'mkcockpit-Config',
2240
                    );
2241
 
2242
            $popup->destroy();
2243
            } )->pack ('-side' => 'left',
2244
                       '-expand' => 'y',
2245
                       '-anchor' => 's',
2246
                       '-padx' => 5,
2247
                       '-pady' => 5,
2248
                      );
2249
        $book_button->Button('-text'    => $Translate{'Abort'},
2250
                             '-width' => '10',
2251
                             '-command' => sub { $popup->destroy() },
2252
                            )->pack ('-side' => 'left',
2253
                                     '-expand' => 'y',
2254
                                     '-anchor' => 's',
2255
                                     '-padx' => 5,
2256
                                     '-pady' => 5,
2257
                                     );
2258
        $book_button->Label ('-text' => $Translate{'RestartRequired'},
2259
                             '-anchor' => 'w',
2260
                             '-foreground' => 'red',
2261
                            ) ->pack ('-side' => 'left',
2262
                                      '-expand' => 'y',
2263
                                      '-anchor' => 's',
2264
                                      '-padx' => 10,
2265
                                      '-pady' => 5,
2266
                                      );
2267
 
2268
        # Frame mit den Labels
2269
        my $popup_label = $Tab->Frame() -> pack('-side' => 'left',
2270
                                                '-expand' => 'y',
2271
                                                '-anchor' => 'w',
2272
                                                '-padx' => 10,
2273
                                                '-pady' => 10,
2274
                                                );
2275
        # Labels anzeigen                        
2276
        foreach $Label ( sort keys %{$CfgEdit->{$key}})
2277
            {
2278
            if ( $Translate{$Label} ne "" )
2279
                {
2280
                $Label = $Translate{$Label};
2281
                }
2282
 
2283
            $popup_label->Label ('-text' => $Label,
2284
                                 '-width' => 30,
2285
                                 '-anchor' => 'w',
2286
                                ) -> pack();
2287
            }
2288
 
2289
        # Frame mit den Daten
2290
        my $popup_values = $Tab->Frame() -> pack('-side' => 'left',
2291
                                                 '-expand' => 'y',
2292
                                                 '-anchor' => 'w',
2293
                                                 '-padx' => 10,
2294
                                                 '-pady' => 10,
2295
                                                 );
2296
        # Eingabefelder mit Daten anzeigen
2297
        foreach $Value ( sort keys %{$CfgEdit->{$key}})
2298
            {                          
2299
            $popup_values->Entry ('-textvariable' => \$CfgEdit->{$key}->{$Value},
2300
                                  '-exportselection' => '1',
2301
                                  '-width' => 30,
2302
                                  '-relief' => 'sunken',
2303
                                 ) -> pack();  
2304
            }
2305
        }
2306
    }
2307
 
2308
 
2309
# Waypoint Player: Goto next Waypoint
2310
sub WpTargetNext()
2311
    {
2312
    $WpPlayerIndex ++;
2313
    if ( $WpPlayerIndex > $#Waypoints )
2314
        {
2315
        # Restart with 1st Wp
2316
        $WpPlayerIndex = 0;
2317
        }
2318
 
2319
    $WpPlayerHoldtime = -1;
2320
    }
2321
 
2322
# Waypoint Player: Goto previous Waypoint
2323
sub WpTargetPrev()
2324
    {
2325
    $WpPlayerIndex --;
2326
    if ( $WpPlayerIndex < 0 )
2327
        {
2328
        # Restart with last Wp
2329
        $WpPlayerIndex = $#Waypoints;
2330
        }
2331
 
2332
    $WpPlayerHoldtime = -1;
2333
    }
2334
 
2335
# Waypoint Player: Goto first Waypoint
2336
sub WpTargetFirst()
2337
    {
2338
    $WpPlayerIndex = 0;
2339
    $WpPlayerHoldtime = -1;
2340
    }
2341
 
2342
# Waypoint Player: Goto last Waypoint
2343
sub WpTargetLast()
2344
    {
2345
    $WpPlayerIndex = $#Waypoints;
2346
    $WpPlayerHoldtime = -1;
2347
    }
2348
 
2349
 
2350
# Waypoint Player: Waypoint Target reached?
2351
sub WpCheckTargetReached()
2352
    {
2353
    if ( $WpPlayerHoldtime == -1 )
2354
        {
2355
        lock (%MkOsd);              # until end of block
2356
 
2357
        if ( $MkOsd{'_Timestamp'} >= time-2  and   # Gueltige OSD Daten
2358
             $MkOsd{'NCFlags'} & 0x04  and         # WPT-Mode
2359
             $MkOsd{'SatsInUse'} >= 6  and  $MkOsd{'CurPos_Stat'} == 1 and  $MkOsd{'HomePos_Stat'} == 1)
2360
            {
2361
            # Gueltige SAT Daten
2362
            my $WpTarget_Lat = $Waypoints[$WpPlayerIndex]{'Pos_Lat'};
2363
            my $WpTarget_Lon = $Waypoints[$WpPlayerIndex]{'Pos_Lon'};
2364
            my $WpTolerance  = $Waypoints[$WpPlayerIndex]{'ToleranceRadius'};
2365
            my $WpHoldtime   = $Waypoints[$WpPlayerIndex]{'Holdtime'};
2366
 
2367
            # Operation Radius pruefen
2368
            my ($HomeDist, $HomeBearing) = &MapGpsTo($MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'}, $WpTarget_Lat, $WpTarget_Lon );
2369
            if ( $HomeDist > $MkOsd{'OperatingRadius'} )
2370
                {
2371
                # Target entsprechend Operation Radius neu berechnen
2372
                $HomeDist = $MkOsd{'OperatingRadius'};
2373
                ($WpTarget_Lat, $WpTarget_Lon) = &MapGpsAt($MkOsd{'HomePos_Lat'}, $MkOsd{'HomePos_Lon'}, $HomeDist, $HomeBearing);
2374
                }
2375
 
2376
            # Abstand zum Ziel pruefen
2377
            my ($Dist, $Bearing) = &MapGpsTo($MkOsd{'CurPos_Lat'}, $MkOsd{'CurPos_Lon'}, $WpTarget_Lat, $WpTarget_Lon );
2378
            $Dist = int ($Dist + 0.5);
2379
            if ( $Dist <= $WpTolerance )
2380
                {
2381
                # Target reached - count down Holdtime
2382
                $WpPlayerHoldtime = 2 * $WpHoldtime;      # 0..2n - decrement im 0.5s timer
2383
                }
2384
            }
2385
        }
2386
 
2387
    if ( $WpPlayerHoldtime == 0 )  # wird im 0.5s timer runtergezaehlt
2388
        {
2389
        # Target reached - Holdtime is over
2390
        $WpPlayerHoldtime = -1;
2391
        return 1;
2392
        }
2393
 
2394
    # Target NOT reached
2395
    return 0;
2396
    }
2397
 
2398
 
2399
# KML Player: 10s forward
2400
sub KmlTargetNext()
2401
    {
2402
    $KmlPlayerIndex += int (10 / $Cfg->{waypoint}->{'KmlTimeBase'} + 0.5);
2403
    if ( $KmlPlayerIndex > $#KmlTargets )
2404
        {
2405
        # Next loop
2406
        $KmlPlayerIndex -= $#KmlTargets;
2407
        }
2408
    }
2409
 
2410
# KML Player: 10s backward
2411
sub KmlTargetPrev()
2412
    {
2413
    $KmlPlayerIndex -= int (10 / $Cfg->{waypoint}->{'KmlTimeBase'} + 0.5);
2414
    if ( $KmlPlayerIndex < 0 )
2415
        {
2416
        # Next loop
2417
        $KmlPlayerIndex += $#KmlTargets;
2418
        }
2419
    }
2420
 
2421
# KML Player: Goto first Target
2422
sub KmlTargetFirst()
2423
    {
2424
    $KmlPlayerIndex = 0;
2425
    }
2426
 
2427
# KML Player: Goto last Target
2428
sub KmlTargetLast()
2429
    {
2430
    $KmlPlayerIndex = $#KmlTargets;
2431
    }
2432
 
2433
 
2434
#
2435
# Call Back
2436
# 
2437
 
2438
# Player CallBack: Play/Pause button
2439
sub CbPlayerPlayPause()
2440
    {
2441
    # Play/Pause-Icon loeschen und neu anzeigen
2442
    $map_canvas->delete('Wp-PlayPause');
2443
 
2444
    if ( ($PlayerMode eq "Pause") or  ($PlayerMode eq "Stop") or  ($PlayerMode eq "Home") )
2445
        {
2446
        $PlayerMode = 'Play';
2447
        $WpPlayerHoldtime = -1;
2448
        $map_canvas->createImage($MapSizeX/2+100, $MapSizeY-48,
2449
                                 '-tags' => 'Wp-PlayPause',
2450
                                 '-anchor' => 'nw',
2451
                                 '-image'  => 'WpPause-Foto',
2452
                                 );
2453
        }
2454
    else
2455
        {
2456
        $PlayerMode = 'Pause';
2457
        $WpPlayerHoldtime = -1;
2458
        $map_canvas->createImage($MapSizeX/2+100, $MapSizeY-48,
2459
                                 '-tags' => 'Wp-PlayPause',
2460
                                 '-anchor' => 'nw',
2461
                                 '-image'  => 'WpPlay-Foto',
2462
                                 );
2463
 
2464
        # momentane Position merken und im Player-Timer dauernd senden
2465
        $PlayerPause_Lon = "";
2466
        $PlayerPause_Lat = "";
2467
 
2468
        lock (%MkOsd);              # until end of block
2469
        if ( $MkOsd{'_Timestamp'} >= time-2 )
2470
            {
2471
            # Gueltige OSD Daten
2472
            if ( $MkOsd{'SatsInUse'} >= 6  and  $MkOsd{'CurPos_Stat'} == 1 )
2473
                {
2474
                $PlayerPause_Lon = $MkOsd{'CurPos_Lon'};
2475
                $PlayerPause_Lat = $MkOsd{'CurPos_Lat'};
2476
                }
2477
            }
2478
        }
2479
    }
2480
 
2481
 
2482
# Player CallBack: Next
2483
sub CbPlayerNext()
2484
    {
2485
    if ( $PlayerMode ne 'Stop' )
2486
        {
2487
 
2488
        if ( $WptKmlMode eq 'WPT' )
2489
           {
2490
           &WpTargetNext();
2491
           }
2492
 
2493
        if ( $WptKmlMode eq 'KML' )
2494
           {
2495
           &KmlTargetNext();
2496
           }
2497
 
2498
        }
2499
    }
2500
 
2501
 
2502
# Player CallBack: Prev
2503
sub CbPlayerPrev()
2504
    {
2505
    if ( $PlayerMode ne 'Stop' )
2506
        {
2507
 
2508
        if ( $WptKmlMode eq 'WPT' )
2509
           {
2510
           &WpTargetPrev();
2511
           }
2512
 
2513
        if ( $WptKmlMode eq 'KML' )
2514
           {
2515
           &KmlTargetPrev();
2516
           }
2517
 
2518
        }
2519
    }
2520
 
2521
 
2522
# Player CallBack: First
2523
sub CbPlayerFirst()
2524
    {
2525
    if ( $PlayerMode ne 'Stop' )
2526
        {
2527
 
2528
        if ( $WptKmlMode eq 'WPT' )
2529
           {
2530
           &WpTargetFirst();
2531
           }
2532
 
2533
        if ( $WptKmlMode eq 'KML' )
2534
           {
2535
           &KmlTargetFirst();
2536
           }
2537
 
2538
        }
2539
    }
2540
 
2541
# Player CallBack: Last
2542
sub CbPlayerLast()
2543
    {
2544
    if ( $PlayerMode ne 'Stop' )
2545
        {
2546
 
2547
        if ( $WptKmlMode eq 'WPT' )
2548
           {
2549
           &WpTargetLast();
2550
           }
2551
 
2552
        if ( $WptKmlMode eq 'KML' )
2553
           {
2554
           &KmlTargetLast();
2555
           }
2556
 
2557
        }
2558
    }
2559
 
2560
 
2561
# Player CallBack: Home
2562
sub CbPlayerHome()
2563
    {
2564
    if ( $PlayerMode ne 'Stop' )
2565
        {
2566
        $PlayerMode = 'Home';
2567
        &WpTargetFirst();
2568
 
2569
        $map_canvas->delete('Wp-PlayPause');
2570
        $map_canvas->createImage($MapSizeX/2+100, $MapSizeY-48,
2571
                                 '-tags' => 'Wp-PlayPause',
2572
                                 '-anchor' => 'nw',
2573
                                 '-image'  => 'WpPlay-Foto',
2574
                                 );
2575
        }
2576
    }
2577
 
2578
 
2579
# Player CallBack: Stop
2580
sub CbPlayerStop()
2581
    {
2582
    if ( $PlayerMode ne 'Stop' )
2583
        {
2584
        $PlayerMode = 'Stop';
2585
        &WpTargetFirst();
2586
 
2587
        # set Play/Pause Icon to "Play
2588
        $map_canvas->delete('Wp-PlayPause');
2589
        $map_canvas->createImage($MapSizeX/2+100, $MapSizeY-48,
2590
                                 '-tags' => 'Wp-PlayPause',
2591
                                 '-anchor' => 'nw',
2592
                                 '-image'  => 'WpPlay-Foto',
2593
                                 );
2594
 
2595
 
2596
        # WP resend required
2597
        $WaypointsModified = 1;
2598
 
2599
        # switch player to Wp Mode
2600
        &WptKmlSwitch ('WPT');
2601
        }
2602
    }
2603
 
2604
 
2605
# Player CallBack: Move MK in Pause-Mode
2606
sub CbPlayerMove()
2607
    {
2608
    my ($Id, $DirX, $DirY) = @_;
2609
 
2610
    if ( $PlayerMode eq 'Pause'  and
2611
         $PlayerPause_Lat ne ""  and  $PlayerPause_Lon ne "" )
2612
        {
2613
        my $Dist = $Cfg->{'waypoint'}->{'PauseMoveDist'} || 1;  # 1m default
2614
 
2615
        my $BearingTop = &MapAngel() - 90.0;
2616
        my $BearingKey = rad2deg atan2($DirX, $DirY);
2617
        my $Bearing = $BearingTop + $BearingKey;
2618
 
2619
        ($PlayerPause_Lat, $PlayerPause_Lon) = &MapGpsAt($PlayerPause_Lat, $PlayerPause_Lon, $Dist, $Bearing)
2620
        }
2621
    }
2622
 
2623
 
2624
# Player CallBack: Toggle WPT/KML button
2625
sub CbPlayerWptKml()
2626
    {
2627
 
2628
    if ( $WptKmlMode =~ /WPT/i )
2629
        {
2630
        # switch player to KML Mode
2631
        &WptKmlSwitch ('KML');
2632
        }
2633
 
2634
    elsif ( $WptKmlMode =~ /KML/i )
2635
        {
2636
        # WP resend required
2637
        $WaypointsModified = 1;
2638
 
2639
        # switch player to Wp Mode
2640
        &WptKmlSwitch ('WPT');
2641
        }
2642
 
2643
    }
2644
 
2645
#
2646
# System Messages
2647
 
2648
# Init Messages for a Subsystem/timer
2649
sub MkMessageInit ()
2650
    {
2651
    my ($Id) = @_;
2652
 
2653
    $MkMessages{$Id} = [];
2654
    }
2655
 
2656
 
2657
# Register message
2658
sub MkMessage ()
2659
    {
2660
    my ($Message, $Id) = @_;
2661
 
2662
    push @{$MkMessages{$Id}}, $Message;
2663
    }
2664
 
2665
 
2666
# show registered messages
2667
sub MkMessageShow()
2668
    {
2669
    my @Messages;
2670
    my $MsgLines = 0;
2671
    my $MaxMsgLen = 0;
2672
 
2673
    # Collect Messages of each category
2674
    foreach my $Id (keys %MkMessages)
2675
        {
2676
        foreach $i ( 0 .. $#{$MkMessages{$Id}} )
2677
            {
2678
            my $Msg = $MkMessages{$Id}[$i];
2679
            push @Messages, $Msg;
2680
 
2681
            $MsgLines ++;
2682
 
2683
            my $Len = length $Msg;
2684
            if ( $Len > $MaxMsgLen )
2685
                {
2686
                $MaxMsgLen = $Len;
2687
                }
2688
            }
2689
        }
2690
 
2691
    $map_canvas->delete('Message-Balloon');  # delete old Balloon
2692
 
2693
    if ( $MsgLines > 0 )
2694
        {
2695
        # draw Balloon
2696
        my @MsgBalloon = ( $MkPos_x ,                       $MkPos_y,
2697
                           $MkPos_x + 30 ,                  $MkPos_y + 40,
2698
                           $MkPos_x + 30 + $MaxMsgLen * 11, $MkPos_y + 40,
2699
                           $MkPos_x + 30 + $MaxMsgLen * 11, $MkPos_y + 44 + $MsgLines * 20,
2700
                           $MkPos_x + 20,                   $MkPos_y + 44 + $MsgLines * 20,
2701
                           $MkPos_x + 20,                   $MkPos_y + 40,
2702
                           $MkPos_x,                        $MkPos_y,
2703
                          );
2704
 
2705
        $map_canvas->createPolygon( @MsgBalloon,
2706
                                    '-tags' => ['Message-Balloon', 'Message-BalloonBubble'],
2707
                                    '-fill' => 'yellow',
2708
                                    '-outline' => 'yellow',
2709
                                    '-width' => 1,
2710
                                  );
2711
        # draw Messages
2712
        my $MsgLine = 1;
2713
        foreach my $Msg (@Messages)
2714
            {
2715
            $map_canvas->createText ( $MkPos_x + 25, $MkPos_y + 32 + $MsgLine * 20 ,
2716
                                      '-tags' => ['Message-Balloon', 'Message-BalloonText'],
2717
                                      '-text' => $Msg,
2718
                                      '-font' => '-*-Arial-Bold-R-Normal--*-200-*',
2719
                                      '-fill' => 'blue',
2720
                                      '-anchor' => 'w',
2721
                                        );
2722
            $MsgLine ++;
2723
            }
2724
 
2725
 
2726
        $map_canvas->lower('Message-Balloon', 'MK-Arrow');
2727
        }
2728
 
2729
    }
2730
 
2731
 
2732
1;
2733
__END__