Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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