1#!/usr/local/bin/perl 2 3 4# Written by Curt Mills, WE7U 5# Released to the public domain. 6# 7 8 9# Script to create Xastir "Overlay" files from "CSV" files of the 10# proper format (comma-delimited files). 11# 12# 1) Creates files in Xastir "log" format if you enter a callsign 13# below. These files can then be put in your ~/.xastir/logs/ 14# directory and brought in via the File->Open Log File menu option. 15# If you start with the CSV files in the ~/.xastir/logs/ directory 16# and process them there with this script, the output files will be 17# placed into the proper place for Xastir to find them. 18# 19# 2) If no callsign is entered, this script will create files in 20# Xastir's "~/.xastir/config/object.log" format. You can then 21# replace or append the file to the object.log file, restart Xastir 22# or "Reload Object/Item History". 23# 24# NOTE: These APRS Items will become part of your locally 25# owned/transmitted objects, so if you don't want them transmitted, 26# turn of Object/Item transmit before bringing them in. 27# 28# Input: Directory name. If no directory name passed in, it will 29# operate on every CSV file in the current directory. 30# 31# Input format: 32# Name N/S lat E/W long // comment fields............. 33# SUPPLY,N,34.0000,W,78.0000,ICON,text1,text2,text3,text4,... 34# 35# 36# The name will have spaces removed if it is longer than nine 37# characters. If it is still too long, vowels will be removed, then 38# it will be truncated to nine characters if still needed. The full 39# name will be transmitted as a comment. All other text fields will 40# also be transmitted as comments, so that they will all appear in 41# the Station Info dialog. 42# 43# Icons will be a default small red circle unless '/' or '\' is the 44# leading character in that field and the next specifies the APRS 45# symbol. In that case the two-letter combination will get used as 46# the symbol for the Item. 47 48 49 50# Change this to match whatever callsign you're running Xastir as, 51# so that the APRS Items appear to have been generated locally. You 52# can then suck this file in as a "log" file from within Xastir. If 53# this field is empty, then instead write the packets out without a 54# header, as in Xastir's "object.log" format. 55$callsign = ""; 56 57if ($callsign ne "") { 58 $callsign = uc($callsign) . '>APRS:'; 59} 60 61 62 63# Main program. Process every ".csv" file found in the directory. 64# 65$dirname = shift; 66if ($dirname == "") { 67 $dirname = "."; 68} 69 70opendir(DIR, $dirname) or die "Can't opendir $dirname: %!"; 71 72while (defined($file = readdir(DIR))) { 73 chomp $file; 74 75 if ( $file =~ /\.csv$/ ) { 76 77 # Do something with "$dirname/$file" 78 &process_file($dirname, $file); 79 } 80 else { 81# printf("$dirname/$file\n"); 82 } 83} 84 85 86 87# Process one file. Creates an output file that matches the 88# basename but changes the "csv" to "overlay". 89# 90sub process_file() { 91 92 $output_file = $_[1]; 93 $output_file =~ s/\.csv$/.overlay/; 94 95 printf("$dirname/$file -> $output_file\n"); 96 97 open(SOURCE, "< $_[1]") 98 or die "Couldn't open $path for reading: $!\n"; 99 100 open(OUTPUT, "> $output_file") 101 or die "Couldn't open $output_file for writing: $!\n"; 102 103 while (<SOURCE>) { 104 &process_line($_); 105 } 106 107 close(SOURCE); 108 close(OUTPUT); 109} 110 111 112 113# Process one line. Write the formatted data to the OUTPUT file. 114# 115sub process_line() { 116 #printf("$_[0]"); 117 118 # Parse the CSV line into an array 119 @list = parse_csv($_[0]); 120 121 if (!($list[0] =~ m/Location/i)) { 122 #print OUTPUT @list; 123 124 # As a temporary measure, create items out of each of the lines, 125 # with a status line for each extra data object so that they 126 # appear in the Station Info dialog. 127 &create_items(@list); 128 } 129} 130 131 132 133# Create an APRS Item out of each array. Create a status line for 134# each extra column associated with a line so that the info shows up 135# in the Station Info dialog. 136# 137# Examples. Name is 3-9 characters: 138# )AID #2!4903.50N/07201.75WA 139# )G/WB4APR!53 . N\002 . Wd 140# 141sub create_items { 142 143 $name = $_[0]; 144 if ($name eq "") { 145 printf("Error, name column is empty\n"); 146 } 147 148 # If too long, try removing spaces first 149 if (length($name) > 9) { 150 $name =~ s/\s//ig; 151 } 152 153 # If still too long, remove vowels 154 if (length($name) > 9) { 155 $name =~ s/a//ig; 156 $name =~ s/e//ig; 157 $name =~ s/i//ig; 158 $name =~ s/o//ig; 159 $name =~ s/u//ig; 160 } 161 162 # Extend to three characters if short 163 if (length($name) < 3) { 164 $name = $name . " "; 165 } 166 167 $name = substr($name,0,9); 168 $name[9] = "\0"; # Terminate name at 9 characters, minimum 3 169 170 $n_s = uc( substr($_[1],0,1) ); 171 $latitude = $_[2]; 172 $e_w = uc( substr($_[3],0,1) ); 173 $longitude = $_[4]; 174 if ($_[5] =~ /ICON/i) { 175 $icon1 = "/"; 176 $icon2 = "/"; 177 } 178 else { 179 $icon1 = substr($_[5],0,1); 180 $icon2 = substr($_[5],1,1); 181 } 182 183 # Convert lat/long to APRS format (or Base-91 Compressed format) 184 $lat_deg = $latitude; 185 $lat_deg =~ s/\.\d+$//; 186 $lat_deg = sprintf("%02d", $lat_deg); 187 $lat_min = $latitude; 188 $lat_min =~ s/^\d+\./0./; 189 $lat_min = $lat_min * 60.0; 190 $lon_deg = $longitude; 191 $lon_deg =~ s/\.\d+$//; 192 $lon_deg = sprintf("%03d", $lon_deg); 193 $lon_min = $longitude; 194 $lon_min =~ s/^\d+\./0./; 195 $lon_min = $lon_min * 60; 196 197 # Create an APRS "Item" packet 198 $line = sprintf("%s)%s!%s%05.2f%s%s%s%05.2f%s%s", 199 $callsign, 200 $name, 201 $lat_deg, 202 $lat_min, 203 $n_s, 204 $icon1, 205 $lon_deg, 206 $lon_min, 207 $e_w, 208 $icon2); 209 210 # Go process the rest of the columns, if any. Create APRS Item 211 # packets with comments from them. 212 for ($i = 6; $i < 106; $i++) { 213 chomp $_[$i]; 214 if ($_[$i] ne "") { 215 #printf("$_[$i]"); 216 printf(OUTPUT "%s%s\n", 217 $line, 218 $_[$i]); 219 } 220 } 221 222 # Write it out to the file, with the full name as a comment 223 printf(OUTPUT "%s%s\n", 224 $line, 225 $_[0]); 226} 227 228 229 230# Parse CSV line into an array, removing double-quotes and such if 231# found. 232# 233sub parse_csv { 234 my $text = shift; # Record containing comma-separated values 235 my @new = (); 236 push(@new, $+) while $text =~ m{ 237 # The first part groups the phrase inside the quotes. 238 # See explanation of this pattern in MRE 239 "([^\"\\]*(?:\\.[^\"\\]*)*)",? 240 | ([^,]+),? 241 | , 242 }gx; 243 push(@new, undef) if substr($text, -1, 1) eq ','; 244 return @new; # List of values that were comma-separated 245} 246 247 248