Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
617 rain-er 1
#!/usr/bin/perl
2
#!/usr/bin/perl -d:ptkdb
3
 
4
###############################################################################
5
#
6
# mkcomm.pl -  MK Communication Routines
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-21 0.0.1 rw created
41
# 2009-03-18 0.0.2 rw NC 0.14e
42
# 2009-04-01 0.1.0 rw RC1
43
# 2009-04-06 0.1.1 rw NC 0.15c
44
# 2009-05-16 0.1.2 rw External control
45
# 2009-08-15 0.1.3 rw SIG-Handler removed
46
#
47
###############################################################################
48
 
49
$Version{'mkcomm.pl'} = "0.1.3 - 2009-08-15";
50
 
51
# MK Protokoll
52
#   http://www.mikrokopter.de/ucwiki/en/SerialCommands?highlight=(command)
53
#   http://www.mikrokopter.de/ucwiki/en/SerialProtocol?highlight=(protocol)
54
 
55
#
56
# Parameter
57
#
58
 
59
# Com Port of MK Comm-Device (BT, WI.232)
60
if ( ! defined $Cfg->{'mkcomm'}->{'Port'} )
61
    {
62
    # set default
63
    $Cfg->{'mkcomm'}->{'Port'} = "COM5";
64
    }
65
 
66
$AddrFC     = "b";
67
$AddrNC     = "c";
68
$AddrMK3MAG = "d";
69
 
70
 
71
if ( $0 =~ /mkcomm.pl$/i )
72
    {
73
    # Program wurde direkt aufgerufen
74
 
75
    # change working directory to program path
76
    my $Cwd = substr ($0, 0, rindex ($0, "mkcomm.pl"));
77
    chdir $Cwd;
78
 
79
    # set path for local Perl libs
80
    push @INC, $Cwd . "perl/lib";
81
    }
82
 
83
 
84
# Packages
85
use threads;                # http://search.cpan.org/~jdhedden/threads-1.72/threads.pm
86
                            # http://perldoc.perl.org/threads.html
87
use threads::shared;        # http://search.cpan.org/~jdhedden/threads-shared-1.28/shared.pm
88
use Thread::Queue;          # http://search.cpan.org/dist/Thread-Queue-2.11/lib/Thread/Queue.pm
89
use Time::HiRes qw(usleep); # http://search.cpan.org/~jhi/Time-HiRes-1.9719/HiRes.pm
90
if ( $^O =~ /Win32/i )
91
    {
92
    require Win32::SerialPort;  # http://search.cpan.org/dist/Win32-SerialPort
93
    }
94
else
95
    {
96
    require Device::SerialPort; # http://search.cpan.org/~cook/Device-SerialPort-1.04/SerialPort.pm
97
    }
98
 
99
require "libmap.pl";
100
 
101
# Hashes exported to other threads and main-program
102
share (%MkOsd);
103
share (%MkTarget);
104
share (%MkNcDebug);
105
share (%Mk);
106
 
107
# Queue for Sending to MK
108
$MkSendQueue = Thread::Queue->new();
109
 
110
sub MkCommExit()
111
    {  
112
    # close COM port
113
    &MkClose();
114
 
115
    if ( defined threads->self() )
116
        {
117
        threads->exit();
118
        }
119
    exit;
120
    }
121
 
122
 
123
sub MkInit()
124
    {
125
    if ( defined $MkPort )
126
        {
127
        return;   # already open
128
        }
129
 
130
    # open COM-Port             
131
    my $MkComPort = $Cfg->{'mkcomm'}->{'Port'};
132
    undef $MkPort;
133
    if ( $^O =~ m/Win32/ )
134
        {
135
        $MkPort = Win32::SerialPort->new ($MkComPort) || die "Error open $MkComPort\n";
136
        }
137
    else
138
        {
139
        $MkPort = Device::SerialPort->new ($MkComPort) || die "Error open $MkComPort\n";
140
        }
141
    # Set COM parameters
142
    $MkPort->baudrate(57600);
143
    $MkPort->parity("none");
144
    $MkPort->databits(8);
145
    $MkPort->stopbits(1);
146
    $MkPort->handshake('none');
147
    $MkPort->write_settings;
148
 
149
    $MkPort->read_const_time(100); # total = (avg * bytes) + const (ms)
150
    }
