Ero sivun ”Toistinaseman mainostaminen APRS-asemille” versioiden välillä

Radioamatööriwikistä
Siirry navigaatioon Siirry hakuun
>OH6KTT
Ei muokkausyhteenvetoa
>OH6KTT
p (väärä scripti äsken)
 
(14 välissä olevaa versiota samalta käyttäjältä ei näytetä)
Rivi 1: Rivi 1:
[[Category: R.NET]]
[[Category: R.NET]]


Tämä sivu on tynkä.
Scripti joka tutkii ajastettuna [[OH6RUC]] toistimen linuxissa [[aprx]] ohjelman tekemää /tmp/aprx-rf.log tiedostoa. Jos logissa näkyy [[APRS]]-asema joka on lähempänä kuin 30km [[OH6RUC]] toistinta ja kyseistä [[APRS]]-asemaa ei ole kuultu edellisen 24h kuluessa, ja toistin on vapaana, scripti aukaisee toistimen ja mainostaa iseaään [[APRS]]-asemalle puheella. Puhe generoidaan festival puhesyntetisaattorilla.


Scripti joka OH6RUC:llä tutkii aprs-rf.logia. Jos asema radiolla kuultu asema on lähempänä kuin 30km niin sille mainostetaan ripiitteriä puheella. Puhe tehdään festival puhesyntetisaattorilla.
''"Tervetuloa OH6RUC toistinaseman kuuluvuusalueelle OH6KTT. Minä olen Kaustisen OH6RUC toistinasema taajuudella 434.900 MHz. Ripiitterierotukseni on -2 MHz. Toistan. Ripiitterierotus on -2 MHz. Automaattinen tiedote ripiitteriä lähestyville APRS-asemille päättyy."''


Sama scripti pitää logia suoraan RF:llä kuulluista APRS-asemista.


Ideoita jatkokehitystä varten:
* 2m tropokelit on mahdollista havaita suoraan RF:llä kuulluista asemista
* Pitkän historian avulla db:stä voisi saada selville digiripiitterin kuuntelukyky eri ilmansuuntiin


<pre>
<pre>
#!/usr/bin/php -q
#!/usr/bin/php -q
<?php
<?php
ini_set('memory_limit','50M');
/*
/*
     aprs-repeater-advertiser.php v1.0 - repeater advertiser to APRS users
     aprs-repeater-advertiser.php v1.11 - repeater advertiser to APRS users
     Copyright (C) 2010  Kari Karvonen <oh6ktt@toimii.net>
     Copyright (C) 2010  Kari Karvonen <oh6ktt@toimii.net>


Rivi 28: Rivi 34:


*/
*/
$debug = 0; /* 0 = no debug, 1 = little debug, 2 = more debug, 3 = annoying */
$aprxrflogfile = "/tmp/aprx-rf.log";
$aprxrflogfile = "/tmp/aprx-rf.log";
$stationdbfile = "/tmp/oh6ruc-aprs-db.txt";
$stationdbfile = "/tmp/oh6ruc-aprs-db.txt";
Rivi 35: Rivi 42:
$floodprotect = 60*60*24; /* after this time old station will be notified again. Seconds. */
$floodprotect = 60*60*24; /* after this time old station will be notified again. Seconds. */
$maxdistance = 30; /* km */
$maxdistance = 30; /* km */
$denytxfile = "/tmp/ptt-on"; /* if this file exist, no announcement will be send */
$maxloglines    = 1000; /* max loglines to analyze (tail) */
$debug = false;
$denytxfile = "/tmp/ptt-on"; /* if this file exist, no advertises will be send */
$prefixwave = "/opt/thelinkbox/wav/aprs-repeater-advertiser-1.wav"; /* wave before callsigns */
$prefixwave = "/opt/thelinkbox/wav/aprs-repeater-advertiser-1.wav"; /* wave before callsigns */
$suffixwave = "/opt/thelinkbox/wav/aprs-repeater-advertiser-2.wav"; /* wave after callsigns */
$suffixwave = "/opt/thelinkbox/wav/aprs-repeater-advertiser-2.wav"; /* wave after callsigns */
$tempwavetxt = "/tmp/aprs-repeater-advertiser.txt";
$tempwavetxt = "/tmp/aprs-repeater-advertiser.txt";
$tempwave = "/tmp/aprs-repeater-advertiser.wav";
$tempwave = "/tmp/aprs-repeater-advertiser.wav";
$repeatedmatch  = ",OH"; /* if this is exists on path (eg APRS,OH6RUC*,OH8RDU*,WIDE) assume packet digirepeated and discard it */
$rangelimit = 2000; /* if range more than this then range is invalid. km. */


