Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

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