151
 
152
# Read one line from MK
153
# Check send-queue
154
sub MkIOLine()
155
    {
156
    # Init serial port
157
    &MkInit();
158
 
159
    my $RxLine = "";           
160
    while ( 1 )
161
        {      
162
        # Check Send-Queue
163
        my $Items = $MkSendQueue->pending();
164
        if ( $Items >= 3 )  # Cmd, Addr, Data
165
            {
166
            my ($Id, $Addr, $Data) = $MkSendQueue->dequeue(3);
167
            &MkSend ($Id, $Addr, $Data);       
168
            }
169
 
170
        # Zeichenweise lesen, blockierend mit Timeout
171
        my ($RxLen, $RxChar) = $MkPort->read(1);  
172
          if ( $RxLen == 1 )
173
              {
174
            if ( "$RxChar" eq "#" )       # 1st char of line
175
                {
176
                $RxLine = "#";
177
                }
178
            elsif ( "$RxChar" eq "\r" )   # last char of line
179
                {
180
                return ($RxLine);
181
                }
182
            else
183
                {
184
                $RxLine = "$RxLine" . "$RxChar";    # collect char
185
                }
186
            }
187
        }
188
    }
189
 
190
 
191
# Read and decode a command from MK
192
# process send queue in &MkIOLine()
193
sub MkIO()
194
    {  
195
    my $RxData = &MkIOLine();     # Blocking Read for complete line
196
 
197
    # Zeile decodieren
198
    if ( substr ($RxData, 0, 1) eq '#' )
199
        {                      
200
        # Zeile decodieren
201
        $Header = substr($RxData, 0, 3);
202
        $Chksum = substr($RxData, -2);
203
        $Data = substr($RxData, 3, length ($RxData) -5);
204
 
205
        # CRC prüfen
206
        if ( &CrcCheck ("$Header" . "$Data", $Chksum ) )
207
            {
208
            # Base64 decodieren
209
            $Data = &Decode64($Data);
210
 
211
            # Daten auswerten und in shared Hash schreiben
212
            if ( &ProcessRx($Header, $Data) )
213
                {
214
                return 1;    # alles OK
215
                }
216
            }
217
        }
218
 
219
    return 0;  # keine Daten empfangen
220
    }
221
 
222
 
223
# Send a command to MK
224
sub MkSend()
225
    {
226
    my ($Id, $Addr, $Data) = @_;
227
 
228
    # Init serial port
229
    &MkInit();
230
 
231
    my $Base64Data = &Encode64($Data);
232
 
233
    my $TxData = "#" . "$Addr" . "$Id" . "$Base64Data";
234
    my $Crc = &Crc($TxData);
235
    my $TxSend  = "$TxData" . "$Crc" . "\r";
236
    $MkPort->write($TxSend);
237
    }
238
 
239
 
240
# close COM-Port
241
sub MkClose()
242
    {
243
    undef $MkPort;
244
    }
245
 
246
 
247
# CRC Prüfung
248
sub CrcCheck ()
249
    {
250
    my ($Data, $Crc) = @_;
251
 
252
    my $Check = &Crc($Data);
253
    if ( $Check ne $Crc )
254
        {
255
        return 0;   # CRC passt nicht
256
        }          
257
    return (1);    # CRC OK
258
    }
259
 
260
 
261
# CRC berechnen
262
sub Crc ()
263
    {
264
    my ($Data) = @_;
265
    my $TmpCrc = 0;
266
    my $Len = length $Data;
267
 
268
    for ($i=0; $i<$Len; $i++)
269
        {
270
        $TmpCrc += ord(substr($Data, $i, 1));
271
        }
272
 
273
    $TmpCrc %= 4096;
274
    my $Crc1 = ord ("=") + $TmpCrc / 64;
275
    my $Crc2 = ord ("=") + $TmpCrc % 64;
276
    $Crc = pack("CC", $Crc1, $Crc2);
277
 
278
    return ($Crc);
279
    }
280
 
281
 