/* code begins */
/* code begins */
Rivi 49: Rivi 58:
$aprxrflog = @file($aprxrflogfile);
$aprxrflog = @file($aprxrflogfile);
if ($aprxrflog == false) die("Cannot open $aprxrflogfile\n");
if ($aprxrflog == false) die("Cannot open $aprxrflogfile\n");
function min_to_dec($deg, $min, $decsec) {
        return($deg/1.0 + $min/60.0 + $decsec/10000.0);
}
function utctimenow() {
        $utcoffset      = intval(date("O")/100)*60;   
        return (time()-$utcoffset);
}
function latlongbearing($lat1, $lon1, $lat2, $lon2) {
        $lat1 = deg2rad($lat1);
        $lat2 = deg2rad($lat2);
        $lon1 = deg2rad ($lon1);
        $lon2 = deg2rad ($lon2);
        $dLon = $lon2-$lon1;
        $y = sin($dLon) * cos($lat2);
        $x = cos($lat1) * sin($lat2) - sin($lat1)*cos($lat2)*cos($dLon);
        $bearrad = atan2($y, $x);
        $beardeg = (rad2deg($bearrad)+360)%360;
        return ($beardeg);
}


function decimal_distance($lat1 = "", $lon1 = "", $lat2 = "", $lon2 = "") {
function decimal_distance($lat1 = "", $lon1 = "", $lat2 = "", $lon2 = "") {
        //$radius is determined using the following formula
         $radius = 6371;
        //(360 degrees)*(60 minutes per degree)*(1.852) km per minute
        //give a circumference of 40003.2 km
        //radius is circumference/(2*pi) which gives us 6637km or 3956miles
         $radius = 3956;
         $lat1 = deg2rad ($lat1);
         $lat1 = deg2rad ($lat1);
         $lat2 = deg2rad ($lat2);
         $lat2 = deg2rad ($lat2);
         $lon1 = deg2rad ($lon1);
         $lon1 = deg2rad ($lon1);
         $lon2 = deg2rad ($lon2);
         $lon2 = deg2rad ($lon2);
        //Haversine Formula (from R.W. Sinnott, "Virtues of the Haversine",
        //Sky and Telescope, vol. 68, no. 2, 1984, p. 159):
         $dlon = $lon2-$lon1;
         $dlon = $lon2-$lon1;
         $dlat = $lat2-$lat1;
         $dlat = $lat2-$lat1;
Rivi 70: Rivi 95:
         $d = $radius * $c;
         $d = $radius * $c;
         return round($d,2);
         return round($d,2);
}
for ($tmp = 0; $tmp < count($aprxrflog); $tmp++) {
        $line = $aprxrflog[$tmp];
        if (preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{3}) '.$repeater_call.'    R (.+)>APOTC1,'.$repeater_call.'(.+):\!(.+)/', $line, $matches)) {
                $callsign = strtolower(trim($matches[8]));
                if (preg_match('/([0-9.]{7})N\/([0-9.]{8})E/',$matches[10],$plaincoords)) {
                        /* koordinaatteja ei ole pakattu */
                        $lat = floatval($plaincoords[1])/100;
                        $long = floatval($plaincoords[2])/100;
                } else {
                        /* koordinaatit on pakattu */           
                        $y1 = ord(substr($matches[10],1,1));
                        $y2 = ord(substr($matches[10],2,1));
                        $y3 = ord(substr($matches[10],3,1));
                        $y4 = ord(substr($matches[10],4,1));
                        $x1 = ord(substr($matches[10],5,1));
                        $x2 = ord(substr($matches[10],6,1));
                        $x3 = ord(substr($matches[10],7,1));
                        $x4 = ord(substr($matches[10],8,1));
                        $lat = 90 - (($y1-33) * 91*91*91 + ($y2-33) * 91*91 + ($y3-33) * 91 + $y4-33) / 380926;
                        $long = -180 + (($x1-33) * 91*91*91 + ($x2-33) * 91*91 + ($x3-33) * 91 + $x4-33) / 190463;
                }
                $distance = decimal_distance($repeater_lat, $repeater_lon, $lat, $long);
                $lastheard  =  mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
                $parserdb[$callsign] = array("lastheard" => $lastheard, "distance" => $distance);
        }
}
}


