Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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