282
# Empfangene Daten decodieren, modifiziertes Base64
283
sub Decode64()
284
    {
285
    my ($DataIn) = @_;
286
 
287
    my $ptrIn  = 0;
288
    my $DataOut  = "";
289
    my $len = length ($DataIn);
290
 
291
    while ( $len > 0 )
292
        {
293
        $a = ord (substr ($DataIn, $ptrIn ++, 1)) - ord ("=");
294
        $b = ord (substr ($DataIn, $ptrIn ++, 1)) - ord ("=");
295
        $c = ord (substr ($DataIn, $ptrIn ++, 1)) - ord ("=");
296
        $d = ord (substr ($DataIn, $ptrIn ++, 1)) - ord ("=");
297
 
298
        $x = ($a << 2) | ($b >> 4);
299
        $y = (($b & 0x0f) << 4) | ($c >> 2);
300
        $z = (($c & 0x03) << 6) | $d;
301
 
302
        foreach $i ( $x, $y, $z )
303
            {
304
            if ( $len--)
305
                {
306
                my $Tmp = pack ('C1', $i);
307
                $DataOut = "$DataOut" . "$Tmp";
308
                }
309
            else
310
                {
311
                last;
312
                }
313
            }
314
        }
315
 
316
    return ($DataOut);
317
    }
318
 
319
 
320
# zu sendende Daten codieren, modifiziertes Base64
321
sub Encode64()
322
    {
323
    my ($Data) = @_;
324
 
325
    my $Length = length $Data;
326
    my $TxBuf = "";
327
    my $ptr = 0;
328
 
329
    while( $Length > 0 )
330
        {
331
        my $a = 0;
332
        my $b = 0;
333
        my $c = 0;
334
        if ($Length) {$a = ord(substr ($Data, $ptr++, $Length--));}
335
        if ($Length) {$b = ord(substr ($Data, $ptr++, $Length--));}
336
        if ($Length) {$c = ord(substr ($Data, $ptr++, $Length--));}
337
 
338
        my $ac = ord("=") +    ($a >> 2);
339
        my $bc = ord("=") + ( (($a & 0x03) << 4) | (($b & 0xf0) >> 4) );
340
        my $cc = ord("=") + ( (($b & 0x0f) << 2) | (($c & 0xc0) >> 6) );
341
        my $dc = ord("=") +    ($c & 0x3f);
342
        $TxBuf = "$TxBuf" . pack ("C4", $ac, $bc, $cc, $dc);
343
        }
344
    return ($TxBuf);
345
    }
346
 
347
 