Rivi 142: Rivi 140:
$chartospeech["0"] = "nolla";
$chartospeech["0"] = "nolla";
$msg = "";
$msg = "";
for ($tmp = 0; $tmp<strlen($callsign); $tmp++) {
for ($tmp = 0; $tmp < strlen($callsign); $tmp++) {
$character = substr($callsign,$tmp,1);
$character = substr($callsign, $tmp, 1);
                 /* don't say -9 */
                 /* don't say -9 */
if ($character == "-") {
if ($character == "-") {
        return $msg;
        return $msg;
                 }
                 }
$aanne = $chartospeech[$character];
$vocal = $chartospeech[$character];
$msg.= $aanne;
$msg.= $vocal;
}
}
return ($msg);
return ($msg);
}
}
$aprxrfloglen = count($aprxrflog);
if ($aprxrfloglen > $maxloglines) $loglinestart = $aprxrfloglen-$maxloglines; else $loglinestart=0;
if ($debug>1) echo "aprxrfloglen $aprxrfloglen maxloglines $maxloglines loglinestart $loglinestart\n";
for ($tmp = $loglinestart; $tmp < $aprxrfloglen; $tmp++) {
        $line = $aprxrflog[$tmp];
        if (preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{3}) '.$repeater_call.'    R (.+)>(.+):(.{1})(.+)/', $line, $matches)) {
                $callsign = strtolower(trim($matches[8]));
                if (strpos($callsign,">")) {
                        /* Callsign parse failed (ugly trace packets) */
if ($debug>2) echo "Ugly callsign $callsign. Discard.\n";
                        continue;
                }
                if (strstr($matches[9],$repeatedmatch)) {
                /* digirepeated patcket, discard */
if ($debug>2) echo "Digirepeated packet. Discard.\n";
                        continue;
}
if (strpos("\!=/@", $matches[10])) {
                        /* ! Position without timestamp (no APRS  messaging), or Ultimeter 2000 WX Station */
                        /* = Position without timestamp (with APRS messaging) */
                        /* / Position with timestamp (no APRS messaging) */
                        /* @ Position with timestamp (with APRS messaging) */
                } else {
                        /* is not position format */
                        if ($debug>1) echo "Unknown position identification ". $matches[10].". Discard.\n";
                        continue;
                }
                if (preg_match('/([0-9]{2})([0-9]{2}).([0-9]{1,})N(.{1})([0-9]{3})([0-9]{2}).([0-9]{1,})E/', $matches[11], $plaincoords)) {
                        /* coordinates are plain format */
                        $coordtype = "plain";
                        $lat = min_to_dec($plaincoords[1], $plaincoords[2], $plaincoords[3]);
                        $long = min_to_dec(intval($plaincoords[5]), $plaincoords[6], $plaincoords[7]);
                } else {
                        /* coordinates are packed */           
                        $coordtype = "packed";
                        $y1 = ord(substr($matches[11],1,1));
                        $y2 = ord(substr($matches[11],2,1));
                        $y3 = ord(substr($matches[11],3,1));
                        $y4 = ord(substr($matches[11],4,1));
                        $x1 = ord(substr($matches[11],5,1));
                        $x2 = ord(substr($matches[11],6,1));
                        $x3 = ord(substr($matches[11],7,1));
                        $x4 = ord(substr($matches[11],8,1));
                        $lat = 90 - (($y1-33) * 91*91*91 + ($y2-33) * 91*91 + ($y3-33) * 91 + $y4-33) / 380926;
                        $long = -180 + (($x1-33) * 91*91*91 + ($x2-33) * 91*91 + ($x3-33) * 91 + $x4-33) / 190463;
                }
                $distance = decimal_distance($repeater_lat, $repeater_lon, $lat, $long);
                if ($distance > $rangelimit) {
                if ($debug > 1) "Calculated distance $distance km. Invalid range limit $rangelimit. Discard\n";
                        continue;
                }
$bearing = latlongbearing($repeater_lat, $repeater_lon, $lat, $long);
                $lastheard = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
                $parserdb[$callsign] = array("lastheard" => $lastheard, "distance" => $distance, "bearing" => $bearing, "lat" => $lat, "long" => $long, "coordtype" => $coordtype);
        }
}


