Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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