348
# Empfangenen Datensatz verarbeiten
349
sub ProcessRx()
350
    {
351
    my ($Header, $Data) = @_;
352
 
353
    my $Adr = substr ($Header, 1, 1);    # b=FC, c=NC, d=MK3MAG
354
    my $Id  = substr ($Header, 2, 1);
355
 
356
    if ( $Id eq "O" )
357
        {
358
        #
359
        # OSD-Daten nach %MkOsd einlesen
360
        #
361
 
362
        # Struktur Datensatz:
363
        #     u8  Version                                     // version of the data structure
364
        #     GPS_Pos_t CurrentPosition;
365
        #     GPS_Pos_t TargetPosition;
366
        #     GPS_PosDev_t TargetPositionDeviation;
367
        #     GPS_Pos_t HomePosition;
368
        #     GPS_PosDev_t HomePositionDeviation;
369
        #     u8  WaypointIndex;                              // index of current waypoints running from 0 to WaypointNumber-1
370
        #     u8  WaypointNumber;                             // number of stored waypoints
371
        #     u8  SatsInUse;                                  // no of satellites used for position solution
372
        #     s16 Altimeter;                                  // hight according to air pressure
373
        #     s16 Variometer;                                 // climb(+) and sink(-) rate
374
        #     u16 FlyingTime;                                 // in seconds
375
        #     u8  UBat;                                       // Battery Voltage in 0.1 Volts
376
        #     u16 GroundSpeed;                                // speed over ground in cm/s (2D)
377
        #     s16 Heading;                                    // current flight direction in deg as angle to north
378
        #     s16 CompassHeading;                             // current compass value
379
        #     s8  AngleNick;                                  // current Nick angle in 1°
380
        #     s8  AngleRoll;                                  // current Rick angle in 1°
381
        #     u8  RC_Quality;                                 // RC_Quality
382
        #     u8  MKFlags;                                    // Flags from FC
383
        #     u8  NCFlags;                                    // Flags from NC
384
        #     u8  Errorcode;                                  // 0 --> okay
385
        #     u8  OperatingRadius                             // current operation radius around the Home Position in m
386
        #     s16 TopSpeed;                                   // velocity in vertical direction in cm/s
387
        #     u8  TargetHoldTime;                             // time in s to stay at the given target, counts down to 0 if target has been reached
388
        #     u8  Reserve[4];                                 // for future use
389
 
390
        # GPS_Pos_t:
391
        #     s32 Longitude;   // in 1E-7 deg
392
        #     s32 Latitude;    // in 1E-7 deg
393
        #     s32 Altitude;    // in mm
394
        #     u8  Status;      // validity of data
395
 
396
        # GPS_PosDev_t:
397
        #     s16 Distance;                                   // distance to target in dm
398
        #     s16 Bearing;                                    // course to target in deg      
399
 
400
        # Status:
401
        #     INVALID         = 0
402
        #     NEWDATA         = 1
403
        #     PROCESSED       = 2
404
 
405
        # MKFlags  0x01: MOTOR_RUN, 0x02 FLY, 0x04: CALIBRATE, 0x08: START, 0x10: EMERGENCY_LANDING
406
        # NCFlags  0x01: FLAG_FREE, 0x02: FLAG_PH, 0x04: FLAG_CH, 0x08: FLAG_RANGE_LIMIT
407
        #          0x10: FLAG_NOSERIALLINK, 0x20: FLAG_TARGET_REACHED, FLAG_MANUAL_CONTROL: 0x40
408
        #          0x80: FLAG_8
409
 
410
        lock (%MkOsd);  # until end of Block
411
 
412
        (
413
        $MkOsd{'Version'},
414
        $MkOsd{'CurPos_Lon'},
415
        $MkOsd{'CurPos_Lat'},
416
        $MkOsd{'CurPos_Alt'},
417
        $MkOsd{'CurPos_Stat'},
418
        $MkOsd{'TargetPos_Lon'},
419
        $MkOsd{'TargetPos_Lat'},
420
        $MkOsd{'TargetPos_Alt'},
421
        $MkOsd{'TargetPos_Stat'},
422
        $MkOsd{'TargetPosDev_Dist'},
423
        $MkOsd{'TargetPosDev_Bearing'},
424
        $MkOsd{'HomePos_Lon'},
425
        $MkOsd{'HomePos_Lat'},
426
        $MkOsd{'HomePos_Alt'},
427
        $MkOsd{'HomePos_Stat'},
428
        $MkOsd{'HomePosDev_Dist'},
429
        $MkOsd{'HomePosDev_Bearing'},
430
        $MkOsd{'WaypointIndex'},
431
        $MkOsd{'WaypointNumber'},
432
        $MkOsd{'SatsInUse'},
433
        $MkOsd{'Altimeter'},
434
        $MkOsd{'Variometer'},
435
        $MkOsd{'FlyingTime'},
436
        $MkOsd{'UBat'},
437
        $MkOsd{'GroundSpeed'},
438
        $MkOsd{'Heading'},
439
        $MkOsd{'CompassHeading'},
440
        $MkOsd{'AngleNick'},
441
        $MkOsd{'AngleRoll'},
442
        $MkOsd{'RC_Quality'},
443
        $MkOsd{'MKFlags'},
444
        $MkOsd{'NCFlags'},
445
        $MkOsd{'Errorcode'},
446
        $MkOsd{'OperatingRadius'},
447
        $MkOsd{'TopSpeed'},
448
        $MkOsd{'TargetHoldTime'},
449
        ) = unpack ('ClllClllCsslllCssCCCssSCSssccCCCCCsC', $Data);
450
 
451
        $MkOsd{'CurPos_Lon'}     = sprintf("%.7f", $MkOsd{'CurPos_Lon'} / 10000000);
452
        $MkOsd{'CurPos_Lat'}     = sprintf("%.7f", $MkOsd{'CurPos_Lat'} / 10000000);
453
        $MkOsd{'CurPos_Alt'}     = sprintf("%.3f", $MkOsd{'CurPos_Alt'} / 1000);
454
        $MkOsd{'TargetPos_Lon'}  = sprintf("%.7f", $MkOsd{'TargetPos_Lon'} / 10000000);
455
        $MkOsd{'TargetPos_Lat'}  = sprintf("%.7f", $MkOsd{'TargetPos_Lat'} / 10000000);
456
        $MkOsd{'TargetPos_Alt'}  = sprintf("%.3f", $MkOsd{'TargetPos_Alt'} / 1000);
457
        $MkOsd{'HomePos_Lon'}    = sprintf("%.7f", $MkOsd{'HomePos_Lon'} / 10000000);
458
        $MkOsd{'HomePos_Lat'}    = sprintf("%.7f", $MkOsd{'HomePos_Lat'} / 10000000);
459
        $MkOsd{'HomePos_Alt'}    = sprintf("%.3f", $MkOsd{'HomePos_Alt'} / 1000);
460
        $MkOsd{'UBat'}           = sprintf("%.1f", $MkOsd{'UBat'} / 10);
461
 
462
        # Timestamp, wann der Datensatz geschtieben wurde
463
        $MkOsd{'_Timestamp'} = time;
464
        }
465
 
466
    elsif ( $Id eq "s" )
467
        {
468
        #
469
        # NC Target position in %MkTarget
470
        #
471
        # Datenstruktur:
472
        #    GPS_Pos_t Position;     // the gps position of the waypoint, see ubx.h for details
473
        #    s16 Heading;            // orientation, future implementation
474
        #    u8  ToleranceRadius;    // in meters, if the MK is within that range around the target, then the next target is 
475
        #    u8  HoldTime;           // in seconds, if the MK was once in the tolerance area around a WP,
476
        #                            // this time defines the delay before the next WP is triggered
477
        #    u8  Event_Flag;         // future emplementation
478
        #    u8  reserve[12];        // reserved
479
 
480
        lock (%MkTarget);  # until end of block
481
 
482
        (
483
        $MkTarget{'Pos_Lon'},
484
        $MkTarget{'Pos_Lat'},
485
        $MkTarget{'Pos_Alt'},
486
        $MkTarget{'Pos_Stat'},
487
        $MkTarget{'Heading'},
488
        $MkTarget{'ToleranceRadius'},
489
        $MkTarget{'HoldTime'},
490
        $MkTarget{'EventFlag'},
491
        ) = unpack ('lllCsCCC', $Data);
492
 
493
        $MkTarget{'Pos_Lon'} = sprintf("%.7f", $MkTarget{'Pos_Lon'} / 10000000);
494
        $MkTarget{'Pos_Lat'} = sprintf("%.7f", $MkTarget{'Pos_Lat'} / 10000000);
495
        $MkTarget{'Pos_Alt'} = sprintf("%.3f", $MkTarget{'Pos_Alt'} / 1000);
496
 
497
        # Timestamp, wann der Datensatz geschtieben wurdw
498
        $MkTarget{'_Timestamp'} = time;
499
        }
500
 
501
    elsif ( $Id eq "W" )
502
        {
503
        #
504
        # Request new waypoint
505
        #
506
        # Datenstruktur:
507
        #    u8 Number of waypoint
508
 
509
        ($WpNumber) = unpack ('C', $Data);
510
 
511
        # keine Ahnung wofuer das gut sein soll
512
 
513
        # print "Request new Waypoint Number: $WpNumber\n";
514
 
515
        }
516
 
517
    elsif ( $Id eq "V" )
518
        {
519
        #
520
        # Version
521
        #
522
        # Datenstruktur:
523
        #    u8 SWMajor
524
        #    u8 SWMinor
525
        #    u8 ProtoMajor
526
        #    u8 ProtoMinor
527
        #    u8 SWPatch
528
        #    u8 Reserved[5]
529
 
530
        (
531
        $Mk{'SWMajor'},
532
        $Mk{'SWMinor'},
533
        $Mk{'ProtoMajor'},
534
        $Mk{'ProtoMinor'},
535
        $Mk{'SWPatch'},
536
        ) = unpack ('C5', $Data);
537
 
538
        $Mk{'_Timestamp'} = time;
539
        }
540
 
541
    elsif ( $Id eq "E" )
542
        {
543
        #
544
        # Error Text
545
        #
546
        # Datenstruktur:
547
        #    s8 ErrorMsg[25]
548
 
549
        $Mk{'ErrorMsg'} = unpack ('Z25', $Data);
550
        }
551
 
552
    elsif ( $Id eq "D" )
553
        {
554
        #
555
        # NC Debug %MkNcDebug
556
        #
557
        # Datenstruktur:
558
        #    u8 Digital[2];
559
        #    u16 Analog[32];
560
 
561
        lock (%MkNcDebug);    # until end of block
562
 
563
        (
564
        $MkNcDebug{'Digital_00'},
565
        $MkNcDebug{'Digital_01'},
566
        $MkNcDebug{'Analog_00'},
567
        $MkNcDebug{'Analog_01'},
568
        $MkNcDebug{'Analog_02'},
569
        $MkNcDebug{'Analog_03'},
570
        $MkNcDebug{'Analog_04'},
571
        $MkNcDebug{'Analog_05'},
572
        $MkNcDebug{'Analog_06'},
573
        $MkNcDebug{'Analog_07'},
574
        $MkNcDebug{'Analog_08'},
575
        $MkNcDebug{'Analog_09'},
576
        $MkNcDebug{'Analog_10'},
577
        $MkNcDebug{'Analog_11'},
578
        $MkNcDebug{'Analog_12'},
579
        $MkNcDebug{'Analog_13'},
580
        $MkNcDebug{'Analog_14'},
581
        $MkNcDebug{'Analog_15'},
582
        $MkNcDebug{'Analog_16'},
583
        $MkNcDebug{'Analog_17'},
584
        $MkNcDebug{'Analog_18'},
585
        $MkNcDebug{'Analog_19'},
586
        $MkNcDebug{'Analog_20'},
587
        $MkNcDebug{'Analog_21'},               
588
        $MkNcDebug{'Analog_22'},
589
        $MkNcDebug{'Analog_23'},
590
        $MkNcDebug{'Analog_24'},
591
        $MkNcDebug{'Analog_25'},
592
        $MkNcDebug{'Analog_26'},
593
        $MkNcDebug{'Analog_27'},
594
        $MkNcDebug{'Analog_28'},
595
        $MkNcDebug{'Analog_29'},
596
        $MkNcDebug{'Analog_30'},
597
        $MkNcDebug{'Analog_31'},
598
        ) = unpack ('C2s32', $Data);
599
 
600
        # Timestamp, wann der Datensatz geschrieben wurde
601
        $MkNcDebug{'_Timestamp'} = time;
602
        }
603
 
604
    elsif ( $Id eq "B" )
605
        {
606
        #
607
        # External Control
608
        #
609
        # Datenstruktur:
610
        #    u8 ConfirmFrame;
611
 
612
        my ($ConfirmFrame) = unpack ('C5', $Data);
613
 
614
        }
615
    else
616
        {
617
        print "Unknown Command: $Header $Data\n";
618
        }
619
    }  