ksort($parserdb);
ksort($parserdb);
foreach ($parserdb as $callsign => $tiedot) {
foreach ($parserdb as $callsign => $attcheddata) {
$distance = $tiedot["distance"];
$distance = $attcheddata["distance"];
$lastheard = $tiedot["lastheard"];
$lastheard = $attcheddata["lastheard"];
if ($debug) echo "Call $callsign. ";
$lat = $attcheddata["lat"];
$long = $attcheddata["long"];
$coordtype = $attcheddata["coordtype"];
$bearing = $attcheddata["bearing"];
$lastheardtxt = date("r", $lastheard);
$advertisedtime = $stationdb[$callsign]["advertisedtime"];
$advertisedtimetxt = date("r",$advertisedtime);
if ($debug>0) echo "Call $callsign. Lat $lat. Long $long. Coordtype $coordtype. Distance $distance. Bearing $bearing. Lastheard $lastheardtxt. Advertised $advertisedtimetxt. ";
if (array_key_exists($callsign, $stationdb)) {
if (array_key_exists($callsign, $stationdb)) {
if ($debug) echo "Found from stationdb. ";
if ($debug>0) echo "Found from stationdb. ";
if ($stationdb[$callsign]["lastheard"]<(time()-$floodprotect)) {
if ($advertisedtime < (utctimenow()-$floodprotect) && $lastheard>$stationdb[$callsign]["lastheard"]) {
        if ($debug) echo "Floodprotect active. ";
        if ($debug>0) if ($advertisedtime < (utctimenow()-$floodprotect)) echo "Floodprotect expired. "; else echo "Floodprotect active. ";
        if ($distance < $maxdistance) {
        if ($distance < $maxdistance) {
/* Found in stationdb, too old ja inside circle */
/* Exists in stationdb. Too old and inside circle */
if ($debug) echo "Inside circle ($distance/$maxdistance). Update stationdb. Add to victims.";
if ($debug>0) echo "Inside $maxdistance km cicle. Add to victims.";
$victims[] = $callsign;
$victims[] = $callsign;
$stationdb[$callsign]["lastheard"] = $lastheard;
$advertisedtime = utctimenow();
$stationdb[$callsign]["distance"] = $distance;
                               
} else {
} else {
/* liian kaukana */
/* Station too far */
if ($debug) echo "Outside circle ($distance/$maxdistance). Update stationdb.";
if ($debug>0) echo "Outside $maxdistance km circle. Skip.";
$stationdb[$callsign]["lastheard"] = $lastheard;
$stationdb[$callsign]["distance"] = $distance;
}
}
} else {
} else {
        if ($debug) echo "Floodprotect active. Update stationdb. ";
        if ($debug>0) if ($advertisedtime < (utctimenow()-$floodprotect)) echo "Floodprotect expired. "; else echo "Floodprotect active. ";
                        $stationdb[$callsign]["lastheard"] = $lastheard;
        if ($debug>0) if ($lastheard>$stationdb[$callsign]["lastheard"]) echo "New packet. "; else echo "Old packed. ";
                        $stationdb[$callsign]["distance"] = $distance;
        if ($debug>0) echo "Skip.";
}
}
} else {
} else {
if ($debug) echo "Not found from stationdb. ";
if ($debug>0) echo "Not found from stationdb. ";
if ($distance < $maxdistance) {
if ($distance < $maxdistance) {
if ($debug) echo "Inside circle ($distance/$maxdistance). Update stationdb. Add to victims.";
if ($debug>0) echo "Inside ${maxdistance}km circle. Add to victims.";
$victims[] = $callsign;
$victims[] = $callsign;
$stationdb[$callsign]["lastheard"] = $lastheard;
$advertisedtime = utctimenow();
$stationdb[$callsign]["distance"] = $distance;
                               
} else {
} else {
if ($debug) echo "Outside circle ($distance/$maxdistance). Ignore.";
if ($debug>0) echo "Outside ${maxdistance}km circle. Skip.";
}
}
}
}
if ($debug) echo "\n";
$stationdb[$callsign]["lastheard"] = $lastheard;
$stationdb[$callsign]["distance"] = $distance;
$stationdb[$callsign]["bearing"] = $bearing;
$stationdb[$callsign]["lat"] = $lat;
$stationdb[$callsign]["long"] = $long;
$stationdb[$callsign]["coordtype"] = $coordtype;
        $stationdb[$callsign]["advertisedtime"] = $advertisedtime;
       
if ($debug>0) echo "\n";
}
}


