Merge remote-tracking branch 'upstream/master'

pull/471/head
Ryan C. Braun 2016-08-09 14:10:55 -05:00
commit 6daa3b7240
48 zmienionych plików z 29300 dodań i 280 usunięć

27
.gitignore vendored
Wyświetl plik

@ -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

Wyświetl plik

@ -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/

Wyświetl plik

@ -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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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.

Wyświetl plik

@ -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

Wyświetl plik

@ -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()

Wyświetl plik

@ -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

Wyświetl plik

@ -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

20
image/motd 100644
Wyświetl plik

@ -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.

Wyświetl plik

@ -1,3 +1,4 @@
blacklist dvb_usb_rtl28xxu
blacklist e4000
blacklist rtl2832
blacklist dvb_usb_rtl2832u

Wyświetl plik

@ -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

Wyświetl plik

@ -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"
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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()

Wyświetl plik

@ -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.

Wyświetl plik

@ -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/")

Wyświetl plik

@ -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()
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

15912
notes/logo.dxf 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -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/

Wyświetl plik

@ -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.

173
test/icao2reg.go 100644
Wyświetl plik

@ -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
}

Wyświetl plik

@ -0,0 +1,3 @@
all:
gcc -o metar_to_text src/*.c

Wyświetl plik

@ -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 );

Wyświetl plik

@ -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)

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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++;
}
}

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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

Wyświetl plik

@ -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);
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

BIN
test/packetrate 100755

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 642 B

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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));

Wyświetl plik

@ -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),

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>&nbsp;{{aircraft.tail}}</strong></span>
<span ng-hide="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong>&nbsp;[--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>&nbsp;{{aircraft.reg}}</strong></span>
<span ng-hide="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong>&nbsp;[--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 ? "&nbsp;(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>&nbsp;{{aircraft.tail}}</strong></span>
<span ng-hide="aircraft.tail" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong>&nbsp;[--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>&nbsp;{{aircraft.reg}}</strong></span>
<span ng-hide="aircraft.reg" ng-class="'label traffic-style'+aircraft.src+aircraft.targettype">{{aircraft.addr_symb}}<strong>&nbsp;[--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 ? "&nbsp;(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>