Generated: Sun Aug 21 11:10:37 2011 from atlas-trk.pl 2011/03/03 28.4 KB.
#!/usr/bin/perl -w # NAME: atlas-trk.pl # AIM: Read, and display an Atlas 'track' file - a text file, with a bunch of nmea # text strings - those emitted from a GP unit... example # $GPRMC,010044,A,3142.142,S,14838.309,E,000.0,342.0,2112110,0.000,E*50 # $GPGGA,010044,3142.142,S,14838.309,E,1,,,-9999,F,,,,*24 # $PATLA,115.80,280.0,116.80,29.0,374*66 # 17/02/2011 - review # 24/12/2010 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; use Time::HiRes qw( usleep gettimeofday tv_interval ); # use constant PI => 4 * atan2(1, 1); my $perl_dir = 'C:\GTools\perl'; unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl'! Check location and \@INC content.\n"; require 'fg_wsg84.pl' or die "Unable to load fg_wsg84.pl ...\n"; require "Bucket2.pm" or die "Unable to load Bucket2.pm ...\n"; # log file stuff our ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $perl_dir."\\temp.$pgmname.txt"; open_log($outfile); # user variables my $load_log = 1; my $in_file = ''; my $SG_EPSILON = 0.0000001; #/** Meters to Feet */ my $SG_METER_TO_FEET = 3.28083989501312335958; #/** Meters to Nautical Miles. 1 nm = 6076.11549 feet */ my $SG_METER_TO_NM = 0.0005399568034557235; my $debug_on = 1; my $def_dir = 'C:\FG\Atlas\Atlas-0.5.0\build\msvc\Tracks'; #my $def_file = $def_dir.'\atlas-track-01.txt'; my $def_file = $def_dir."\\left-gil-cir-04.txt"; #my $def_file = $def_dir."\\atlas-gil-08.trk.txt"; #my $def_file = $def_dir."\\atlas-gil-01.trk.txt"; ### program variables my @warnings = (); my $cwd = cwd(); my $os = $^O; my $gps_first = 1; my $FG_PI = get_fg_PI(); # features my $show_dist_calc = 0; my $chk_checksum = 1; my $use_pos_latlon = 1; my $massage_latlon = 1; my $min_flying_speed = 55; # Knots # debug my $dbg_01 = 0; my $dbg_03 = 0; # program variables my $gps_count = 0; my ($gps_time_rmc,$gps_ok_rmc,$gps_lat_rmc,$gps_long_rmc,$gps_speed,$gps_bearing,$gps_date,$gps_mvar); my ($first_lon,$first_lat,$first_alt); my ($last_lat,$last_lon,$last_alt); my ($g_sg_az1,$g_sg_az2,$g_sg_dist); my $clast_speed = ''; my $clast_alt = ''; my $clast_bearing = ''; my $g_total_dist = 0; my $g_curr_heading = 0; my $gps_min_lat = 400; my $gps_max_lat = -400; my $gps_min_lon = 400; my $gps_max_lon = -400; my ($g_time_gga,$g_lat_gga,$g_lon_gga,$g_fixqual,$g_nsat,$g_hdop_gga,$g_alt_gga,$g_gheight,$g_DGPS_age,$g_DGPS_ID); my ($g_nav1_freq,$g_nav1_rad,$g_nav2_freq,$g_nav2_rad,$g_adf_freq); my $tot_secs = 0; my $gga_count = 0; my @GPRMC = (); my @GPGGA = (); sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { #prt( "\nNo warnings issued.\n\n" ); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub deg_to_rad($) { my $deg = shift; return ($deg * $FG_PI / 180); } sub get_lat_lon_at_dist_on_heading($$$$) { my ($lat,$lon,$dist,$heading) = @_; # // The simpliest lat/lon to distance formula # assumes a perfect sphere, of my $r = 365239.5; # feet! my $rad = deg_to_rad($heading); my $a = cos($rad) * $dist; my $o = sin($rad) * $dist; my $dlat = $a / $r; my $dlon = $o / cos(deg_to_rad($lat + $dlat)) / $r; my $nlat = ($lat + $dlat); my $nlon = ($lon + $dlon); return $nlat,$nlon; } # @_ = (3352.3955,S) == -33 52.3955 == -33.8732583333333 sub get_latitude { my ($deg, $min) = unpack "a2a*", $_[0]; my $lat = $deg + $min / 60; $lat = - $lat if $_[1] =~ /[Ss]/; return $lat; } # @_ = (15113.3678,E) == +151 13.6678 == 151.222796666667 sub get_longitude { my ($deg, $min) = unpack "a3a*", $_[0]; my $long = $deg + $min / 60; $long = - $long if $_[1] =~ /[Ww]/; return $long; } sub get_message_checksum($) { my ($line) = shift; my @arr = split(//, $line); my $len = length $line; my $cnt = scalar @arr; #prt( "len $len, count $cnt, "); my $chksum = 0; my ($let,$val,$ins,$i,$rem,$hex,$ok); $ins = 0; $rem = ''; for ($i = 0; $i < $cnt; $i++) { $let = $arr[$i]; $val = ord($let); if ($ins) { if ($let eq '*') { $ins = 0; $i++; for ( ;$i < $cnt; $i++) { $rem .= $arr[$i]; } } else { $chksum ^= $val; } } else { if ($let eq '$') { $ins = 1; } } } $hex = sprintf("%02X", $chksum); $ok = (($rem eq $hex) ? "ok" : "FAILED"); prt( "[01] checksum = [$hex] ($rem) $ok\n" ) if ($dbg_01); return $hex; } sub get_gps_info_example_not_used($) { my ($rfield) = @_; # Now process the new RMC record - example ### $GPRMC,130210.030,A,3352.3955,S,15113.3678,E,0.257256,125.59,260605,,*10 $gps_time_rmc = join ':', unpack "a2" x 3, ${$rfield}[1]; $gps_ok_rmc = ${$rfield}[2]; $gps_lat_rmc = get_latitude(${$rfield}[3..4]); $gps_long_rmc = get_longitude(${$rfield}[5..6]); $gps_speed = ${$rfield}[7]; $gps_bearing = ${$rfield}[8]; $gps_date = join '/', unpack "a2" x 3, ${$rfield}[9]; $gps_mvar = ${$rfield}[10] . ${$rfield}[11]; # field[12] is checksum } # from : http://www.codepedia.com/1/The+GPRMC+Sentence # The GPRMC sentence consists of twelve comma-delimited words. # but seems to miss mentioning the magnetic variation # eg - $GPRMC,012255,A,3139.338,S,14837.161,E,115.3,341.6,1702111,0.000,E*56 # 0 - The Command Word '$GPRMC' # 1 - Satellite-Derived Time - current time, in UTC, in a compressed form "HHMMSS.XXX," # where HH represents hours, MM represents minutes, SS represents seconds, and XXX represents milliseconds # 2 - Satellite Fix Status - 'A' = Active, 'V' = inValid # 3 - Latitude Decimal Degrees - format "HHMM.M" where HH represents hours and MM.M represents minutes # 4 - Latitude Hemisphere - 'N' = North, 'S' = South # 5 - Longitude Decimal Degrees - format "HHHMM.M" where HHH represents hours and MM.M represents minutes # 6 - Longitude Hemisphere - 'E' = East, 'W' = West # 7 - Speed - rate over land, in Knots # 8 - Bearing - azimuth, in degrees between 0 and 360 # 9 - UTC Date - 2 two-digit numbers for days, months plus year (2 or 3 digits) # 10-11 - 0.000,E - Magnetic Variation (missed from spec?) - BUT FG uses a dummy '0.000,E' WHY? # 12 - 2 digit hex after '*' - The Checksum - XOR of everything between '$' and '*', as a 2 digit HEX value sub process_GPRMC_msg { my ($line) = @_; my @field = split /[,*]/, $line; # split on comma, and * (checksum) my $tcnt = scalar @field; my $secs = 0; # recommended minimum specific GPS/Transit data if (($tcnt >= 12) && ($field[0] eq '$GPRMC')) { # Each time we see this # sentence, print out the accumulated information # from the previous burst. #gps_output() unless ($gps_first) ; $gps_first = 0; # Now process the new RMC record - example # 0 1 2 3 ... 4 5 ... 6 7 8 9 10/11 12 ### $GPRMC,130210.030,A,3352.3955,S,15113.3678,E,0.257256,125.59,260605, , *10 $gps_time_rmc = join ':', unpack "a2" x 3, $field[1]; #// HHMMSS utc $gps_ok_rmc = $field[2]; $gps_lat_rmc = get_latitude(@field[3..4]); $gps_long_rmc = get_longitude(@field[5..6]); $gps_speed = $field[7]; # ground speed, in Knots $gps_bearing = $field[8]; $gps_date = join '/', unpack "a2" x 3, $field[9]; #// DDMMYYY (YYY = years since 1900) $gps_mvar = $field[10] . $field[11]; $secs = get_time_in_seconds($gps_time_rmc); # 0=secs 1=lat 2=lon 3=speed 4=bearing push(@GPRMC, [ $secs, $gps_lat_rmc, $gps_long_rmc, $gps_speed, $gps_bearing ]); # field[12] is checksum ###last SWITCH; if ($use_pos_latlon) { my $latpos = ($gps_lat_rmc + 90); my $lonpos = ($gps_long_rmc + 180); $gps_min_lat = $latpos if ($latpos < $gps_min_lat); $gps_max_lat = $latpos if ($latpos > $gps_max_lat); $gps_min_lon = $lonpos if ($lonpos < $gps_min_lon); $gps_max_lon = $lonpos if ($lonpos > $gps_max_lon); } else { $gps_min_lat = $gps_lat_rmc if ($gps_lat_rmc < $gps_min_lat); $gps_max_lat = $gps_lat_rmc if ($gps_lat_rmc > $gps_max_lat); $gps_min_lon = $gps_long_rmc if ($gps_long_rmc < $gps_min_lon); $gps_max_lon = $gps_long_rmc if ($gps_long_rmc > $gps_max_lon); } if ($chk_checksum) { my $cs = get_message_checksum($line); if ($cs ne $field[12]) { prtw("WARNING: GPGGA message [$line] BAD checksum [$cs] vs [".$field[12]."]!\n"); } } return 1; } else { prtw("WARNING: GPGGA has field count of $tcnt!\n"); pgm_exit(1,""); } return 0; } # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # $GPGGA,012255,3139.338,S,14837.161,E,1, , ,1862,F, , , , *04 # from : http://aprs.gids.nl/nmea/#gga # $GPGGA # Global Positioning System Fix Data # Off Name Example Data Description # 0 - Sentence Identifier $GPGGA Global Positioning System Fix Data # 1 - Time 170834 17:08:34 Z # 2-3 Latitude 4124.8963,N 41d 24.8963' N or 41d 24' 54" N # 4-5 Longitude 08151.6838,W 81d 51.6838' W or 81d 51' 41" W # 6 - Fix Quality: 1 0=Invalid - 1=GPS fix - 2=DGPS fix 1 Data is from a GPS fix # 7 - Number of Satellites 05 5 Satellites are in view # 8 - Horizontal Dilution of Precision (HDOP) 1.5 Relative accuracy of horizontal position # 9-10 Altitude 280.2,M 280.2 meters above mean sea level # 11-12 Height of geoid above WGS84 ellipsoid -34.0,M -34.0 meters # 13 - Time since last DGPS update blank No last update # 14 - DGPS reference station id blank No station id # 15 - Checksum *75 Used by program to check for transmission errors sub process_GPGGA_msg { my ($line) = @_; my @field = split /[,*]/, $line; # split on comma, and * (checksum) my $len = scalar @field; my $secs = 0; # GPS fix data if (($len > 15) && ($field[0] eq '$GPGGA')) { $g_time_gga = join ':', unpack "a2" x 3, $field[1]; $g_lat_gga = get_latitude(@field[2..3]); # // Latitude // DDMM.MMM, 'N' or 'S' $g_lon_gga = get_longitude(@field[4..5]); $g_fixqual = $field[6]; $g_nsat = $field[7]; $g_hdop_gga = $field[8]; $g_alt_gga = $field[9]; # // Altitude if ($g_alt_gga <= -9999) { # invalid altitude - leave as is } else { $g_alt_gga *= $SG_METER_TO_FEET; } # char *units = tokens[10]; // 'F' or 'M' #// If units are metres, convert them to feet. #if (strcmp(units, "M") == 0) { #d->alt *= SG_METER_TO_FEET; #} # $field[10] is altitude units (M or F) $g_gheight = $field[11]; # $field[12] is geoid height units (M or F) $g_DGPS_age = $field[13]; $g_DGPS_ID = $field[14]; # field[15] is checksum; $secs = get_time_in_seconds($g_time_gga); # 0=secs 1=lat 2=lon 3=alt 4=geod alt push(@GPGGA, [ $secs, $g_lat_gga, $g_lon_gga. $g_alt_gga, $g_gheight ]); if ($chk_checksum) { my $cs = get_message_checksum($line); if ($cs ne $field[15]) { prtw("WARNING: GPGGA message [$line] BAD checksum [$cs] vs [".$field[15]."]!\n"); } } return 1; } else { prtw("WARNING: Count = $len - NOT GPGGA sentence [$line]\n"); } return 0; } # $PATLA,115.80,280.0,116.80,29.0,251*60 sub process_PATLA_msg { my ($line) = @_; my @field = split /[,*]/, $line; # split on comma, and * (checksum) my $tcnt = scalar @field; # recommended minimum specific GPS/Transit data if (($tcnt >= 7) && ($field[0] eq '$PATLA')) { # (tokenCount == 7)) #// NAV1, NAV2 and ADF $g_nav1_freq = $field[1]; $g_nav1_rad = $field[2]; $g_nav2_freq = $field[3]; $g_nav2_rad = $field[4]; $g_adf_freq = $field[5]; #// VOR frequencies are transmitted in the PATLA line as #// floats (eg, 112.30), but we store them as ints (112300). $g_nav1_freq = int($g_nav1_freq * 1000); $g_nav2_freq = int($g_nav2_freq * 1000); if ($chk_checksum) { my $cs = get_message_checksum($line); if ($cs ne $field[6]) { prtw("WARNING: PATLA message [$line] BAD checksum [$cs] vs [".$field[6]."]!\n"); } } return 1; } else { prtw("WARNING: PATLA message [$line] count is $tcnt, NOT 7!\n"); } return 0; } sub bark_if_RMC_ne_GGA() { my $diff1 = abs($gps_lat_rmc - $g_lat_gga); if ($diff1 > $SG_EPSILON) { prtw("WARNING: RMC $gps_lat_rmc NE GGA $g_lat_gga ($diff1)\n"); } my $diff2 = abs($gps_long_rmc - $g_lon_gga); if ($diff2 > $SG_EPSILON) { prtw("WARNING: RMC $gps_long_rmc NE GGA $g_lon_gga ($diff2)\n"); } } sub get_time_in_seconds($) { my ($txt) = @_; my @arr = split(/:/,$txt); if (scalar @arr == 3) { my $secs = $arr[2]; $secs += $arr[1] * 60; $secs += $arr[0] * 60 * 60; return $secs; } return 0; } sub get_hhmmss($) { my ($secs) = @_; my $mins = int($secs / 60); $secs = $secs - ($mins * 60); my $hrs = int($mins / 60); $mins = $mins - ($hrs * 60); $hrs = "0$hrs" if ($hrs < 10); $mins = "0$mins" if ($mins < 10); $secs = "0$secs" if ($secs < 10); return "$hrs:$mins:$secs"; } sub get_decimal_stg($$$) { my ($dec,$il,$dl) = @_; my (@arr); if ($dec =~ /\./) { @arr = split(/\./,$dec); if (scalar @arr == 2) { $arr[0] = " ".$arr[0] while (length($arr[0]) < $il); $dec = $arr[0]; if ($dl > 0) { $dec .= "."; $arr[1] = substr($arr[1],0,$dl) if (length($arr[1]) > $dl); $dec .= $arr[1]; } } } else { $dec = " $dec" while (length($dec) < $il); if ($dl) { $dec .= "."; while ($dl--) { $dec .= "0"; } } } return $dec; } sub get_heading_stg($) { my ($hdg) = @_; #return get_decimal_stg($hdg,3,1); return get_decimal_stg($hdg,3,0).'D'; } sub get_sg_dist_stg($) { my ($sg_dist) = @_; my $sg_dlen = 5; my $sg_km = $sg_dist / 1000; my $sg_im = int($sg_dist); my $sg_ikm = int($sg_km + 0.5); # if (abs($sg_pdist) < $CP_EPSILON) my $sg_dist_stg = ""; if (abs($sg_km) > $SG_EPSILON) { # = 0.0000001; # EQUALS SG_EPSILON 20101121 if ($sg_ikm && ($sg_km >= 1)) { $sg_km = int(($sg_km * 10) + 0.05) / 10; $sg_dist_stg .= get_decimal_stg($sg_km,$sg_dlen - 2,1)." km"; } else { #$sg_dist_stg .= "$sg_im m, <1km"; $sg_dist_stg .= get_decimal_stg($sg_im,$sg_dlen,0)." m."; } } else { #$sg_dist_stg .= "0 m"; $sg_dist_stg .= get_decimal_stg('0',$sg_dlen,0)." m."; } return $sg_dist_stg; } sub get_dist_stg($$) { my ($dlat,$dlon) = @_; my ($sg_az1,$sg_az2,$sg_dist,$res); $res = fg_geo_inverse_wgs_84 ($first_lat,$first_lon,$dlat,$dlon,\$g_sg_az1,\$g_sg_az2,\$g_sg_dist); $res = fg_geo_inverse_wgs_84 ($last_lat,$last_lon,$dlat,$dlon,\$sg_az1,\$sg_az2,\$sg_dist); $g_total_dist += $sg_dist; $g_sg_az1 = int(($g_sg_az1 * 10) + 0.05) / 10; $g_sg_az2 = $g_sg_az1 + 180; $g_sg_az2 -= 360 if ($g_sg_az2 >= 360); $sg_az1 = int(($sg_az1 * 10) + 0.05) / 10; $g_curr_heading = $sg_az1; # only keep to first decimal place return "hm: ".get_heading_stg($g_sg_az2)." at ".get_sg_dist_stg($g_sg_dist); } sub get_last_dist_stg($$) { my ($dlat,$dlon) = @_; my ($sg_az1,$sg_az2,$sg_dist); my $res = fg_geo_inverse_wgs_84 ($first_lat,$first_lon,$dlat,$dlon,\$g_sg_az1,\$g_sg_az2,\$g_sg_dist); $res = fg_geo_inverse_wgs_84 ($last_lat,$last_lon,$dlat,$dlon,\$sg_az1,\$sg_az2,\$sg_dist); $g_total_dist += $sg_dist; $g_sg_az1 = int(($g_sg_az1 * 10) + 0.05) / 10; $g_sg_az2 = $g_sg_az1 + 180; $g_sg_az2 -= 360 if ($g_sg_az2 >= 360); # $g_sg_az2 = int(($g_sg_az2 * 10) + 0.05) / 10; my $sg_km = $sg_dist / 1000; my $sg_im = int($sg_dist); my $sg_ikm = int($sg_km + 0.5); # if (abs($sg_pdist) < $CP_EPSILON) my $dist_hdg = " "; #my $dist_hdg = " (SGD: "; $sg_az1 = int(($sg_az1 * 10) + 0.05) / 10; $g_curr_heading = $sg_az1; # only keep to first decimal place if (abs($sg_km) > $SG_EPSILON) { # = 0.0000001; # EQUALS SG_EPSILON 20101121 if ($sg_ikm && ($sg_km >= 1)) { $sg_km = int(($sg_km * 10) + 0.05) / 10; $dist_hdg .= "$sg_km km"; } else { $dist_hdg .= "$sg_im m, <1km"; } } else { $dist_hdg .= "0 m"; } $dist_hdg .= " on $sg_az1"; # $dist_hdg .= ")"; return $dist_hdg; } sub process_in_file($) { my ($inf) = @_; if (! open INF, "<$inf") { pgm_exit(1,"ERROR: Unable to open file [$inf]\n"); } my @lines = <INF>; close INF; my $lncnt = scalar @lines; prt("Processing $lncnt lines, from [$inf]...\n"); my ($line,$inc,$lnn,$clat,$clon); my ($len,$last_sp,$flag,$ccnt,$last_sec,$first_sec,$ctime,$secs,$diff,$dmsg,$hmsg,$ok,$calt); my ($cradm,$last_radm,$spdm,$flying); $lnn = 0; $ok = 0; $last_radm = ''; $flying = 0; if ($show_dist_calc) { prt("Line# Time Latitude Longitude Alt Speed Hdg Calculated heading, distance...\n"); } else { prt("Line# Time Latitude Longitude Alt Speed Bearing...\n"); } foreach $line (@lines) { chomp $line; $lnn++; if ($line =~ /^\$GPRMC,(.+)\*(.+)$/) { $inc = $1; if ( process_GPRMC_msg($line) ) { #prt("$lnn: $inc\n"); $clat = sprintf("%3.8f",$gps_lat_rmc); $clon = sprintf("%4.8f",$gps_long_rmc); $ctime = $gps_time_rmc; $secs = get_time_in_seconds($gps_time_rmc); $flag = 0; if ($gps_count) { if (abs($last_lat - $gps_lat_rmc) < $SG_EPSILON) { $len = length($clat); $clat = ' ' x $len; $flag |= 1; } if (abs($last_lon - $gps_long_rmc) < $SG_EPSILON) { $len = length($clon); $clon = ' ' x $len; $flag |= 2; } if ($last_sec == $secs) { $len = length($ctime); $ctime = ' ' x $len; } else { $diff = abs($secs - $last_sec); $tot_secs += $diff if ($diff < 10); } } else { $first_lat = $gps_lat_rmc; $first_lon = $gps_long_rmc; $first_sec = $secs; $last_lat = $gps_lat_rmc; $last_lon = $gps_long_rmc; } $gps_count++; $ccnt = sprintf("%6d",$gps_count); $dmsg = get_dist_stg($gps_lat_rmc,$gps_long_rmc); #$hmsg = get_heading_stg($g_curr_heading); $hmsg = get_heading_stg($gps_bearing); #prt("$ccnt: $ctime $clat $clon $gps_speed $hmsg $dmsg (line $lnn)\n") if ($flag != 3); $ok = 1 if ($flag != 3); $last_lat = $gps_lat_rmc; $last_lon = $gps_long_rmc; $last_sp = $gps_speed; $last_sec = $secs; $flying = 1 if ($gps_speed >= $min_flying_speed); $spdm = int($gps_speed + 0.5); $spdm = " $spdm" while (length($spdm) < 3); $spdm .= "kts"; } } elsif ($line =~ /^\$GPGGA,(.+)$/) { if ( process_GPGGA_msg($line) ) { $ok |= 2; $gga_count++; bark_if_RMC_ne_GGA() if ($ok & 1); if ($g_alt_gga < 0) { if ($g_alt_gga <= -9999) { $calt = "n/a"; } else { $calt = int($g_alt_gga - 0.5); } } else { $calt = int($g_alt_gga + 0.5); } $calt = " $calt" while (length($calt) < 5); $calt .= "ft"; } } elsif ($line =~ /^\$PATLA,(.+)$/) { if ( process_PATLA_msg($line) ) { $cradm = "$g_nav1_freq,$g_nav1_rad,$g_nav2_freq,$g_nav2_rad,$g_adf_freq"; if ($cradm ne $last_radm) { $last_radm = $cradm; } else { $cradm = ''; } $ok |= 4; } } if ($ok == 7) { #prt("$ccnt: $ctime $clat $clon $calt $gps_speed $hmsg $dmsg $cradm (line $lnn)\n"); if ($clast_speed eq $spdm) { $len = length($spdm); $spdm = ' ' x $len; } else { $clast_speed = $spdm; } if ($clast_alt eq $calt) { $len = length($calt); $calt = ' ' x $len; } else { $clast_alt = $calt; } if ($clast_bearing eq $hmsg) { $len = length($hmsg); $hmsg = ' ' x $len; } else { $clast_bearing = $hmsg; } if ($dbg_03) { if ($show_dist_calc) { prt("$ccnt: $ctime $clat $clon $calt $spdm $hmsg $dmsg $cradm (line $lnn)\n"); } else { prt("$ccnt: $ctime $clat $clon $calt $spdm $hmsg\n"); } } $ok = 0; } } $ccnt = sprintf("%6d",$gps_count); $ctime = get_hhmmss($tot_secs); if ($use_pos_latlon) { $gps_min_lat -= 90; $gps_min_lon -= 180; $gps_max_lat -= 90; $gps_max_lon -= 180; } # massage the lengths for display if ($massage_latlon) { $gps_min_lat = sprintf("%3.8f",$gps_min_lat); $gps_min_lon = sprintf("%4.8f",$gps_min_lon); $gps_max_lat = sprintf("%3.8f",$gps_max_lat); $gps_max_lon = sprintf("%4.8f",$gps_max_lon); } prt("$ccnt: $ctime lat $gps_min_lat to $gps_max_lat, lon $gps_min_lon to $gps_max_lon (line $lnn)\n"); prt("Box $gps_min_lat, $gps_min_lon - Width ".($gps_max_lon - $gps_min_lon)."\n"); prt(" $gps_max_lat, $gps_max_lon - Height ".($gps_max_lat - $gps_min_lat)."\n"); } sub process_message_arrays($$) { my ($rgmc,$rggp) = @_; my $cntgmc = scalar @{$rgmc}; my $cntggp = scalar @{$rggp}; prt("Got $cntgmc GPGMC, and $cntggp GPGGP messages\n"); if ($cntgmc == $cntggp) { my ($i,$spd_kt,$okspd,$bgni,$endi,$secs,$bgns,$ends); # 0=secs 1=lat 2=lon 3=speed 4=bearing # push(@GPRMC, [ $secs, $gps_lat_rmc, $gps_long_rmc, $gps_speed, $gps_bearing ]); # 0=secs 1=lat 2=lon 3=alt 4=geod alt # push(@GPGGA, [ $secs, $g_lat_gga, $g_lon_gga. $g_alt_gga, $g_gheight ]); $bgns = 0; $ends = 0; for ($i = 0; $i < $cntgmc; $i++) { $spd_kt = ${$rgmc}[$i][3]; $secs = ${$rgmc}[$i][0]; if ($spd_kt >= $min_flying_speed) { $bgns = $secs; last; } } prt("Bgn: Discarded $i - speed below $min_flying_speed...\n"); $okspd = 0; $bgni = $i; for (; $i < $cntgmc; $i++) { $spd_kt = ${$rgmc}[$i][3]; $secs = ${$rgmc}[$i][0]; last if ($spd_kt < $min_flying_speed); $okspd++; $ends = $secs; } $endi = $i; prt("End: Discarded ".($cntgmc - $i)." - speed below.\n"); if ($okspd) { my ($lat,$lon,$hdg,$clat,$clon,$dtm,$len,$chdg,$cspd); my $llat = 0; my $llon = 0; my $ltm = ''; my $lhdg = 0; my $lspd = 0; my $lsec = 0; prt("Got $okspd ok records... From $bgns to $ends secs, or ".get_hhmmss($ends - $bgns)." of flight\n"); for ($i = $bgni; $i < $endi; $i++) { $lat = ${$rgmc}[$i][1]; $lon = ${$rgmc}[$i][2]; $spd_kt = ${$rgmc}[$i][3]; $hdg = ${$rgmc}[$i][4]; $secs = ${$rgmc}[$i][0]; $clat = sprintf("%3.8f",$lat); $clon = sprintf("%4.8f",$lon); $dtm = get_hhmmss($secs - $bgns); $spd_kt = int($spd_kt + 0.5); $hdg = int($hdg + 0.5); $chdg = sprintf("%03d", $hdg); $cspd = sprintf("%03d",$spd_kt); if ($lat == $llat) { $len = length($clat); $clat = ' ' x $len; } if ($lon == $llon) { $len = length($clon); $clon = ' ' x $len; } if ($lsec == $secs) { $len = length($dtm); $dtm = ' ' x $len; } if ($hdg == $lhdg) { $len = length($chdg); $chdg = ' ' x $len; } if ($spd_kt == $lspd) { $len = length($cspd); $cspd = ' ' x $len; } prt("$dtm: $clat,$clon $cspd $chdg\n"); $llat = $lat; $llon = $lon; $lsec = $secs; $lspd = $spd_kt; $lhdg = $hdg; } } } else { prtw("WARNING: Message counts NOT equal!\n"); } } ######################################### ### MAIN ### parse_args(@ARGV); ### prt( "$pgmname: in [$cwd]: Hello, World...\n" ); process_in_file($in_file); process_message_arrays(\@GPRMC,\@GPGGA); pgm_exit(0,"Normal exit(0)"); ######################################## sub give_help { prt("$pgmname: version 0.0.1 2010-09-11\n"); prt("Usage: $pgmname [options] in-file\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have following argument!\n") if (!@av); } sub parse_args { my (@av) = @_; my ($arg,$sarg); while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { $in_file = $arg; prt("Set input to [$in_file]\n"); } shift @av; } if ((length($in_file) == 0) && $debug_on) { $in_file = $def_file; } if (length($in_file) == 0) { pgm_exit(1,"ERROR: No input files found in command!\n"); } if (! -f $in_file) { pgm_exit(1,"ERROR: Unable to find in file [$in_file]! Check name, location...\n"); } } # eof - template.pl