if ($debug>0) echo "Updating $stationdbfile\n";
file_put_contents($stationdbfile, serialize($stationdb));
file_put_contents($stationdbfile, serialize($stationdb));


Rivi 206: Rivi 278:
                         $msg .= callsign2finnish($victim).", ";
                         $msg .= callsign2finnish($victim).", ";
                 }
                 }
                 $msg=substr($msg,0,-2);
                 $msg = substr($msg,0,-2);
                 file_put_contents($tempwavetxt, utf8_decode($msg));
                 if ($debug>0) echo "$msg\n";
                 system("/usr/bin/text2wave -F 8000 < ".$tempwavetxt." -o ".$tempwave);
                if ($debug<1) file_put_contents($tempwavetxt, utf8_decode($msg));
                 system("/usr/sbin/tlbcmd \"port OH6RUC-Kaustinen; say -c ".$prefixwave."; say -c ".$tempwave."; say -c ".$suffixwave."\"");                 
                 if ($debug<1) system("/usr/bin/text2wave -F 8000 < ".$tempwavetxt." -o ".$tempwave);
                 if ($debug<1) system("/usr/sbin/tlbcmd \"port OH6RUC-Kaustinen; say -c ".$prefixwave."; say -c ".$tempwave."; say -c ".$suffixwave."\"");                 
         } else {
         } else {
                 if ($debug) echo "Cannot advertise. Advertises denied by $denytxfile lock file.\n";
                 if ($debug>0) echo "Cannot advertise. Advertises denied by $denytxfile lock file.\n";
         }
         }
}
}
?>
?>
</pre>
</pre>
Tämä scripti on ajastettu crontabissa
# Katsotaan onko kuuluvuusalueella uusia APRS-asemia ja mainostetaan jos on
4,8,12,16,20,24,28,32,36,40,44,48,52,56 * * * * tlb /opt/thelinkbox/scripts/aprs-repeater-advertiser.php > /dev/null

Nykyinen versio 21. joulukuuta 2010 kello 18.05


Scripti joka tutkii ajastettuna OH6RUC toistimen linuxissa aprx ohjelman tekemää /tmp/aprx-rf.log tiedostoa. Jos logissa näkyy APRS-asema joka on lähempänä kuin 30km OH6RUC toistinta ja kyseistä APRS-asemaa ei ole kuultu edellisen 24h kuluessa, ja toistin on vapaana, scripti aukaisee toistimen ja mainostaa iseaään APRS-asemalle puheella. Puhe generoidaan festival puhesyntetisaattorilla.

"Tervetuloa OH6RUC toistinaseman kuuluvuusalueelle OH6KTT. Minä olen Kaustisen OH6RUC toistinasema taajuudella 434.900 MHz. Ripiitterierotukseni on -2 MHz. Toistan. Ripiitterierotus on -2 MHz. Automaattinen tiedote ripiitteriä lähestyville APRS-asemille päättyy."

Sama scripti pitää logia suoraan RF:llä kuulluista APRS-asemista.

Ideoita jatkokehitystä varten:

  • 2m tropokelit on mahdollista havaita suoraan RF:llä kuulluista asemista
  • Pitkän historian avulla db:stä voisi saada selville digiripiitterin kuuntelukyky eri ilmansuuntiin