620
 
621
 
622
# send Target or Waypoint to MK
623
sub MkFlyTo()
624
    {
625
    my %Param = @_;
626
 
627
    my $x               = $Param{'-x'};
628
    my $y               = $Param{'-y'};
629
    my $Lat             = $Param{'-lat'};
630
    my $Lon             = $Param{'-lon'};
631
    my $Alt             = $Param{'-alt'};
632
    my $Heading         = $Param{'-heading'};
633
    my $ToleranceRadius = $Param{'-toleranceradius'};
634
    my $Holdtime        = $Param{'-holdtime'};
635
    my $EventFlag       = $Param{'-eventflag'};
636
    my $Mode            = $Param{'-mode'};
637
 
638
    if ( $x ne ""  and  $y ne ""  and  $Lat eq ""  and  $Lon eq "" )
639
        {
640
        ($Lat, $Lon) = &MapXY2Gps($x, $y);
641
        }
642
 
643
    if ( $Alt eq "" )             { $Alt = $MkOsd{'CurPos_Alt'}; }
644
    if ( $Heading eq "" )         { $Heading         = $Cfg->{'waypoint'}->{'DefaultHeading'}; }
645
    if ( $ToleranceRadius eq "" ) { $ToleranceRadius = $Cfg->{'waypoint'}->{'DefaultToleranceRadius'}; }
646
    if ( $Holdtime eq "" )        { $Holdtime        = $Cfg->{'waypoint'}->{'DefaultHoldtime'}; }
647
    if ( $EventFlag eq "" )       { $EventFlag       = $Cfg->{'waypoint'}->{'DefaultEventFlag'}; }
648
 
649
    my $Status = 1;     # valid
650
    if ( $Mode =~ /delete/i )
651
        {
652
        $Status = 0;    # invalid -> delete NC WP-List
653
        }
654
 
655
    my $Lat_i = sprintf "%d", $Lat * 10000000;
656
    my $Lon_i = sprintf "%d", $Lon * 10000000;
657
    my $Alt_i = sprintf "%d", $Alt * 1000;
658
 
659
    # Datenstruktur:
660
    #    GPS_Pos_t Position;     // the gps position of the waypoint, see ubx.h for details
661
    #    s16 Heading;            // orientation, future implementation
662
    #    u8  ToleranceRadius;    // in meters, if the MK is within that range around the target, then the next target is 
663
    #    u8  HoldTime;           // in seconds, if the MK was once in the tolerance area around a WP,
664
    #                            // this time defines the delay before the next WP is triggered
665
    #    u8  Event_Flag;         // future emplementation
666
    #    u8  reserve[12];        // reserved
667
 
668
    my $Wp = pack ('lllCsC15',
669
                   $Lon_i,
670
                   $Lat_i,
671
                   $Alt_i,
672
                   $Status,
673
                   $Heading,
674
                   $ToleranceRadius,
675
                   $Holdtime,
676
                   $EventFlag,
677
                   0,0,0,0,0,0,0,0,0,0,0,0,
678
                  );
679
 
680
    if ( $Mode =~ /waypoint/i )
681
        {
682
        $MkSendQueue->enqueue( "w", "$AddrNC", $Wp );
683
        # &MkSend( "w", "$AddrNC", $Wp );
684
        }
685
    elsif ( $Mode =~ /target/i )
686
        {
687
        $MkSendQueue->enqueue( "s", "$AddrNC", $Wp );
688
        # &MkSend( "w", "$AddrNC", $Wp );
689
        }
690
    else
691
        {
692
        # ignore
693
        }
694
 
695
    return 0;
696
    }
