kopia lustrzana https://github.com/cyoung/stratux
Merge remote-tracking branch 'upstream/master'
commit
6daa3b7240
|
@ -12,3 +12,30 @@ libdump978.so
|
|||
*.img
|
||||
|
||||
*.zip
|
||||
|
||||
test/bmp180_read
|
||||
|
||||
test/es_dump_csv
|
||||
|
||||
test/extract_latlng
|
||||
|
||||
test/extract_metar
|
||||
|
||||
test/getairmet
|
||||
|
||||
test/icao2reg
|
||||
|
||||
test/maxgap
|
||||
|
||||
test/nexrad_annunciator
|
||||
|
||||
test/packetrate
|
||||
|
||||
test/replay
|
||||
|
||||
test/sensortest
|
||||
|
||||
test/uat_read
|
||||
|
||||
test/uatsummary
|
||||
|
||||
|
|
10
Makefile
10
Makefile
|
@ -38,12 +38,14 @@ www:
|
|||
install:
|
||||
cp -f gen_gdl90 /usr/bin/gen_gdl90
|
||||
chmod 755 /usr/bin/gen_gdl90
|
||||
cp init.d-stratux /etc/init.d/stratux
|
||||
cp image/10-stratux.rules /etc/udev/rules.d/10-stratux.rules
|
||||
cp image/99-uavionix.rules /etc/udev/rules.d/99-uavionix.rules
|
||||
chmod 755 /etc/init.d/stratux
|
||||
ln -sf /etc/init.d/stratux /etc/rc2.d/S01stratux
|
||||
ln -sf /etc/init.d/stratux /etc/rc6.d/K01stratux
|
||||
rm -f /etc/init.d/stratux
|
||||
cp __lib__systemd__system__stratux.service /lib/systemd/system/stratux.service
|
||||
cp __root__stratux-pre-start.sh /root/stratux-pre-start.sh
|
||||
chmod 644 /lib/systemd/system/stratux.service
|
||||
chmod 744 /root/stratux-pre-start.sh
|
||||
ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target.wants/stratux.service
|
||||
make www
|
||||
cp -f dump1090/dump1090 /usr/bin/
|
||||
|
||||
|
|
13
README.md
13
README.md
|
@ -7,16 +7,11 @@
|
|||
RTL-SDR UAT tools
|
||||
|
||||
|
||||
Use Pi 2 and ForeFlight 7.3.1 (1792) (Sep 18, 2015).
|
||||
Use with Raspberry Pi 3.
|
||||
|
||||
Raspberry Pi 2 with the Edimax EW-7811Un Wi-Fi dongle is supported but not recommended for new builds.
|
||||
|
||||
Supported WiFi adapters:
|
||||
* Edimax EW-7811Un
|
||||
|
||||
Tested RTL-SDR:
|
||||
* NooElec NESDR Nano 2 (best)
|
||||
* NooElec NESDR Mini 2
|
||||
* Generic R820T (degraded performance)
|
||||
Tested and works well with most common R820T and R820T2 RTL-SDR devices.
|
||||
|
||||
Apps with stratux recognition/support:
|
||||
* Seattle Avionics FlyQ EFB 2.1.1+.
|
||||
|
@ -30,7 +25,7 @@ Apps with stratux recognition/support:
|
|||
* DroidEFB 2.1.1+.
|
||||
|
||||
Tested weather/traffic displays:
|
||||
* ForeFlight 7+ - weather, traffic, AHRS.
|
||||
* ForeFlight 7+ - weather, traffic. AHRS not functional.
|
||||
* Avare
|
||||
|
||||
Questions? [See the FAQ](https://github.com/cyoung/stratux/wiki/FAQ)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
[Unit]
|
||||
Description=Stratux
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/root/stratux-pre-start.sh
|
||||
ExecStart=/usr/bin/gen_gdl90
|
||||
ExecStop=pkill dump1090
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitCORE=1073741824
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
|
||||
# Check if we need to run an update.
|
||||
if [ -e /root/update*stratux*v*.sh ] ; then
|
||||
UPDATE_SCRIPT=`ls -1t /root/update*stratux*v*.sh | head -1`
|
||||
if [ -n "$UPDATE_SCRIPT" ] ; then
|
||||
# Execute the script, remove it, then reboot.
|
||||
echo
|
||||
echo "Running update script ${UPDATE_SCRIPT}..."
|
||||
bash ${UPDATE_SCRIPT}
|
||||
rm -f $UPDATE_SCRIPT
|
||||
reboot
|
||||
fi
|
||||
fi
|
||||
|
|
@ -144,10 +144,21 @@ void make_atan2_table(void) {
|
|||
}
|
||||
|
||||
static void convert_to_phi(uint16_t *dest, uint16_t *src, int n) {
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
dest[i] = iqphase[src[i]];
|
||||
// unroll the loop. n is always > 2048, usually 36864
|
||||
for (i = 0; i+8 <= n; i += 8) {
|
||||
dest[i] = iqphase[src[i]];
|
||||
dest[i+1] = iqphase[src[i+1]];
|
||||
dest[i+2] = iqphase[src[i+2]];
|
||||
dest[i+3] = iqphase[src[i+3]];
|
||||
dest[i+4] = iqphase[src[i+4]];
|
||||
dest[i+5] = iqphase[src[i+5]];
|
||||
dest[i+6] = iqphase[src[i+6]];
|
||||
dest[i+7] = iqphase[src[i+7]];
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
dest[i] = iqphase[src[i]];
|
||||
}
|
||||
|
||||
static void calc_power(uint16_t *samples, int len) { // sets signal_strength to scaled amplitude. 0 = no signal, 1000 = saturated receiver on all samples in measurement.
|
||||
|
|
|
@ -25,7 +25,7 @@ if [ -f /root/.aliases ]; then
|
|||
. /root/.aliases
|
||||
fi
|
||||
|
||||
# Uesful aliases for stratux debugging
|
||||
# Useful aliases for stratux debugging
|
||||
if [ -f /root/.stxAliases ]; then
|
||||
. /root/.stxAliases
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#!/usr/bin/python
|
||||
# @Author Ryan Dewsbury (helno)
|
||||
#
|
||||
# This script throttles a fan based on CPU temperature.
|
||||
#
|
||||
# It expects a fan that's externally powered, and uses GPIO pin 11 for control.
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
import os
|
||||
|
||||
# Return CPU temperature as float
|
||||
def getCPUtemp():
|
||||
cTemp = os.popen('vcgencmd measure_temp').readline()
|
||||
return float(cTemp.replace("temp=","").replace("'C\n",""))
|
||||
|
||||
GPIO.setmode(GPIO.BOARD)
|
||||
GPIO.setup(11,GPIO.OUT)
|
||||
GPIO.setwarnings(False)
|
||||
p=GPIO.PWM(11,1000)
|
||||
PWM = 50
|
||||
|
||||
while True:
|
||||
|
||||
CPU_temp = getCPUtemp()
|
||||
if CPU_temp > 40.5:
|
||||
PWM = min(max(PWM + 1, 0), 100)
|
||||
p.start(PWM)
|
||||
elif CPU_temp < 39.5:
|
||||
PWM = min(max(PWM - 1, 0), 100)
|
||||
p.start(PWM)
|
||||
time.sleep(5)
|
||||
|
||||
GPIO.cleanup()
|
|
@ -16,7 +16,7 @@ iface wlan0 inet static
|
|||
|
||||
##
|
||||
## Second Wifi Dongle for local work and internet access
|
||||
## wifi mist be open for these settings to work
|
||||
## wifi must be open for these settings to work
|
||||
##
|
||||
## uncomment the next two lines to activate the service as well as modify the settings and comments below
|
||||
#allow-hotplug wlan1
|
||||
|
|
|
@ -31,6 +31,9 @@ cp -f root mnt/etc/ssh/authorized_keys/root
|
|||
chown root.root mnt/etc/ssh/authorized_keys/root
|
||||
chmod 644 mnt/etc/ssh/authorized_keys/root
|
||||
|
||||
#motd
|
||||
cp -f motd mnt/etc/motd
|
||||
|
||||
#dhcpd config
|
||||
cp -f dhcpd.conf mnt/etc/dhcp/dhcpd.conf
|
||||
|
||||
|
@ -50,9 +53,14 @@ cp -f interfaces mnt/etc/network/interfaces
|
|||
#custom hostapd start script
|
||||
cp stratux-wifi.sh mnt/usr/sbin/
|
||||
chmod 755 mnt/usr/sbin/stratux-wifi.sh
|
||||
|
||||
#ping udev
|
||||
cp -f 99-uavionix.rules mnt/etc/udev/rules.d
|
||||
|
||||
#fan/temp control script
|
||||
cp fancontrol.py mnt/usr/bin/
|
||||
chmod 755 mnt/usr/bin/fancontrol.py
|
||||
|
||||
#isc-dhcp-server config
|
||||
cp -f isc-dhcp-server mnt/etc/default/isc-dhcp-server
|
||||
|
||||
|
@ -93,7 +101,6 @@ git clone https://github.com/cyoung/stratux --recursive
|
|||
cd stratux
|
||||
make
|
||||
make install
|
||||
systemctl enable stratux
|
||||
|
||||
#system tweaks
|
||||
cp -f modules.txt mnt/etc/modules
|
||||
|
@ -110,10 +117,15 @@ make
|
|||
make install
|
||||
|
||||
#disable serial console
|
||||
sed -i /etc/inittab -e "s|^.*:.*:respawn:.*ttyAMA0|#&|"
|
||||
sed -i /boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
|
||||
|
||||
#Set the keyboard layout to US.
|
||||
sed -i /etc/default/keyboard -e "/^XKBLAYOUT/s/\".*\"/\"us\"/"
|
||||
|
||||
#boot settings
|
||||
cp -f config.txt mnt/boot/
|
||||
|
||||
#external OLED screen
|
||||
#apt-get install -y libjpeg-dev i2c-tools python-smbus python-pip python-dev python-pil screen
|
||||
#git clone https://github.com/rm-hull/ssd1306
|
||||
#cd ssd1306 && python setup.py install
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
ad88888ba 888888888888 88888888ba db 888888888888 88 88 8b d8
|
||||
d8" "8b 88 88 "8b d88b 88 88 88 Y8, ,8P
|
||||
Y8, 88 88 ,8P d8'`8b 88 88 88 `8b d8'
|
||||
`Y8aaaaa, 88 88aaaaaa8P' d8' `8b 88 88 88 Y88P
|
||||
`"""""8b, 88 88""""88' d8YaaaaY8b 88 88 88 d88b
|
||||
`8b 88 88 `8b d8""""""""8b 88 88 88 ,8P Y8,
|
||||
Y8a a8P 88 88 `8b d8' `8b 88 Y8a. .a8P d8' `8b
|
||||
"Y88888P" 88 88 `8b d8' `8b 88 `"Y8888Y"' 8P Y8
|
||||
|
||||
|
||||
|
||||
NOTE TO DEVELOPERS: Make sure that your system has an acceptable clock source, i.e., a GPS
|
||||
with sufficient signal or enable ntpd (internet connection required).
|
||||
|
||||
|
||||
Everything here comes with ABSOLUTELY NO WARRANTY, to the extent
|
||||
permitted by applicable law.
|
||||
|
||||
Type 'stratux-help' for a few debugging commands.
|
|
@ -1,3 +1,4 @@
|
|||
blacklist dvb_usb_rtl28xxu
|
||||
blacklist e4000
|
||||
blacklist rtl2832
|
||||
blacklist dvb_usb_rtl2832u
|
||||
|
|
|
@ -13,7 +13,7 @@ DAEMON_CONF=/etc/hostapd/hostapd.conf
|
|||
DAEMON_SBIN=/usr/sbin/hostapd
|
||||
EW7811Un=$(lsusb | grep EW-7811Un)
|
||||
RPI_REV=`cat /proc/cpuinfo | grep 'Revision' | awk '{print $3}' | sed 's/^1000//'`
|
||||
if [ "$RPI_REV" = "a01041" ] || [ "$RPI_REV" = "a21041" ] || [ "$RPI_REV" = "900092" ] && [ "$EW7811Un" != '' ]; then
|
||||
if [ "$RPI_REV" = "a01041" ] || [ "$RPI_REV" = "a21041" ] || [ "$RPI_REV" = "900092" ] || [ "$RPI_REV" = "900093" ] && [ "$EW7811Un" != '' ]; then
|
||||
# This is a RPi2B or RPi0 with Edimax USB Wifi dongle.
|
||||
DAEMON_CONF=/etc/hostapd/hostapd-edimax.conf
|
||||
DAEMON_SBIN=/usr/sbin/hostapd-edimax
|
||||
|
|
|
@ -36,10 +36,10 @@ echo ""
|
|||
echo "###################################################"
|
||||
echo ""
|
||||
echo "stratux-off Shutdown Stratux"
|
||||
echo "sa List all services running, check for '[+] stratux'"
|
||||
echo "sa List all services running"
|
||||
echo "stxrestart Restart Startux service only"
|
||||
echo "stxstop Stop Stratux Service."
|
||||
echo "stxstart Start Stratux Service."
|
||||
echo "stxstart Start Stratux Service."
|
||||
echo "sdr0 Test to see if sdr0 is in use by Stratux."
|
||||
echo "sdr1 Test to see if sdr1 is in use by Startux."
|
||||
echo "sdrs Test to see if both SDRs are in use by Stratux."
|
||||
|
@ -48,9 +48,11 @@ echo "d900 Run dump1090 on SDR0 in interactive mode."
|
|||
echo "d901 Run dump1090 on SDR0 in interactive mode."
|
||||
echo "kal0 Find Channels for calibrating PPM of SDR0."
|
||||
echo "kal1 Find Channels for calibrating PPM of SDR1."
|
||||
echo "kalChan0 Use the Chan from above to get ppm pf SDR0. Example: kalChan0 151"
|
||||
echo "kalChan1 Use the Chan from above to get ppm pf SDR1. Example: kalChan1 151"
|
||||
echo "kalChan0 Use the Chan from above to get ppm pf SDR0. Example: kalChan0 151"
|
||||
echo "kalChan1 Use the Chan from above to get ppm pf SDR1. Example: kalChan1 151"
|
||||
echo "setSerial0 Set the PPM error to SDR0. Value from kalChan0. Example: setSerial0 -45"
|
||||
echo "setSerial1 Set the PPM error to SDR1. Value from kalChan1. Example: setSerial0 23"
|
||||
echo "setSerial1 Set the PPM error to SDR1. Value from kalChan1. Example: setSerial1 23"
|
||||
echo "hostapd_manager.sh Sets the Change SSID, Channel, or Encryption for your Stratux"
|
||||
echo "raspi-config Open Raspberry Pi settings to expand filesystem"
|
||||
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: stratux
|
||||
# Required-Start: $network
|
||||
# Required-Stop:
|
||||
# Should-Start:
|
||||
# Should-Stop:
|
||||
# Default-Start: 2
|
||||
# Default-Stop: 6
|
||||
# Short-Description: Stratux ADS-B Receiver
|
||||
# Description: RTL-SDR ADS-B receiver
|
||||
### END INIT INFO
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin
|
||||
DAEMON_SBIN=/usr/bin/gen_gdl90
|
||||
DAEMON_DEFS=
|
||||
DAEMON_CONF=
|
||||
NAME=stratux
|
||||
DESC="Stratux ADS-B Receiver"
|
||||
PIDFILE=/var/run/stratux.pid
|
||||
|
||||
[ -x "$DAEMON_SBIN" ] || exit 0
|
||||
|
||||
DAEMON_OPTS=""
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
log_daemon_msg "Starting $DESC" "$NAME"
|
||||
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
# Check if we need to run an update.
|
||||
if [ -e /root/update*stratux*v*.sh ] ; then
|
||||
UPDATE_SCRIPT=`ls -1t /root/update*stratux*v*.sh | head -1`
|
||||
if [ -n "$UPDATE_SCRIPT" ] ; then
|
||||
# Execute the script, remove it, then reboot.
|
||||
echo
|
||||
echo "Running update script ${UPDATE_SCRIPT}..."
|
||||
sh ${UPDATE_SCRIPT}
|
||||
rm -f $UPDATE_SCRIPT
|
||||
reboot
|
||||
fi
|
||||
fi
|
||||
start-stop-daemon --start --background --oknodo --quiet --exec "$DAEMON_SBIN" \
|
||||
--pidfile "$PIDFILE" --make-pidfile -- $DAEMON_OPTS >/dev/null
|
||||
log_end_msg "$?"
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \
|
||||
--pidfile "$PIDFILE"
|
||||
pkill dump1090 || true
|
||||
log_end_msg "$?"
|
||||
;;
|
||||
reload)
|
||||
log_daemon_msg "Reloading $DESC" "$NAME"
|
||||
start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \
|
||||
--pidfile "$PIDFILE"
|
||||
log_end_msg "$?"
|
||||
;;
|
||||
restart|force-reload)
|
||||
$0 stop
|
||||
sleep 8
|
||||
$0 start
|
||||
;;
|
||||
status)
|
||||
status_of_proc "$DAEMON_SBIN" "$NAME"
|
||||
exit $?
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
|
@ -435,12 +435,12 @@ func dataLog() {
|
|||
// Check if we need to create a new database.
|
||||
createDatabase := false
|
||||
|
||||
if _, err := os.Stat(dataLogFile); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(dataLogFilef); os.IsNotExist(err) {
|
||||
createDatabase = true
|
||||
log.Printf("creating new database '%s'.\n", dataLogFile)
|
||||
log.Printf("creating new database '%s'.\n", dataLogFilef)
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", dataLogFile)
|
||||
db, err := sql.Open("sqlite3", dataLogFilef)
|
||||
if err != nil {
|
||||
log.Printf("sql.Open(): %s\n", err.Error())
|
||||
}
|
||||
|
@ -449,7 +449,7 @@ func dataLog() {
|
|||
db.Close()
|
||||
dataLogStarted = false
|
||||
//close(dataLogChan)
|
||||
log.Printf("datalog.go: dataLog() has closed DB in %s\n", dataLogFile)
|
||||
log.Printf("datalog.go: dataLog() has closed DB in %s\n", dataLogFilef)
|
||||
}()
|
||||
|
||||
_, err = db.Exec("PRAGMA journal_mode=WAL")
|
||||
|
@ -593,9 +593,6 @@ func initDataLog() {
|
|||
|
||||
func dataLogWatchdog() {
|
||||
for {
|
||||
if globalSettings.DEBUG {
|
||||
log.Printf("datalog.go: Watchdog loop iterating. dataLogStarted = %t\n", dataLogStarted)
|
||||
}
|
||||
if !dataLogStarted && globalSettings.ReplayLog { // case 1: sqlite logging isn't running, and we want to start it
|
||||
log.Printf("datalog.go: Watchdog wants to START logging.\n")
|
||||
go dataLog()
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
|
@ -36,15 +37,19 @@ import (
|
|||
|
||||
// http://www.faa.gov/nextgen/programs/adsb/wsa/media/GDL90_Public_ICD_RevA.PDF
|
||||
|
||||
var debugLogf string // Set according to OS config.
|
||||
var dataLogFilef string // Set according to OS config.
|
||||
|
||||
const (
|
||||
configLocation = "/etc/stratux.conf"
|
||||
indexFilename = "/var/log/stratux/LOGINDEX"
|
||||
managementAddr = ":80"
|
||||
debugLog = "/var/log/stratux.log"
|
||||
configLocation = "/etc/stratux.conf"
|
||||
managementAddr = ":80"
|
||||
debugLog = "/var/log/stratux.log"
|
||||
dataLogFile = "/var/log/stratux.sqlite"
|
||||
//FlightBox: log to /root.
|
||||
debugLog_FB = "/root/stratux.log"
|
||||
dataLogFile_FB = "/var/log/stratux.sqlite"
|
||||
maxDatagramSize = 8192
|
||||
maxUserMsgQueueSize = 25000 // About 10MB per port per connected client.
|
||||
logDirectory = "/var/log/stratux"
|
||||
dataLogFile = "/var/log/stratux.sqlite"
|
||||
|
||||
UPLINK_BLOCK_DATA_BITS = 576
|
||||
UPLINK_BLOCK_BITS = (UPLINK_BLOCK_DATA_BITS + 160)
|
||||
|
@ -100,11 +105,12 @@ var developerMode bool
|
|||
type msg struct {
|
||||
MessageClass uint
|
||||
TimeReceived time.Time
|
||||
Data []byte
|
||||
Data string
|
||||
Products []uint32
|
||||
Signal_amplitude int
|
||||
Signal_strength float64
|
||||
ADSBTowerID string // Index in the 'ADSBTowers' map, if this is a parseable uplink message.
|
||||
uatMsg *uatparse.UATMsg
|
||||
}
|
||||
|
||||
// Raw inputs.
|
||||
|
@ -121,40 +127,10 @@ type ADSBTower struct {
|
|||
Energy_last_minute uint64 // Summation of power observed for this tower across all messages last minute
|
||||
Signal_strength_last_minute float64 // Average RSSI (dB) observed for this tower last minute
|
||||
Messages_last_minute uint64
|
||||
Messages_total uint64
|
||||
}
|
||||
|
||||
var ADSBTowers map[string]ADSBTower // Running list of all towers seen. (lat,lng) -> ADSBTower
|
||||
|
||||
func constructFilenames() {
|
||||
var fileIndexNumber uint
|
||||
|
||||
// First, create the log file directory if it does not exist
|
||||
os.Mkdir(logDirectory, 0755)
|
||||
|
||||
f, err := os.Open(indexFilename)
|
||||
if err != nil {
|
||||
log.Printf("Unable to open index file %s using index of 0\n", indexFilename)
|
||||
fileIndexNumber = 0
|
||||
} else {
|
||||
_, err := fmt.Fscanf(f, "%d\n", &fileIndexNumber)
|
||||
if err != nil {
|
||||
log.Printf("Unable to read index file %s using index of 0\n", indexFilename)
|
||||
}
|
||||
f.Close()
|
||||
fileIndexNumber++
|
||||
}
|
||||
fo, err := os.Create(indexFilename)
|
||||
if err != nil {
|
||||
log.Printf("Error creating index file %s\n", indexFilename)
|
||||
}
|
||||
_, err2 := fmt.Fprintf(fo, "%d\n", fileIndexNumber)
|
||||
if err2 != nil {
|
||||
log.Printf("Error writing to index file %s\n", indexFilename)
|
||||
}
|
||||
fo.Sync()
|
||||
fo.Close()
|
||||
}
|
||||
var ADSBTowerMutex *sync.Mutex
|
||||
|
||||
// Construct the CRC table. Adapted from FAA ref above.
|
||||
func crcInit() {
|
||||
|
@ -498,7 +474,8 @@ func makeStratuxStatus() []byte {
|
|||
msg[26] = byte((v & 0xFF00) >> 8)
|
||||
msg[27] = byte(v & 0xFF)
|
||||
|
||||
// Number of ADS-B towers.
|
||||
// Number of ADS-B towers. Map structure is protected by ADSBTowerMutex.
|
||||
ADSBTowerMutex.Lock()
|
||||
num_towers := uint8(len(ADSBTowers))
|
||||
|
||||
msg[28] = byte(num_towers)
|
||||
|
@ -515,7 +492,7 @@ func makeStratuxStatus() []byte {
|
|||
msg = append(msg, tmp[1]) // Longitude.
|
||||
msg = append(msg, tmp[2]) // Longitude.
|
||||
}
|
||||
|
||||
ADSBTowerMutex.Unlock()
|
||||
return prepareMessage(msg)
|
||||
}
|
||||
|
||||
|
@ -631,7 +608,9 @@ func updateMessageStats() {
|
|||
m := len(MsgLog)
|
||||
UAT_messages_last_minute := uint(0)
|
||||
ES_messages_last_minute := uint(0)
|
||||
products_last_minute := make(map[string]uint32)
|
||||
|
||||
ADSBTowerMutex.Lock()
|
||||
defer ADSBTowerMutex.Unlock()
|
||||
|
||||
// Clear out ADSBTowers stats.
|
||||
for t, tinf := range ADSBTowers {
|
||||
|
@ -645,12 +624,20 @@ func updateMessageStats() {
|
|||
t = append(t, MsgLog[i])
|
||||
if MsgLog[i].MessageClass == MSGCLASS_UAT {
|
||||
UAT_messages_last_minute++
|
||||
for _, p := range MsgLog[i].Products {
|
||||
products_last_minute[getProductNameFromId(int(p))]++
|
||||
}
|
||||
if len(MsgLog[i].ADSBTowerID) > 0 { // Update tower stats.
|
||||
tid := MsgLog[i].ADSBTowerID
|
||||
|
||||
if _, ok := ADSBTowers[tid]; !ok { // First time we've seen the tower? Start tracking.
|
||||
var newTower ADSBTower
|
||||
newTower.Lat = MsgLog[i].uatMsg.Lat
|
||||
newTower.Lng = MsgLog[i].uatMsg.Lon
|
||||
newTower.Signal_strength_max = -999 // dBmax = 0, so this needs to initialize below scale ( << -48 dB)
|
||||
ADSBTowers[tid] = newTower
|
||||
}
|
||||
|
||||
twr := ADSBTowers[tid]
|
||||
twr.Signal_strength_now = MsgLog[i].Signal_strength
|
||||
|
||||
twr.Energy_last_minute += uint64((MsgLog[i].Signal_amplitude) * (MsgLog[i].Signal_amplitude))
|
||||
twr.Messages_last_minute++
|
||||
if MsgLog[i].Signal_strength > twr.Signal_strength_max { // Update alltime max signal strength.
|
||||
|
@ -666,7 +653,6 @@ func updateMessageStats() {
|
|||
MsgLog = t
|
||||
globalStatus.UAT_messages_last_minute = UAT_messages_last_minute
|
||||
globalStatus.ES_messages_last_minute = ES_messages_last_minute
|
||||
globalStatus.UAT_products_last_minute = products_last_minute
|
||||
|
||||
// Update "max messages/min" counters.
|
||||
if globalStatus.UAT_messages_max < UAT_messages_last_minute {
|
||||
|
@ -678,8 +664,8 @@ func updateMessageStats() {
|
|||
|
||||
// Update average signal strength over last minute for all ADSB towers.
|
||||
for t, tinf := range ADSBTowers {
|
||||
if tinf.Messages_last_minute == 0 {
|
||||
tinf.Signal_strength_last_minute = -99
|
||||
if tinf.Messages_last_minute == 0 || tinf.Energy_last_minute == 0 {
|
||||
tinf.Signal_strength_last_minute = -999
|
||||
} else {
|
||||
tinf.Signal_strength_last_minute = 10 * (math.Log10(float64((tinf.Energy_last_minute / tinf.Messages_last_minute))) - 6)
|
||||
}
|
||||
|
@ -726,7 +712,7 @@ func cpuTempMonitor() {
|
|||
|
||||
func updateStatus() {
|
||||
if mySituation.Quality == 2 {
|
||||
globalStatus.GPS_solution = "GPS + SBAS (WAAS / EGNOS)"
|
||||
globalStatus.GPS_solution = "GPS + SBAS (WAAS)"
|
||||
} else if mySituation.Quality == 1 {
|
||||
globalStatus.GPS_solution = "3D GPS"
|
||||
} else if mySituation.Quality == 6 {
|
||||
|
@ -754,11 +740,11 @@ func updateStatus() {
|
|||
globalStatus.GPS_satellites_locked = mySituation.Satellites
|
||||
globalStatus.GPS_satellites_seen = mySituation.SatellitesSeen
|
||||
globalStatus.GPS_satellites_tracked = mySituation.SatellitesTracked
|
||||
globalStatus.GPS_position_accuracy = mySituation.Accuracy
|
||||
|
||||
// Update Uptime value
|
||||
globalStatus.Uptime = int64(stratuxClock.Milliseconds)
|
||||
globalStatus.UptimeClock = stratuxClock.Time
|
||||
globalStatus.Clock = time.Now()
|
||||
|
||||
usage = du.NewDiskUsage("/")
|
||||
globalStatus.DiskBytesFree = usage.Free()
|
||||
|
@ -861,9 +847,13 @@ func parseInput(buf string) ([]byte, uint16) {
|
|||
var thisMsg msg
|
||||
thisMsg.MessageClass = MSGCLASS_UAT
|
||||
thisMsg.TimeReceived = stratuxClock.Time
|
||||
thisMsg.Data = frame
|
||||
thisMsg.Data = buf
|
||||
thisMsg.Signal_amplitude = thisSignalStrength
|
||||
thisMsg.Signal_strength = 20 * math.Log10((float64(thisSignalStrength))/1000)
|
||||
if thisSignalStrength > 0 {
|
||||
thisMsg.Signal_strength = 20 * math.Log10((float64(thisSignalStrength))/1000)
|
||||
} else {
|
||||
thisMsg.Signal_strength = -999
|
||||
}
|
||||
thisMsg.Products = make([]uint32, 0)
|
||||
if msgtype == MSGTYPE_UPLINK {
|
||||
// Parse the UAT message.
|
||||
|
@ -872,18 +862,6 @@ func parseInput(buf string) ([]byte, uint16) {
|
|||
uatMsg.DecodeUplink()
|
||||
towerid := fmt.Sprintf("(%f,%f)", uatMsg.Lat, uatMsg.Lon)
|
||||
thisMsg.ADSBTowerID = towerid
|
||||
if _, ok := ADSBTowers[towerid]; !ok { // First time we've seen the tower. Start tracking.
|
||||
var newTower ADSBTower
|
||||
newTower.Lat = uatMsg.Lat
|
||||
newTower.Lng = uatMsg.Lon
|
||||
newTower.Signal_strength_now = thisMsg.Signal_strength
|
||||
newTower.Signal_strength_max = -999 // dBmax = 0, so this needs to initialize below scale ( << -48 dB)
|
||||
ADSBTowers[towerid] = newTower
|
||||
}
|
||||
twr := ADSBTowers[towerid]
|
||||
twr.Messages_total++
|
||||
twr.Signal_strength_now = thisMsg.Signal_strength
|
||||
ADSBTowers[towerid] = twr
|
||||
// Get all of the "product ids".
|
||||
for _, f := range uatMsg.Frames {
|
||||
thisMsg.Products = append(thisMsg.Products, f.Product_id)
|
||||
|
@ -893,6 +871,7 @@ func parseInput(buf string) ([]byte, uint16) {
|
|||
for _, r := range textReports {
|
||||
registerADSBTextMessageReceived(r)
|
||||
}
|
||||
thisMsg.uatMsg = uatMsg
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,7 +976,6 @@ type status struct {
|
|||
Connected_Users uint
|
||||
DiskBytesFree uint64
|
||||
UAT_messages_last_minute uint
|
||||
UAT_products_last_minute map[string]uint32
|
||||
UAT_messages_max uint
|
||||
ES_messages_last_minute uint
|
||||
ES_messages_max uint
|
||||
|
@ -1005,11 +983,11 @@ type status struct {
|
|||
GPS_satellites_locked uint16
|
||||
GPS_satellites_seen uint16
|
||||
GPS_satellites_tracked uint16
|
||||
GPS_position_accuracy float32
|
||||
GPS_connected bool
|
||||
GPS_solution string
|
||||
RY835AI_connected bool
|
||||
Uptime int64
|
||||
Clock time.Time
|
||||
UptimeClock time.Time
|
||||
CPUTemp float32
|
||||
NetworkDataMessagesSent uint64
|
||||
|
@ -1236,8 +1214,38 @@ func main() {
|
|||
globalStatus.Version = stratuxVersion
|
||||
globalStatus.Build = stratuxBuild
|
||||
globalStatus.Errors = make([]string, 0)
|
||||
//FlightBox: detect via presence of /etc/FlightBox file.
|
||||
if _, err := os.Stat("/etc/FlightBox"); !os.IsNotExist(err) {
|
||||
globalStatus.HardwareBuild = "FlightBox"
|
||||
debugLogf = debugLog_FB
|
||||
dataLogFilef = dataLogFile_FB
|
||||
} else { // if not using the FlightBox config, use "normal" log file locations
|
||||
debugLogf = debugLog
|
||||
dataLogFilef = dataLogFile
|
||||
}
|
||||
//FIXME: All of this should be removed by 08/01/2016.
|
||||
// Check if Raspbian version is <8.0. Throw a warning if so.
|
||||
vt, err := ioutil.ReadFile("/etc/debian_version")
|
||||
if err == nil {
|
||||
vtS := strings.Trim(string(vt), "\n")
|
||||
vtF, err := strconv.ParseFloat(vtS, 32)
|
||||
if err == nil {
|
||||
if vtF < 8.0 {
|
||||
var err_os error
|
||||
if globalStatus.HardwareBuild == "FlightBox" {
|
||||
err_os = fmt.Errorf("You are running an old Stratux image that can't be updated fully and is now deprecated. Visit https://www.openflightsolutions.com/flightbox/image-update-required for further information.")
|
||||
} else {
|
||||
err_os = fmt.Errorf("You are running an old Stratux image that can't be updated fully and is now deprecated. Visit http://stratux.me/ to update using the latest release image.")
|
||||
}
|
||||
addSystemError(err_os)
|
||||
} else {
|
||||
// Running Jessie or better. Remove some old init.d files.
|
||||
// This made its way in here because /etc/init.d/stratux invokes the update script, which can't delete the init.d file.
|
||||
os.Remove("/etc/init.d/stratux")
|
||||
os.Remove("/etc/rc2.d/S01stratux")
|
||||
os.Remove("/etc/rc6.d/K01stratux")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replayESFilename := flag.String("eslog", "none", "ES Log filename")
|
||||
|
@ -1258,9 +1266,9 @@ func main() {
|
|||
}
|
||||
|
||||
// Duplicate log.* output to debugLog.
|
||||
fp, err := os.OpenFile(debugLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
fp, err := os.OpenFile(debugLogf, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
err_log := fmt.Errorf("Failed to open '%s': %s", debugLog, err.Error())
|
||||
err_log := fmt.Errorf("Failed to open '%s': %s", debugLogf, err.Error())
|
||||
addSystemError(err_log)
|
||||
log.Printf("%s\n", err_log.Error())
|
||||
} else {
|
||||
|
@ -1270,9 +1278,9 @@ func main() {
|
|||
}
|
||||
|
||||
log.Printf("Stratux %s (%s) starting.\n", stratuxVersion, stratuxBuild)
|
||||
constructFilenames()
|
||||
|
||||
ADSBTowers = make(map[string]ADSBTower)
|
||||
ADSBTowerMutex = &sync.Mutex{}
|
||||
MsgLog = make([]msg, 0)
|
||||
|
||||
crcInit() // Initialize CRC16 table.
|
||||
|
|
|
@ -151,6 +151,8 @@ func handleSituationRequest(w http.ResponseWriter, r *http.Request) {
|
|||
func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
|
||||
setNoCache(w)
|
||||
setJSONHeaders(w)
|
||||
|
||||
ADSBTowerMutex.Lock()
|
||||
towersJSON, err := json.Marshal(&ADSBTowers)
|
||||
if err != nil {
|
||||
log.Printf("Error sending tower JSON data: %s\n", err.Error())
|
||||
|
@ -158,6 +160,7 @@ func handleTowersRequest(w http.ResponseWriter, r *http.Request) {
|
|||
// for testing purposes, we can return a fixed reply
|
||||
// towersJSON = []byte(`{"(38.490880,-76.135554)":{"Lat":38.49087953567505,"Lng":-76.13555431365967,"Signal_strength_last_minute":100,"Signal_strength_max":67,"Messages_last_minute":1,"Messages_total":1059},"(38.978698,-76.309276)":{"Lat":38.97869825363159,"Lng":-76.30927562713623,"Signal_strength_last_minute":495,"Signal_strength_max":32,"Messages_last_minute":45,"Messages_total":83},"(39.179285,-76.668413)":{"Lat":39.17928457260132,"Lng":-76.66841268539429,"Signal_strength_last_minute":50,"Signal_strength_max":24,"Messages_last_minute":1,"Messages_total":16},"(39.666309,-74.315300)":{"Lat":39.66630935668945,"Lng":-74.31529998779297,"Signal_strength_last_minute":9884,"Signal_strength_max":35,"Messages_last_minute":4,"Messages_total":134}}`)
|
||||
fmt.Fprintf(w, "%s\n", towersJSON)
|
||||
ADSBTowerMutex.Unlock()
|
||||
}
|
||||
|
||||
// AJAX call - /getSatellites. Responds with all GNSS satellites that are being tracked, along with status information.
|
||||
|
@ -403,6 +406,7 @@ type dirlisting struct {
|
|||
ServerUA string
|
||||
}
|
||||
|
||||
//FIXME: This needs to be switched to show a "sessions log" from the sqlite database.
|
||||
func viewLogs(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
names, err := ioutil.ReadDir("/var/log/stratux/")
|
||||
|
|
|
@ -466,11 +466,11 @@ func ffMonitor() {
|
|||
|
||||
addr := net.UDPAddr{Port: 50113, IP: net.ParseIP("0.0.0.0")}
|
||||
conn, err := net.ListenUDP("udp", &addr)
|
||||
defer conn.Close()
|
||||
if err != nil {
|
||||
log.Printf("ffMonitor(): error listening on port 50113: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
for {
|
||||
buf := make([]byte, 1024)
|
||||
n, addr, err := conn.ReadFrom(buf)
|
||||
|
@ -519,5 +519,4 @@ func initNetwork() {
|
|||
go messageQueueSender()
|
||||
go sleepMonitor()
|
||||
go networkStatsCounter()
|
||||
go ffMonitor()
|
||||
}
|
||||
|
|
|
@ -773,7 +773,9 @@ func processNMEALine(l string) (sentenceUsed bool) {
|
|||
return false
|
||||
}
|
||||
if utcWeek < 1877 || utcWeek >= 32767 { // unless we're in a flying Delorean, UTC dates before 2016-JAN-01 are not valid. Check underflow condition as well.
|
||||
log.Printf("GPS week # %v out of scope; not setting time and date\n", utcWeek)
|
||||
if globalSettings.DEBUG {
|
||||
log.Printf("GPS week # %v out of scope; not setting time and date\n", utcWeek)
|
||||
}
|
||||
return false
|
||||
} /* else {
|
||||
log.Printf("GPS week # %v valid; evaluate time and date\n", utcWeek) //debug option
|
||||
|
|
186
main/traffic.go
186
main/traffic.go
|
@ -13,10 +13,11 @@ import (
|
|||
"bufio"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
//"strconv"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -75,7 +76,8 @@ const (
|
|||
|
||||
type TrafficInfo struct {
|
||||
Icao_addr uint32
|
||||
Tail string
|
||||
Reg string // Registration. Calculated from Icao_addr for civil aircraft of US registry.
|
||||
Tail string // Callsign. Transmitted by aircraft.
|
||||
Emitter_category uint8 // Formatted using GDL90 standard, e.g. in a Mode ES report, A7 becomes 0x07, B0 becomes 0x08, etc.
|
||||
OnGround bool // Air-ground status. On-ground is "true".
|
||||
Addr_type uint8 // UAT address qualifier. Used by GDL90 format, so translations for ES TIS-B/ADS-R are needed.
|
||||
|
@ -149,6 +151,8 @@ var traffic map[uint32]TrafficInfo
|
|||
var trafficMutex *sync.Mutex
|
||||
var seenTraffic map[uint32]bool // Historical list of all ICAO addresses seen.
|
||||
|
||||
var OwnshipTrafficInfo TrafficInfo
|
||||
|
||||
func cleanupOldEntries() {
|
||||
for icao_addr, ti := range traffic {
|
||||
if stratuxClock.Since(ti.Last_seen) > 60*time.Second { // keep it in the database for up to 60 seconds, so we don't lose tail number, etc...
|
||||
|
@ -166,6 +170,7 @@ func sendTrafficUpdates() {
|
|||
log.Printf("List of all aircraft being tracked:\n")
|
||||
log.Printf("==================================================================\n")
|
||||
}
|
||||
code, _ := strconv.ParseInt(globalSettings.OwnshipModeS, 16, 32)
|
||||
for icao, ti := range traffic { // TO-DO: Limit number of aircraft in traffic message. ForeFlight 7.5 chokes at ~1000-2000 messages depending on iDevice RAM. Practical limit likely around ~500 aircraft without filtering.
|
||||
if isGPSValid() {
|
||||
// func distRect(lat1, lon1, lat2, lon2 float64) (dist, bearing, distN, distE float64) {
|
||||
|
@ -194,7 +199,13 @@ func sendTrafficUpdates() {
|
|||
}
|
||||
if ti.Position_valid && ti.Age < 6 { // ... but don't pass stale data to the EFB. TO-DO: Coast old traffic? Need to determine how FF, WingX, etc deal with stale targets.
|
||||
logTraffic(ti) // only add to the SQLite log if it's not stale
|
||||
msg = append(msg, makeTrafficReportMsg(ti)...)
|
||||
|
||||
if ti.Icao_addr == uint32(code) { //
|
||||
log.Printf("Ownship target detected for code %X\n", code) // DEBUG - REMOVE
|
||||
OwnshipTrafficInfo = ti
|
||||
} else {
|
||||
msg = append(msg, makeTrafficReportMsg(ti)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -340,6 +351,12 @@ func parseDownlinkReport(s string, signalLevel int) {
|
|||
ti.Last_seen = stratuxClock.Time // need to initialize to current stratuxClock so it doesn't get cut before we have a chance to populate a position message
|
||||
ti.Icao_addr = icao_addr
|
||||
ti.ExtrapolatedPosition = false
|
||||
|
||||
thisReg, validReg := icao2reg(icao_addr)
|
||||
if validReg {
|
||||
ti.Reg = thisReg
|
||||
ti.Tail = thisReg
|
||||
}
|
||||
}
|
||||
|
||||
ti.Addr_type = addr_type
|
||||
|
@ -380,8 +397,12 @@ func parseDownlinkReport(s string, signalLevel int) {
|
|||
ti.NACp = int((frame[25] >> 4) & 0x0F)
|
||||
}
|
||||
|
||||
power := 20 * (math.Log10(float64(signalLevel) / 1000)) // reported amplitude is 0-1000. Normalize to max = 1 and do amplitude dB calculation (20 dB per decade)
|
||||
|
||||
var power float64
|
||||
if signalLevel > 0 {
|
||||
power = 20 * (math.Log10(float64(signalLevel) / 1000)) // reported amplitude is 0-1000. Normalize to max = 1 and do amplitude dB calculation (20 dB per decade)
|
||||
} else {
|
||||
power = -999
|
||||
}
|
||||
//log.Printf("%s (%X) seen with amplitude of %d, corresponding to normalized power of %f.2 dB\n",ti.Tail,ti.Icao_addr,signalLevel,power)
|
||||
|
||||
ti.SignalLevel = power
|
||||
|
@ -597,7 +618,7 @@ func esListen() {
|
|||
var thisMsg msg
|
||||
thisMsg.MessageClass = MSGCLASS_ES
|
||||
thisMsg.TimeReceived = stratuxClock.Time
|
||||
thisMsg.Data = []byte(buf)
|
||||
thisMsg.Data = buf
|
||||
MsgLog = append(MsgLog, thisMsg)
|
||||
|
||||
var eslog esmsg
|
||||
|
@ -641,9 +662,19 @@ func esListen() {
|
|||
ti.Icao_addr = icao
|
||||
ti.ExtrapolatedPosition = false
|
||||
ti.Last_source = TRAFFIC_SOURCE_1090ES
|
||||
|
||||
thisReg, validReg := icao2reg(icao)
|
||||
if validReg {
|
||||
ti.Reg = thisReg
|
||||
ti.Tail = thisReg
|
||||
}
|
||||
}
|
||||
|
||||
ti.SignalLevel = 10 * math.Log10(newTi.SignalLevel)
|
||||
if newTi.SignalLevel > 0 {
|
||||
ti.SignalLevel = 10 * math.Log10(newTi.SignalLevel)
|
||||
} else {
|
||||
ti.SignalLevel = -999
|
||||
}
|
||||
|
||||
// generate human readable summary of message types for debug
|
||||
// TO-DO: Use for ES message statistics?
|
||||
|
@ -991,6 +1022,147 @@ func updateDemoTraffic(icao uint32, tail string, relAlt float32, gs float64, off
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
icao2reg() : Converts 24-bit Mode S addresses to N-numbers and C-numbers.
|
||||
|
||||
Input: uint32 representing the Mode S address. Valid range for
|
||||
translation is 0xA00001 - 0xADF7C7, inclusive.
|
||||
|
||||
Values outside the range A000001-AFFFFFF or C00001-C3FFFF
|
||||
are flagged as foreign.
|
||||
|
||||
Values between ADF7C8 - AFFFFF are allocated to the United States,
|
||||
but are not used for aicraft on the civil registry. These could be
|
||||
military, other public aircraft, or future use.
|
||||
|
||||
|
||||
Values between C0CDF9 - C3FFFF are allocated to Canada,
|
||||
but are not used for aicraft on the civil registry. These could be
|
||||
military, other public aircraft, or future use.
|
||||
|
||||
Output:
|
||||
string: String containing the decoded tail number (if decoding succeeded),
|
||||
"NON-NA" (for non-US / non Canada allocation), and "US-MIL" or "CA-MIL" for non-civil US / Canada allocation.
|
||||
|
||||
bool: True if the Mode S address successfully translated to an
|
||||
N number. False for all other conditions.
|
||||
*/
|
||||
|
||||
func icao2reg(icao_addr uint32) (string, bool) {
|
||||
// Initialize local variables
|
||||
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
|
||||
nationalOffset := uint32(0xA00001) // default is US
|
||||
tail := ""
|
||||
nation := ""
|
||||
|
||||
// Determine nationality
|
||||
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
|
||||
nation = "US"
|
||||
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
|
||||
nation = "CA"
|
||||
} else {
|
||||
// future national decoding is TO-DO
|
||||
return "NON-NA", false
|
||||
}
|
||||
|
||||
if nation == "CA" { // Canada decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xC0CDF8 {
|
||||
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
|
||||
return "CA-MIL", false
|
||||
}
|
||||
|
||||
nationalOffset := uint32(0xC00001)
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
|
||||
// Fifth letter
|
||||
e := serial % 26
|
||||
|
||||
// Fourth letter
|
||||
d := (serial / 26) % 26
|
||||
|
||||
// Third letter
|
||||
c := (serial / 676) % 26 // 676 == 26*26
|
||||
|
||||
// Second letter
|
||||
b := (serial / 17576) % 26 // 17576 == 26*26*26
|
||||
|
||||
b_str := "FGI"
|
||||
|
||||
//fmt.Printf("B = %d, C = %d, D = %d, E = %d\n",b,c,d,e)
|
||||
tail = fmt.Sprintf("C-%c%c%c%c", b_str[b], c+65, d+65, e+65)
|
||||
}
|
||||
|
||||
if nation == "US" { // FAA decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xADF7C7 {
|
||||
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
|
||||
return "US-MIL", false
|
||||
}
|
||||
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
// First digit
|
||||
a := (serial / 101711) + 1
|
||||
|
||||
// Second digit
|
||||
a_remainder := serial % 101711
|
||||
b := ((a_remainder + 9510) / 10111) - 1
|
||||
|
||||
// Third digit
|
||||
b_remainder := (a_remainder + 9510) % 10111
|
||||
c := ((b_remainder + 350) / 951) - 1
|
||||
|
||||
// This next bit is more convoluted. First, figure out if we're using the "short" method of
|
||||
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
|
||||
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
|
||||
// is less than 601.
|
||||
|
||||
c_remainder := (b_remainder + 350) % 951
|
||||
var d, e int32
|
||||
|
||||
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
|
||||
d = 24 + (c_remainder-601)/35
|
||||
e = (c_remainder - 601) % 35
|
||||
|
||||
} else { // two-letter decoding method
|
||||
if (b < 0) || (c < 0) {
|
||||
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
|
||||
}
|
||||
|
||||
d = (c_remainder - 1) / 25
|
||||
e = (c_remainder - 1) % 25
|
||||
|
||||
if e < 0 {
|
||||
d -= 1
|
||||
e += 25
|
||||
}
|
||||
}
|
||||
|
||||
a_char := fmt.Sprintf("%d", a)
|
||||
var b_char, c_char, d_char, e_char string
|
||||
|
||||
if b >= 0 {
|
||||
b_char = fmt.Sprintf("%d", b)
|
||||
}
|
||||
|
||||
if b >= 0 && c >= 0 {
|
||||
c_char = fmt.Sprintf("%d", c)
|
||||
}
|
||||
|
||||
if d > -1 {
|
||||
d_char = string(base34alphabet[d])
|
||||
if e > 0 {
|
||||
e_char = string(base34alphabet[e-1])
|
||||
}
|
||||
}
|
||||
|
||||
tail = "N" + a_char + b_char + c_char + d_char + e_char
|
||||
|
||||
}
|
||||
|
||||
return tail, true
|
||||
}
|
||||
|
||||
func initTraffic() {
|
||||
traffic = make(map[uint32]TrafficInfo)
|
||||
seenTraffic = make(map[uint32]bool)
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -18,7 +18,8 @@ mkdir -p work/bin
|
|||
cp gen_gdl90 work/bin/
|
||||
cp libdump978.so work/bin/
|
||||
cp linux-mpu9150/libimu.so work/bin/
|
||||
cp init.d-stratux work/bin/
|
||||
cp __lib__systemd__system__stratux.service work/bin/
|
||||
cp __root__stratux-pre-start.sh work/bin/
|
||||
cp dump1090/dump1090 work/bin/
|
||||
cp -r web work/bin/
|
||||
cp image/hostapd.conf work/bin/
|
||||
|
@ -30,6 +31,8 @@ cp image/stxAliases.txt work/bin/
|
|||
cp image/hostapd_manager.sh work/bin/
|
||||
cp image/10-stratux.rules work/bin/
|
||||
cp image/99-uavionix.rules work/bin/
|
||||
cp image/motd work/bin/
|
||||
cp image/fancontrol.py work/bin/
|
||||
|
||||
#TODO: librtlsdr.
|
||||
cd work/
|
||||
|
|
|
@ -4,10 +4,20 @@ cp -f libimu.so /usr/lib/libimu.so
|
|||
|
||||
|
||||
# Startup script.
|
||||
cp -f init.d-stratux /etc/init.d/stratux
|
||||
chmod 755 /etc/init.d/stratux
|
||||
ln -fs /etc/init.d/stratux /etc/rc2.d/S01stratux
|
||||
ln -fs /etc/init.d/stratux /etc/rc6.d/K01stratux
|
||||
RASPBIAN_VERSION=`cat /etc/debian_version`
|
||||
if test "$RASPBIAN_VERSION" = "8.0" ; then
|
||||
# Install the systemd startup scripts in any case, even if they won't be used. If this is being run, then the old init.d script
|
||||
# is still intact and we just leave it. If running Wheezy, then remove the old init.d script.
|
||||
rm -f /etc/init.d/stratux
|
||||
rm -f /etc/rc2.d/S01stratux
|
||||
rm -f /etc/rc6.d/K01stratux
|
||||
fi
|
||||
|
||||
cp -f __lib__systemd__system__stratux.service /lib/systemd/system/stratux.service
|
||||
cp -f __root__stratux-pre-start.sh /root/stratux-pre-start.sh
|
||||
chmod 644 /lib/systemd/system/stratux.service
|
||||
chmod 744 /root/stratux-pre-start.sh
|
||||
ln -fs /lib/systemd/system/stratux.service /etc/systemd/system/multi-user.target.wants/stratux.service
|
||||
|
||||
#wifi config
|
||||
cp -f hostapd.conf /etc/hostapd/hostapd.conf
|
||||
|
@ -19,6 +29,9 @@ cp -f hostapd_manager.sh /usr/sbin/
|
|||
#boot config
|
||||
cp -f config.txt /boot/config.txt
|
||||
|
||||
#disable serial console
|
||||
sed -i /boot/cmdline.txt -e "s/console=ttyAMA0,[0-9]\+ //"
|
||||
|
||||
#modprobe.d blacklist
|
||||
cp -f rtl-sdr-blacklist.conf /etc/modprobe.d/
|
||||
|
||||
|
@ -33,6 +46,13 @@ cp -f stxAliases /root/.stxAliases
|
|||
# /etc/modules
|
||||
cp -f modules.txt /etc/modules
|
||||
|
||||
#motd
|
||||
cp -f motd /etc/motd
|
||||
|
||||
#fan control utility
|
||||
cp -f fancontrol.py /usr/bin/
|
||||
chmod 755 /usr/bin/fancontrol.py
|
||||
|
||||
cp -f dump1090 /usr/bin/
|
||||
|
||||
# Web files install.
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
|
||||
icao2reg: Converts a 24-bit numeric value to a tail number of FAA
|
||||
or Canadian registry.
|
||||
|
||||
(c) 2016 AvSquirrel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
icao := uint32(0xAC82EC)
|
||||
args := os.Args
|
||||
if len(args) > 1 {
|
||||
code, err := strconv.ParseInt(args[1], 16, 32)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing argument %s. Input should be 24-bit hexadecimal, e.g. 'A00001'\n", args[1])
|
||||
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
|
||||
} else {
|
||||
icao = uint32(code)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Usage: ./icao2faa [code], where [code] is a 24-bit hexadecimal string, e.g. A00001\n")
|
||||
fmt.Printf("Showing example decoding for Mode S code %X,\n", icao)
|
||||
}
|
||||
|
||||
tail, valid := icao2reg(icao)
|
||||
|
||||
if valid {
|
||||
fmt.Printf("ICAO %X successfully decodes as %s\n", icao, tail)
|
||||
} else {
|
||||
fmt.Printf("ICAO %X did not successfully decode. Response is `%s`\n", icao, tail)
|
||||
}
|
||||
}
|
||||
|
||||
func icao2reg(icao_addr uint32) (string, bool) {
|
||||
// Initialize local variables
|
||||
base34alphabet := string("ABCDEFGHJKLMNPQRSTUVWXYZ0123456789")
|
||||
nationalOffset := uint32(0xA00001) // default is US
|
||||
tail := ""
|
||||
nation := ""
|
||||
|
||||
// Determine nationality
|
||||
if (icao_addr >= 0xA00001) && (icao_addr <= 0xAFFFFF) {
|
||||
nation = "US"
|
||||
} else if (icao_addr >= 0xC00001) && (icao_addr <= 0xC3FFFF) {
|
||||
nation = "CA"
|
||||
} else {
|
||||
// future national decoding is TO-DO
|
||||
return "NON-NA", false
|
||||
}
|
||||
|
||||
if nation == "CA" { // Canada decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xC0CDF8 {
|
||||
//fmt.Printf("%X is a Canada aircraft, but not a CF-, CG-, or CI- registration.\n", icao_addr)
|
||||
return "CA-MIL", false
|
||||
}
|
||||
|
||||
nationalOffset := uint32(0xC00001)
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
|
||||
// Fifth letter
|
||||
e := serial % 26
|
||||
|
||||
// Fourth letter
|
||||
d := (serial / 26) % 26
|
||||
|
||||
// Third letter
|
||||
c := (serial / 676) % 26 // 676 == 26*26
|
||||
|
||||
// Second letter
|
||||
b := (serial / 17576) % 26 // 17576 == 26*26*26
|
||||
|
||||
b_str := "FGI"
|
||||
|
||||
fmt.Printf("B = %d, C = %d, D = %d, E = %d\n", b, c, d, e)
|
||||
tail = fmt.Sprintf("C-%c%c%c%c", b_str[b], c+65, d+65, e+65)
|
||||
}
|
||||
|
||||
if nation == "US" { // FAA decoding
|
||||
// First, discard addresses that are not assigned to aircraft on the civil registry
|
||||
if icao_addr > 0xADF7C7 {
|
||||
//fmt.Printf("%X is a US aircraft, but not on the civil registry.\n", icao_addr)
|
||||
return "US-MIL", false
|
||||
}
|
||||
|
||||
serial := int32(icao_addr - nationalOffset)
|
||||
// First digit
|
||||
a := (serial / 101711) + 1
|
||||
|
||||
// Second digit
|
||||
a_remainder := serial % 101711
|
||||
b := ((a_remainder + 9510) / 10111) - 1
|
||||
|
||||
// Third digit
|
||||
b_remainder := (a_remainder + 9510) % 10111
|
||||
c := ((b_remainder + 350) / 951) - 1
|
||||
|
||||
// This next bit is more convoluted. First, figure out if we're using the "short" method of
|
||||
// decoding the last two digits (two letters, one letter and one blank, or two blanks).
|
||||
// This will be the case if digit "B" or "C" are calculated as negative, or if c_remainder
|
||||
// is less than 601.
|
||||
|
||||
c_remainder := (b_remainder + 350) % 951
|
||||
var d, e int32
|
||||
|
||||
if (b >= 0) && (c >= 0) && (c_remainder > 600) { // alphanumeric decoding method
|
||||
d = 24 + (c_remainder-601)/35
|
||||
e = (c_remainder - 601) % 35
|
||||
|
||||
} else { // two-letter decoding method
|
||||
if (b < 0) || (c < 0) {
|
||||
c_remainder -= 350 // otherwise " " == 350, "A " == 351, "AA" == 352, etc.
|
||||
}
|
||||
|
||||
d = (c_remainder - 1) / 25
|
||||
e = (c_remainder - 1) % 25
|
||||
|
||||
if e < 0 {
|
||||
d -= 1
|
||||
e += 25
|
||||
}
|
||||
}
|
||||
|
||||
a_char := fmt.Sprintf("%d", a)
|
||||
var b_char, c_char, d_char, e_char string
|
||||
|
||||
if b >= 0 {
|
||||
b_char = fmt.Sprintf("%d", b)
|
||||
}
|
||||
|
||||
if b >= 0 && c >= 0 {
|
||||
c_char = fmt.Sprintf("%d", c)
|
||||
}
|
||||
|
||||
if d > -1 {
|
||||
d_char = string(base34alphabet[d])
|
||||
if e > 0 {
|
||||
e_char = string(base34alphabet[e-1])
|
||||
}
|
||||
}
|
||||
|
||||
tail = "N" + a_char + b_char + c_char + d_char + e_char
|
||||
|
||||
}
|
||||
|
||||
return tail, true
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
all:
|
||||
gcc -o metar_to_text src/*.c
|
||||
|
|
@ -0,0 +1,382 @@
|
|||
|
||||
/* ref: http://limulus.net/mdsplib */
|
||||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: metar.h */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 19 Jan 1996 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: METAR Decoder Header File. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* 7 Jul 2001 by Eric McCarthy: Made suitable for */
|
||||
/* use as header for the metar.a library. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
/* Used in the METAR structs. */
|
||||
typedef unsigned short int MDSP_BOOL;
|
||||
|
||||
|
||||
/*********************************************/
|
||||
/* */
|
||||
/* RUNWAY VISUAL RANGE STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*********************************************/
|
||||
|
||||
typedef struct runway_VisRange {
|
||||
char runway_designator[6];
|
||||
MDSP_BOOL vrbl_visRange;
|
||||
MDSP_BOOL below_min_RVR;
|
||||
MDSP_BOOL above_max_RVR;
|
||||
int visRange;
|
||||
int Max_visRange;
|
||||
int Min_visRange;
|
||||
} Runway_VisRange;
|
||||
|
||||
/***********************************************/
|
||||
/* */
|
||||
/* DISPATCH VISUAL RANGE STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/***********************************************/
|
||||
|
||||
typedef struct dispatch_VisRange {
|
||||
MDSP_BOOL vrbl_visRange;
|
||||
MDSP_BOOL below_min_DVR;
|
||||
MDSP_BOOL above_max_DVR;
|
||||
int visRange;
|
||||
int Max_visRange;
|
||||
int Min_visRange;
|
||||
} Dispatch_VisRange;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* CLOUD CONDITION STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct cloud_Conditions {
|
||||
char cloud_type[5];
|
||||
char cloud_hgt_char[4];
|
||||
char other_cld_phenom[4];
|
||||
int cloud_hgt_meters;
|
||||
} Cloud_Conditions;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* WIND GROUP DATA STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct windstruct {
|
||||
char windUnits[ 4 ];
|
||||
MDSP_BOOL windVRB;
|
||||
int windDir;
|
||||
int windSpeed;
|
||||
int windGust;
|
||||
} WindStruct;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* RECENT WX GROUP STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct recent_wx {
|
||||
char Recent_weather[ 5 ];
|
||||
int Bhh;
|
||||
int Bmm;
|
||||
int Ehh;
|
||||
int Emm;
|
||||
} Recent_Wx;
|
||||
|
||||
/***************************************/
|
||||
/* */
|
||||
/* DECODED METAR STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/***************************************/
|
||||
|
||||
typedef struct decoded_METAR {
|
||||
char synoptic_cloud_type[ 6 ];
|
||||
char snow_depth_group[ 6 ];
|
||||
char codeName[ 6 ];
|
||||
char stnid[5];
|
||||
char horiz_vsby[5];
|
||||
char dir_min_horiz_vsby[3];
|
||||
char vsby_Dir[ 3 ];
|
||||
char WxObstruct[10][8];
|
||||
char autoIndicator[5];
|
||||
char VSBY_2ndSite_LOC[10];
|
||||
char SKY_2ndSite_LOC[10];
|
||||
char SKY_2ndSite[10];
|
||||
char SectorVsby_Dir[ 3 ];
|
||||
char ObscurAloft[ 12 ];
|
||||
char ObscurAloftSkyCond[ 12 ];
|
||||
char VrbSkyBelow[ 4 ];
|
||||
char VrbSkyAbove[ 4 ];
|
||||
char LTG_DIR[ 3 ];
|
||||
char CloudLow;
|
||||
char CloudMedium;
|
||||
char CloudHigh;
|
||||
char CIG_2ndSite_LOC[10];
|
||||
char VIRGA_DIR[3];
|
||||
char TornadicType[15];
|
||||
char TornadicLOC[10];
|
||||
char TornadicDIR[4];
|
||||
char TornadicMovDir[3];
|
||||
char CHINO_LOC[6];
|
||||
char VISNO_LOC[6];
|
||||
char PartialObscurationAmt[2][7];
|
||||
char PartialObscurationPhenom[2][12];
|
||||
char SfcObscuration[6][10];
|
||||
char charPrevailVsby[12];
|
||||
char charVertVsby[10];
|
||||
char TS_LOC[3];
|
||||
char TS_MOVMNT[3];
|
||||
|
||||
MDSP_BOOL Indeterminant3_6HrPrecip;
|
||||
MDSP_BOOL Indeterminant_24HrPrecip;
|
||||
MDSP_BOOL CIGNO;
|
||||
MDSP_BOOL SLPNO;
|
||||
MDSP_BOOL ACFTMSHP;
|
||||
MDSP_BOOL NOSPECI;
|
||||
MDSP_BOOL FIRST;
|
||||
MDSP_BOOL LAST;
|
||||
MDSP_BOOL SunSensorOut;
|
||||
MDSP_BOOL AUTO;
|
||||
MDSP_BOOL COR;
|
||||
MDSP_BOOL NIL_rpt;
|
||||
MDSP_BOOL CAVOK;
|
||||
MDSP_BOOL RVRNO;
|
||||
MDSP_BOOL A_altstng;
|
||||
MDSP_BOOL Q_altstng;
|
||||
MDSP_BOOL VIRGA;
|
||||
MDSP_BOOL VOLCASH;
|
||||
MDSP_BOOL GR;
|
||||
MDSP_BOOL CHINO;
|
||||
MDSP_BOOL VISNO;
|
||||
MDSP_BOOL PNO;
|
||||
MDSP_BOOL PWINO;
|
||||
MDSP_BOOL FZRANO;
|
||||
MDSP_BOOL TSNO;
|
||||
MDSP_BOOL DollarSign;
|
||||
MDSP_BOOL PRESRR;
|
||||
MDSP_BOOL PRESFR;
|
||||
MDSP_BOOL Wshft_FROPA;
|
||||
MDSP_BOOL OCNL_LTG;
|
||||
MDSP_BOOL FRQ_LTG;
|
||||
MDSP_BOOL CNS_LTG;
|
||||
MDSP_BOOL CG_LTG;
|
||||
MDSP_BOOL IC_LTG;
|
||||
MDSP_BOOL CC_LTG;
|
||||
MDSP_BOOL CA_LTG;
|
||||
MDSP_BOOL DSNT_LTG;
|
||||
MDSP_BOOL AP_LTG;
|
||||
MDSP_BOOL VcyStn_LTG;
|
||||
MDSP_BOOL OVHD_LTG;
|
||||
MDSP_BOOL LightningVCTS;
|
||||
MDSP_BOOL LightningTS;
|
||||
|
||||
int TornadicDistance;
|
||||
int ob_hour;
|
||||
int ob_minute;
|
||||
int ob_date;
|
||||
int minWnDir;
|
||||
int maxWnDir;
|
||||
int VertVsby;
|
||||
int temp;
|
||||
int dew_pt_temp;
|
||||
int QFE;
|
||||
int hectoPasc_altstng;
|
||||
int char_prestndcy;
|
||||
int minCeiling;
|
||||
int maxCeiling;
|
||||
int WshfTime_hour;
|
||||
int WshfTime_minute;
|
||||
int min_vrbl_wind_dir;
|
||||
int max_vrbl_wind_dir;
|
||||
int PKWND_dir;
|
||||
int PKWND_speed;
|
||||
int PKWND_hour;
|
||||
int PKWND_minute;
|
||||
int SKY_2ndSite_Meters;
|
||||
int Ceiling;
|
||||
int Estimated_Ceiling;
|
||||
int SNINCR;
|
||||
int SNINCR_TotalDepth;
|
||||
int SunshineDur;
|
||||
int ObscurAloftHgt;
|
||||
int VrbSkyLayerHgt;
|
||||
int Num8thsSkyObscured;
|
||||
int CIG_2ndSite_Meters;
|
||||
int snow_depth;
|
||||
int BTornadicHour;
|
||||
int BTornadicMinute;
|
||||
int ETornadicHour;
|
||||
int ETornadicMinute;
|
||||
|
||||
|
||||
float SectorVsby;
|
||||
float WaterEquivSnow;
|
||||
float VSBY_2ndSite;
|
||||
float prevail_vsbySM;
|
||||
float prevail_vsbyM;
|
||||
float prevail_vsbyKM;
|
||||
float prestndcy;
|
||||
float precip_amt;
|
||||
float precip_24_amt;
|
||||
float maxtemp;
|
||||
float mintemp;
|
||||
float max24temp;
|
||||
float min24temp;
|
||||
float minVsby;
|
||||
float maxVsby;
|
||||
float hourlyPrecip;
|
||||
float TWR_VSBY;
|
||||
float SFC_VSBY;
|
||||
float Temp_2_tenths;
|
||||
float DP_Temp_2_tenths;
|
||||
float SLP;
|
||||
float GR_Size;
|
||||
|
||||
double inches_altstng;
|
||||
|
||||
Runway_VisRange RRVR[12];
|
||||
Dispatch_VisRange DVR;
|
||||
Recent_Wx ReWx[3];
|
||||
WindStruct winData;
|
||||
Cloud_Conditions cldTypHgt[6];
|
||||
|
||||
} Decoded_METAR;
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: DcdMETAR */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 14 Sep 1994 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: DcdMETAR takes a pointer to a METAR report char- */
|
||||
/* acter string as input, decodes the report, and */
|
||||
/* puts the individual decoded/parsed groups into */
|
||||
/* a structure that has the variable type */
|
||||
/* Decoded_METAR. */
|
||||
/* */
|
||||
/* Input: string - a pointer to a METAR report character */
|
||||
/* string. */
|
||||
/* */
|
||||
/* Output: Mptr - a pointer to a structure that has the */
|
||||
/* variable type Decoded_METAR. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* 3 Jul 2001 by Eric McCarthy: Added stringCpy */
|
||||
/* so cosnt char *'s could be passed in. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
int DcdMETAR( char *string , Decoded_METAR *Mptr );
|
||||
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: prtDMETR */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 15 Sep 1994 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: prtDMETR prints, in order of the ASOS METAR */
|
||||
/* format, all non-initialized members of the structure */
|
||||
/* addressed by the Decoded_METAR pointer. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* None. */
|
||||
/* */
|
||||
/* Input: Mptr - ptr to a decoded_METAR structure. */
|
||||
/* */
|
||||
/* Output: NONE */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
void prtDMETR( Decoded_METAR *Mptr );
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: dcdNetMETAR */
|
||||
/* Date: 24 Jul 2001 */
|
||||
/* Programmer: Eric McCarthy */
|
||||
/* Language: C */
|
||||
/* */
|
||||
/* Abstract: dcdNetMETAR */
|
||||
/* The METARs supplied by the NWS server need to */
|
||||
/* be reformatted before they can be sent through */
|
||||
/* dcdMETAR. This calls dcdMETAR on the correctly */
|
||||
/* formated METAR. */
|
||||
/* */
|
||||
/* Input: a pointer to a METAR string from a NWS server */
|
||||
/* */
|
||||
/* Output: Mptr - a pointer to a structure that has the */
|
||||
/* variable type Decoded_METAR. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
int dcdNetMETAR (char *string, Decoded_METAR *Mptr);
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: sprint_metar */
|
||||
/* Date: 24 Jul 2001 */
|
||||
/* Programmer: Eric McCarthy */
|
||||
/* Language: C */
|
||||
/* */
|
||||
/* Abstract: sprtDMETR */
|
||||
/* Does what prtDMETR does, but into a string. */
|
||||
/* */
|
||||
/* Input: string containing the printout, decoded METAR */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
void sprint_metar( char *string, Decoded_METAR *Mptr );
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma comment(compiler)
|
||||
#pragma comment(date)
|
||||
#pragma comment(timestamp)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#pragma title("antoi - char array to integer")
|
||||
#pragma pagesize (80)
|
||||
|
||||
#pragma page(1)
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: antoi */
|
||||
/* Date: Jan 28, 1991 */
|
||||
/* Organization: W/OSO242 - Graphics and Display Section */
|
||||
/* Programmer: Allan Darling */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: This function will convert a character array */
|
||||
/* (string) of length (len) into an integer. */
|
||||
/* The integer is created via a call to the */
|
||||
/* function atoi. This function extends the */
|
||||
/* functionality of atoi by removing the */
|
||||
/* requirement for a sentinal delimited string */
|
||||
/* as input. */
|
||||
/* */
|
||||
/* Input: - Pointer to an array of characters. */
|
||||
/* - Integer indicating the number of character to include */
|
||||
/* in the conversion. */
|
||||
/* */
|
||||
/* Output:- An integer corresponding to the value in the character */
|
||||
/* array or MAXNEG (-2147483648) if the function is */
|
||||
/* unable to acquire system storage. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
int antoi(char * string, int len)
|
||||
{
|
||||
|
||||
/*******************/
|
||||
/* local variables */
|
||||
/*******************/
|
||||
|
||||
char * tmpstr;
|
||||
int i,
|
||||
retval;
|
||||
|
||||
|
||||
/*****************/
|
||||
/* function body */
|
||||
/*****************/
|
||||
|
||||
tmpstr = malloc((len+1) * sizeof(char));
|
||||
|
||||
if (tmpstr == NULL) return (-2147483648);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
tmpstr[i] = string[i];
|
||||
|
||||
tmpstr[len] = '\0';
|
||||
|
||||
retval = atoi(tmpstr);
|
||||
|
||||
free(tmpstr);
|
||||
|
||||
return(retval);
|
||||
|
||||
} /* end antoi */
|
||||
|
||||
#pragma page(1)
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma comment (compiler)
|
||||
#pragma comment (date)
|
||||
#pragma comment (timestamp)
|
||||
#pragma pagesize(80)
|
||||
|
||||
#include "local.h" /* standard header file */
|
||||
|
||||
#pragma subtitle(" ")
|
||||
#pragma page(1)
|
||||
#pragma subtitle("charcmp - characters compare with patterns ")
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: charcmp */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 12 Dec 1995 */
|
||||
/* Programmer: CINDY L. CHONG */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: This function will compare each character in the */
|
||||
/* string match with each character in the pattern */
|
||||
/* which is made up of characters. The str can */
|
||||
/* be longer than the pattern. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* None. */
|
||||
/* */
|
||||
/* Input: str is a pointer to char */
|
||||
/* pattern is a pointer to char */
|
||||
/* */
|
||||
/* Output: Return true if str matches pattern, */
|
||||
/* otherwise, return false */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
#pragma page(1)
|
||||
|
||||
MDSP_BOOL charcmp(char *str, char *pattern)
|
||||
{
|
||||
|
||||
|
||||
/**********************************************************/
|
||||
/* Loop while str and pattern is not equal to null, then */
|
||||
/* inscreases str and pattern by one */
|
||||
/**********************************************************/
|
||||
|
||||
for (; *pattern != '\0'; pattern++)
|
||||
{
|
||||
if (*str == '\0')
|
||||
return FALSE;
|
||||
|
||||
/************************************************************/
|
||||
/* If pattern match str, then increase str and jump out the */
|
||||
/* case and read next char of the str and pattern */
|
||||
/************************************************************/
|
||||
|
||||
if ( isspace(*pattern) )
|
||||
pattern = nxtalpha(pattern);
|
||||
|
||||
switch( *pattern )
|
||||
{
|
||||
case 'c':
|
||||
if ( !isalnum(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
if ( !isalpha(*str) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
str++;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if ( !iscntrl(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if ( !isdigit(*str) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
str++;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if ( !isgraph(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if ( !islower(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if ( !isprint(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
if ( !ispunct(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if ( !isspace(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
if ( !isupper(*str++) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (*str++ != ' ')
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if ( !isspace(*str) )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ( isspace(*str) )
|
||||
str++;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
pattern++;
|
||||
if (*pattern != *str)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
pattern++;
|
||||
str++;
|
||||
break;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
|
||||
} /* end switch */
|
||||
|
||||
} /* end for */
|
||||
|
||||
return (TRUE);
|
||||
}
|
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,685 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "metar_structs.h"
|
||||
#ifdef SYNOPTIC
|
||||
|
||||
char *BldSynop( Decoded_METAR * , char * );
|
||||
/*char *Sec0MeSm(Decoded_METAR *);*/
|
||||
/*char *Sec1MeSm(Decoded_METAR *, char *);*/
|
||||
/*char *Sec3MeSm(Decoded_METAR *, char *);*/
|
||||
/*char *Sec5MeSm(Decoded_METAR *, char *);*/
|
||||
#endif
|
||||
|
||||
void prtDMETR( Decoded_METAR *);
|
||||
int DcdMETAR( char *, Decoded_METAR * );
|
||||
|
||||
#pragma page(1)
|
||||
#pragma subtitle(" ")
|
||||
#pragma subtitle("subtitle - description ")
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: dRVMETAR */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 28 Oct 1994 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: DRVMETAR is a main routine that acts a driver */
|
||||
/* for testing the METAR Decoder function. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* None. */
|
||||
/* DcdMETAR */
|
||||
/* prtDcdMetar */
|
||||
/* Sec0MTSm */
|
||||
/* Sec1MTSm */
|
||||
/* */
|
||||
/* Input: None */
|
||||
/* */
|
||||
/* Output: None */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
#pragma page(1)
|
||||
main()
|
||||
{
|
||||
static char *string[] =
|
||||
{
|
||||
|
||||
"KMKG 18022G29KT 3SM BR BKN018 BR 24/22 A2995 RMK A02 VIS 2",
|
||||
|
||||
|
||||
"KPIT 132351Z 33013KT 4SM +TSRA BR BKN018CB OVC031 12/11 A2977 RMK "
|
||||
"AO2 PK WND 31041/2305 WSHFT 2300 PRESSRR SLP090 FRQ LTGCGCC OHD "
|
||||
"TS OHD MOV E CB OHD MOV E 8/3// P0051 60052 T01170111 10222 20122 "
|
||||
"53030",
|
||||
|
||||
|
||||
"KCAK 132351Z 28016G22KT 10SM BKN021 OVC030 11/09 A2981 RMK AO2 "
|
||||
"TSE00RAE10 PRESRR SLP093 TS MOV NE CIG RGD 8/5// P0002 60066 "
|
||||
"T01110094 10217 20111 51053",
|
||||
|
||||
"KBUF 132354Z 21007KT 3SM +TSRA BR FEW009 OVC 12/11 A2959 RMK "
|
||||
"AO2 PRESFR SLP021 8/9// TS ALQDS MOV E OCNL LTGICCCCG P0031 "
|
||||
"60073 T01170111 10233 20111 50000 0",
|
||||
|
||||
|
||||
"KPIT 132356Z 32012G21KT 4SM TSRA BR BKN018CB OVC031 12/11 A2978 "
|
||||
"RMK AO2 WSHFT 2338 PRESFR FRQ LTGCGCC OHD TS OHD MOV E CB OHD MOV "
|
||||
"E P0001",
|
||||
|
||||
|
||||
"KCAK 132358Z 28015G22KT 10SM BKN013 OVC023 11/10 A2982 RMK AO2",
|
||||
|
||||
"KBUF 140001Z 22008KT 3SM +TSRA BR BKN009 BKN013 OVC022 12/12 A2959 "
|
||||
"RMK AO2 P0003",
|
||||
|
||||
|
||||
|
||||
"KRIL 031853Z AUTO 33008KT 10SM SCT022 BKN032 OVC060 07/01 A3004 "
|
||||
"RMK AO2 SLP157 T00720006 TSNO",
|
||||
|
||||
|
||||
"METAR KCLE 091657Z COR 35021KT 3SM -PL SHPL VV004 M03/M04 A2964 "
|
||||
"RMK VIS S M1/4=",
|
||||
|
||||
"METAR KCLE 091657Z COR 35021KT 3SM -PE SHPE VV004 M03/M04 A2964 "
|
||||
"RMK VIS S M1/4=",
|
||||
|
||||
"METAR KCLE 091657Z COR 35021KT 3SM -PE TSPL VV004 M03/M04 A2964 "
|
||||
"RMK VIS S M1/4=",
|
||||
|
||||
"METAR KCLE 091657Z COR 35021KT 3SM -PL TSPE VV004 M03/M04 A2964 "
|
||||
"RMK VIS S M1/4=",
|
||||
|
||||
|
||||
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FQT LTGIG W-N",
|
||||
|
||||
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FQT LTGIG W-N=",
|
||||
|
||||
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FRQ LTGIC NW",
|
||||
|
||||
"KMLB 200450Z 18006KT 7SM OVC100 23/22 A2986 RMK FRQ LTGCC NW=",
|
||||
|
||||
|
||||
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
|
||||
"RMK VIS N-NE M1/4",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
|
||||
|
||||
"METAR KLAX 281156Z AUTO VRB100G135KT 130V210 3 9999 "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
|
||||
"+TS VCTS FEW/// SCT000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
|
||||
"TORNADO B13 DSNT NE A01 PK WND 18515/45 "
|
||||
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"VIS 2 1/2 RWY11 "
|
||||
"DVR/1000V1600FT "
|
||||
"SHRAB05E30SHSNB20E55 FZDZB1057E1059 CIG 1000V1500 CIG 020 RWY11 "
|
||||
"PRESFR PRESRR SLP013 FG FEW/// HZ SCT000 VIS NW 2 1/2 GR 3/4 "
|
||||
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
|
||||
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
|
||||
"933125 98096 P0125 60225 70565 "
|
||||
"T00261015 10369 21026 "
|
||||
"404800360 52101 VISNO RWY05 CHINO RWY27 PNO RVRNO "
|
||||
"PWINO FZRANO TSNO $",
|
||||
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2 "
|
||||
"PWINO FZRANO TSNO $",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2 1/2 "
|
||||
"PWINO FZRANO TSNO $",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2 1/2=",
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK VIS S 2",
|
||||
|
||||
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
|
||||
"RMK VIS N-NE 1",
|
||||
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2=",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK VIS S 2=",
|
||||
|
||||
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
|
||||
"RMK VIS N-NE 1=",
|
||||
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW-NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK CIG 003V026 SLP046 ESTMD SLP VIS SW-NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK VIS S 2",
|
||||
|
||||
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
|
||||
"RMK VIS N-NE 1",
|
||||
|
||||
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK SLP046 ESTMD SLP VIS SW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK CIG 003V026 SLP046 ESTMD SLP VIS NW 2",
|
||||
|
||||
"METAR KAFF 091657Z COR 35021KT 3SM -SG BR VV004 M03/M04 A2964 "
|
||||
"RMK VIS S 2",
|
||||
|
||||
"SPECI KEKO 151609Z 00000KT 5SM BR FEW003 SCT013 M04/M06 A3018 "
|
||||
"RMK VIS NE 1",
|
||||
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1/8SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/12 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 6SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M12/M18 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 8SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/12 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 9SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/M01 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005TCU BKN010ACSL OVC250CB MM/12 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/MM A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M12 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/MM A2992",
|
||||
|
||||
"SPECI KGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
|
||||
"A2900 RMK A02A PK WND 18056/28 OCNL LTG AP "
|
||||
"RAB15E25TSB20 FCB1430 PRESFR "
|
||||
"SLP 701 P 0254 T01990182",
|
||||
|
||||
|
||||
"METAR KLAX 281156Z AUTO VRB100G135KT 130V210 3 9999 "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
|
||||
"+TS VCTS FEW/// SCT000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
|
||||
"TORNADO B13 DSNT NE A01 PK WND 18515/45 "
|
||||
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"VIS 2 1/2 RWY11 "
|
||||
"DVR/1000V1600FT "
|
||||
"SHRAB05E30SHSNB20E55 FZDZB1057E1059 CIG 1000V1500 CIG 020 RWY11 "
|
||||
"PRESFR PRESRR SLP013 FG FEW/// HZ SCT000 VIS NW 2 1/2 GR 3/4 "
|
||||
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
|
||||
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
|
||||
"933125 98096 P0125 60225 70565 "
|
||||
"T00261015 10369 21026 "
|
||||
"404800360 52101 VISNO RWY05 CHINO RWY27 PNO RVRNO "
|
||||
"PWINO FZRANO TSNO $",
|
||||
|
||||
"KP88 1919Z 09001KT 14/03 RMK AO / PKWND 002/RNO 158 Z T01440034",
|
||||
|
||||
"K40B 1924Z 29004KT 15/M07 RMK AO PKWND 011/RM MV263 T01501072",
|
||||
|
||||
|
||||
|
||||
"SPECI KGFI 041430Z COR 18045G56KT "
|
||||
"M1/4SM R15/0200FT R01L/0600V1000FT R01L/M0600FT R27/P6000FT "
|
||||
"+FC +TS -FZDZ VV010 04/M02 "
|
||||
"A2900 RMK TORNADO B13 6 NE A02A PK WND 18056/28 WSHFT 30 FROPA "
|
||||
"TWR VIS 1 1/2 VIS NE 2 1/2 VIS 2 1/2 RWY11 DVR/0600V1000FT "
|
||||
"OCNL LTGICCG OVHD RAB15E25 TSB20 FCB1430 TS SE MOV NE GR 1 3/4 "
|
||||
"VIRGA SW CIG 005V010 FG SCT000 BKN014 V OVC CB DSNT W "
|
||||
"CIG 002 RWY11 PRESFR PRESRR "
|
||||
"SLP701 ACFT MSHP NOSPECI SNINCR 2/10 FIRST "
|
||||
"P0254 60217 70125 4/021 933036 8/903 98096 T00261015 "
|
||||
"11021 21001 401120084 52032RVRNO PWINO PNO FZRANO TSNO "
|
||||
"VISNO RWY06 CHINO RWY12 $",
|
||||
|
||||
|
||||
|
||||
"KPHX 281156Z 12004KT 16KM CLR 15/05 A2996 RMK AOA SLP135 T01500050 "
|
||||
"10250 20150 53006",
|
||||
"KFCA 281156Z 30003KT 10SM CLR 06/02 A3009 RMRK AO TNO $ SLP191 "
|
||||
"T00610023 10167 20056 53003",
|
||||
"KAST 281156Z 00000KT 10SM BKN095 09/08 A2997 REMARK AOA SLP150 "
|
||||
"T00940084 10161 20094 52005 ",
|
||||
"KHVR 281156Z 03003KT 10SM OVC020 09/07 A3010 REMARKS AO TNO ZRNO "
|
||||
"$ SLP194 T00940073 10156 20089 51005",
|
||||
|
||||
"KGGW 281156Z 35006KT 5SM BR OVC010 10/09 A3003 RMK AOA $ SLP177 "
|
||||
"70003 T01000095 10156 20110 53008",
|
||||
"KELY 1153Z AUTO 14004KT 10SM SCT075 01/M01 A3011 RMK AOA TNO ZRNO "
|
||||
"SLP171 70001 T00061011 10139 21006 51005",
|
||||
"KFLG 281156Z 29006KT 10SM CLR 04/M01 A3012 RMK AO TNO SLP147 "
|
||||
"T00391011 21006 51004",
|
||||
"KGTF 281156Z 27005KT 7SM BKN080 04/04 A3010 RMK AOA SLP205 "
|
||||
"T00440045 10117 20039 51006",
|
||||
"KHLN 281156Z AUTO 27005KT 10SM OVC023 07/05 A3011 RMK AOA OVC V "
|
||||
"BKN $ SLP202 60000 70001 T00670050 10122 20061 53003",
|
||||
|
||||
"K13A 1918Z 20011KT 26/M06 RMK AO PKWND 020/RNO 644V264 T02611061",
|
||||
|
||||
|
||||
"KGGW 1756Z 33018KT 10SM OVC015 M03/M06 A3041 RMK AOA SLP338 "
|
||||
"4/007 60002 T10281055 11028 21072 51009",
|
||||
"KPHX 1756Z 130004KT 10SM CLR 18/M03 A3001 RMK AOA SLP154 "
|
||||
"T01781033 10178 20067 58007",
|
||||
"KFCA 1756Z 29005KT 10SM CLR 05/M11 A3049 RMK AOA TNO SLP352 "
|
||||
"T00501111 10050 21044 50004",
|
||||
"KAST 1756Z 01006KT 10SM CLR 11/04 A3047 RMK AOA SLP316 "
|
||||
"T01110045 10111 20000 50002",
|
||||
"KHVR 1756Z 31007KT 5SM -SN SCT011 BKN024 OVC030 M05/M08 A3056 "
|
||||
"RMK AOA 933004 "
|
||||
"BKN V SCT TNO P0000 $ SLP389 4/015 60002 "
|
||||
"T10501077 11050 21078 51010",
|
||||
"KELY 1753Z 34010KT 10SM CLR 01/M07 A3022 RMK AOA TNO FZRNO "
|
||||
"SLP240 T00111066 10011 21078 58007",
|
||||
"KFLG 1756Z 07006KT 10SM CLR 06/M12 A3009 RMK AO TNO FZRNO "
|
||||
"SLP178 T00561122 10061 21100 58005",
|
||||
"KGTF 1756Z 35010KT 1/2SM -SN FG VV09 M06/M08 A3051 RMK AOA "
|
||||
"933004 SFC VSBY 3/4 "
|
||||
"P0009 SLP393 60010 T10611077 11044 21067 53013",
|
||||
"KHLN 1756Z 35012KT 10SM SCT032 OVC060 M02/M09 A3048 RMK AOA "
|
||||
"SLP369 60000 T10171094 11017 21061 53006",
|
||||
"KAST 1756Z 01006KT 10SM CLR 11/04 A3047 RMK AOA SLP316 61104 "
|
||||
"71235 T01110045 10111 20000 401720056 58002",
|
||||
"METAR KLAX 04281156Z AUTO VRB100G135KT 130V210 3 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT FC "
|
||||
"+TS BLPY FEW000 BKN050 SCT150 OVC250 3/M1 A2991 RMK "
|
||||
"TORNADO B13 DSNT NE A02 PK WND 18515/45 "
|
||||
"WSHFT 1350 FROPA TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"VIS 2 1/2 RWY11 OCNL LTG VCY STN "
|
||||
"RAB1030E1145 FZDZE56 BLPYE57 CIG 1000V1500 CIG 020 RWY11 "
|
||||
"PRESFR PRESRR SLP013 FG FEW000 VIS NW2 1/2 GR 3/4 "
|
||||
"VIRGA SE -XRAFG3 CIGE005 BKN014 V OVC "
|
||||
"FU BKN020 NOSPECI LAST 8/365 SNINCR 2/10 4/178 "
|
||||
"933125 98096 P0125 60225 70565 "
|
||||
"T00261015 10369 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
|
||||
|
||||
"METAR KGFI 041356Z AUTO 17012KT 130V210 3 1/2SM R15L/0500FT -RA "
|
||||
"SCT050 OVC110 26/18 A2991 RMK FUNNEL CLOUDS A02 RAB30 "
|
||||
"SLP 101 GR M1/4 VIRGA SCT V BKN P 0010 T02640178",
|
||||
|
||||
"METAR KGFI 041356Z AUTO 05008KT 10SM R15L/P6000FT CLR A2991 "
|
||||
"RMK WATERSPOUTS VCY STN NW A02 SLP 101 10288 20243 52021 $ ",
|
||||
|
||||
"SPECI KGFI 041420Z AUTO 18030KT 3 1/2SM RVRNO TS -RA BKN008 OVC060 "
|
||||
"26/22 A2991 RMK A02 RA15TSB20 PRESFR SLP 101 P 0000 T02640218",
|
||||
|
||||
"KABE 281900Z NIL",
|
||||
|
||||
"METAR KPIT NIL",
|
||||
|
||||
"METAR KCLE 04281156Z 170100G135KT 110V180 M1/4SM "
|
||||
"R01L/P6000FT +TSSHRA VCFG "
|
||||
"BKN025 SCT100 OVC200 M26/ A2991 RMK PK WND 18515/45 A02 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"CIG 1000V1500 PRESFR FRQ LTG CG NW "
|
||||
"RAB1030E1145 FZDZE56 PRESRR SLP135 GS "
|
||||
"T1263 "
|
||||
"VIRGA NW 8/365 4/178 P 0125 60225 7//// 70565 10369 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
"METAR KPHL 040256Z AUTO 170100G135KT 130V210 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
|
||||
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 LTG DSNT "
|
||||
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP037 GR 2 3/4 "
|
||||
"VIRGA E 8/365 4/178 P 0125 70565 21026 T0263 10369 60225 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
"SPECI KGFI 041420Z AUTO 18030KT 2 1/2SM RVRNO TS -RA BKN008 "
|
||||
"OVC060 25/22 A2991 RMK A02 LTG DSNT W "
|
||||
"RAB15TSB20 PRESFR SLP101 P 0000 "
|
||||
"254/218",
|
||||
|
||||
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
|
||||
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR M1/4 "
|
||||
"VIRGA SE 8/365 4/178 P 0125 6//// 60225 70565 T0263 10369 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
|
||||
|
||||
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
|
||||
"FC +TS BKN050 SCT150 OVC250 M26/ A2991 RMK A02 PK WND 185150/1345 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
|
||||
"VIRGA 35 8/365 4/178 P 0125 6//// 60225 70565 T0263 10369 21026 "
|
||||
"VIRGA 35 8/365 4/178 P 0125 21026 70565 10369 60225 T0263 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
|
||||
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
|
||||
"FC +TS BKN050 SCT150 OVC250 3/M1 A2991 RMK A02 PK WND 18515/45 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
|
||||
"VIRGA 35 8/365 4/178 P 0125 60225 70565 T00261015 10369 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO $",
|
||||
|
||||
"METAR KGFI 041356Z AUTO 170100G135KT 130V210 3 1/2SM "
|
||||
"R15L/0500FT R22L/2700FT R16/1200FT R34/1000V1600FT R01L/P6000FT "
|
||||
"FC +TS BKN050 SCT150 OVC250 3/M1 A2991 RMK A02 PK WND 185150/1345 "
|
||||
"WSHFT 1350 TWR VIS 1 1/2 SFC VIS 1/4 VIS 1/4V1 1/4 "
|
||||
"RAB1030E1145 FZDZE56 CIG 1000V1500 PRESFR PRESRR SLP997 GR 25 "
|
||||
"VIRGA 35 8/365 4/178 P 0125 60225 70565 T00261015 10369 21026 "
|
||||
"404800360 52101 PWINO FZRANO TSNO",
|
||||
|
||||
|
||||
|
||||
"METAR KGFI 041356Z AUTO 05008KT 10SM R15L/P6000FT CLR A2991 RMK "
|
||||
"A02 SLP 101 10288 20243 52021",
|
||||
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
|
||||
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
|
||||
"SLP 701 P 0254 M199/M182",
|
||||
|
||||
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
|
||||
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
|
||||
"SLP 701 P 0254 M199/182",
|
||||
|
||||
"SPECI DGFI 041430Z 18045G56KT M1/4SM R15/0200FT FC +TS VV010 20/18 "
|
||||
"M20/M18 A2900 RMK A02A PK WND 18056/28 RAB15E25TSB20 FCB1430 PRESFR "
|
||||
"SLP 701 P 0254 199/M182",
|
||||
|
||||
"METAR APIT 171755Z AUTO 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 4/369 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 8/563 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1 1/2V2 SLP875 SGB1213E1225",
|
||||
|
||||
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
|
||||
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK SLP056 "
|
||||
"RAE0123",
|
||||
|
||||
"SPECI APIT 171755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 8/321 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1 SLP875 FGB1713",
|
||||
|
||||
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1V2 SLP875",
|
||||
|
||||
|
||||
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1 1/2V2 1/2 SLP875",
|
||||
|
||||
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1V2 1/2 SLP875",
|
||||
|
||||
|
||||
"EGPF 1720Z 00000KT 9999 -SHRA STC014 SCT020CB BNK024 12/09 "
|
||||
"Q1003 NOSIG",
|
||||
|
||||
"NZAA 1700Z 03010KT 30KM 03 5CU022 7SC035 11/07 Q1006.5 NOSIG",
|
||||
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
|
||||
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK KAUKAU 30050KT",
|
||||
"DGAA 1800Z 22012KT 9999 SCT009 BKN120 25/21 Q1015",
|
||||
"DAAT 1830Z 30010KT CAVOK 29/06 Q1019",
|
||||
|
||||
"GQPP 1800Z 34023KT 3000 DRSA SKC 24/20 Q1011 NSG",
|
||||
"DAAG 1830Z 06006KT 9999 SCT020 25/22 Q1015",
|
||||
"DABB 1830Z 04010KT 9999 SCT030TCU SCT033CB 27/18 Q1017",
|
||||
"DABC 1830Z 00000KT 9999 SCT026TCU SCT036CB 22/18 Q1020 RETS",
|
||||
|
||||
"NZAA 1700Z 03010KT 30KM 03 5CU022 7SC035 11/07 Q1006.5 NOSIG",
|
||||
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
|
||||
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK K",
|
||||
"NZWN 1700Z 35030G49KT 320V030 20KM 02 5SC021 7SC046 12/08 "
|
||||
" Q0994.2 TEMPO 6000 RA 5ST012 2CB015 RMK KAUKAU 30050KT",
|
||||
"DGAA 1800Z 22012KT 9999 SCT009 BKN120 25/21 Q1015",
|
||||
|
||||
"GFLL 1900Z NIL",
|
||||
|
||||
"GOOY 1800Z 03006G17KT 340V080 6000 TSRA BKN016 BKN030CB "
|
||||
"BKN133 26/23 Q1013 NOSIG",
|
||||
|
||||
"GCXO 1930Z 32018KT 8000 SCT003 SCT007 18/16 Q1019",
|
||||
|
||||
"APIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1 1/2V2",
|
||||
|
||||
"BPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1V2",
|
||||
|
||||
"CPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1V2 1/2",
|
||||
|
||||
"DPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1 1/2V2 1/2",
|
||||
|
||||
"EPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 1/2V3/4",
|
||||
|
||||
"FPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 3/4V2 1/2",
|
||||
|
||||
"GPIT 1755Z 22015G25KT 1 3/4SM R22L/2700FT R16/1200FT "
|
||||
"R34/1000V1600FT R01L/P6000FT R04RR/900FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/16 A2992 "
|
||||
"RMK 58033 6003/ TWELVE 70125 10039 20029 410840112 "
|
||||
"PCPN 0009 WSHFT 1715 PK WND 2032/1725 "
|
||||
"CIG 20V25 WND 12V25 TWR VIS 2 1/2 "
|
||||
"SFC VIS 1 1/2 VIS 3/4V3",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/M16 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/16 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB 18/M16 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/M16 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB MM/16 A2992",
|
||||
|
||||
"KPIT 1935Z 22015G25KT 1 3/4SM R22L/2700FT "
|
||||
"TSRA -DZ FG +SNPE SCT005 BKN010 OVC250CB M18/MM A2992",
|
||||
|
||||
|
||||
NULL};
|
||||
|
||||
/***************************/
|
||||
/* DECLARE LOCAL VARIABLES */
|
||||
/***************************/
|
||||
|
||||
Decoded_METAR Metar;
|
||||
Decoded_METAR *Mptr = &Metar;
|
||||
int j,
|
||||
ErReturn;
|
||||
static char *synopRTRN = NULL;
|
||||
char bltn_prefix[20];
|
||||
|
||||
/***************************************************/
|
||||
/* START BODY OF MAIN ROUTINE FOR CALLING DcdMETAR */
|
||||
/***************************************************/
|
||||
|
||||
j = 0;
|
||||
|
||||
while( string[j] != NULL)
|
||||
{
|
||||
/*-- PRINT INPUT METAR REPORT ----------------------------*/
|
||||
printf("\n\nINPUT METAR REPORT:\n\n %s\n\n",string[j] );
|
||||
|
||||
/*-- DECODE INPUT REPORT ---------------------------------*/
|
||||
if ( (ErReturn = DcdMETAR( string[ j ], Mptr )) != 0 )
|
||||
printf("DcdMETAR: Error Return Number: %d\n",ErReturn);
|
||||
|
||||
/*-- PRINT DECODED METAR REPORT ELEMENTS -----------------*/
|
||||
printf("\n\nFINAL DECODED PRODUCT...\n\n");
|
||||
prtDMETR( Mptr );
|
||||
#ifdef OLDSTUFF
|
||||
/************************************************/
|
||||
/* Convert Decoded METAR into Synoptic format */
|
||||
/************************************************/
|
||||
|
||||
printf("Just after call to prtDMETR\n");
|
||||
|
||||
sprintf( bltn_prefix, "AAXX YYGGi##," );
|
||||
synopRTRN = BldSynop( Mptr, bltn_prefix );
|
||||
printf("After BldSynop, SynopRep =:\n%s\n",synopRTRN);
|
||||
/**********************************************************/
|
||||
/*-- ENCODE SECTION 0 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
|
||||
/**********************************************************/
|
||||
printf("Just before call to Sec0MeSM\n");
|
||||
|
||||
if( (synopRTRN = Sec0MeSm( Mptr )) == NULL )
|
||||
printf("Sec0MeSm returned a NULL pointer\n");
|
||||
else
|
||||
printf("After Sec0MeSm: %s\n",synopRTRN);
|
||||
|
||||
/**********************************************************/
|
||||
/*-- ENCODE SECTION 1 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
|
||||
/**********************************************************/
|
||||
if( synopRTRN != NULL )
|
||||
synopRTRN = Sec1MeSm( Mptr,synopRTRN );
|
||||
printf("After Sec1MeSm: %s\n",synopRTRN);
|
||||
|
||||
/**********************************************************/
|
||||
/*-- ENCODE SECTION 3 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
|
||||
/**********************************************************/
|
||||
|
||||
if( synopRTRN != NULL )
|
||||
synopRTRN = Sec3MeSm( Mptr,synopRTRN );
|
||||
printf("After Sec3MeSm: %s\n",synopRTRN);
|
||||
|
||||
/**********************************************************/
|
||||
/*-- ENCODE SECTION 5 OF THE SYNTHETIC SYNOPTIC REPORT ---*/
|
||||
/**********************************************************/
|
||||
|
||||
if( synopRTRN != NULL )
|
||||
synopRTRN = Sec5MeSm( Mptr,synopRTRN);
|
||||
printf("After Sec5MeSm: %s\n",synopRTRN);
|
||||
|
||||
/**********************************************************/
|
||||
/*-- PRINT THE ENCODED SYNTHETIC SYNOPTIC REPORT ---------*/
|
||||
/**********************************************************/
|
||||
|
||||
if( synopRTRN != NULL ) {
|
||||
printf("\n\nOutput Synoptic Report: %s\n\n",synopRTRN);
|
||||
free( synopRTRN);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
j++;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "metar_structs.h"
|
||||
|
||||
#pragma subtitle(" ")
|
||||
#pragma page(1)
|
||||
#pragma subtitle("subtitle - description ")
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: fracPart */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 13 Jun 1995 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: Convert a character string fraction into a */
|
||||
/* decimal (floating point) number. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* None. */
|
||||
/* */
|
||||
/* Input: string - a pointer to a character string frac- */
|
||||
/* tion. */
|
||||
/* Output: A decimal (floating point) number. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
#pragma page(1)
|
||||
|
||||
float fracPart( char *string )
|
||||
{
|
||||
|
||||
/***************************/
|
||||
/* DECLARE LOCAL VARIABLES */
|
||||
/***************************/
|
||||
|
||||
char buf[ 6 ],
|
||||
*slash;
|
||||
|
||||
float numerator,
|
||||
denominator;
|
||||
|
||||
/*************************/
|
||||
/* START BODY OF ROUTINE */
|
||||
/*************************/
|
||||
|
||||
slash = strchr(string, '/');
|
||||
|
||||
memset(buf , '\0', 6);
|
||||
strncpy( buf, string, slash-string);
|
||||
|
||||
numerator = (float) atoi(buf);
|
||||
|
||||
memset(buf , '\0', 6);
|
||||
strcpy( buf, slash+1);
|
||||
|
||||
denominator = (float) atoi(buf);
|
||||
|
||||
if( denominator == 0.0 )
|
||||
return ((float) MAXINT);
|
||||
else
|
||||
return (numerator/denominator);
|
||||
|
||||
}
|
||||
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,283 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef METARX
|
||||
#define METARX
|
||||
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: METAR H */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 19 Jan 1996 */
|
||||
/* Programmer: CARL MCCALLA */
|
||||
/* Language: C/370 */
|
||||
/* */
|
||||
/* Abstract: METAR Decoder Header File. */
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
|
||||
|
||||
#include "local.h" /* standard header file */
|
||||
|
||||
|
||||
/*********************************************/
|
||||
/* */
|
||||
/* RUNWAY VISUAL RANGE STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*********************************************/
|
||||
|
||||
typedef struct runway_VisRange {
|
||||
char runway_designator[6];
|
||||
MDSP_BOOL vrbl_visRange;
|
||||
MDSP_BOOL below_min_RVR;
|
||||
MDSP_BOOL above_max_RVR;
|
||||
int visRange;
|
||||
int Max_visRange;
|
||||
int Min_visRange;
|
||||
} Runway_VisRange;
|
||||
|
||||
/***********************************************/
|
||||
/* */
|
||||
/* DISPATCH VISUAL RANGE STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/***********************************************/
|
||||
|
||||
typedef struct dispatch_VisRange {
|
||||
MDSP_BOOL vrbl_visRange;
|
||||
MDSP_BOOL below_min_DVR;
|
||||
MDSP_BOOL above_max_DVR;
|
||||
int visRange;
|
||||
int Max_visRange;
|
||||
int Min_visRange;
|
||||
} Dispatch_VisRange;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* CLOUD CONDITION STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct cloud_Conditions {
|
||||
char cloud_type[5];
|
||||
char cloud_hgt_char[4];
|
||||
char other_cld_phenom[4];
|
||||
int cloud_hgt_meters;
|
||||
} Cloud_Conditions;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* WIND GROUP DATA STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct windstruct {
|
||||
char windUnits[ 4 ];
|
||||
MDSP_BOOL windVRB;
|
||||
int windDir;
|
||||
int windSpeed;
|
||||
int windGust;
|
||||
} WindStruct;
|
||||
|
||||
/*****************************************/
|
||||
/* */
|
||||
/* RECENT WX GROUP STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/*****************************************/
|
||||
|
||||
typedef struct recent_wx {
|
||||
char Recent_weather[ 5 ];
|
||||
int Bhh;
|
||||
int Bmm;
|
||||
int Ehh;
|
||||
int Emm;
|
||||
} Recent_Wx;
|
||||
|
||||
/***************************************/
|
||||
/* */
|
||||
/* DECODED METAR STRUCTURE DECLARATION */
|
||||
/* AND VARIABLE TYPE DEFINITION */
|
||||
/* */
|
||||
/***************************************/
|
||||
|
||||
typedef struct decoded_METAR {
|
||||
char synoptic_cloud_type[ 6 ];
|
||||
char snow_depth_group[ 6 ];
|
||||
char codeName[ 6 ];
|
||||
char stnid[5];
|
||||
char horiz_vsby[5];
|
||||
char dir_min_horiz_vsby[3];
|
||||
char vsby_Dir[ 3 ];
|
||||
char WxObstruct[10][8];
|
||||
char autoIndicator[5];
|
||||
char VSBY_2ndSite_LOC[10];
|
||||
char SKY_2ndSite_LOC[10];
|
||||
char SKY_2ndSite[10];
|
||||
char SectorVsby_Dir[ 3 ];
|
||||
char ObscurAloft[ 12 ];
|
||||
char ObscurAloftSkyCond[ 12 ];
|
||||
char VrbSkyBelow[ 4 ];
|
||||
char VrbSkyAbove[ 4 ];
|
||||
char LTG_DIR[ 3 ];
|
||||
char CloudLow;
|
||||
char CloudMedium;
|
||||
char CloudHigh;
|
||||
char CIG_2ndSite_LOC[10];
|
||||
char VIRGA_DIR[3];
|
||||
char TornadicType[15];
|
||||
char TornadicLOC[10];
|
||||
char TornadicDIR[4];
|
||||
char TornadicMovDir[3];
|
||||
char CHINO_LOC[6];
|
||||
char VISNO_LOC[6];
|
||||
char PartialObscurationAmt[2][7];
|
||||
char PartialObscurationPhenom[2][12];
|
||||
char SfcObscuration[6][10];
|
||||
char charPrevailVsby[12];
|
||||
char charVertVsby[10];
|
||||
char TS_LOC[3];
|
||||
char TS_MOVMNT[3];
|
||||
|
||||
MDSP_BOOL Indeterminant3_6HrPrecip;
|
||||
MDSP_BOOL Indeterminant_24HrPrecip;
|
||||
MDSP_BOOL CIGNO;
|
||||
MDSP_BOOL SLPNO;
|
||||
MDSP_BOOL ACFTMSHP;
|
||||
MDSP_BOOL NOSPECI;
|
||||
MDSP_BOOL FIRST;
|
||||
MDSP_BOOL LAST;
|
||||
MDSP_BOOL SunSensorOut;
|
||||
MDSP_BOOL AUTO;
|
||||
MDSP_BOOL COR;
|
||||
MDSP_BOOL NIL_rpt;
|
||||
MDSP_BOOL CAVOK;
|
||||
MDSP_BOOL RVRNO;
|
||||
MDSP_BOOL A_altstng;
|
||||
MDSP_BOOL Q_altstng;
|
||||
MDSP_BOOL VIRGA;
|
||||
MDSP_BOOL VOLCASH;
|
||||
MDSP_BOOL GR;
|
||||
MDSP_BOOL CHINO;
|
||||
MDSP_BOOL VISNO;
|
||||
MDSP_BOOL PNO;
|
||||
MDSP_BOOL PWINO;
|
||||
MDSP_BOOL FZRANO;
|
||||
MDSP_BOOL TSNO;
|
||||
MDSP_BOOL DollarSign;
|
||||
MDSP_BOOL PRESRR;
|
||||
MDSP_BOOL PRESFR;
|
||||
MDSP_BOOL Wshft_FROPA;
|
||||
MDSP_BOOL OCNL_LTG;
|
||||
MDSP_BOOL FRQ_LTG;
|
||||
MDSP_BOOL CNS_LTG;
|
||||
MDSP_BOOL CG_LTG;
|
||||
MDSP_BOOL IC_LTG;
|
||||
MDSP_BOOL CC_LTG;
|
||||
MDSP_BOOL CA_LTG;
|
||||
MDSP_BOOL DSNT_LTG;
|
||||
MDSP_BOOL AP_LTG;
|
||||
MDSP_BOOL VcyStn_LTG;
|
||||
MDSP_BOOL OVHD_LTG;
|
||||
MDSP_BOOL LightningVCTS;
|
||||
MDSP_BOOL LightningTS;
|
||||
|
||||
int TornadicDistance;
|
||||
int ob_hour;
|
||||
int ob_minute;
|
||||
int ob_date;
|
||||
int minWnDir;
|
||||
int maxWnDir;
|
||||
int VertVsby;
|
||||
int temp;
|
||||
int dew_pt_temp;
|
||||
int QFE;
|
||||
int hectoPasc_altstng;
|
||||
int char_prestndcy;
|
||||
int minCeiling;
|
||||
int maxCeiling;
|
||||
int WshfTime_hour;
|
||||
int WshfTime_minute;
|
||||
int min_vrbl_wind_dir;
|
||||
int max_vrbl_wind_dir;
|
||||
int PKWND_dir;
|
||||
int PKWND_speed;
|
||||
int PKWND_hour;
|
||||
int PKWND_minute;
|
||||
int SKY_2ndSite_Meters;
|
||||
int Ceiling;
|
||||
int Estimated_Ceiling;
|
||||
int SNINCR;
|
||||
int SNINCR_TotalDepth;
|
||||
int SunshineDur;
|
||||
int ObscurAloftHgt;
|
||||
int VrbSkyLayerHgt;
|
||||
int Num8thsSkyObscured;
|
||||
int CIG_2ndSite_Meters;
|
||||
int snow_depth;
|
||||
int BTornadicHour;
|
||||
int BTornadicMinute;
|
||||
int ETornadicHour;
|
||||
int ETornadicMinute;
|
||||
|
||||
|
||||
float SectorVsby;
|
||||
float WaterEquivSnow;
|
||||
float VSBY_2ndSite;
|
||||
float prevail_vsbySM;
|
||||
float prevail_vsbyM;
|
||||
float prevail_vsbyKM;
|
||||
float prestndcy;
|
||||
float precip_amt;
|
||||
float precip_24_amt;
|
||||
float maxtemp;
|
||||
float mintemp;
|
||||
float max24temp;
|
||||
float min24temp;
|
||||
float minVsby;
|
||||
float maxVsby;
|
||||
float hourlyPrecip;
|
||||
float TWR_VSBY;
|
||||
float SFC_VSBY;
|
||||
float Temp_2_tenths;
|
||||
float DP_Temp_2_tenths;
|
||||
float SLP;
|
||||
float GR_Size;
|
||||
|
||||
double inches_altstng;
|
||||
|
||||
Runway_VisRange RRVR[12];
|
||||
Dispatch_VisRange DVR;
|
||||
Recent_Wx ReWx[3];
|
||||
WindStruct winData;
|
||||
Cloud_Conditions cldTypHgt[6];
|
||||
|
||||
} Decoded_METAR;
|
||||
|
||||
#define MAXWXSYMBOLS 10 /*-- NOT TO EXCEED 10 PRES. WX GRPS --*/
|
||||
#define MAXTOKENS 500 /*-- RPT NOT TO EXCEED 500 GRPS --*/
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,963 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "metar_structs.h"
|
||||
|
||||
|
||||
void say_text(char *speech, char *text) {
|
||||
int i;
|
||||
char tmp[2];
|
||||
for (i = 0; i < strlen(text); i++) {
|
||||
switch(text[i]) {
|
||||
case '-':
|
||||
strcat(speech, "minus");
|
||||
break;
|
||||
case '0':
|
||||
strcat(speech, "zero");
|
||||
break;
|
||||
case '1':
|
||||
strcat(speech, "one");
|
||||
break;
|
||||
case '2':
|
||||
strcat(speech, "two");
|
||||
break;
|
||||
case '3':
|
||||
strcat(speech, "three");
|
||||
break;
|
||||
case '4':
|
||||
strcat(speech, "four");
|
||||
break;
|
||||
case '5':
|
||||
strcat(speech, "five");
|
||||
break;
|
||||
case '6':
|
||||
strcat(speech, "six");
|
||||
break;
|
||||
case '7':
|
||||
strcat(speech, "seven");
|
||||
break;
|
||||
case '8':
|
||||
strcat(speech, "eight");
|
||||
break;
|
||||
case '9':
|
||||
strcat(speech, "niner");
|
||||
break;
|
||||
case '@':
|
||||
strcat(speech, "at");
|
||||
break;
|
||||
default:
|
||||
sprintf(tmp, "%c", text[i]);
|
||||
strcat(speech, tmp);
|
||||
break;
|
||||
}
|
||||
strcat(speech, " ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sprint_metar (char * string, Decoded_METAR *Mptr)
|
||||
{
|
||||
|
||||
/***************************/
|
||||
/* DECLARE LOCAL VARIABLES */
|
||||
/***************************/
|
||||
|
||||
int i;
|
||||
char temp[100];
|
||||
|
||||
/*************************/
|
||||
/* START BODY OF ROUTINE */
|
||||
/*************************/
|
||||
|
||||
|
||||
strcat(string, "ME TAR. ");
|
||||
|
||||
if ( Mptr->stnid[ 0 ] == '\0' ) {
|
||||
strcat(string, "Error");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < strlen(Mptr->stnid); i++) {
|
||||
sprintf(temp, "%c ", Mptr->stnid[i]);
|
||||
strcat(string, temp);
|
||||
}
|
||||
strcat(string, ". ");
|
||||
|
||||
if (Mptr->ob_hour != MAXINT && Mptr->ob_minute != MAXINT) {
|
||||
if (Mptr->AUTO) {
|
||||
strcat(string, "Automated ");
|
||||
}
|
||||
if (Mptr->COR) {
|
||||
strcat(string, "Corrected ");
|
||||
}
|
||||
strcat(string, "Observation ");
|
||||
sprintf(temp, "%d%d", Mptr->ob_hour, Mptr->ob_minute);
|
||||
say_text(string, temp);
|
||||
strcat(string, "zulu. ");
|
||||
}
|
||||
|
||||
strcat(string, "Wind ");
|
||||
if (Mptr->winData.windDir != MAXINT) {
|
||||
sprintf(temp, "%03d", Mptr->winData.windDir);
|
||||
say_text(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->winData.windVRB ) {
|
||||
strcat(string, "variable ");
|
||||
}
|
||||
|
||||
//FIXME.
|
||||
if ( Mptr->minWnDir != MAXINT ) {
|
||||
sprintf(temp, "%03d", Mptr->minWnDir);
|
||||
say_text(string, temp);
|
||||
}
|
||||
|
||||
//FIXME.
|
||||
if ( Mptr->maxWnDir != MAXINT ) {
|
||||
sprintf(temp, "%03d", Mptr->maxWnDir);
|
||||
say_text(string, temp);
|
||||
}
|
||||
|
||||
|
||||
if ( Mptr->winData.windSpeed != MAXINT ) {
|
||||
sprintf(temp, "@%d", Mptr->winData.windSpeed);
|
||||
say_text(string, temp);
|
||||
} else {
|
||||
strcat(string, "calm ");
|
||||
}
|
||||
|
||||
if ( Mptr->winData.windGust != MAXINT ) {
|
||||
strcat(string, "gusting ");
|
||||
sprintf(temp, "%d", Mptr->winData.windGust);
|
||||
say_text(string, temp);
|
||||
}
|
||||
|
||||
strcat(string, ". ");
|
||||
|
||||
if ( Mptr->prevail_vsbyM != (float) MAXINT ) {
|
||||
strcat(string, "Visibility ");
|
||||
sprintf(temp, "%d", (int)Mptr->prevail_vsbyM);
|
||||
say_text(string, temp);
|
||||
strcat(string, "miles. ");
|
||||
}
|
||||
|
||||
if ( Mptr->prevail_vsbySM != (float) MAXINT ) {
|
||||
strcat(string, "Visibility ");
|
||||
sprintf(temp, "%d", (int)Mptr->prevail_vsbySM);
|
||||
say_text(string, temp);
|
||||
strcat(string, "miles. ");
|
||||
}
|
||||
|
||||
|
||||
/* for ( i = 0; i < 12; i++ )
|
||||
{
|
||||
if( Mptr->RRVR[i].runway_designator[0] != '\0' ) {
|
||||
sprintf(temp, "RUNWAY DESIGNATOR : %s\n",
|
||||
Mptr->RRVR[i].runway_designator);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->RRVR[i].visRange != MAXINT ) {
|
||||
sprintf(temp, "R_WAY VIS RANGE (FT): %d\n",
|
||||
Mptr->RRVR[i].visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->RRVR[i].vrbl_visRange ) {
|
||||
sprintf(temp, "VRBL VISUAL RANGE : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->RRVR[i].below_min_RVR ) {
|
||||
sprintf(temp, "BELOW MIN RVR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->RRVR[i].above_max_RVR ) {
|
||||
sprintf(temp, "ABOVE MAX RVR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->RRVR[i].Max_visRange != MAXINT ) {
|
||||
sprintf(temp, "MX R_WAY VISRNG (FT): %d\n",
|
||||
Mptr->RRVR[i].Max_visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->RRVR[i].Min_visRange != MAXINT ) {
|
||||
sprintf(temp, "MN R_WAY VISRNG (FT): %d\n",
|
||||
Mptr->RRVR[i].Min_visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if( Mptr->DVR.visRange != MAXINT ) {
|
||||
sprintf(temp, "DISPATCH VIS RANGE : %d\n",
|
||||
Mptr->DVR.visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DVR.vrbl_visRange ) {
|
||||
sprintf(temp, "VRBL DISPATCH VISRNG: TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DVR.below_min_DVR ) {
|
||||
sprintf(temp, "BELOW MIN DVR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DVR.above_max_DVR ) {
|
||||
sprintf(temp, "ABOVE MAX DVR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->DVR.Max_visRange != MAXINT ) {
|
||||
sprintf(temp, "MX DSPAT VISRNG (FT): %d\n",
|
||||
Mptr->DVR.Max_visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->DVR.Min_visRange != MAXINT ) {
|
||||
sprintf(temp, "MN DSPAT VISRNG (FT): %d\n",
|
||||
Mptr->DVR.Min_visRange);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
i = 0;
|
||||
while ( Mptr->WxObstruct[i][0] != '\0' && i < MAXWXSYMBOLS )
|
||||
{
|
||||
sprintf(temp, "WX/OBSTRUCT VISION : %s\n",
|
||||
Mptr->WxObstruct[i] );
|
||||
strcat(string, temp);
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( Mptr->PartialObscurationAmt[0][0] != '\0' ) {
|
||||
sprintf(temp, "OBSCURATION AMOUNT : %s\n",
|
||||
&(Mptr->PartialObscurationAmt[0][0]));
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PartialObscurationPhenom[0][0] != '\0' ) {
|
||||
sprintf(temp, "OBSCURATION PHENOM : %s\n",
|
||||
&(Mptr->PartialObscurationPhenom[0][0]));
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
if ( Mptr->PartialObscurationAmt[1][0] != '\0' ) {
|
||||
sprintf(temp, "OBSCURATION AMOUNT : %s\n",
|
||||
&(Mptr->PartialObscurationAmt[1][0]));
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PartialObscurationPhenom[1][0] != '\0' ) {
|
||||
sprintf(temp, "OBSCURATION PHENOM : %s\n",
|
||||
&(Mptr->PartialObscurationPhenom[1][0]));
|
||||
strcat(string, temp);
|
||||
}
|
||||
*/
|
||||
|
||||
strcat(string, "Sky condition ");
|
||||
|
||||
i = 0;
|
||||
while ( Mptr->cldTypHgt[ i ].cloud_type[0] != '\0' &&
|
||||
i < 6 )
|
||||
{
|
||||
if ( Mptr->cldTypHgt[ i ].cloud_type[0] != '\0' ) {
|
||||
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "CLR") == 0) {
|
||||
strcat(string, "clear. ");
|
||||
} else {
|
||||
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "FEW") == 0) {
|
||||
strcat(string, "scattered ");
|
||||
}
|
||||
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "SCT") == 0) {
|
||||
strcat(string, "scattered ");
|
||||
}
|
||||
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "BKN") == 0) {
|
||||
strcat(string, "broken ");
|
||||
}
|
||||
if (strcmp(Mptr->cldTypHgt[ i ].cloud_type, "OVC") == 0) {
|
||||
strcat(string, "overcast ");
|
||||
}
|
||||
//TODO: Others?
|
||||
}
|
||||
}
|
||||
|
||||
if ( Mptr->cldTypHgt[ i ].cloud_hgt_char[0] != '\0' ) {
|
||||
char thousands[4];
|
||||
char hundreds[4];
|
||||
int height = atoi(Mptr->cldTypHgt[i].cloud_hgt_char);
|
||||
if ((height - (height%10)) > 0) {
|
||||
sprintf(thousands, "%d", height/10);
|
||||
say_text(string, thousands);
|
||||
strcat(string, "thousand ");
|
||||
}
|
||||
if (height%10) {
|
||||
sprintf(hundreds, "%d", height%10);
|
||||
say_text(string, hundreds);
|
||||
strcat(string, "hundred ");
|
||||
}
|
||||
}
|
||||
|
||||
strcat(string, ". ");
|
||||
/*
|
||||
//TODO: TCU, Towering Cumulus, etc.
|
||||
if ( Mptr->cldTypHgt[ i ].other_cld_phenom[0] != '\0' ) {
|
||||
sprintf(temp, "OTHER CLOUD PHENOM : %s\n",
|
||||
Mptr->cldTypHgt[ i ].other_cld_phenom);
|
||||
strcat(string, temp);
|
||||
}
|
||||
*/
|
||||
|
||||
i++;
|
||||
|
||||
}
|
||||
|
||||
if ( Mptr->temp != MAXINT ) {
|
||||
strcat(string, "Temperature ");
|
||||
sprintf(temp, "%d", Mptr->temp);
|
||||
say_text(string, temp);
|
||||
strcat(string, "celsius. ");
|
||||
}
|
||||
|
||||
if ( Mptr->dew_pt_temp != MAXINT ) {
|
||||
strcat(string, "Dew point ");
|
||||
sprintf(temp, "%d", Mptr->dew_pt_temp);
|
||||
say_text(string, temp);
|
||||
strcat(string, "celsius. ");
|
||||
}
|
||||
|
||||
if ( Mptr->A_altstng ) {
|
||||
strcat(string, "Altimeter ");
|
||||
sprintf(temp, "%d", (int)Mptr->inches_altstng);
|
||||
say_text(string, temp);
|
||||
strcat(string, ", ");
|
||||
sprintf(temp, "%02d", (int)(100*Mptr->inches_altstng)%100);
|
||||
say_text(string, temp);
|
||||
strcat(string, ". ");
|
||||
}
|
||||
|
||||
/*
|
||||
if ( Mptr->TornadicType[0] != '\0' ) {
|
||||
sprintf(temp, "TORNADIC ACTVTY TYPE: %s\n",
|
||||
Mptr->TornadicType );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->BTornadicHour != MAXINT ) {
|
||||
sprintf(temp, "TORN. ACTVTY BEGHOUR: %d\n",
|
||||
Mptr->BTornadicHour );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->BTornadicMinute != MAXINT ) {
|
||||
sprintf(temp, "TORN. ACTVTY BEGMIN : %d\n",
|
||||
Mptr->BTornadicMinute );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ETornadicHour != MAXINT ) {
|
||||
sprintf(temp, "TORN. ACTVTY ENDHOUR: %d\n",
|
||||
Mptr->ETornadicHour );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ETornadicMinute != MAXINT ) {
|
||||
sprintf(temp, "TORN. ACTVTY ENDMIN : %d\n",
|
||||
Mptr->ETornadicMinute );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TornadicDistance != MAXINT ) {
|
||||
sprintf(temp, "TORN. DIST. FROM STN: %d\n",
|
||||
Mptr->TornadicDistance );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TornadicLOC[0] != '\0' ) {
|
||||
sprintf(temp, "TORNADIC LOCATION : %s\n",
|
||||
Mptr->TornadicLOC );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TornadicDIR[0] != '\0' ) {
|
||||
sprintf(temp, "TORNAD. DIR FROM STN: %s\n",
|
||||
Mptr->TornadicDIR );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TornadicMovDir[0] != '\0' ) {
|
||||
sprintf(temp, "TORNADO DIR OF MOVM.: %s\n",
|
||||
Mptr->TornadicMovDir );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
if ( Mptr->autoIndicator[0] != '\0' ) {
|
||||
sprintf(temp, "AUTO INDICATOR : %s\n",
|
||||
Mptr->autoIndicator);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PKWND_dir != MAXINT ) {
|
||||
sprintf(temp, "PEAK WIND DIRECTION : %d\n",Mptr->PKWND_dir);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->PKWND_speed != MAXINT ) {
|
||||
sprintf(temp, "PEAK WIND SPEED : %d\n",Mptr->PKWND_speed);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->PKWND_hour != MAXINT ) {
|
||||
sprintf(temp, "PEAK WIND HOUR : %d\n",Mptr->PKWND_hour);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->PKWND_minute != MAXINT ) {
|
||||
sprintf(temp, "PEAK WIND MINUTE : %d\n",Mptr->PKWND_minute);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->WshfTime_hour != MAXINT ) {
|
||||
sprintf(temp, "HOUR OF WIND SHIFT : %d\n",Mptr->WshfTime_hour);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->WshfTime_minute != MAXINT ) {
|
||||
sprintf(temp, "MINUTE OF WIND SHIFT: %d\n",Mptr->WshfTime_minute);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->Wshft_FROPA != FALSE ) {
|
||||
sprintf(temp, "FROPA ASSOC. W/WSHFT: TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TWR_VSBY != (float) MAXINT ) {
|
||||
sprintf(temp, "TOWER VISIBILITY : %.2f\n",Mptr->TWR_VSBY);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->SFC_VSBY != (float) MAXINT ) {
|
||||
sprintf(temp, "SURFACE VISIBILITY : %.2f\n",Mptr->SFC_VSBY);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->minVsby != (float) MAXINT ) {
|
||||
sprintf(temp, "MIN VRBL_VIS (SM) : %.4f\n",Mptr->minVsby);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->maxVsby != (float) MAXINT ) {
|
||||
sprintf(temp, "MAX VRBL_VIS (SM) : %.4f\n",Mptr->maxVsby);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->VSBY_2ndSite != (float) MAXINT ) {
|
||||
sprintf(temp, "VSBY_2ndSite (SM) : %.4f\n",Mptr->VSBY_2ndSite);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->VSBY_2ndSite_LOC[0] != '\0' ) {
|
||||
sprintf(temp, "VSBY_2ndSite LOC. : %s\n",
|
||||
Mptr->VSBY_2ndSite_LOC);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->OCNL_LTG ) {
|
||||
sprintf(temp, "OCCASSIONAL LTG : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->FRQ_LTG ) {
|
||||
sprintf(temp, "FREQUENT LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CNS_LTG ) {
|
||||
sprintf(temp, "CONTINUOUS LTG : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CG_LTG ) {
|
||||
sprintf(temp, "CLOUD-GROUND LTG : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->IC_LTG ) {
|
||||
sprintf(temp, "IN-CLOUD LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CC_LTG ) {
|
||||
sprintf(temp, "CLD-CLD LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CA_LTG ) {
|
||||
sprintf(temp, "CLOUD-AIR LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->AP_LTG ) {
|
||||
sprintf(temp, "LIGHTNING AT AIRPORT: TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->OVHD_LTG ) {
|
||||
sprintf(temp, "LIGHTNING OVERHEAD : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DSNT_LTG ) {
|
||||
sprintf(temp, "DISTANT LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->LightningVCTS ) {
|
||||
sprintf(temp, "L'NING W/I 5-10(ALP): TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->LightningTS ) {
|
||||
sprintf(temp, "L'NING W/I 5 (ALP) : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VcyStn_LTG ) {
|
||||
sprintf(temp, "VCY STN LIGHTNING : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->LTG_DIR[0] != '\0' ) {
|
||||
sprintf(temp, "DIREC. OF LIGHTNING : %s\n", Mptr->LTG_DIR);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
i = 0;
|
||||
while( i < 3 && Mptr->ReWx[ i ].Recent_weather[0] != '\0' )
|
||||
{
|
||||
sprintf(temp, "RECENT WEATHER : %s",
|
||||
Mptr->ReWx[i].Recent_weather);
|
||||
strcat(string, temp);
|
||||
|
||||
if ( Mptr->ReWx[i].Bhh != MAXINT ) {
|
||||
sprintf(temp, " BEG_hh = %d",Mptr->ReWx[i].Bhh);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->ReWx[i].Bmm != MAXINT ) {
|
||||
sprintf(temp, " BEG_mm = %d",Mptr->ReWx[i].Bmm);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ReWx[i].Ehh != MAXINT ) {
|
||||
sprintf(temp, " END_hh = %d",Mptr->ReWx[i].Ehh);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->ReWx[i].Emm != MAXINT ) {
|
||||
sprintf(temp, " END_mm = %d",Mptr->ReWx[i].Emm);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
strcat(string, "\n");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( Mptr->minCeiling != MAXINT ) {
|
||||
sprintf(temp, "MIN VRBL_CIG (FT) : %d\n",Mptr->minCeiling);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->maxCeiling != MAXINT ) {
|
||||
sprintf(temp, "MAX VRBL_CIG (FT)) : %d\n",Mptr->maxCeiling);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CIG_2ndSite_Meters != MAXINT ) {
|
||||
sprintf(temp, "CIG2ndSite (FT) : %d\n",Mptr->CIG_2ndSite_Meters);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->CIG_2ndSite_LOC[0] != '\0' ) {
|
||||
sprintf(temp, "CIG @ 2nd Site LOC. : %s\n",Mptr->CIG_2ndSite_LOC);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PRESFR ) {
|
||||
sprintf(temp, "PRESFR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->PRESRR ) {
|
||||
sprintf(temp, "PRESRR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SLPNO ) {
|
||||
sprintf(temp, "SLPNO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SLP != (float) MAXINT ) {
|
||||
sprintf(temp, "SLP (hPa) : %.1f\n", Mptr->SLP);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SectorVsby != (float) MAXINT ) {
|
||||
sprintf(temp, "SECTOR VSBY (MILES) : %.2f\n", Mptr->SectorVsby );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SectorVsby_Dir[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "SECTOR VSBY OCTANT : %s\n", Mptr->SectorVsby_Dir );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TS_LOC[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "THUNDERSTORM LOCAT. : %s\n", Mptr->TS_LOC );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TS_MOVMNT[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "THUNDERSTORM MOVMNT.: %s\n", Mptr->TS_MOVMNT);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->GR ) {
|
||||
sprintf(temp, "GR (HAILSTONES) : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->GR_Size != (float) MAXINT ) {
|
||||
sprintf(temp, "HLSTO SIZE (INCHES) : %.3f\n",Mptr->GR_Size);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VIRGA ) {
|
||||
sprintf(temp, "VIRGA : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VIRGA_DIR[0] != '\0' ) {
|
||||
sprintf(temp, "DIR OF VIRGA FRM STN: %s\n", Mptr->VIRGA_DIR);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
for( i = 0; i < 6; i++ ) {
|
||||
if( Mptr->SfcObscuration[i][0] != '\0' ) {
|
||||
sprintf(temp, "SfcObscuration : %s\n",
|
||||
&(Mptr->SfcObscuration[i][0]) );
|
||||
strcat(string, temp);
|
||||
}
|
||||
}
|
||||
|
||||
if ( Mptr->Num8thsSkyObscured != MAXINT ) {
|
||||
sprintf(temp, "8ths of SkyObscured : %d\n",Mptr->Num8thsSkyObscured);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CIGNO ) {
|
||||
sprintf(temp, "CIGNO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->Ceiling != MAXINT ) {
|
||||
sprintf(temp, "Ceiling (ft) : %d\n",Mptr->Ceiling);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->Estimated_Ceiling != MAXINT ) {
|
||||
sprintf(temp, "Estimated CIG (ft) : %d\n",Mptr->Estimated_Ceiling);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VrbSkyBelow[0] != '\0' ) {
|
||||
sprintf(temp, "VRB SKY COND BELOW : %s\n",Mptr->VrbSkyBelow);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VrbSkyAbove[0] != '\0' ) {
|
||||
sprintf(temp, "VRB SKY COND ABOVE : %s\n",Mptr->VrbSkyAbove);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VrbSkyLayerHgt != MAXINT ) {
|
||||
sprintf(temp, "VRBSKY COND HGT (FT): %d\n",Mptr->VrbSkyLayerHgt);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ObscurAloftHgt != MAXINT ) {
|
||||
sprintf(temp, "Hgt Obscur Aloft(ft): %d\n",Mptr->ObscurAloftHgt);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ObscurAloft[0] != '\0' ) {
|
||||
sprintf(temp, "Obscur Phenom Aloft : %s\n",Mptr->ObscurAloft);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->ObscurAloftSkyCond[0] != '\0' ) {
|
||||
sprintf(temp, "Obscur ALOFT SKYCOND: %s\n",Mptr->ObscurAloftSkyCond);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
if ( Mptr->NOSPECI ) {
|
||||
sprintf(temp, "NOSPECI : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->LAST ) {
|
||||
sprintf(temp, "LAST : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->synoptic_cloud_type[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "SYNOPTIC CLOUD GROUP: %s\n",Mptr->synoptic_cloud_type);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CloudLow != '\0' ) {
|
||||
sprintf(temp, "LOW CLOUD CODE : %c\n",Mptr->CloudLow);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CloudMedium != '\0' ) {
|
||||
sprintf(temp, "MEDIUM CLOUD CODE : %c\n",Mptr->CloudMedium);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CloudHigh != '\0' ) {
|
||||
sprintf(temp, "HIGH CLOUD CODE : %c\n",Mptr->CloudHigh);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SNINCR != MAXINT ) {
|
||||
sprintf(temp, "SNINCR (INCHES) : %d\n",Mptr->SNINCR);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SNINCR_TotalDepth != MAXINT ) {
|
||||
sprintf(temp, "SNINCR(TOT. INCHES) : %d\n",Mptr->SNINCR_TotalDepth);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->snow_depth_group[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "SNOW DEPTH GROUP : %s\n",Mptr->snow_depth_group);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->snow_depth != MAXINT ) {
|
||||
sprintf(temp, "SNOW DEPTH (INCHES) : %d\n",Mptr->snow_depth);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->WaterEquivSnow != (float) MAXINT ) {
|
||||
sprintf(temp, "H2O EquivSno(inches): %.2f\n",Mptr->WaterEquivSnow);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SunshineDur != MAXINT ) {
|
||||
sprintf(temp, "SUNSHINE (MINUTES) : %d\n",Mptr->SunshineDur);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->SunSensorOut ) {
|
||||
sprintf(temp, "SUN SENSOR OUT : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->hourlyPrecip != (float) MAXINT ) {
|
||||
sprintf(temp, "HRLY PRECIP (INCHES): %.2f\n",Mptr->hourlyPrecip);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->precip_amt != (float) MAXINT) {
|
||||
sprintf(temp, "3/6HR PRCIP (INCHES): %.2f\n",
|
||||
Mptr->precip_amt);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->Indeterminant3_6HrPrecip ) {
|
||||
sprintf(temp, "INDTRMN 3/6HR PRECIP: TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if( Mptr->precip_24_amt != (float) MAXINT) {
|
||||
sprintf(temp, "24HR PRECIP (INCHES): %.2f\n",
|
||||
Mptr->precip_24_amt);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->Indeterminant_24HrPrecip ) {
|
||||
sprintf(temp, "INDTRMN 24 HR PRECIP: TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->Temp_2_tenths != (float) MAXINT ) {
|
||||
sprintf(temp, "TMP2TENTHS (CELSIUS): %.1f\n",Mptr->Temp_2_tenths);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DP_Temp_2_tenths != (float) MAXINT ) {
|
||||
sprintf(temp, "DPT2TENTHS (CELSIUS): %.1f\n",Mptr->DP_Temp_2_tenths);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->maxtemp != (float) MAXINT) {
|
||||
sprintf(temp, "MAX TEMP (CELSIUS) : %.1f\n",
|
||||
Mptr->maxtemp);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->mintemp != (float) MAXINT) {
|
||||
sprintf(temp, "MIN TEMP (CELSIUS) : %.1f\n",
|
||||
Mptr->mintemp);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->max24temp != (float) MAXINT) {
|
||||
sprintf(temp, "24HrMAXTMP (CELSIUS): %.1f\n",
|
||||
Mptr->max24temp);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->min24temp != (float) MAXINT) {
|
||||
sprintf(temp, "24HrMINTMP (CELSIUS): %.1f\n",
|
||||
Mptr->min24temp);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->char_prestndcy != MAXINT) {
|
||||
sprintf(temp, "CHAR PRESS TENDENCY : %d\n",
|
||||
Mptr->char_prestndcy );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->prestndcy != (float) MAXINT) {
|
||||
sprintf(temp, "PRES. TENDENCY (hPa): %.1f\n",
|
||||
Mptr->prestndcy );
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PWINO ) {
|
||||
sprintf(temp, "PWINO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->PNO ) {
|
||||
sprintf(temp, "PNO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CHINO ) {
|
||||
sprintf(temp, "CHINO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CHINO_LOC[0] != '\0' ) {
|
||||
sprintf(temp, "CHINO_LOC : %s\n",Mptr->CHINO_LOC);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VISNO ) {
|
||||
sprintf(temp, "VISNO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VISNO_LOC[0] != '\0' ) {
|
||||
sprintf(temp, "VISNO_LOC : %s\n",Mptr->VISNO_LOC);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->FZRANO ) {
|
||||
sprintf(temp, "FZRANO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->TSNO ) {
|
||||
sprintf(temp, "TSNO : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->DollarSign) {
|
||||
sprintf(temp, "DOLLAR $IGN INDCATR : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->horiz_vsby[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "HORIZ VISIBILITY : %s\n",Mptr->horiz_vsby);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->dir_min_horiz_vsby[ 0 ] != '\0' ) {
|
||||
sprintf(temp, "DIR MIN HORIZ VSBY : %s\n",Mptr->dir_min_horiz_vsby);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->CAVOK ) {
|
||||
sprintf(temp, "CAVOK : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
|
||||
if( Mptr->VertVsby != MAXINT ) {
|
||||
sprintf(temp, "Vert. Vsby (meters) : %d\n",
|
||||
Mptr->VertVsby );
|
||||
strcat(string, temp);
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
if( Mptr->charVertVsby[0] != '\0' )
|
||||
sprintf(temp, "Vert. Vsby (CHAR) : %s\n",
|
||||
Mptr->charVertVsby );
|
||||
*/
|
||||
/*
|
||||
if ( Mptr->QFE != MAXINT ) {
|
||||
sprintf(temp, "QFE : %d\n", Mptr->QFE);
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->VOLCASH ) {
|
||||
sprintf(temp, "VOLCANIC ASH : TRUE\n");
|
||||
strcat(string, temp);
|
||||
}
|
||||
|
||||
if ( Mptr->min_vrbl_wind_dir != MAXINT ) {
|
||||
sprintf(temp, "MIN VRBL WIND DIR : %d\n",Mptr->min_vrbl_wind_dir);
|
||||
strcat(string, temp);
|
||||
}
|
||||
if ( Mptr->max_vrbl_wind_dir != MAXINT ) {
|
||||
sprintf(temp, "MAX VRBL WIND DIR : %d\n",Mptr->max_vrbl_wind_dir);
|
||||
strcat(string, temp);
|
||||
}
|
||||
*/
|
||||
|
||||
strcat(string, "\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
void prtDMETR (Decoded_METAR *Mptr)
|
||||
{
|
||||
char string[5000];
|
||||
|
||||
sprint_metar(string, Mptr);
|
||||
printf(string);
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma comment (compiler)
|
||||
#pragma comment (date)
|
||||
#pragma comment (timestamp)
|
||||
#pragma pagesize(80)
|
||||
|
||||
#include "local.h" /* standard header file */
|
||||
|
||||
#pragma page(1)
|
||||
#pragma subtitle(" ")
|
||||
#pragma subtitle("stspack2 - Local string test functions ")
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: stspack2 */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 05 Oct 1992 */
|
||||
/* Programmer: ALLAN DARLING */
|
||||
/* Language: C/2 */
|
||||
/* */
|
||||
/* Abstract: The stspack2 package contains functions to */
|
||||
/* perform the isalnum through isxdigit functions */
|
||||
/* on strings. The functions come in four forms: */
|
||||
/* those that test NULL delimited strings and are */
|
||||
/* named in the form sxxxxxxx, those that test at */
|
||||
/* most n characters and are named in the form */
|
||||
/* nxxxxxxx, those that search forward in a string */
|
||||
/* and are named in the form nxtyyyyy, and those */
|
||||
/* that search backward in a string and are named */
|
||||
/* in the form lstyyyyy. */
|
||||
/* */
|
||||
/* The xxxxxxx is the name of the test applied to */
|
||||
/* each character in the string, such as isalpha, */
|
||||
/* thus a function to test a NULL delimited string */
|
||||
/* an return a nonzero value if all characters in */
|
||||
/* the string are digits is named sisdigit. */
|
||||
/* */
|
||||
/* The yyyyy is the name of the test applied to */
|
||||
/* characters in a string, minus the 'is' prefix. */
|
||||
/* Thus a function to find the next digit in a NULL */
|
||||
/* delimited string and return a pointer to it is */
|
||||
/* named nxtdigit. */
|
||||
/* */
|
||||
/* The only exception to the naming rule is for the */
|
||||
/* functions that test for hexadecimal digits. */
|
||||
/* These are named sisxdigi, nisxdigi, nxtxdigi, */
|
||||
/* and lstxdigi because of the eight character */
|
||||
/* function name limitation. */
|
||||
/* */
|
||||
/* The nxxxxxxx class of functions will test up to */
|
||||
/* n characters or the first NULL character */
|
||||
/* encountered, whichever comes first. For all */
|
||||
/* classes of functions, the string sentinal is */
|
||||
/* not included in the test. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* isalnum, isalpha, iscntrl, isdigit, isgraph, */
|
||||
/* islower, isprint, ispunct, isspace, isupper, */
|
||||
/* isxdigit. */
|
||||
/* */
|
||||
/* Input: For sxxxxxxx class functions, a pointer to a */
|
||||
/* NULL delimited character string. */
|
||||
/* */
|
||||
/* For nxtyyyyy class functions, a pointer to a */
|
||||
/* NULL delimited character string. */
|
||||
/* */
|
||||
/* for nxxxxxxx class functions, a pointer to a */
|
||||
/* character array, and a positive, nonzero integer.*/
|
||||
/* */
|
||||
/* for lstyyyyy class functions, a pointer to a */
|
||||
/* character array, and a positive, nonzero integer.*/
|
||||
/* */
|
||||
/* Output: A nonzero value if the test is true for all */
|
||||
/* characters in the string, a zero value otherwise.*/
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
#pragma page(1)
|
||||
|
||||
int nisalnum(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isalnum(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisalnum */
|
||||
|
||||
|
||||
int nisalpha(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isalpha(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisalpha */
|
||||
|
||||
|
||||
int niscntrl(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!iscntrl(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end niscntrl */
|
||||
|
||||
|
||||
int nisdigit(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isdigit(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisdigit */
|
||||
|
||||
|
||||
int nisgraph(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isgraph(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisgraph */
|
||||
|
||||
|
||||
int nislower(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!islower(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nislower */
|
||||
|
||||
|
||||
int nisprint(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isprint(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisprint */
|
||||
|
||||
|
||||
int nispunct(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!ispunct(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nispunct */
|
||||
|
||||
|
||||
int nisspace(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isspace(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisspace */
|
||||
|
||||
|
||||
int nisupper(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isupper(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisupper */
|
||||
|
||||
|
||||
int nisxdigi(char *s, int n) {
|
||||
|
||||
for (; *s && n; s++, n--)
|
||||
|
||||
if (!isxdigit(*s))
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end nisxdigi */
|
||||
|
||||
#pragma page(1)
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
METAR Decoder Software Package Library: Parses Aviation Routine Weather Reports
|
||||
Copyright (C) 2003 Eric McCarthy
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma comment (compiler)
|
||||
#pragma comment (date)
|
||||
#pragma comment (timestamp)
|
||||
#pragma pagesize(80)
|
||||
|
||||
#include "local.h" /* standard header file */
|
||||
|
||||
#pragma page(1)
|
||||
#pragma subtitle(" ")
|
||||
#pragma subtitle("stspack3 - Local string test functions ")
|
||||
/********************************************************************/
|
||||
/* */
|
||||
/* Title: stspack3 */
|
||||
/* Organization: W/OSO242 - GRAPHICS AND DISPLAY SECTION */
|
||||
/* Date: 05 Oct 1992 */
|
||||
/* Programmer: ALLAN DARLING */
|
||||
/* Language: C/2 */
|
||||
/* */
|
||||
/* Abstract: The stspack3 package contains functions to */
|
||||
/* perform the isalnum through isxdigit functions */
|
||||
/* on strings. The functions come in four forms: */
|
||||
/* those that test NULL delimited strings and are */
|
||||
/* named in the form sxxxxxxx, those that test at */
|
||||
/* most n characters and are named in the form */
|
||||
/* nxxxxxxx, those that search forward in a string */
|
||||
/* and are named in the form nxtyyyyy, and those */
|
||||
/* that search backward in a string and are named */
|
||||
/* in the form lstyyyyy. */
|
||||
/* */
|
||||
/* The xxxxxxx is the name of the test applied to */
|
||||
/* each character in the string, such as isalpha, */
|
||||
/* thus a function to test a NULL delimited string */
|
||||
/* an return a nonzero value if all characters in */
|
||||
/* the string are digits is named sisdigit. */
|
||||
/* */
|
||||
/* The yyyyy is the name of the test applied to */
|
||||
/* characters in a string, minus the 'is' prefix. */
|
||||
/* Thus a function to find the next digit in a NULL */
|
||||
/* delimited string and return a pointer to it is */
|
||||
/* named nxtdigit. */
|
||||
/* */
|
||||
/* The only exception to the naming rule is for the */
|
||||
/* functions that test for hexadecimal digits. */
|
||||
/* These are named sisxdigi, nisxdigi, nxtxdigi, */
|
||||
/* and lstxdigi because of the eight character */
|
||||
/* function name limitation. */
|
||||
/* */
|
||||
/* The nxxxxxxx class of functions will test up to */
|
||||
/* n characters or the first NULL character */
|
||||
/* encountered, whichever comes first. For all */
|
||||
/* classes of functions, the string sentinal is */
|
||||
/* not included in the test. */
|
||||
/* */
|
||||
/* External Functions Called: */
|
||||
/* isalnum, isalpha, iscntrl, isdigit, isgraph, */
|
||||
/* islower, isprint, ispunct, isspace, isupper, */
|
||||
/* isxdigit. */
|
||||
/* */
|
||||
/* Input: For sxxxxxxx class functions, a pointer to a */
|
||||
/* NULL delimited character string. */
|
||||
/* */
|
||||
/* For nxtyyyyy class functions, a pointer to a */
|
||||
/* NULL delimited character string. */
|
||||
/* */
|
||||
/* for nxxxxxxx class functions, a pointer to a */
|
||||
/* character array, and a positive, nonzero integer.*/
|
||||
/* */
|
||||
/* for lstyyyyy class functions, a pointer to a */
|
||||
/* character array, and a positive, nonzero integer.*/
|
||||
/* */
|
||||
/* Output: A nonzero value if the test is true for all */
|
||||
/* characters in the string, a zero value otherwise.*/
|
||||
/* */
|
||||
/* Modification History: */
|
||||
/* None. */
|
||||
/* */
|
||||
/********************************************************************/
|
||||
#pragma page(1)
|
||||
char *nxtalnum(char *s) {
|
||||
|
||||
for (; !isalnum(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtalnum */
|
||||
|
||||
|
||||
char *nxtalpha(char *s) {
|
||||
|
||||
for (; !isalpha(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtalpha */
|
||||
|
||||
|
||||
char *nxtcntrl(char *s) {
|
||||
|
||||
for (; !iscntrl(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtcntrl */
|
||||
|
||||
|
||||
char *nxtdigit(char *s) {
|
||||
|
||||
for (; !isdigit(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtdigit */
|
||||
|
||||
|
||||
char *nxtgraph(char *s) {
|
||||
|
||||
for (; !isgraph(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtgraph */
|
||||
|
||||
|
||||
char *nxtlower(char *s) {
|
||||
|
||||
for (; !islower(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtlower */
|
||||
|
||||
|
||||
char *nxtprint(char *s) {
|
||||
|
||||
for (; !isprint(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtprint */
|
||||
|
||||
|
||||
char *nxtpunct(char *s) {
|
||||
|
||||
for (; !ispunct(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtpunct */
|
||||
|
||||
|
||||
char *nxtspace(char *s) {
|
||||
|
||||
for (; !isspace(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtspace */
|
||||
|
||||
|
||||
char *nxtupper(char *s) {
|
||||
|
||||
for (; !isupper(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtupper */
|
||||
|
||||
|
||||
char *nxtxdigi(char *s) {
|
||||
|
||||
for (; !isxdigit(*s) && *s; s++) ;
|
||||
|
||||
if (*s)
|
||||
return (s);
|
||||
else
|
||||
return (NULL);
|
||||
|
||||
} /* end nxtxdigi */
|
||||
|
||||
|
||||
#pragma page(1)
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 642 B |
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from oled.device import ssd1306, sh1106
|
||||
from oled.render import canvas
|
||||
|
||||
from PIL import ImageDraw, ImageFont, Image
|
||||
|
||||
import urllib2
|
||||
import json
|
||||
import time
|
||||
|
||||
font2 = ImageFont.truetype('/root/stratux/test/screen/CnC_Red_Alert.ttf', 12)
|
||||
oled = ssd1306(port=1, address=0x3C)
|
||||
|
||||
with canvas(oled) as draw:
|
||||
logo = Image.open('/root/stratux/test/screen/logo.bmp')
|
||||
draw.bitmap((32, 0), logo, fill=1)
|
||||
|
||||
time.sleep(10)
|
||||
|
||||
n = 0
|
||||
|
||||
while 1:
|
||||
time.sleep(1)
|
||||
response = urllib2.urlopen('http://localhost/getStatus')
|
||||
getStatusHTML = response.read()
|
||||
getStatusData = json.loads(getStatusHTML)
|
||||
CPUTemp = getStatusData["CPUTemp"]
|
||||
uat_current = getStatusData["UAT_messages_last_minute"]
|
||||
uat_max = getStatusData["UAT_messages_max"]
|
||||
es_current = getStatusData["ES_messages_last_minute"]
|
||||
es_max = getStatusData["ES_messages_max"]
|
||||
|
||||
response = urllib2.urlopen('http://localhost/getTowers')
|
||||
getTowersHTML = response.read()
|
||||
getTowersData = json.loads(getTowersHTML)
|
||||
NumTowers = len(getTowersData)
|
||||
|
||||
|
||||
|
||||
|
||||
with canvas(oled) as draw:
|
||||
pad = 2 # Two pixels on the left and right.
|
||||
text_margin = 25
|
||||
# UAT status.
|
||||
draw.text((50, 0), "UAT", font=font2, fill=255)
|
||||
# "Status bar", 2 pixels high.
|
||||
status_bar_width_max = oled.width - (2 * pad) - (2 * text_margin)
|
||||
status_bar_width = 0
|
||||
if uat_max > 0:
|
||||
status_bar_width = int((float(uat_current) / uat_max) * status_bar_width_max)
|
||||
draw.rectangle((pad + text_margin, 14, pad + text_margin + status_bar_width, 20), outline=255, fill=255) # Top left, bottom right.
|
||||
# Draw the current (left) and max (right) numbers.
|
||||
draw.text((pad, 14), str(uat_current), font=font2, fill=255)
|
||||
draw.text(((2*pad) + text_margin + status_bar_width_max, 14), str(uat_max), font=font2, fill=255)
|
||||
# ES status.
|
||||
draw.text((44, 24), "1090ES", font=font2, fill=255)
|
||||
status_bar_width = 0
|
||||
if es_max > 0:
|
||||
status_bar_width = int((float(es_current) / es_max) * status_bar_width_max)
|
||||
draw.rectangle((pad + text_margin, 34, pad + text_margin + status_bar_width, 40), outline=255, fill=255) # Top left, bottom right.
|
||||
# Draw the current (left) and max (right) numbers.
|
||||
draw.text((pad, 34), str(es_current), font=font2, fill=255)
|
||||
draw.text(((2*pad) + text_margin + status_bar_width_max, 34), str(es_max), font=font2, fill=255)
|
||||
# Other stats.
|
||||
seq = (n / 5) % 2
|
||||
t = ""
|
||||
if seq == 0:
|
||||
t = "CPU: %0.1fC, Towers: %d" % (CPUTemp, NumTowers)
|
||||
if seq == 1:
|
||||
t = "GPS Sat: %d/%d/%d" % (getStatusData["GPS_satellites_locked"], getStatusData["GPS_satellites_seen"], getStatusData["GPS_satellites_tracked"])
|
||||
if getStatusData["GPS_solution"] == "GPS + SBAS (WAAS / EGNOS)":
|
||||
t = t + " (WAAS)"
|
||||
print t
|
||||
draw.text((pad, 45), t, font=font2, fill=255)
|
||||
|
||||
n = n+1
|
|
@ -112,6 +112,10 @@ func dlac_decode(data []byte, data_len uint32) string {
|
|||
//TODO: Make a new "FISB Time" structure that also encodes the type of timestamp received.
|
||||
//TODO: pass up error.
|
||||
func (f *UATFrame) decodeTimeFormat() {
|
||||
if len(f.Raw_data) < 3 {
|
||||
return // Can't determine time format.
|
||||
}
|
||||
|
||||
t_opt := ((uint32(f.Raw_data[1]) & 0x01) << 1) | (uint32(f.Raw_data[2]) >> 7)
|
||||
|
||||
var fisb_data []byte
|
||||
|
@ -185,6 +189,10 @@ func formatDLACData(p string) []string {
|
|||
|
||||
// Whole frame contents is DLAC encoded text.
|
||||
func (f *UATFrame) decodeTextFrame() {
|
||||
if len(f.FISB_data) < int(f.FISB_length) {
|
||||
return
|
||||
}
|
||||
|
||||
p := dlac_decode(f.FISB_data, f.FISB_length)
|
||||
|
||||
f.Text_data = formatDLACData(p)
|
||||
|
@ -404,55 +412,63 @@ func (f *UATFrame) decodeAirmet() {
|
|||
f.Points = points
|
||||
}
|
||||
case 9: // Extended Range 3D Point (AGL). p.47.
|
||||
lng_raw := (int32(record_data[0]) << 11) | (int32(record_data[1]) << 3) | (int32(record_data[2]) & 0xE0 >> 5)
|
||||
lat_raw := ((int32(record_data[2]) & 0x1F) << 14) | (int32(record_data[3]) << 6) | ((int32(record_data[4]) & 0xFC) >> 2)
|
||||
alt_raw := ((int32(record_data[4]) & 0x03) << 8) | int32(record_data[5])
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "lat_raw=%d, lng_raw=%d, alt_raw=%d\n", lat_raw, lng_raw, alt_raw)
|
||||
lat, lng := airmetLatLng(lat_raw, lng_raw, false)
|
||||
|
||||
alt := alt_raw * 100
|
||||
fmt.Fprintf(ioutil.Discard, "lat=%f,lng=%f,alt=%d\n", lat, lng, alt)
|
||||
fmt.Fprintf(ioutil.Discard, "coord:%f,%f\n", lat, lng)
|
||||
var point GeoPoint
|
||||
point.Lat = lat
|
||||
point.Lon = lng
|
||||
point.Alt = alt
|
||||
f.Points = []GeoPoint{point}
|
||||
case 7, 8: // Extended Range Circular Prism (MSL). (8 = AGL)
|
||||
lng_bot_raw := (int32(record_data[0]) << 10) | (int32(record_data[1]) << 2) | (int32(record_data[2]) & 0xC0 >> 6)
|
||||
lat_bot_raw := ((int32(record_data[2]) & 0x3F) << 12) | (int32(record_data[3]) << 4) | ((int32(record_data[4]) & 0xF0) >> 4)
|
||||
lng_top_raw := ((int32(record_data[4]) & 0x0F) << 14) | (int32(record_data[5]) << 6) | ((int32(record_data[6]) & 0xFC) >> 2)
|
||||
lat_top_raw := ((int32(record_data[6]) & 0x03) << 16) | (int32(record_data[7]) << 8) | int32(record_data[8])
|
||||
|
||||
alt_bot_raw := (int32(record_data[9]) & 0xFE) >> 1
|
||||
alt_top_raw := ((int32(record_data[9]) & 0x01) << 6) | ((int32(record_data[10]) & 0xFC) >> 2)
|
||||
|
||||
r_lng_raw := ((int32(record_data[10]) & 0x03) << 7) | ((int32(record_data[11]) & 0xFE) >> 1)
|
||||
r_lat_raw := ((int32(record_data[11]) & 0x01) << 8) | int32(record_data[12])
|
||||
alpha := int32(record_data[13])
|
||||
|
||||
lat_bot, lng_bot := airmetLatLng(lat_bot_raw, lng_bot_raw, true)
|
||||
lat_top, lng_top := airmetLatLng(lat_top_raw, lng_top_raw, true)
|
||||
|
||||
alt_bot := alt_bot_raw * 5
|
||||
alt_top := alt_top_raw * 500
|
||||
|
||||
r_lng := float64(r_lng_raw) * float64(0.2)
|
||||
r_lat := float64(r_lat_raw) * float64(0.2)
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "lat_bot, lng_bot = %f, %f\n", lat_bot, lng_bot)
|
||||
fmt.Fprintf(ioutil.Discard, "lat_top, lng_top = %f, %f\n", lat_top, lng_top)
|
||||
|
||||
if geometry_overlay_options == 8 {
|
||||
fmt.Fprintf(ioutil.Discard, "alt_bot, alt_top = %d AGL, %d AGL\n", alt_bot, alt_top)
|
||||
if len(record_data) < 6 {
|
||||
fmt.Fprintf(ioutil.Discard, "invalid data: Extended Range 3D Point. Should be 6 bytes; % seen.\n", len(record_data))
|
||||
} else {
|
||||
fmt.Fprintf(ioutil.Discard, "alt_bot, alt_top = %d MSL, %d MSL\n", alt_bot, alt_top)
|
||||
lng_raw := (int32(record_data[0]) << 11) | (int32(record_data[1]) << 3) | (int32(record_data[2]) & 0xE0 >> 5)
|
||||
lat_raw := ((int32(record_data[2]) & 0x1F) << 14) | (int32(record_data[3]) << 6) | ((int32(record_data[4]) & 0xFC) >> 2)
|
||||
alt_raw := ((int32(record_data[4]) & 0x03) << 8) | int32(record_data[5])
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "lat_raw=%d, lng_raw=%d, alt_raw=%d\n", lat_raw, lng_raw, alt_raw)
|
||||
lat, lng := airmetLatLng(lat_raw, lng_raw, false)
|
||||
|
||||
alt := alt_raw * 100
|
||||
fmt.Fprintf(ioutil.Discard, "lat=%f,lng=%f,alt=%d\n", lat, lng, alt)
|
||||
fmt.Fprintf(ioutil.Discard, "coord:%f,%f\n", lat, lng)
|
||||
var point GeoPoint
|
||||
point.Lat = lat
|
||||
point.Lon = lng
|
||||
point.Alt = alt
|
||||
f.Points = []GeoPoint{point}
|
||||
}
|
||||
fmt.Fprintf(ioutil.Discard, "r_lng, r_lat = %f, %f\n", r_lng, r_lat)
|
||||
case 7, 8: // Extended Range Circular Prism (7 = MSL, 8 = AGL)
|
||||
if len(record_data) < 14 {
|
||||
fmt.Fprintf(ioutil.Discard, "invalid data: Extended Range Circular Prism. Should be 14 bytes; % seen.\n", len(record_data))
|
||||
} else {
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "alpha=%d\n", alpha)
|
||||
lng_bot_raw := (int32(record_data[0]) << 10) | (int32(record_data[1]) << 2) | (int32(record_data[2]) & 0xC0 >> 6)
|
||||
lat_bot_raw := ((int32(record_data[2]) & 0x3F) << 12) | (int32(record_data[3]) << 4) | ((int32(record_data[4]) & 0xF0) >> 4)
|
||||
lng_top_raw := ((int32(record_data[4]) & 0x0F) << 14) | (int32(record_data[5]) << 6) | ((int32(record_data[6]) & 0xFC) >> 2)
|
||||
lat_top_raw := ((int32(record_data[6]) & 0x03) << 16) | (int32(record_data[7]) << 8) | int32(record_data[8])
|
||||
|
||||
alt_bot_raw := (int32(record_data[9]) & 0xFE) >> 1
|
||||
alt_top_raw := ((int32(record_data[9]) & 0x01) << 6) | ((int32(record_data[10]) & 0xFC) >> 2)
|
||||
|
||||
r_lng_raw := ((int32(record_data[10]) & 0x03) << 7) | ((int32(record_data[11]) & 0xFE) >> 1)
|
||||
r_lat_raw := ((int32(record_data[11]) & 0x01) << 8) | int32(record_data[12])
|
||||
alpha := int32(record_data[13])
|
||||
|
||||
lat_bot, lng_bot := airmetLatLng(lat_bot_raw, lng_bot_raw, true)
|
||||
lat_top, lng_top := airmetLatLng(lat_top_raw, lng_top_raw, true)
|
||||
|
||||
alt_bot := alt_bot_raw * 5
|
||||
alt_top := alt_top_raw * 500
|
||||
|
||||
r_lng := float64(r_lng_raw) * float64(0.2)
|
||||
r_lat := float64(r_lat_raw) * float64(0.2)
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "lat_bot, lng_bot = %f, %f\n", lat_bot, lng_bot)
|
||||
fmt.Fprintf(ioutil.Discard, "lat_top, lng_top = %f, %f\n", lat_top, lng_top)
|
||||
|
||||
if geometry_overlay_options == 8 {
|
||||
fmt.Fprintf(ioutil.Discard, "alt_bot, alt_top = %d AGL, %d AGL\n", alt_bot, alt_top)
|
||||
} else {
|
||||
fmt.Fprintf(ioutil.Discard, "alt_bot, alt_top = %d MSL, %d MSL\n", alt_bot, alt_top)
|
||||
}
|
||||
fmt.Fprintf(ioutil.Discard, "r_lng, r_lat = %f, %f\n", r_lng, r_lat)
|
||||
|
||||
fmt.Fprintf(ioutil.Discard, "alpha=%d\n", alpha)
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(ioutil.Discard, "unknown geometry: %d\n", geometry_overlay_options)
|
||||
}
|
||||
|
@ -465,6 +481,10 @@ func (f *UATFrame) decodeAirmet() {
|
|||
|
||||
func (f *UATFrame) decodeInfoFrame() {
|
||||
|
||||
if len(f.Raw_data) < 2 {
|
||||
return // Can't determine Product_id.
|
||||
}
|
||||
|
||||
f.Product_id = ((uint32(f.Raw_data[0]) & 0x1f) << 6) | (uint32(f.Raw_data[1]) >> 2)
|
||||
|
||||
if f.Frame_type != 0 {
|
||||
|
@ -476,8 +496,10 @@ func (f *UATFrame) decodeInfoFrame() {
|
|||
switch f.Product_id {
|
||||
case 413:
|
||||
f.decodeTextFrame()
|
||||
case 8, 11, 13:
|
||||
f.decodeAirmet()
|
||||
/*
|
||||
case 8, 11, 13:
|
||||
f.decodeAirmet()
|
||||
*/
|
||||
default:
|
||||
fmt.Fprintf(ioutil.Discard, "don't know what to do with product id: %d\n", f.Product_id)
|
||||
}
|
||||
|
@ -489,6 +511,10 @@ func (u *UATMsg) DecodeUplink() error {
|
|||
// position_valid := (uint32(frame[5]) & 0x01) != 0
|
||||
frame := u.msg
|
||||
|
||||
if len(frame) < UPLINK_FRAME_DATA_BYTES {
|
||||
return errors.New(fmt.Sprintf("DecodeUplink: short read (%d).", len(frame)))
|
||||
}
|
||||
|
||||
raw_lat := (uint32(frame[0]) << 15) | (uint32(frame[1]) << 7) | (uint32(frame[2]) >> 1)
|
||||
|
||||
raw_lon := ((uint32(frame[2]) & 0x01) << 23) | (uint32(frame[3]) << 15) | (uint32(frame[4]) << 7) | (uint32(frame[5]) >> 1)
|
||||
|
@ -527,9 +553,11 @@ func (u *UATMsg) DecodeUplink() error {
|
|||
if pos+int(frame_length) > total_len {
|
||||
break // Overrun?
|
||||
}
|
||||
if frame_length == 0 && frame_type == 0 {
|
||||
break // No more frames.
|
||||
|
||||
if frame_length == 0 { // Empty frame. Quit here.
|
||||
break
|
||||
}
|
||||
|
||||
pos = pos + 2
|
||||
|
||||
data = data[2 : frame_length+2]
|
||||
|
@ -585,9 +613,14 @@ func New(buf string) (*UATMsg, error) {
|
|||
buf = strings.Trim(buf, "\r\n") // Remove newlines.
|
||||
x := strings.Split(buf, ";") // We want to discard everything before the first ';'.
|
||||
|
||||
if len(x) < 2 {
|
||||
return ret, errors.New(fmt.Sprintf("New UATMsg: Invalid format (%s).", buf))
|
||||
}
|
||||
|
||||
/*
|
||||
RS_Err int
|
||||
SignalStrength int
|
||||
Parse _;rs=?;ss=? - if available.
|
||||
RS_Err int
|
||||
SignalStrength int
|
||||
*/
|
||||
ret.SignalStrength = -1
|
||||
ret.RS_Err = -1
|
||||
|
@ -614,10 +647,10 @@ func New(buf string) (*UATMsg, error) {
|
|||
}
|
||||
|
||||
if s[0] != '+' { // Only want + ("Uplink") messages currently. - (Downlink) or messages that start with other are discarded.
|
||||
return ret, errors.New("New UATMsg: expecting uplink frames.")
|
||||
return ret, errors.New("New UATMsg: expecting uplink frame.")
|
||||
}
|
||||
|
||||
s = s[1:]
|
||||
s = s[1:] // Remove the preceding '+' or '-' character.
|
||||
|
||||
// Convert the hex string into a byte array.
|
||||
frame := make([]byte, UPLINK_FRAME_DATA_BYTES)
|
||||
|
|
|
@ -80,10 +80,11 @@ function SettingsCtrl($rootScope, $scope, $state, $location, $window, $http) {
|
|||
});
|
||||
|
||||
$scope.updateppm = function () {
|
||||
settings["PPM"] = 0
|
||||
if (($scope.PPM !== undefined) && ($scope.PPM !== null) && ($scope.PPM !== settings["PPM"])) {
|
||||
settings["PPM"] = parseInt($scope.PPM);
|
||||
newsettings = {
|
||||
"PPM": parseInt($scope.PPM)
|
||||
"PPM": settings["PPM"]
|
||||
};
|
||||
// console.log(angular.toJson(newsettings));
|
||||
setSettings(angular.toJson(newsettings));
|
||||
|
|
|
@ -40,14 +40,13 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
console.log('Received status update.')
|
||||
|
||||
var status = JSON.parse(msg.data)
|
||||
// Update Status
|
||||
// Update Status
|
||||
$scope.Version = status.Version;
|
||||
$scope.Build = status.Build.substr(0, 10);
|
||||
$scope.Devices = status.Devices;
|
||||
$scope.Ping_connected = status.Ping_connected;
|
||||
$scope.Connected_Users = status.Connected_Users;
|
||||
$scope.UAT_messages_last_minute = status.UAT_messages_last_minute;
|
||||
// $scope.UAT_products_last_minute = JSON.stringify(status.UAT_products_last_minute);
|
||||
$scope.UAT_messages_max = status.UAT_messages_max;
|
||||
$scope.ES_messages_last_minute = status.ES_messages_last_minute;
|
||||
$scope.ES_messages_max = status.ES_messages_max;
|
||||
|
@ -55,20 +54,15 @@ function StatusCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
$scope.GPS_satellites_tracked = status.GPS_satellites_tracked;
|
||||
$scope.GPS_satellites_seen = status.GPS_satellites_seen;
|
||||
$scope.GPS_solution = status.GPS_solution;
|
||||
$scope.GPS_position_accuracy = String(status.GPS_solution ? ", " + status.GPS_position_accuracy.toFixed(1) : "");
|
||||
$scope.RY835AI_connected = status.RY835AI_connected;
|
||||
var tempClock = new Date(Date.parse(status.Clock));
|
||||
var clockString = tempClock.toUTCString();
|
||||
$scope.Clock = clockString;
|
||||
var tempLocalClock = new Date;
|
||||
$scope.LocalClock = tempLocalClock.toUTCString();
|
||||
$scope.SecondsFast = (Math.round(tempClock-tempLocalClock)/1000).toFixed(2);
|
||||
|
||||
// Errors array.
|
||||
if (status.Errors.length > 0) {
|
||||
$scope.visible_errors = true;
|
||||
$scope.Errors = status.Errors;
|
||||
}
|
||||
|
||||
|
||||
var uptime = status.Uptime;
|
||||
if (uptime != undefined) {
|
||||
var up_d = parseInt((uptime/1000) / 86400),
|
||||
|
|
|
@ -59,6 +59,7 @@ function TrafficCtrl($rootScope, $scope, $state, $http, $interval) {
|
|||
}
|
||||
new_traffic.icao = obj.Icao_addr.toString(16).toUpperCase();
|
||||
new_traffic.tail = obj.Tail;
|
||||
new_traffic.reg = obj.Reg;
|
||||
if (obj.Squawk == 0) {
|
||||
new_traffic.squawk = "----";
|
||||
} else {
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
</div>
|
||||
<div class="row" ng-class="{'section_invisible': !visible_gps}">
|
||||
<label class="col-xs-6">GPS solution:</label>
|
||||
<span class="col-xs-6">{{GPS_solution}}</span>
|
||||
<span class="col-xs-6">{{GPS_solution}}{{GPS_position_accuracy}}</span>
|
||||
</div>
|
||||
<div class="row" ng-class="{'section_invisible': !visible_gps}">
|
||||
<label class="col-xs-6">GPS satellites:</label>
|
||||
|
@ -100,22 +100,6 @@
|
|||
<span class="col-xs-7">{{CPUTemp}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4 label_adj">
|
||||
<span class="col-xs-4"><strong>Stratux Clock:</strong></span>
|
||||
<span class="col-xs-8">{{Clock}}</span>
|
||||
</div>
|
||||
<div class="col-sm-4 label_adj">
|
||||
<span class="col-xs-4"><strong>Device Clock:</strong></span>
|
||||
<span class="col-xs-8">{{LocalClock}}</span>
|
||||
</div>
|
||||
<div class="col-sm-4 label_adj">
|
||||
<span class="col-xs-4"><strong>Difference:</strong></span>
|
||||
<span class="col-xs-8">{{SecondsFast}} sec</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
<div class="panel-body traffic-page">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3"><strong>Callsign</strong></span>
|
||||
<span class="col-xs-3" ng-hide="showReg"><strong>Callsign</strong></span>
|
||||
<span class="col-xs-3" ng-show="showReg"><strong>Tail Num</strong></span>
|
||||
<span class="col-xs-2" ng-hide="showSquawk"><strong>Code</strong></span>
|
||||
<span class="col-xs-2" ng-show="showSquawk"><strong>Squawk</strong></span>
|
||||
<span class="col-xs-5 text-right" ng-hide="GPS_connected && RelDist"><strong>Location</strong></span>
|
||||
|
@ -29,11 +30,15 @@
|
|||
<div class="row" ng-repeat="aircraft in data_list | orderBy: 'dist'">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-3">
|
||||
<span class="col-xs-3" ng-hide="showReg">
|
||||
<span ng-show="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> {{aircraft.tail}}</strong></span>
|
||||
<span ng-hide="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> [--N/A--]</strong></span>
|
||||
</span>
|
||||
<span class="col-xs-3" ng-show="showReg">
|
||||
<span ng-show="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> {{aircraft.reg}}</strong></span>
|
||||
<span ng-hide="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> [--N/A--]</strong></span>
|
||||
</span>
|
||||
|
||||
|
||||
<span class="col-xs-2">
|
||||
<span style="font-size:80%" ng-hide="showSquawk">{{aircraft.icao}}<span style="font-size:50%">{{aircraft.addr_type == 3 ? " (TFID)" : ""}}</span></span>
|
||||
<span ng-show="showSquawk"><span ng-show="aircraft.squawk < 1000">0</span><span ng-show="aircraft.squawk < 100">0</span><span ng-show="aircraft.squawk < 10">0</span>{{aircraft.squawk}}</span>
|
||||
|
@ -60,19 +65,26 @@
|
|||
<div class="panel-body traffic-footer">
|
||||
<div class="separator"></div>
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<label class="control-label col-xs-6">Show Tail Number</label>
|
||||
<span class="col-xs-3"><ui-switch ng-model='showReg' settings-change></ui-switch></span>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="control-label col-xs-6">Show Squawk</label>
|
||||
<span class="col-xs-3"><ui-switch ng-model='showSquawk' settings-change></ui-switch></span>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<label class="control-label col-xs-6">Show Distance</label>
|
||||
<label class="control-label col-xs-6" ng-show="GPS_connected">Show Distance</label>
|
||||
<label class="control-label text-muted col-xs-6" ng-hide="GPS_connected">Show Distance N/A</label>
|
||||
<span class="col-xs-3"><ui-switch ng-model='RelDist' settings-change></ui-switch></span>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-sm-4">
|
||||
<label class="control-label col-xs-6">GPS Status</label>
|
||||
<span ng-show="GPS_connected" class="label label-success col-xs-3" style="font-size:100%; display:block; height: 34px; line-height: 34px">Valid</span>
|
||||
<span ng-hide="GPS_connected" class="label label-danger col-xs-3" style="font-size:100%; display:block; height: 34px; line-height: 34px">No Fix</span>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -85,7 +97,8 @@
|
|||
<div class="panel-body traffic-page">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-4"><strong>Callsign</strong></span>
|
||||
<span class="col-xs-4" ng-hide="showReg"><strong>Callsign</strong></span>
|
||||
<span class="col-xs-4" ng-show="showReg"><strong>Tail Num</strong></span>
|
||||
<span class="col-xs-3"><strong>Code</strong></span>
|
||||
<span class="col-xs-3"><strong>Squawk</strong></span>
|
||||
</div>
|
||||
|
@ -102,9 +115,13 @@
|
|||
<div class="row" ng-repeat="aircraft in data_list_invalid | orderBy: 'icao'">
|
||||
<div class="separator"></div>
|
||||
<div class="col-sm-6">
|
||||
<span class="col-xs-4">
|
||||
<span class="col-xs-4" ng-hide="showReg">
|
||||
<span ng-show="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> {{aircraft.tail}}</strong></span>
|
||||
<span ng-hide="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> [--N/A--]</strong></span>
|
||||
</span>
|
||||
<span class="col-xs-4" ng-show="showReg">
|
||||
<span ng-show="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> {{aircraft.reg}}</strong></span>
|
||||
<span ng-hide="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong> [--N/A--]</strong></span>
|
||||
</span>
|
||||
<span class="col-xs-3" style="font-size:80%">{{aircraft.icao}}<span style="font-size:50%">{{aircraft.addr_type == 3 ? " (TFID)" : ""}}</span></span>
|
||||
<span class="col-xs-3"><span ng-show="aircraft.squawk < 1000">0</span><span ng-show="aircraft.squawk < 100">0</span><span ng-show="aircraft.squawk < 10">0</span>{{aircraft.squawk}}</span>
|
||||
|
|
Ładowanie…
Reference in New Issue