#!/usr/bin/php -q
<?php
ini_set('memory_limit','50M');
/*
    aprs-repeater-advertiser.php v1.11 - repeater advertiser to APRS users
    Copyright (C) 2010  Kari Karvonen <oh6ktt@toimii.net>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/
$debug		= 0; /* 0 = no debug, 1 = little debug, 2 = more debug, 3 = annoying */
$aprxrflogfile 	= "/tmp/aprx-rf.log";
$stationdbfile	= "/tmp/oh6ruc-aprs-db.txt";
$repeater_call  = "OH6RUC"; /* need to match aprs-rf.log */
$repeater_lat	= "63.53666";
$repeater_lon	= "23.69180";
$floodprotect	= 60*60*24; /* after this time old station will be notified again. Seconds. */
$maxdistance	= 30; /* km */
$maxloglines    = 1000; /* max loglines to analyze (tail) */
$denytxfile	= "/tmp/ptt-on"; /* if this file exist, no advertises will be send */
$prefixwave	= "/opt/thelinkbox/wav/aprs-repeater-advertiser-1.wav"; /* wave before callsigns */
$suffixwave	= "/opt/thelinkbox/wav/aprs-repeater-advertiser-2.wav"; /* wave after callsigns */
$tempwavetxt 	= "/tmp/aprs-repeater-advertiser.txt";
$tempwave 	= "/tmp/aprs-repeater-advertiser.wav";
$repeatedmatch  = ",OH"; /* if this is exists on path (eg APRS,OH6RUC*,OH8RDU*,WIDE) assume packet digirepeated and discard it */
$rangelimit	= 2000; /* if range more than this then range is invalid. km. */

/* code begins */
$parserdb	= array();
$victims	= array();
$stationdb	= unserialize(@file_get_contents($stationdbfile));
if (empty($stationdb)) $stationdb = array();
$aprxrflog 	= @file($aprxrflogfile);
if ($aprxrflog == false) die("Cannot open $aprxrflogfile\n");

function min_to_dec($deg, $min, $decsec) {
        return($deg/1.0 + $min/60.0 + $decsec/10000.0);
}

function utctimenow() {
        $utcoffset      = intval(date("O")/100)*60;    
        return (time()-$utcoffset);
}

function latlongbearing($lat1, $lon1, $lat2, $lon2) {
        $lat1 = deg2rad($lat1);
        $lat2 = deg2rad($lat2);
        $lon1 = deg2rad ($lon1);
        $lon2 = deg2rad ($lon2);
        $dLon = $lon2-$lon1;
        $y = sin($dLon) * cos($lat2);
        $x = cos($lat1) * sin($lat2) - sin($lat1)*cos($lat2)*cos($dLon);
        $bearrad = atan2($y, $x);
        $beardeg = (rad2deg($bearrad)+360)%360;
        return ($beardeg);
}

function decimal_distance($lat1 = "", $lon1 = "", $lat2 = "", $lon2 = "") {
        $radius = 6371;
        $lat1 = deg2rad ($lat1);
        $lat2 = deg2rad ($lat2);
        $lon1 = deg2rad ($lon1);
        $lon2 = deg2rad ($lon2);
        $dlon = $lon2-$lon1;
        $dlat = $lat2-$lat1;
        $sinlat = sin($dlat/2);
        $sinlon = sin($dlon/2);
        $a = ($sinlat * $sinlat) + cos($lat1) * cos($lat2) * ($sinlon*$sinlon);
        $c = 2 * asin(min(1,sqrt($a)));
        $d = $radius * $c;
        return round($d,2);
}

function callsign2finnish($callsign) {
	$chartospeech = array();
	$chartospeech["-"] = "viiva";
	$chartospeech["a"] = "aa";
	$chartospeech["b"] = "bee";
	$chartospeech["c"] = "see";
	$chartospeech["d"] = "dee";
	$chartospeech["e"] = "ee";
	$chartospeech["f"] = "äf";
	$chartospeech["g"] = "gee";
	$chartospeech["h"] = "hoo";
	$chartospeech["i"] = "hee";
	$chartospeech["j"] = "jii";
	$chartospeech["k"] = "koo";
	$chartospeech["l"] = "äl";
	$chartospeech["m"] = "äm";
	$chartospeech["n"] = "äm";
	$chartospeech["o"] = "oo";
	$chartospeech["p"] = "pee";
	$chartospeech["q"] = "kuu";
	$chartospeech["r"] = "är";
	$chartospeech["s"] = "äs";
	$chartospeech["t"] = "tee";
	$chartospeech["u"] = "uu";
	$chartospeech["v"] = "vee";
	$chartospeech["w"] = "tuplavee";
	$chartospeech["x"] = "äks";
	$chartospeech["y"] = "yy";
	$chartospeech["z"] = "tseta";
	$chartospeech["å"] = "oo";
	$chartospeech["ä"] = "ää";
	$chartospeech["ö"] = "öö";
	$chartospeech["1"] = "yks";
	$chartospeech["2"] = "kaks";
	$chartospeech["3"] = "kol";
	$chartospeech["4"] = "nel";
	$chartospeech["5"] = "viis";
	$chartospeech["6"] = "kuus";
	$chartospeech["7"] = "seiska";
	$chartospeech["8"] = "kasi";
	$chartospeech["9"] = "ysi";
	$chartospeech["0"] = "nolla";
	$msg = "";
	for ($tmp = 0; $tmp < strlen($callsign); $tmp++) {
		$character = substr($callsign, $tmp, 1);
                /* don't say -9 */
		if ($character == "-") {
		        return $msg;
                }
		$vocal = $chartospeech[$character];
		$msg.= $vocal;		
	}
	return ($msg);
}