697
 
698
 
699
# send External control to MK
700
sub ExternalControl()
701
    {
702
    my %Param = @_;
703
 
704
    my $RemoteButtons = $Param{'-remotebuttons'};
705
    my $Nick = $Param{'-nick'};
706
    my $Roll = $Param{'-roll'};
707
    my $Yaw = $Param{'-yaw'};
708
    my $Gas = $Param{'-gas'};
709
    my $Hight = $Param{'-hight'};
710
    my $Free = $Param{'-free'};
711
    my $Frame = $Param{'-frame'};
712
    my $Config = $Param{'-config'};
713
 
714
    # Datenstruktur:
715
    #    u8      Digital[2];
716
    #    u8      RemoteButtons;
717
    #    s8      Nick;
718
    #    s8      Roll;
719
    #    s8      Yaw;
720
    #    u8      Gas;
721
    #    s8      Height;
722
    #    u8      free;
723
    #    u8      Frame;
724
    #    u8      Config;
725
 
726
    my $Ec = pack ('CCCcccCcCCC',
727
                   0, 0,
728
                   $RemoteButtons,
729
                   $Nick,
730
                   $Roll,
731
                   $Yaw,
732
                   $Gas,
733
                   $Hight,
734
                   $Free,
735
                   $Frame,
736
                   $Config
737
                  );
738
 
739
    $MkSendQueue->enqueue( "b", "$AddrNC", $Ec );
740
    # &MkSend( "b", "$AddrNC", $Ec );
741
 
742
    return 0;
743
    }
744
 
745
 
746
# when called as thread
747
sub MkCommLoop()
748
    {
749
    while (1)
750
       {
751
       &MkIO();
752
       }
753
    }
754
 
755
 
756
#
757
# Hauptprgramm
758
#       
759
 
760
if ( $0 =~ /mkcomm.pl$/i )
761
    {
762
    # Program wurde direkt aufgerufen
763
    &MkCommLoop();
764
 
765
    # should never exit
766
    }
767
 
768
1;
769
 
770
__END__
771