$aprxrfloglen = count($aprxrflog);
if ($aprxrfloglen > $maxloglines) $loglinestart = $aprxrfloglen-$maxloglines; else $loglinestart=0;
if ($debug>1) echo "aprxrfloglen $aprxrfloglen maxloglines $maxloglines loglinestart $loglinestart\n";

for ($tmp = $loglinestart; $tmp < $aprxrfloglen; $tmp++) {
        $line = $aprxrflog[$tmp];
        if (preg_match('/^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{3}) '.$repeater_call.'    R (.+)>(.+):(.{1})(.+)/', $line, $matches)) {
                $callsign = strtolower(trim($matches[8]));
                if (strpos($callsign,">")) {
                        /* Callsign parse failed (ugly trace packets) */
			if ($debug>2) echo "Ugly callsign $callsign. Discard.\n";
                        continue;
                }
                if (strstr($matches[9],$repeatedmatch)) {
                	/* digirepeated patcket, discard */
			if ($debug>2) echo "Digirepeated packet. Discard.\n";
                        continue;
		}
		if (strpos("\!=/@", $matches[10])) {
                        /* ! Position without timestamp (no APRS  messaging), or Ultimeter 2000 WX Station */
                        /* = Position without timestamp (with APRS messaging) */ 
                        /* / Position with timestamp (no APRS messaging) */
                        /* @ Position with timestamp (with APRS messaging) */
                } else {
                        /* is not position format */
                        if ($debug>1) echo "Unknown position identification ". $matches[10].". Discard.\n";
                        continue;
                }
                if (preg_match('/([0-9]{2})([0-9]{2}).([0-9]{1,})N(.{1})([0-9]{3})([0-9]{2}).([0-9]{1,})E/', $matches[11], $plaincoords)) {
                        /* coordinates are plain format */
                        $coordtype = "plain";
                        $lat = min_to_dec($plaincoords[1], $plaincoords[2], $plaincoords[3]);
                        $long = min_to_dec(intval($plaincoords[5]), $plaincoords[6], $plaincoords[7]);
                } else {
                        /* coordinates are packed */            
                        $coordtype = "packed";
                        $y1 = ord(substr($matches[11],1,1));
                        $y2 = ord(substr($matches[11],2,1));
                        $y3 = ord(substr($matches[11],3,1));
                        $y4 = ord(substr($matches[11],4,1));
                        $x1 = ord(substr($matches[11],5,1));
                        $x2 = ord(substr($matches[11],6,1));
                        $x3 = ord(substr($matches[11],7,1));
                        $x4 = ord(substr($matches[11],8,1));
                        $lat = 90 - (($y1-33) * 91*91*91 + ($y2-33) * 91*91 + ($y3-33) * 91 + $y4-33) / 380926;
                        $long = -180 + (($x1-33) * 91*91*91 + ($x2-33) * 91*91 + ($x3-33) * 91 + $x4-33) / 190463;
                }
                $distance = decimal_distance($repeater_lat, $repeater_lon, $lat, $long);
                if ($distance > $rangelimit) {
                	if ($debug > 1) "Calculated distance $distance km. Invalid range limit $rangelimit. Discard\n";
                        continue;
                }
		$bearing = latlongbearing($repeater_lat, $repeater_lon, $lat, $long);
                $lastheard = mktime($matches[4], $matches[5], $matches[6], $matches[2], $matches[3], $matches[1]);
                $parserdb[$callsign] = array("lastheard" => $lastheard, "distance" => $distance, "bearing" => $bearing, "lat" => $lat, "long" => $long, "coordtype" => $coordtype);
        }
}


ksort($parserdb);
foreach ($parserdb as $callsign => $attcheddata) {
	$distance = $attcheddata["distance"];
	$lastheard = $attcheddata["lastheard"];
	$lat = $attcheddata["lat"];
	$long = $attcheddata["long"];
	$coordtype = $attcheddata["coordtype"];
	$bearing = $attcheddata["bearing"];
	$lastheardtxt = date("r", $lastheard);
	$advertisedtime = $stationdb[$callsign]["advertisedtime"];
	$advertisedtimetxt = date("r",$advertisedtime);
	if ($debug>0) echo "Call $callsign. Lat $lat. Long $long. Coordtype $coordtype. Distance $distance. Bearing $bearing. Lastheard $lastheardtxt. Advertised $advertisedtimetxt. ";
	if (array_key_exists($callsign, $stationdb)) {
		if ($debug>0) echo "Found from stationdb. ";
		if ($advertisedtime < (utctimenow()-$floodprotect) && $lastheard>$stationdb[$callsign]["lastheard"]) {
		        if ($debug>0) if ($advertisedtime < (utctimenow()-$floodprotect)) echo "Floodprotect expired. "; else echo "Floodprotect active. ";
		        if ($distance < $maxdistance) {
				/* Exists in stationdb. Too old and inside circle */
				if ($debug>0) echo "Inside $maxdistance km cicle. Add to victims.";
				$victims[] = $callsign;
				$advertisedtime = utctimenow();
                                
			} else {
				/* Station too far */
				if ($debug>0) echo "Outside $maxdistance km circle. Skip.";
			}
		} else {
		        if ($debug>0) if ($advertisedtime < (utctimenow()-$floodprotect)) echo "Floodprotect expired. "; else echo "Floodprotect active. ";
		        if ($debug>0) if ($lastheard>$stationdb[$callsign]["lastheard"]) echo "New packet. "; else echo "Old packed. ";
		        if ($debug>0) echo "Skip.";
		}
	} else {
		if ($debug>0) echo "Not found from stationdb. ";
		if ($distance < $maxdistance) {
			if ($debug>0) echo "Inside ${maxdistance}km circle. Add to victims.";
			$victims[] = $callsign;
			$advertisedtime = utctimenow();
			                                
		} else {
			if ($debug>0) echo "Outside ${maxdistance}km circle. Skip.";
		}
	}
	$stationdb[$callsign]["lastheard"] = $lastheard;
	$stationdb[$callsign]["distance"] = $distance;
	$stationdb[$callsign]["bearing"] = $bearing;
	$stationdb[$callsign]["lat"] = $lat;
	$stationdb[$callsign]["long"] = $long;
	$stationdb[$callsign]["coordtype"] = $coordtype;
        $stationdb[$callsign]["advertisedtime"] = $advertisedtime; 
	        
	if ($debug>0) echo "\n";
}

if ($debug>0) echo "Updating $stationdbfile\n";
file_put_contents($stationdbfile, serialize($stationdb));

$msg = "";
if (count($victims) == 0) {
        /* do nothing */
} else {
        if (!file_exists($denytxfile)) {
                @unlink($tempwavetxt);
                @unlink($tempwave);
                foreach ($victims as $victim) {
                        $msg .= callsign2finnish($victim).", ";
                }
                $msg = substr($msg,0,-2);
                if ($debug>0) echo "$msg\n";
                if ($debug<1) file_put_contents($tempwavetxt, utf8_decode($msg));
                if ($debug<1) system("/usr/bin/text2wave -F 8000 < ".$tempwavetxt." -o ".$tempwave);
                if ($debug<1) system("/usr/sbin/tlbcmd \"port OH6RUC-Kaustinen; say -c ".$prefixwave."; say -c ".$tempwave."; say -c ".$suffixwave."\"");                
        } else {
                if ($debug>0) echo "Cannot advertise. Advertises denied by $denytxfile lock file.\n";
        }
}
?>

Tämä scripti on ajastettu crontabissa

# Katsotaan onko kuuluvuusalueella uusia APRS-asemia ja mainostetaan jos on
4,8,12,16,20,24,28,32,36,40,44,48,52,56 * * * * tlb /opt/thelinkbox/scripts/aprs-repeater-advertiser.php > /dev/null