mirror of https://github.com/wb2osz/direwolf.git
Rewrite GPS handling. Lots of other clean up.
This commit is contained in:
parent
dd27f9960b
commit
4c60979844
|
@ -28,8 +28,14 @@
|
|||
*.desktop text
|
||||
*.conf text
|
||||
*.rc text
|
||||
*.spec text
|
||||
*.bat text
|
||||
*.1 text
|
||||
*.md text
|
||||
COPYING text
|
||||
Makefile* text
|
||||
README* text
|
||||
|
||||
*.ico binary
|
||||
*.png binary
|
||||
|
||||
Makefile* text
|
|
@ -6,6 +6,10 @@ z*
|
|||
*~
|
||||
*.xlsx
|
||||
*.stackdump
|
||||
direwolf.conf
|
||||
*.wav
|
||||
fsk_fast_filter.h
|
||||
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
|
|
16
CHANGES.md
16
CHANGES.md
|
@ -3,6 +3,22 @@
|
|||
|
||||
----------
|
||||
|
||||
## Version 1.3 -- Development snapshot G -- November 2015 ##
|
||||
|
||||
### New Feature: ###
|
||||
|
||||
- GPS Tracker beacons are now available for the Windows version. Previously this was only in the Linux version.
|
||||
|
||||
- Implemented AGW network protocol 'M' message for sending UNPROTO information without digipeater path.
|
||||
|
||||
### Bugs Fixed: ###
|
||||
|
||||
- Tracker beacons were not always updating the location properly.
|
||||
|
||||
- In Mac OSX version: Assertion failed: (adev[a].inbuf_size_in_bytes >= 100 && adev[a].inbuf_size_in_bytes <= 32768), function audio_get, file audio_portaudio.c, line 917.
|
||||
|
||||
----------
|
||||
|
||||
## Version 1.3 -- Development snapshot F -- September 2015 ##
|
||||
|
||||
### New Feature: ###
|
||||
|
|
500
Makefile.linux
500
Makefile.linux
|
@ -2,7 +2,9 @@
|
|||
# Makefile for Linux version of Dire Wolf.
|
||||
#
|
||||
|
||||
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc direwolf.desktop direwolf.conf
|
||||
APPS := direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc
|
||||
|
||||
all : $(APPS) direwolf.desktop direwolf.conf
|
||||
@echo " "
|
||||
@echo "Next step - install with:"
|
||||
@echo " "
|
||||
|
@ -12,6 +14,9 @@ all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx
|
|||
CC := gcc
|
||||
CFLAGS := -O3 -pthread -Igeotranz
|
||||
|
||||
LDFLAGS := -lm -lpthread -lrt
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The DSP filters spend a lot of time spinning around in little
|
||||
|
@ -184,24 +189,27 @@ endif
|
|||
#
|
||||
# If you are planning to distribute the binary version to other
|
||||
# people (in some ham radio software collection, RPM, or DEB package),
|
||||
# avoid # fine tuning it for your particular computer. It could
|
||||
# avoid fine tuning it for your particular computer. It could
|
||||
# cause compatibility issues for those with older computers.
|
||||
#
|
||||
|
||||
|
||||
#CFLAGS += -D_FORTIFY_SOURCE
|
||||
|
||||
# If you want to use OSS (for FreeBSD, OpenBSD) instead of
|
||||
# ALSA (for Linux), comment out (or remove) the two lines below.
|
||||
|
||||
CFLAGS += -DUSE_ALSA
|
||||
LDLIBS += -lasound
|
||||
LDFLAGS += -lasound
|
||||
|
||||
|
||||
# Uncomment following lines to enable GPS interface & tracker function.
|
||||
# Enable GPS if header file is present.
|
||||
# Finding libgps.so* is more difficult because it
|
||||
# is in different places on different operating systems.
|
||||
|
||||
#CFLAGS += -DENABLE_GPS
|
||||
#LDLIBS += -lgps
|
||||
enable_gpsd := $(wildcard /usr/include/gps.h)
|
||||
ifneq ($(enable_gpsd),)
|
||||
CFLAGS += -DENABLE_GPSD
|
||||
LDFLAGS += -lgps
|
||||
endif
|
||||
|
||||
|
||||
# Name of current directory.
|
||||
|
@ -210,7 +218,10 @@ LDLIBS += -lasound
|
|||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
# Main application.
|
||||
|
||||
# -------------------------------- Main application -----------------------------------------
|
||||
|
||||
|
||||
|
||||
direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hdlc_rec.o \
|
||||
hdlc_rec2.o multi_modem.o redecode.o rdq.o rrbb.o dlq.o \
|
||||
|
@ -218,10 +229,17 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
|
|||
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||
gen_tone.o audio.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o morse.o \
|
||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o dtime_now.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
|
||||
dwgps.o dwgpsnmea.o dwgpsd.o dtime_now.o \
|
||||
misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread -lrt $(LDLIBS) -lm
|
||||
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
ifneq ($(enable_gpsd),)
|
||||
@echo " "
|
||||
@echo "This includes support for gpsd."
|
||||
else
|
||||
@echo " "
|
||||
@echo "This does NOT include support for gpsd."
|
||||
endif
|
||||
|
||||
# Optimization for slow processors.
|
||||
|
||||
|
@ -231,10 +249,100 @@ demod_afsk.o : fsk_fast_filter.h
|
|||
|
||||
|
||||
fsk_fast_filter.h : demod_afsk.c
|
||||
$(CC) $(CFLAGS) -o gen_fff -DGEN_FFF demod_afsk.c dsp.c textcolor.c -lm
|
||||
$(CC) $(CFLAGS) -o gen_fff -DGEN_FFF demod_afsk.c dsp.c textcolor.c $(LDFLAGS)
|
||||
./gen_fff > fsk_fast_filter.h
|
||||
|
||||
|
||||
#
|
||||
# The destination field is often used to identify the manufacturer/model.
|
||||
# These are not hardcoded into Dire Wolf. Instead they are read from
|
||||
# a file called tocalls.txt at application start up time.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff symbolsX.txt~ symbolsX.txt
|
||||
|
||||
|
||||
# ---------------------------------------- Other utilities included ------------------------------
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
tt2text : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
utm2ll : utm2ll.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c morse.c textcolor.c dsp.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
# Unit test for AFSK demodulator
|
||||
|
||||
atest : atest.c fsk_fast_filter.h demod.c demod_afsk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c dwgpsnmea.o \
|
||||
dwgps.o serial_port.o telemetry.c latlong.c symbols.c tt_text.c textcolor.c \
|
||||
misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# Touch Tone to Speech sample application.
|
||||
|
||||
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# ----------------------------------------- Libraries --------------------------------------------
|
||||
|
||||
# UTM, USNG, MGRS conversions.
|
||||
|
||||
|
@ -277,7 +385,19 @@ strlcat.o : misc/strlcat.c
|
|||
|
||||
|
||||
|
||||
# ------------------------------------- Installation ----------------------------------
|
||||
|
||||
|
||||
|
||||
# Generate apprpriate sample configuration file for this platform.
|
||||
# Originally, there was one sample for all platforms. It got too cluttered
|
||||
# and confusing saying, this is for windows, and this is for Linux, and this ...
|
||||
# Trying to maintain 3 different versions in parallel is error prone.
|
||||
# We now have a single generic version which can be used to generate
|
||||
# the various platform specific versions.
|
||||
|
||||
# generic.conf should be checked into source control.
|
||||
# direwolf.conf should NOT. It is generated when compiling on the target platform.
|
||||
|
||||
direwolf.conf : generic.conf
|
||||
egrep '^C|^L' generic.conf | cut -c2-999 > direwolf.conf
|
||||
|
@ -289,13 +409,17 @@ direwolf.conf : generic.conf
|
|||
# from source, that is not a standard part of the operating system,
|
||||
# should go in /usr/local/bin.
|
||||
|
||||
# However, if you are preparing a "binary" RPM or DEB package, the
|
||||
# However, if you are preparing a "binary" DEB or RPM package, the
|
||||
# installation location should be /usr/bin.
|
||||
|
||||
# This is a step in the right direction but not sufficient to use /usr instead.
|
||||
# Eventually I'd like to have targets here to build the .DEB and .RPM packages.
|
||||
|
||||
INSTALLDIR := /usr/local
|
||||
|
||||
# Command to "install" to system directories. Use "ginstall" for Mac.
|
||||
|
||||
INSTALL=install
|
||||
|
||||
# direwolf.desktop was previously handcrafted for the Raspberry Pi.
|
||||
# It was hardcoded with lxterminal, /home/pi, and so on.
|
||||
|
@ -324,49 +448,89 @@ endif
|
|||
@echo 'Keywords=Ham Radio;APRS;Soundcard TNC;KISS;AGWPE;AX.25' >> $@
|
||||
|
||||
|
||||
# Optional installation into /usr/local/...
|
||||
# Installation into /usr/local/...
|
||||
# Needs to be run as root or with sudo.
|
||||
# TODO: Review file locations.
|
||||
|
||||
install : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx gen_packets \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
||||
install direwolf $(INSTALLDIR)/bin
|
||||
install decode_aprs $(INSTALLDIR)/bin
|
||||
install text2tt $(INSTALLDIR)/bin
|
||||
install tt2text $(INSTALLDIR)/bin
|
||||
install ll2utm $(INSTALLDIR)/bin
|
||||
install utm2ll $(INSTALLDIR)/bin
|
||||
install aclients $(INSTALLDIR)/bin
|
||||
install log2gpx $(INSTALLDIR)/bin
|
||||
install gen_packets $(INSTALLDIR)/bin
|
||||
install atest $(INSTALLDIR)/bin
|
||||
install ttcalc $(INSTALLDIR)/bin
|
||||
install dwespeak.sh $(INSTALLDIR)/bin
|
||||
install telemetry-toolkit/*.p[ly] $(INSTALLDIR)/bin
|
||||
install -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||
install -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||
install -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||
install -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||
install -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||
install -D --mode=644 README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
install -D --mode=644 CHANGES.md $(INSTALLDIR)/share/doc/direwolf/CHANGES.md
|
||||
install -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
install -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
install -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
install -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
install -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
install -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
install -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
install -D --mode=644 man1/aclients.1 $(INSTALLDIR)/man/man1/aclients.1
|
||||
install -D --mode=644 man1/atest.1 $(INSTALLDIR)/man/man1/atest.1
|
||||
install -D --mode=644 man1/decode_aprs.1 $(INSTALLDIR)/man/man1/decode_aprs.1
|
||||
install -D --mode=644 man1/direwolf.1 $(INSTALLDIR)/man/man1/direwolf.1
|
||||
install -D --mode=644 man1/gen_packets.1 $(INSTALLDIR)/man/man1/gen_packets.1
|
||||
install -D --mode=644 man1/ll2utm.1 $(INSTALLDIR)/man/man1/ll2utm.1
|
||||
install -D --mode=644 man1/log2gpx.1 $(INSTALLDIR)/man/man1/log2gpx.1
|
||||
install -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
|
||||
install -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
|
||||
install -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
|
||||
|
||||
.PHONY: install
|
||||
install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
||||
#
|
||||
# Applications, not installed with package manager, normally go in /usr/local/bin.
|
||||
# /usr/bin is used instead when installing from .DEB or .RPM package.
|
||||
#
|
||||
$(INSTALL) direwolf $(INSTALLDIR)/bin
|
||||
$(INSTALL) decode_aprs $(INSTALLDIR)/bin
|
||||
$(INSTALL) text2tt $(INSTALLDIR)/bin
|
||||
$(INSTALL) tt2text $(INSTALLDIR)/bin
|
||||
$(INSTALL) ll2utm $(INSTALLDIR)/bin
|
||||
$(INSTALL) utm2ll $(INSTALLDIR)/bin
|
||||
$(INSTALL) aclients $(INSTALLDIR)/bin
|
||||
$(INSTALL) log2gpx $(INSTALLDIR)/bin
|
||||
$(INSTALL) gen_packets $(INSTALLDIR)/bin
|
||||
$(INSTALL) atest $(INSTALLDIR)/bin
|
||||
$(INSTALL) ttcalc $(INSTALLDIR)/bin
|
||||
$(INSTALL) dwespeak.sh $(INSTALLDIR)/bin
|
||||
#
|
||||
# Telemetry Toolkit executables. Other .conf and .txt files will go into doc directory.
|
||||
#
|
||||
$(INSTALL) telemetry-toolkit/telem-balloon.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-bits.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data91.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-eqns.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-parm.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-unit.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-volts.py $(INSTALLDIR)/bin
|
||||
#
|
||||
# Misc. data such as "tocall" to system mapping.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||
$(INSTALL) -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||
$(INSTALL) -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||
$(INSTALL) -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||
$(INSTALL) -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||
#
|
||||
# Documentation. Various plain text files and PDF.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
$(INSTALL) -D --mode=644 CHANGES.md $(INSTALLDIR)/share/doc/direwolf/CHANGES.md
|
||||
$(INSTALL) -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
$(INSTALL) -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
#
|
||||
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
|
||||
#
|
||||
# Sample config files also go into the doc directory.
|
||||
# When building from source, these can be put in home directory with "make install-conf".
|
||||
# When installed from .DEB or .RPM package, the user will need to copy these to
|
||||
# the home directory or other desired location.
|
||||
# Someone suggested that these could go into an "examples" subdirectory under doc.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 direwolf.conf $(INSTALLDIR)/share/doc/direwolf/direwolf.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-m0xer-3.txt $(INSTALLDIR)/share/doc/direwolf/telem-m0xer-3.txt
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-balloon.conf $(INSTALLDIR)/share/doc/direwolf/telem-balloon.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-volts.conf $(INSTALLDIR)/share/doc/direwolf/telem-volts.conf
|
||||
#
|
||||
# "man" pages
|
||||
#
|
||||
$(INSTALL) -D --mode=644 man1/aclients.1 $(INSTALLDIR)/man/man1/aclients.1
|
||||
$(INSTALL) -D --mode=644 man1/atest.1 $(INSTALLDIR)/man/man1/atest.1
|
||||
$(INSTALL) -D --mode=644 man1/decode_aprs.1 $(INSTALLDIR)/man/man1/decode_aprs.1
|
||||
$(INSTALL) -D --mode=644 man1/direwolf.1 $(INSTALLDIR)/man/man1/direwolf.1
|
||||
$(INSTALL) -D --mode=644 man1/gen_packets.1 $(INSTALLDIR)/man/man1/gen_packets.1
|
||||
$(INSTALL) -D --mode=644 man1/ll2utm.1 $(INSTALLDIR)/man/man1/ll2utm.1
|
||||
$(INSTALL) -D --mode=644 man1/log2gpx.1 $(INSTALLDIR)/man/man1/log2gpx.1
|
||||
$(INSTALL) -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
|
||||
$(INSTALL) -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
|
||||
$(INSTALL) -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
|
||||
#
|
||||
@echo " "
|
||||
@echo "If this is your first install, not an upgrade, type this to put a copy"
|
||||
@echo "of the sample configuration file (direwolf.conf) in your home directory:"
|
||||
|
@ -375,12 +539,6 @@ install : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx ge
|
|||
@echo " "
|
||||
|
||||
|
||||
# TODO: Should we put the sample direwolf.conf file somewhere like
|
||||
# /usr/share/doc/direwolf/examples and add that to the
|
||||
# end of the search path list?
|
||||
# That would make it easy to see user customizations compared to the
|
||||
# latest sample.
|
||||
|
||||
# These would be done as ordinary user.
|
||||
|
||||
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
||||
|
@ -409,41 +567,123 @@ install-rpi : dw-start.sh
|
|||
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c latlong.c log.c telemetry.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^ -lm
|
||||
# ---------------------------------- Automated Smoke Test --------------------------------
|
||||
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o text2tt tt_text.c
|
||||
|
||||
tt2text : tt_text.c
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o tt2text tt_text.c
|
||||
# Combine some unit tests into a single regression sanity check.
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest check-modem1200 check-modem300 check-modem9600
|
||||
|
||||
ll2utm : ll2utm.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
# Can we encode and decode at popular data rates?
|
||||
|
||||
utm2ll : utm2ll.c geotranz.a textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
check-modem1200 : gen_packets atest
|
||||
gen_packets -n 100 -o /tmp/test1.wav
|
||||
atest -F0 -PE -L70 -G71 /tmp/test1.wav
|
||||
atest -F1 -PE -L73 -G75 /tmp/test1.wav
|
||||
#rm /tmp/test1.wav
|
||||
|
||||
check-modem300 : gen_packets atest
|
||||
gen_packets -B300 -n 100 -o /tmp/test3.wav
|
||||
atest -B300 -F0 -L68 -G69 /tmp/test3.wav
|
||||
atest -B300 -F1 -L73 -G75 /tmp/test3.wav
|
||||
rm /tmp/test3.wav
|
||||
|
||||
check-modem9600 : gen_packets atest
|
||||
gen_packets -B9600 -n 100 -o /tmp/test9.wav
|
||||
atest -B9600 -F0 -L57 -G59 /tmp/test9.wav
|
||||
atest -B9600 -F1 -L66 -G67 /tmp/test9.wav
|
||||
rm /tmp/test9.wav
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
.PHONY : dtest
|
||||
dtest : digipeater.c pfilter.o ax25_pad.o dedupe.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DDIGITEST -o $@ $^ $(LDFLAGS)
|
||||
./dtest
|
||||
rm dtest
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
# Unit test for APRStt tone sequence parsing.
|
||||
|
||||
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c morse.c textcolor.c dsp.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) -lm
|
||||
.PHONY : ttest
|
||||
ttest : aprs_tt.c tt_text.c latlong.o textcolor.o misc.a geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^ $(LDFLAGS)
|
||||
./ttest
|
||||
rm ttest
|
||||
|
||||
|
||||
# Unit test for APRStt tone sequence / text conversions.
|
||||
|
||||
.PHONY: tttexttest
|
||||
tttexttest : tt_text.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTTT_TEST -o $@ $^ $(LDFLAGS)
|
||||
./tttexttest
|
||||
rm tttexttest
|
||||
|
||||
|
||||
# Unit test for Packet Filtering.
|
||||
|
||||
.PHONY: pftest
|
||||
pftest : pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o symbols.o telemetry.o tt_text.o misc.a
|
||||
$(CC) $(CFLAGS) -DPFTEST -o $@ $^ $(LDFLAGS)
|
||||
./pftest
|
||||
rm pftest
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
.PHONY: tlmtest
|
||||
tlmtest : telemetry.c ax25_pad.o fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^ $(LDFLAGS)
|
||||
./tlmtest
|
||||
rm tlmtest
|
||||
|
||||
# Unit test for location coordinate conversion.
|
||||
|
||||
.PHONY: lltest
|
||||
lltest : latlong.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DLLTEST -o $@ $^ $(LDFLAGS)
|
||||
./lltest
|
||||
rm lltest
|
||||
|
||||
# Unit test for encoding position & object report.
|
||||
|
||||
.PHONY: enctest
|
||||
enctest : encode_aprs.c latlong.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -DEN_MAIN -o $@ $^ $(LDFLAGS)
|
||||
./enctest
|
||||
rm enctest
|
||||
|
||||
|
||||
# Unit test for KISS encapsulation.
|
||||
|
||||
.PHONY: kisstest
|
||||
kisstest : kiss_frame.c
|
||||
$(CC) $(CFLAGS) -DKISSTEST -o $@ $^ $(LDFLAGS)
|
||||
./kisstest
|
||||
rm kisstest
|
||||
|
||||
|
||||
|
||||
# ----------------------------- Manual tests and experiments ---------------------------
|
||||
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^
|
||||
./itest
|
||||
|
||||
# Unit test for UDP reception with AFSK demodulator
|
||||
|
||||
udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c rrbb.c
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
./udptest
|
||||
|
||||
demod.o : tune.h
|
||||
demod_afsk.o : tune.h
|
||||
|
@ -451,80 +691,19 @@ demod_9600.o : tune.h
|
|||
|
||||
testagc : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c latlong.c symbols.c tune.h textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -o atest $^ -lm
|
||||
$(CC) $(CFLAGS) -o atest $^ $(LDFLAGS)
|
||||
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
||||
|
||||
|
||||
# Unit test for AFSK demodulator
|
||||
|
||||
|
||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c latlong.c symbols.c tt_text.c textcolor.c \
|
||||
misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
|
||||
dtest : digipeater.c pfilter.c ax25_pad.c dedupe.c fcs_calc.c tq.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./dtest
|
||||
# ------------------------------- Source distribution ---------------------------------
|
||||
|
||||
# probably obsolete and can be removed after move to github.
|
||||
|
||||
|
||||
# Unit test for APRStt.
|
||||
|
||||
ttest : aprs_tt.c tt_text.c latlong.c textcolor.o misc.a geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^
|
||||
./itest
|
||||
|
||||
|
||||
# Unit test for UDP reception with AFSK demodulator
|
||||
|
||||
udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c rrbb.c
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||
./udptest
|
||||
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
|
||||
etest : telemetry.c ax25_pad.c fcs_calc.c textcolor.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||
./etest
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
# Touch Tone to Speech sample application.
|
||||
|
||||
ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -g -o $@ $^
|
||||
|
||||
|
||||
depend : $(wildcard *.c)
|
||||
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -f direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc \
|
||||
fsk_fast_filter.h *.o *.a direwolf.desktop
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
# Package it up for distribution.
|
||||
|
||||
.PHONY: dist-src
|
||||
dist-src : README.md CHANGES.md
|
||||
|
@ -556,22 +735,17 @@ dist-src : README.md CHANGES.md
|
|||
$z/telemetry-toolkit/* )
|
||||
|
||||
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
# -----------------------------------------------------------------------------------------
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
diff symbolsX.txt~ symbolsX.txt
|
||||
|
||||
.PHONY: clean
|
||||
clean :
|
||||
rm -f $(APPS) fsk_fast_filter.h *.o *.a direwolf.desktop
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
depend : $(wildcard *.c)
|
||||
makedepend -f $(lastword $(MAKEFILE_LIST)) -- $(CFLAGS) -- $^
|
||||
|
||||
|
||||
#
|
||||
|
|
184
Makefile.macosx
184
Makefile.macosx
|
@ -2,6 +2,14 @@
|
|||
# Makefile for Macintosh 10.8+ version of Dire Wolf.
|
||||
#
|
||||
|
||||
# TODO: This is a modified version of Makefile.linux and it
|
||||
# has fallen a little behind. For example, it is missing the check target.
|
||||
# It would be more maintainable if we could use a single file for both.
|
||||
# The differences are not that great.
|
||||
# Maybe the most of the differences could go in to platform specific include
|
||||
# files rather than cluttering it up with too many if blocks.
|
||||
|
||||
|
||||
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients atest log2gpx gen_packets ttcalc direwolf.conf
|
||||
@echo " "
|
||||
@echo "Next step install with: "
|
||||
|
@ -179,7 +187,7 @@ CFLAGS += -DUSE_PORTAUDIO -I/opt/local/include
|
|||
# Not available for MacOSX.
|
||||
# Although MacPorts has gpsd, wonder if it's the same thing.
|
||||
|
||||
#CFLAGS += -DENABLE_GPS
|
||||
#CFLAGS += -DENABLE_GPSD
|
||||
#LDLIBS += -lgps
|
||||
|
||||
# Name of current directory.
|
||||
|
@ -197,7 +205,8 @@ direwolf : direwolf.o aprs_tt.o audio_portaudio.o audio_stats.o ax25_pad.o beaco
|
|||
geotranz.a hdlc_rec.o hdlc_rec2.o hdlc_send.o igate.o kiss_frame.o \
|
||||
kiss.o kissnet.o latlong.o latlong.o log.o morse.o multi_modem.o \
|
||||
nmea.o serial_port.o pfilter.o ptt.o rdq.o recv.o redecode.o rrbb.o server.o \
|
||||
symbols.o telemetry.o textcolor.o tq.o tt_text.o tt_user.o xmit.o
|
||||
symbols.o telemetry.o textcolor.o tq.o tt_text.o tt_user.o xmit.o \
|
||||
dwgps.o dwgpsnmea.o dwgpsd.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread $(LDLIBS) -lm
|
||||
|
||||
|
||||
|
@ -264,45 +273,89 @@ INSTALLDIR := /usr/local
|
|||
# Needs to be run as root or with sudo.
|
||||
# TODO: Review file locations.
|
||||
|
||||
install : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx gen_packets \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png
|
||||
ginstall direwolf $(INSTALLDIR)/bin
|
||||
ginstall decode_aprs $(INSTALLDIR)/bin
|
||||
ginstall text2tt $(INSTALLDIR)/bin
|
||||
ginstall tt2text $(INSTALLDIR)/bin
|
||||
ginstall ll2utm $(INSTALLDIR)/bin
|
||||
ginstall utm2ll $(INSTALLDIR)/bin
|
||||
ginstall aclients $(INSTALLDIR)/bin
|
||||
ginstall log2gpx $(INSTALLDIR)/bin
|
||||
ginstall gen_packets $(INSTALLDIR)/bin
|
||||
ginstall atest $(INSTALLDIR)/bin
|
||||
ginstall ttcalc $(INSTALLDIR)/bin
|
||||
ginstall dwespeak.sh $(INSTALLDIR)/bin
|
||||
ginstall telemetry-toolkit/*.p[ly] $(INSTALLDIR)/bin
|
||||
ginstall -D --mode=644 tocalls.txt $(INSTALLDIR)/share/direwolf/tocalls.txt
|
||||
ginstall -D --mode=644 symbols-new.txt $(INSTALLDIR)/share/direwolf/symbols-new.txt
|
||||
ginstall -D --mode=644 symbolsX.txt $(INSTALLDIR)/share/direwolf/symbolsX.txt
|
||||
ginstall -D --mode=644 dw-icon.png $(INSTALLDIR)/share/direwolf/dw-icon.png
|
||||
ginstall -D --mode=644 README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
ginstall -D --mode=644 CHANGES.md $(INSTALLDIR)/share/doc/direwolf/CHANGES.md
|
||||
ginstall -D --mode=644 direwolf.conf $(INSTALLDIR)/share/direwolf/config/direwolf.conf
|
||||
ginstall -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
ginstall -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
ginstall -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
ginstall -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
ginstall -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
ginstall -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
ginstall -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
ginstall -D --mode=644 man1/aclients.1 $(INSTALLDIR)/man/man1/aclients.1
|
||||
ginstall -D --mode=644 man1/atest.1 $(INSTALLDIR)/man/man1/atest.1
|
||||
ginstall -D --mode=644 man1/decode_aprs.1 $(INSTALLDIR)/man/man1/decode_aprs.1
|
||||
ginstall -D --mode=644 man1/direwolf.1 $(INSTALLDIR)/man/man1/direwolf.1
|
||||
ginstall -D --mode=644 man1/gen_packets.1 $(INSTALLDIR)/man/man1/gen_packets.1
|
||||
ginstall -D --mode=644 man1/ll2utm.1 $(INSTALLDIR)/man/man1/ll2utm.1
|
||||
ginstall -D --mode=644 man1/log2gpx.1 $(INSTALLDIR)/man/man1/log2gpx.1
|
||||
ginstall -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
|
||||
ginstall -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
|
||||
ginstall -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
|
||||
# Command to "install" to system directories. "install" for Linux. "ginstall" for Mac.
|
||||
|
||||
INSTALL=ginstall
|
||||
|
||||
.PHONY: install
|
||||
install : $(APPS) direwolf.conf tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
||||
#
|
||||
# Applications, not installed with package manager, normally go in /usr/local/bin.
|
||||
# /usr/bin is used instead when installing from .DEB or .RPM package.
|
||||
#
|
||||
$(INSTALL) direwolf $(INSTALLDIR)/bin
|
||||
$(INSTALL) decode_aprs $(INSTALLDIR)/bin
|
||||
$(INSTALL) text2tt $(INSTALLDIR)/bin
|
||||
$(INSTALL) tt2text $(INSTALLDIR)/bin
|
||||
$(INSTALL) ll2utm $(INSTALLDIR)/bin
|
||||
$(INSTALL) utm2ll $(INSTALLDIR)/bin
|
||||
$(INSTALL) aclients $(INSTALLDIR)/bin
|
||||
$(INSTALL) log2gpx $(INSTALLDIR)/bin
|
||||
$(INSTALL) gen_packets $(INSTALLDIR)/bin
|
||||
$(INSTALL) atest $(INSTALLDIR)/bin
|
||||
$(INSTALL) ttcalc $(INSTALLDIR)/bin
|
||||
$(INSTALL) dwespeak.sh $(INSTALLDIR)/bin
|
||||
#
|
||||
# Telemetry Toolkit executables. Other .conf and .txt files will go into doc directory.
|
||||
#
|
||||
$(INSTALL) telemetry-toolkit/telem-balloon.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-bits.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-data91.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-eqns.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-parm.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-unit.pl $(INSTALLDIR)/bin
|
||||
$(INSTALL) telemetry-toolkit/telem-volts.py $(INSTALLDIR)/bin
|
||||
#
|
||||
# Misc. data such as "tocall" to system mapping.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||
$(INSTALL) -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||
$(INSTALL) -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||
$(INSTALL) -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||
$(INSTALL) -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||
#
|
||||
# Documentation. Various plain text files and PDF.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 README.md $(INSTALLDIR)/share/doc/direwolf/README.md
|
||||
$(INSTALL) -D --mode=644 CHANGES.md $(INSTALLDIR)/share/doc/direwolf/CHANGES.md
|
||||
$(INSTALL) -D --mode=644 LICENSE-dire-wolf.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||
$(INSTALL) -D --mode=644 LICENSE-other.txt $(INSTALLDIR)/share/doc/direwolf/LICENSE-other.txt
|
||||
#
|
||||
$(INSTALL) -D --mode=644 doc/User-Guide.pdf $(INSTALLDIR)/share/doc/direwolf/User-Guide.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-APRS-Tracker.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||
$(INSTALL) -D --mode=644 doc/Raspberry-Pi-SDR-IGate.pdf $(INSTALLDIR)/share/doc/direwolf/Raspberry-Pi-SDR-IGate.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-Implementation-Notes.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRStt-interface-for-SARTrack.pdf $(INSTALLDIR)/share/doc/direwolf/APRStt-interface-for-SARTrack.pdf
|
||||
$(INSTALL) -D --mode=644 doc/APRS-Telemetry-Toolkit.pdf $(INSTALLDIR)/share/doc/direwolf/APRS-Telemetry-Toolkit.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-1-1200-baud.pdf
|
||||
$(INSTALL) -D --mode=644 doc/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf $(INSTALLDIR)/share/doc/direwolf/A-Better-APRS-Packet-Demodulator-Part-2-9600-baud.pdf
|
||||
#
|
||||
# Sample config files also go into the doc directory.
|
||||
# When building from source, these can be put in home directory with "make install-conf".
|
||||
# When installed from .DEB or .RPM package, the user will need to copy these to
|
||||
# the home directory or other desired location.
|
||||
# Someone suggested that these could go into an "examples" subdirectory under doc.
|
||||
#
|
||||
$(INSTALL) -D --mode=644 direwolf.conf $(INSTALLDIR)/share/doc/direwolf/direwolf.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-m0xer-3.txt $(INSTALLDIR)/share/doc/direwolf/telem-m0xer-3.txt
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-balloon.conf $(INSTALLDIR)/share/doc/direwolf/telem-balloon.conf
|
||||
$(INSTALL) -D --mode=644 telemetry-toolkit/telem-volts.conf $(INSTALLDIR)/share/doc/direwolf/telem-volts.conf
|
||||
#
|
||||
# "man" pages
|
||||
#
|
||||
$(INSTALL) -D --mode=644 man1/aclients.1 $(INSTALLDIR)/man/man1/aclients.1
|
||||
$(INSTALL) -D --mode=644 man1/atest.1 $(INSTALLDIR)/man/man1/atest.1
|
||||
$(INSTALL) -D --mode=644 man1/decode_aprs.1 $(INSTALLDIR)/man/man1/decode_aprs.1
|
||||
$(INSTALL) -D --mode=644 man1/direwolf.1 $(INSTALLDIR)/man/man1/direwolf.1
|
||||
$(INSTALL) -D --mode=644 man1/gen_packets.1 $(INSTALLDIR)/man/man1/gen_packets.1
|
||||
$(INSTALL) -D --mode=644 man1/ll2utm.1 $(INSTALLDIR)/man/man1/ll2utm.1
|
||||
$(INSTALL) -D --mode=644 man1/log2gpx.1 $(INSTALLDIR)/man/man1/log2gpx.1
|
||||
$(INSTALL) -D --mode=644 man1/text2tt.1 $(INSTALLDIR)/man/man1/text2tt.1
|
||||
$(INSTALL) -D --mode=644 man1/tt2text.1 $(INSTALLDIR)/man/man1/tt2text.1
|
||||
$(INSTALL) -D --mode=644 man1/utm2ll.1 $(INSTALLDIR)/man/man1/utm2ll.1
|
||||
#
|
||||
@echo " "
|
||||
@echo "If this is your first install, not an upgrade, type this to put a copy"
|
||||
@echo "of the sample configuration file (direwolf.conf) in your home directory:"
|
||||
|
@ -333,16 +386,16 @@ install-conf : direwolf.conf
|
|||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c latlong.c log.c telemetry.o tt_text.o
|
||||
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^ -lm
|
||||
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o $@ $^ -lm
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o text2tt tt_text.c
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^
|
||||
|
||||
tt2text : tt_text.c
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o tt2text tt_text.c
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
@ -378,21 +431,22 @@ testagc : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o
|
|||
# Unit test for AFSK demodulator
|
||||
|
||||
|
||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c latlong.c symbols.c textcolor.c tt_text.c
|
||||
atest : atest.c fsk_fast_filter.h demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o telemetry.c latlong.c symbols.c textcolor.c tt_text.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
|
||||
dtest : digipeater.c pfilter.c ax25_pad.c dedupe.c fcs_calc.c tq.c textcolor.c
|
||||
dtest : digipeater.c pfilter.o ax25_pad.o dedupe.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./dtest
|
||||
|
||||
|
||||
# Unit test for APRStt.
|
||||
|
||||
ttest : aprs_tt.c tt_text.c latlong.c misc.a geotranz.a
|
||||
ttest : aprs_tt.c tt_text.c latlong.c geotranz.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^
|
||||
|
||||
|
||||
|
@ -414,9 +468,9 @@ udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec
|
|||
# Unit test for telemetry decoding.
|
||||
|
||||
|
||||
etest : telemetry.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
||||
tlmtest : telemetry.c ax25_pad.c fcs_calc.c textcolor.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
./etest
|
||||
./tlmtest
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
@ -514,3 +568,31 @@ dist-src : README.md CHANGES.md \
|
|||
$z/dw-start.sh $z/direwolf.spec \
|
||||
$z/dwespeak.bat $z/dwespeak.sh \
|
||||
$z/telemetry-toolkit/* )
|
||||
|
||||
|
||||
#
|
||||
# The destination field is often used to identify the manufacturer/model.
|
||||
# These are not hardcoded into Dire Wolf. Instead they are read from
|
||||
# a file called tocalls.txt at application start up time.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff symbolsX.txt~ symbolsX.txt
|
||||
|
|
292
Makefile.win
292
Makefile.win
|
@ -56,13 +56,10 @@ CFLAGS += -g
|
|||
# you can compile this yourself with different options.
|
||||
#
|
||||
|
||||
# Name of zip file for distribution.
|
||||
|
||||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
|
||||
# Main application.
|
||||
# -------------------------------------- Main application --------------------------------
|
||||
|
||||
demod.o : fsk_demod_state.h
|
||||
demod_9600.o : fsk_demod_state.h
|
||||
|
@ -75,7 +72,8 @@ direwolf : direwolf.o config.o recv.o demod.o dsp.o demod_afsk.o demod_9600.o hd
|
|||
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||
gen_tone.o morse.o audio_win.o audio_stats.o digipeater.o pfilter.o dedupe.o tq.o xmit.o \
|
||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o dtime_now.o \
|
||||
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o serial_port.o log.o telemetry.o \
|
||||
dwgps.o dwgpsnmea.o dtime_now.o \
|
||||
dw-icon.o regex.a misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
@ -95,6 +93,79 @@ fsk_fast_filter.h : demod_afsk.c
|
|||
./gen_fff > fsk_fast_filter.h
|
||||
|
||||
|
||||
#
|
||||
# The destination field is often used to identify the manufacturer/model.
|
||||
# These are not hardcoded into Dire Wolf. Instead they are read from
|
||||
# a file called tocalls.txt at application start up time.
|
||||
#
|
||||
# The original permanent symbols are built in but the "new" symbols,
|
||||
# using overlays, are often updated. These are also read from files.
|
||||
#
|
||||
# You can obtain an updated copy by typing "make tocalls-symbols".
|
||||
# This is not part of the normal build process. You have to do this explicitly.
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
-diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
-diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
-diff symbolsX.txt~ symbolsX.txt
|
||||
|
||||
|
||||
|
||||
# ---------------------------- Other utilities included with distribution -------------------------
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
decode_aprs : decode_aprs.c dwgpsnmea.o dwgps.o serial_port.o symbols.o ax25_pad.o textcolor.o fcs_calc.o latlong.o log.o telemetry.o tt_text.o regex.a misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -DDECAMAIN -o decode_aprs $^
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o $@ $^
|
||||
|
||||
tt2text : tt_text.c misc.a
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c textcolor.c geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
utm2ll : utm2ll.c textcolor.c geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
|
||||
log2gpx : log2gpx.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.o ax25_pad.o hdlc_send.o fcs_calc.o gen_tone.o morse.o textcolor.o dsp.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------- Libraries --------------------------------------------
|
||||
|
||||
|
||||
|
||||
# UTM, USNG, MGRS conversions.
|
||||
|
||||
geotranz.a : error_string.o mgrs.o polarst.o tranmerc.o ups.o usng.o utm.o
|
||||
|
@ -136,8 +207,8 @@ regex.o : regex/regex.c
|
|||
$(CC) $(CFLAGS) -Dbool=int -Dtrue=1 -Dfalse=0 -c -o $@ $^
|
||||
|
||||
|
||||
# There are also a couple other functions in the misc
|
||||
# subdirectory that are missing on Windows.
|
||||
# There are several string functios found in Linux
|
||||
# but not on Windows. Need to provide our own copy.
|
||||
|
||||
misc.a : strsep.o strtok_r.o strcasestr.o strlcpy.o strlcat.o
|
||||
ar -cr $@ $^
|
||||
|
@ -158,41 +229,129 @@ strlcat.o : misc/strlcat.c
|
|||
$(CC) $(CFLAGS) -I. -c -o $@ $^
|
||||
|
||||
|
||||
# Separate application to decode raw data.
|
||||
|
||||
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c latlong.c log.o telemetry.o tt_text.o regex.a misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^
|
||||
# --------------------------------- Automated Smoke Test --------------------------------
|
||||
|
||||
|
||||
# Convert between text and touch tone representation.
|
||||
|
||||
text2tt : tt_text.c
|
||||
$(CC) $(CFLAGS) -DENC_MAIN -o text2tt tt_text.c
|
||||
|
||||
tt2text : tt_text.c
|
||||
$(CC) $(CFLAGS) -DDEC_MAIN -o tt2text tt_text.c
|
||||
# Combine some unit tests into a single regression sanity check.
|
||||
|
||||
|
||||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
check : dtest ttest tttexttest pftest tlmtest lltest enctest kisstest check-modem1200 check-modem300 check-modem9600
|
||||
|
||||
ll2utm : ll2utm.c textcolor.c geotranz.a misc.a
|
||||
# Can we encode and decode at popular data rates?
|
||||
|
||||
check-modem1200 : gen_packets atest
|
||||
gen_packets -n 100 -o test1.wav
|
||||
atest -F0 -PE -L70 -G71 test1.wav
|
||||
atest -F1 -PE -L73 -G75 test1.wav
|
||||
#rm test1.wav
|
||||
|
||||
check-modem300 : gen_packets atest
|
||||
gen_packets -B300 -n 100 -o test3.wav
|
||||
atest -B300 -F0 -L68 -G69 test3.wav
|
||||
atest -B300 -F1 -L73 -G75 test3.wav
|
||||
rm test3.wav
|
||||
|
||||
check-modem9600 : gen_packets atest
|
||||
gen_packets -B9600 -n 100 -o test9.wav
|
||||
atest -B9600 -F0 -L57 -G59 test9.wav
|
||||
atest -B9600 -F1 -L66 -G67 test9.wav
|
||||
rm test9.wav
|
||||
|
||||
# Unit test for AFSK demodulator
|
||||
|
||||
atest : atest.c fsk_fast_filter.h demod.c demod_afsk.c demod_9600.c \
|
||||
dsp.o hdlc_rec.o hdlc_rec2.o multi_modem.o \
|
||||
rrbb.o fcs_calc.o ax25_pad.o decode_aprs.o \
|
||||
dwgpsnmea.o dwgps.o serial_port.o latlong.c \
|
||||
symbols.c tt_text.c textcolor.c telemetry.c \
|
||||
misc.a regex.a
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
#./atest ..\\direwolf-0.2\\02_Track_2.wav
|
||||
#atest -B 9600 z9.wav
|
||||
#atest za100.wav
|
||||
|
||||
utm2ll : utm2ll.c textcolor.c geotranz.a misc.a
|
||||
atest9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
||||
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c latlong.c symbols.c textcolor.c telemetry.c misc.a regex.a \
|
||||
fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
./atest9 -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
||||
#./atest9 -B 9600 noise96.wav
|
||||
|
||||
|
||||
# Convert from log file to GPX.
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
#log2gpx : log2gpx.c misc/strsep.c misc/strtok_r.c
|
||||
log2gpx : log2gpx.c misc.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
.PHONY: dtest
|
||||
dtest : digipeater.c pfilter.o ax25_pad.o dedupe.o fcs_calc.o tq.o textcolor.o \
|
||||
decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o telemetry.o symbols.o tt_text.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DDIGITEST -o $@ $^
|
||||
./dtest
|
||||
rm dtest.exe
|
||||
|
||||
# Unit test for APRStt tone seqence parsing.
|
||||
|
||||
.PHONTY: ttest
|
||||
ttest : aprs_tt.c tt_text.c latlong.o textcolor.o geotranz.a misc.a
|
||||
$(CC) $(CFLAGS) -Igeotranz -DTT_MAIN -o $@ $^
|
||||
./ttest
|
||||
rm ttest.exe
|
||||
|
||||
# Unit test for APRStt tone sequence / text conversions.
|
||||
|
||||
.PHONY: tttexttest
|
||||
tttexttest : tt_text.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DTTT_TEST -o $@ $^
|
||||
./tttexttest
|
||||
rm tttexttest.exe
|
||||
|
||||
# Unit test for Packet Filtering.
|
||||
|
||||
.PHONY: pftest
|
||||
pftest : pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o dwgpsnmea.o dwgps.o serial_port.o latlong.o symbols.o telemetry.o tt_text.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DPFTEST -o $@ $^
|
||||
./pftest
|
||||
rm pftest.exe
|
||||
|
||||
|
||||
# Test application to generate sound.
|
||||
|
||||
gen_packets : gen_packets.o ax25_pad.o hdlc_send.o fcs_calc.o gen_tone.o morse.o textcolor.o dsp.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
.PHONY: tlmtest
|
||||
tlmtest : telemetry.c ax25_pad.o fcs_calc.o textcolor.o misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./tlmtest
|
||||
rm tlmtest.exe
|
||||
|
||||
|
||||
# Unit test for location coordinate conversion.
|
||||
|
||||
.PHONY: lltest
|
||||
lltest : latlong.c textcolor.o misc.a
|
||||
$(CC) $(CFLAGS) -DLLTEST -o $@ $^
|
||||
./lltest
|
||||
rm lltest.exe
|
||||
|
||||
# Unit test for encoding position & object report.
|
||||
|
||||
.PHONY: enctest
|
||||
enctest : encode_aprs.c latlong.c textcolor.c misc.a
|
||||
$(CC) $(CFLAGS) -DEN_MAIN -o $@ $^
|
||||
./enctest
|
||||
rm enctest.exe
|
||||
|
||||
|
||||
# Unit test for KISS encapsulation.
|
||||
|
||||
.PHONY: kisstest
|
||||
kisstest : kiss_frame.c
|
||||
$(CC) $(CFLAGS) -DKISSTEST -o $@ $^
|
||||
./kisstest
|
||||
rm kisstest.exe
|
||||
|
||||
|
||||
# ------------------------------ Other manual testing & experimenting -------------------------------
|
||||
|
||||
|
||||
# For tweaking the demodulator.
|
||||
|
||||
|
@ -236,54 +395,14 @@ testagc9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.
|
|||
#./atest -B 9600 noisy96.wav | grep "packets decoded in" >atest.out
|
||||
echo " " > tune.h
|
||||
|
||||
|
||||
# Unit test for AFSK demodulator
|
||||
|
||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
||||
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c latlong.c symbols.c tt_text.c textcolor.c telemetry.c misc.a regex.a \
|
||||
fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
#./atest ..\\direwolf-0.2\\02_Track_2.wav
|
||||
#atest -B 9600 z9.wav
|
||||
#atest za100.wav
|
||||
|
||||
atest9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
||||
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c latlong.c symbols.c textcolor.c telemetry.c misc.a regex.a \
|
||||
fsk_fast_filter.h
|
||||
echo " " > tune.h
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
./atest9 -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
||||
#./atest9 -B 9600 noise96.wav
|
||||
|
||||
|
||||
# Unit test for inner digipeater algorithm
|
||||
|
||||
|
||||
dtest : digipeater.c pfilter.c ax25_pad.c dedupe.c fcs_calc.c tq.c textcolor.c misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./dtest
|
||||
rm dtest.exe
|
||||
|
||||
# Unit test for APRStt.
|
||||
|
||||
ttest : aprs_tt.c tt_text.c latlong.c misc.a geotranz.a
|
||||
$(CC) $(CFLAGS) -DTT_MAIN -o $@ $^
|
||||
|
||||
|
||||
# Unit test for IGate
|
||||
|
||||
itest : igate.c textcolor.c ax25_pad.c fcs_calc.c misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DITEST -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
# Unit test for telemetry decoding.
|
||||
|
||||
|
||||
etest : telemetry.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $^
|
||||
./etest
|
||||
|
||||
|
||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||
|
||||
|
@ -299,14 +418,20 @@ ttcalc : ttcalc.o ax25_pad.o fcs_calc.o textcolor.o misc.a regex.a
|
|||
|
||||
# Send GPS location to KISS TNC each second.
|
||||
|
||||
walk96 : walk96.c nmea.c kiss_frame.c \
|
||||
walk96 : walk96.c dwgps.o dwgpsnmea.o kiss_frame.o \
|
||||
latlong.o encode_aprs.o serial_port.o textcolor.o \
|
||||
ax25_pad.o fcs_calc.o regex.a \
|
||||
misc.a
|
||||
ax25_pad.o fcs_calc.o \
|
||||
xmit.o hdlc_send.o gen_tone.o ptt.o tq.o \
|
||||
hdlc_rec.o hdlc_rec2.o rrbb.o dsp.o audio_win.o \
|
||||
multi_modem.o demod.o demod_afsk.o demod_9600.o rdq.o \
|
||||
server.o morse.o audio_stats.o dtime_now.o dlq.o \
|
||||
regex.a misc.a
|
||||
$(CC) $(CFLAGS) -DWALK96 -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------
|
||||
|
||||
|
||||
.PHONY: depend
|
||||
depend : $(wildcard *.c)
|
||||
|
@ -318,7 +443,12 @@ clean :
|
|||
echo " " > tune.h
|
||||
|
||||
|
||||
# Package it up for distribution: Prebuilt Windows & source versions.
|
||||
|
||||
# ------------------------------- Packaging for distribution ----------------------
|
||||
|
||||
# Name of zip file for distribution.
|
||||
|
||||
z := $(notdir ${CURDIR})
|
||||
|
||||
|
||||
# Left out RPi Tracker due to Comcast upload size limit.
|
||||
|
@ -418,7 +548,7 @@ dist-src : README.md CHANGES.md \
|
|||
unix2dos telemetry-toolkit/telem-volts.conf
|
||||
|
||||
|
||||
|
||||
# Reminders if pdf files are not up to date.
|
||||
|
||||
doc/User-Guide.pdf : doc/User-Guide.docx
|
||||
echo "***** User-Guide.pdf is out of date *****"
|
||||
|
@ -448,22 +578,6 @@ backup :
|
|||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
cp -r . /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
.PHONY: tocalls-symbols
|
||||
tocalls-symbols :
|
||||
cp tocalls.txt tocalls.txt~
|
||||
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||
diff tocalls.txt~ tocalls.txt
|
||||
cp symbols-new.txt symbols-new.txt~
|
||||
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||
diff symbols-new.txt~ symbols-new.txt
|
||||
cp symbolsX.txt symbolsX.txt~
|
||||
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||
diff symbolsX.txt~ symbolsX.txt
|
||||
|
||||
#
|
||||
# The following is updated by "make depend"
|
||||
|
|
19
aclients.c
19
aclients.c
|
@ -71,6 +71,7 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#include "direwolf.h"
|
||||
|
@ -115,7 +116,7 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
case AF_INET:
|
||||
sa4 = (struct sockaddr_in *)pAddr;
|
||||
#if __WIN32__
|
||||
sprintf (pStringBuf, "%d.%d.%d.%d", sa4->sin_addr.S_un.S_un_b.s_b1,
|
||||
snprintf (pStringBuf, StringBufSize, "%d.%d.%d.%d", sa4->sin_addr.S_un.S_un_b.s_b1,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b2,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b3,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b4);
|
||||
|
@ -126,7 +127,7 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
case AF_INET6:
|
||||
sa6 = (struct sockaddr_in6 *)pAddr;
|
||||
#if __WIN32__
|
||||
sprintf (pStringBuf, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
snprintf (pStringBuf, StringBufSize, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[0]),
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[1]),
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[2]),
|
||||
|
@ -140,7 +141,7 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
#endif
|
||||
break;
|
||||
default:
|
||||
sprintf (pStringBuf, "Invalid address family!");
|
||||
snprintf (pStringBuf, StringBufSize, "Invalid address family!");
|
||||
}
|
||||
assert (strlen(pStringBuf) < StringBufSize);
|
||||
return pStringBuf;
|
||||
|
@ -222,20 +223,20 @@ int main (int argc, char *argv[])
|
|||
char stemp[100];
|
||||
char *p;
|
||||
|
||||
strcpy (stemp, argv[j+1]);
|
||||
strlcpy (stemp, argv[j+1], sizeof(stemp));
|
||||
p = strtok (stemp, "=");
|
||||
if (p == NULL) {
|
||||
printf ("Internal error 1\n");
|
||||
exit (1);
|
||||
}
|
||||
strcpy (hostname[j], "localhost");
|
||||
strcpy (port[j], p);
|
||||
strlcpy (hostname[j], "localhost", sizeof(hostname[j]));
|
||||
strlcpy (port[j], p, sizeof(port[j]));
|
||||
p = strtok (NULL, "=");
|
||||
if (p == NULL) {
|
||||
printf ("Missing description after %s\n", port[j]);
|
||||
exit (1);
|
||||
}
|
||||
strcpy (description[j], p);
|
||||
strlcpy (description[j], p, sizeof(description[j]));
|
||||
}
|
||||
|
||||
//printf ("_WIN32_WINNT = %04x\n", _WIN32_WINNT);
|
||||
|
@ -579,14 +580,14 @@ static void * client_thread_net (void *arg)
|
|||
|
||||
//printf ("server %d, portx = %d\n", my_index, mon_cmd.portx);
|
||||
|
||||
use_chan == mon_cmd.portx;
|
||||
use_chan = mon_cmd.portx;
|
||||
memset (&alevel, 0xff, sizeof(alevel));
|
||||
pp = ax25_from_frame ((unsigned char *)(data+1), mon_cmd.data_len-1, alevel);
|
||||
assert (pp != NULL);
|
||||
ax25_format_addrs (pp, result);
|
||||
info_len = ax25_get_info (pp, (unsigned char **)(&pinfo));
|
||||
pinfo[info_len] = '\0';
|
||||
strcat (result, pinfo);
|
||||
strlcat (result, pinfo, sizeof(result));
|
||||
for (p=result; *p!='\0'; p++) {
|
||||
if (! isprint(*p)) *p = ' ';
|
||||
}
|
||||
|
|
364
aprs_tt.c
364
aprs_tt.c
|
@ -22,9 +22,14 @@
|
|||
*
|
||||
* Module: aprs_tt.c
|
||||
*
|
||||
* Purpose: APRStt gateway.
|
||||
* Purpose: First half of APRStt gateway.
|
||||
*
|
||||
* Description: This file contains functions to parse the tone sequences
|
||||
* and extract meaning from them.
|
||||
*
|
||||
* tt_user.c maintains information about users and
|
||||
* generates the APRS Object Reports.
|
||||
*
|
||||
* Description: Transfer touch tone messages into the APRS network.
|
||||
*
|
||||
* References: This is based upon APRStt (TM) documents with some
|
||||
* artistic freedom.
|
||||
|
@ -38,7 +43,7 @@
|
|||
|
||||
// TODO: clean up terminolgy.
|
||||
// "Message" has a specific meaning in APRS and this is not it.
|
||||
// Touch Tone sequence might be appropriate.
|
||||
// Touch Tone sequence should be appropriate.
|
||||
// What do we call the parts separated by * key? Entry? Field?
|
||||
|
||||
|
||||
|
@ -67,9 +72,7 @@
|
|||
#include "tq.h"
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||
#endif
|
||||
|
||||
|
||||
// geotranz
|
||||
|
||||
|
@ -103,9 +106,11 @@ static int parse_location (char *e);
|
|||
static int parse_comment (char *e);
|
||||
static int expand_macro (char *e);
|
||||
static void raw_tt_data_to_app (int chan, char *msg);
|
||||
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr);
|
||||
|
||||
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr, size_t valstrsize);
|
||||
|
||||
#if TT_MAIN
|
||||
static void check_result (void);
|
||||
#endif
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
|
@ -285,8 +290,8 @@ void aprs_tt_button (int chan, char button)
|
|||
*
|
||||
* Returns: None
|
||||
*
|
||||
* Description: Process a complete message.
|
||||
* It should have one or more fields separatedy by *
|
||||
* Description: Process a complete tone sequence.
|
||||
* It should have one or more fields separated by *
|
||||
* and terminated by a final # like these:
|
||||
*
|
||||
* callsign #
|
||||
|
@ -312,27 +317,22 @@ static char m_callsign[20]; /* really object name */
|
|||
*/
|
||||
|
||||
static char m_symtab_or_overlay;
|
||||
static char m_symbol_code;
|
||||
static char m_symbol_code; // Default 'A'
|
||||
|
||||
static char m_loc_text[24];
|
||||
static double m_longitude;
|
||||
static double m_latitude;
|
||||
static double m_longitude; // Set to G_UNKNOWN if not defined.
|
||||
static double m_latitude; // Set to G_UNKNOWN if not defined.
|
||||
static char m_comment[200];
|
||||
static char m_freq[12];
|
||||
static char m_mic_e;
|
||||
static char m_dao[6];
|
||||
static int m_ssid;
|
||||
|
||||
//#define G_UNKNOWN -999999
|
||||
static int m_ssid; // Default 12 for APRStt user.
|
||||
|
||||
|
||||
|
||||
void aprs_tt_sequence (int chan, char *msg)
|
||||
{
|
||||
int err;
|
||||
char audible_response[1000];
|
||||
packet_t pp;
|
||||
char script_response[1000];
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
@ -367,37 +367,40 @@ void aprs_tt_sequence (int chan, char *msg)
|
|||
*/
|
||||
err = parse_fields (msg);
|
||||
|
||||
#if defined(DEBUG) || defined(TT_MAIN)
|
||||
#if defined(DEBUG)
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("callsign=\"%s\", ssid=%d, symbol=\"%c%c\", freq=\"%s\", comment=\"%s\", lat=%.4f, lon=%.4f, dao=\"%s\"\n",
|
||||
m_callsign, m_ssid, m_symtab_or_overlay, m_symbol_code, m_freq, m_comment, m_latitude, m_longitude, m_dao);
|
||||
#endif
|
||||
|
||||
#if TT_MAIN
|
||||
check_result (); // for unit testing.
|
||||
#else
|
||||
|
||||
/*
|
||||
* If digested successfully. Add to our list of users and schedule transmissions.
|
||||
*/
|
||||
|
||||
if (err == 0) {
|
||||
|
||||
/*
|
||||
* Digested successfully. Add to our list of users and schedule transmissions.
|
||||
*/
|
||||
|
||||
#ifndef TT_MAIN
|
||||
err = tt_user_heard (m_callsign, m_ssid, m_symtab_or_overlay, m_symbol_code,
|
||||
m_loc_text, m_latitude, m_longitude,
|
||||
m_freq, m_comment, m_mic_e, m_dao);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If a command / script was supplied, run it now.
|
||||
* This can do additional processing and provide a custom audible response.
|
||||
* This is done even for the error case.
|
||||
*/
|
||||
char script_response[1000];
|
||||
|
||||
strlcpy (script_response, "", sizeof(script_response));
|
||||
|
||||
if (strlen(tt_config.ttcmd) > 0) {
|
||||
|
||||
dw_run_cmd (tt_config.ttcmd, 1, script_response, (int)sizeof(script_response));
|
||||
dw_run_cmd (tt_config.ttcmd, 1, script_response, sizeof(script_response));
|
||||
|
||||
}
|
||||
|
||||
|
@ -407,11 +410,15 @@ void aprs_tt_sequence (int chan, char *msg)
|
|||
* Use high priority queue for consistent timing.
|
||||
*/
|
||||
|
||||
char audible_response[1000];
|
||||
|
||||
snprintf (audible_response, sizeof(audible_response),
|
||||
"APRSTT>%s:%s",
|
||||
tt_config.response[err].method,
|
||||
(strlen(script_response) > 0) ? script_response : tt_config.response[err].mtext);
|
||||
|
||||
packet_t pp;
|
||||
|
||||
pp = ax25_from_text (audible_response, 0);
|
||||
|
||||
if (pp == NULL) {
|
||||
|
@ -422,6 +429,7 @@ void aprs_tt_sequence (int chan, char *msg)
|
|||
|
||||
tq_append (chan, TQ_PRIO_0_HI, pp);
|
||||
|
||||
#endif /* ifndef TT_MAIN */
|
||||
|
||||
} /* end aprs_tt_sequence */
|
||||
|
||||
|
@ -461,14 +469,14 @@ static int parse_fields (char *msg)
|
|||
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//printf ("parse_fields (%s).\n", msg);
|
||||
//dw_printf ("parse_fields (%s).\n", msg);
|
||||
|
||||
strlcpy (stemp, msg, sizeof(stemp));
|
||||
e = strtok_r (stemp, "*#", &save);
|
||||
while (e != NULL) {
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//printf ("parse_fields () field = %s\n", e);
|
||||
//dw_printf ("parse_fields () field = %s\n", e);
|
||||
|
||||
switch (*e) {
|
||||
|
||||
|
@ -539,7 +547,7 @@ static int parse_fields (char *msg)
|
|||
}
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//printf ("parse_fields () normal return\n");
|
||||
//dw_printf ("parse_fields () normal return\n");
|
||||
|
||||
return (0);
|
||||
|
||||
|
@ -566,21 +574,23 @@ static int parse_fields (char *msg)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
#define VALSTRSIZE 20
|
||||
|
||||
static int expand_macro (char *e)
|
||||
{
|
||||
int len;
|
||||
//int len;
|
||||
int ipat;
|
||||
char xstr[20], ystr[20], zstr[20], bstr[20], dstr[20];
|
||||
char xstr[VALSTRSIZE], ystr[VALSTRSIZE], zstr[VALSTRSIZE], bstr[VALSTRSIZE], dstr[VALSTRSIZE];
|
||||
char stemp[MAX_MSG_LEN+1];
|
||||
char *d, *s;
|
||||
char *d;
|
||||
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("Macro tone sequence: '%s'\n", e);
|
||||
|
||||
len = strlen(e);
|
||||
//len = strlen(e);
|
||||
|
||||
ipat = find_ttloc_match (e, xstr, ystr, zstr, bstr, dstr);
|
||||
ipat = find_ttloc_match (e, xstr, ystr, zstr, bstr, dstr, VALSTRSIZE);
|
||||
|
||||
if (ipat >= 0) {
|
||||
|
||||
|
@ -723,7 +733,7 @@ static int checksum_not_ok (char *str, int len, char found)
|
|||
static int parse_callsign (char *e)
|
||||
{
|
||||
int len;
|
||||
int c_length;
|
||||
//int c_length;
|
||||
char tttemp[40], stemp[30];
|
||||
|
||||
assert (*e == 'A');
|
||||
|
@ -838,8 +848,9 @@ static int parse_callsign (char *e)
|
|||
static int parse_object_name (char *e)
|
||||
{
|
||||
int len;
|
||||
int c_length;
|
||||
char tttemp[40], stemp[30];
|
||||
//int c_length;
|
||||
//char tttemp[40];
|
||||
//char stemp[30];
|
||||
|
||||
assert (e[0] == 'A');
|
||||
assert (e[1] == 'A');
|
||||
|
@ -991,19 +1002,15 @@ static int parse_symbol (char *e)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/* Average radius of earth in meters. */
|
||||
#define R 6371000.
|
||||
|
||||
|
||||
|
||||
|
||||
static int parse_location (char *e)
|
||||
{
|
||||
int len;
|
||||
//int len;
|
||||
int ipat;
|
||||
char xstr[20], ystr[20], zstr[20], bstr[20], dstr[20];
|
||||
char xstr[VALSTRSIZE], ystr[VALSTRSIZE], zstr[VALSTRSIZE], bstr[VALSTRSIZE], dstr[VALSTRSIZE];
|
||||
double x, y, dist, bearing;
|
||||
double lat0, lon0;
|
||||
double lat9, lon9;
|
||||
|
@ -1022,9 +1029,9 @@ static int parse_location (char *e)
|
|||
/* If this ever changes, be sure to update corresponding */
|
||||
/* section in process_comment() in decode_aprs.c */
|
||||
|
||||
len = strlen(e);
|
||||
//len = strlen(e);
|
||||
|
||||
ipat = find_ttloc_match (e, xstr, ystr, zstr, bstr, dstr);
|
||||
ipat = find_ttloc_match (e, xstr, ystr, zstr, bstr, dstr, VALSTRSIZE);
|
||||
if (ipat >= 0) {
|
||||
|
||||
//dw_printf ("ipat=%d, x=%s, y=%s, b=%s, d=%s\n", ipat, xstr, ystr, bstr, dstr);
|
||||
|
@ -1140,7 +1147,7 @@ static int parse_location (char *e)
|
|||
m_latitude = R2D(lat0);
|
||||
m_longitude = R2D(lon0);
|
||||
|
||||
//printf ("DEBUG: from UTM, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude);
|
||||
//dw_printf ("DEBUG: from UTM, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude);
|
||||
}
|
||||
else {
|
||||
char message[300];
|
||||
|
@ -1190,7 +1197,7 @@ static int parse_location (char *e)
|
|||
m_latitude = R2D(lat0);
|
||||
m_longitude = R2D(lon0);
|
||||
|
||||
//printf ("DEBUG: from MGRS/USNG, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude);
|
||||
//dw_printf ("DEBUG: from MGRS/USNG, latitude = %.6f, longitude = %.6f\n", m_latitude, m_longitude);
|
||||
}
|
||||
else {
|
||||
char message[300];
|
||||
|
@ -1219,7 +1226,7 @@ static int parse_location (char *e)
|
|||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("Case MHEAD: Convert to text \"%s\".\n", stemp);
|
||||
|
||||
if (tt_mhead_to_text (stemp, 0, mh) == 0) {
|
||||
if (tt_mhead_to_text (stemp, 0, mh, sizeof(mh)) == 0) {
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("Case MHEAD: Resulting text \"%s\".\n", mh);
|
||||
|
||||
|
@ -1277,6 +1284,8 @@ static int parse_location (char *e)
|
|||
* APRStt messsage.
|
||||
* In this case, it should start with "B".
|
||||
*
|
||||
* valstrsize - size of the outputs so we can check for buffer overflow.
|
||||
*
|
||||
* Outputs: xstr - All digits matching x positions in configuration.
|
||||
* ystr - y
|
||||
* zstr - z
|
||||
|
@ -1290,7 +1299,7 @@ static int parse_location (char *e)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr)
|
||||
static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *bstr, char *dstr, size_t valstrsize)
|
||||
{
|
||||
int ipat; /* Index into patterns from configuration file */
|
||||
int len; /* Length of pattern we are trying to match. */
|
||||
|
@ -1307,11 +1316,11 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
if (strlen(e) == len) {
|
||||
|
||||
match = 1;
|
||||
strlcpy (xstr, "", sizeof(xstr));
|
||||
strlcpy (ystr, "", sizeof(ystr));
|
||||
strlcpy (zstr, "", sizeof(zstr));
|
||||
strlcpy (bstr, "", sizeof(bstr));
|
||||
strlcpy (dstr, "", sizeof(dstr));
|
||||
strlcpy (xstr, "", valstrsize);
|
||||
strlcpy (ystr, "", valstrsize);
|
||||
strlcpy (zstr, "", valstrsize);
|
||||
strlcpy (bstr, "", valstrsize);
|
||||
strlcpy (dstr, "", valstrsize);
|
||||
|
||||
for (k=0; k<len; k++) {
|
||||
mc = tt_config.ttloc_ptr[ipat].pattern[k];
|
||||
|
@ -1342,7 +1351,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
char stemp[2];
|
||||
stemp[0] = e[k];
|
||||
stemp[1] = '\0';
|
||||
strlcat (xstr, stemp, sizeof(xstr));
|
||||
strlcat (xstr, stemp, valstrsize);
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
|
@ -1354,7 +1363,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
char stemp[2];
|
||||
stemp[0] = e[k];
|
||||
stemp[1] = '\0';
|
||||
strlcat (ystr, stemp, sizeof(ystr));
|
||||
strlcat (ystr, stemp, valstrsize);
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
|
@ -1366,7 +1375,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
char stemp[2];
|
||||
stemp[0] = e[k];
|
||||
stemp[1] = '\0';
|
||||
strlcat (zstr, stemp, sizeof(zstr));
|
||||
strlcat (zstr, stemp, valstrsize);
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
|
@ -1378,7 +1387,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
char stemp[2];
|
||||
stemp[0] = e[k];
|
||||
stemp[1] = '\0';
|
||||
strlcat (bstr, stemp, sizeof(bstr));
|
||||
strlcat (bstr, stemp, valstrsize);
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
|
@ -1390,7 +1399,7 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
char stemp[2];
|
||||
stemp[0] = e[k];
|
||||
stemp[1] = '\0';
|
||||
strlcat (dstr, stemp, sizeof(dstr));
|
||||
strlcat (dstr, stemp, valstrsize);
|
||||
}
|
||||
else {
|
||||
match = 0;
|
||||
|
@ -1447,7 +1456,6 @@ static int find_ttloc_match (char *e, char *xstr, char *ystr, char *zstr, char *
|
|||
static int parse_comment (char *e)
|
||||
{
|
||||
int len;
|
||||
int n;
|
||||
|
||||
assert (*e == 'C');
|
||||
|
||||
|
@ -1579,7 +1587,7 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
|||
* is one line of text.
|
||||
* 2 = Also remove any trailing whitespace.
|
||||
*
|
||||
* maxresult - Amount of space available for result.
|
||||
* resultsiz - Amount of space available for result.
|
||||
*
|
||||
* Outputs: result - Output captured from running command.
|
||||
*
|
||||
|
@ -1594,21 +1602,21 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int dw_run_cmd (char *cmd, int oneline, char *result, int maxresult)
|
||||
int dw_run_cmd (char *cmd, int oneline, char *result, size_t resultsiz)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
strlcpy (result, "", sizeof(result));
|
||||
strlcpy (result, "", resultsiz);
|
||||
|
||||
fp = popen (cmd, "r");
|
||||
if (fp != NULL) {
|
||||
int remaining = maxresult;
|
||||
int remaining = (int)resultsiz;
|
||||
char *pr = result;
|
||||
int err;
|
||||
|
||||
while (remaining > 2 && fgets(pr, remaining, fp) != NULL) {
|
||||
pr = result + strlen(result);
|
||||
remaining = maxresult - strlen(result);
|
||||
remaining = (int)resultsiz - strlen(result);
|
||||
}
|
||||
|
||||
if ((err = pclose(fp)) != 0) {
|
||||
|
@ -1670,106 +1678,182 @@ int dw_run_cmd (char *cmd, int oneline, char *result, int maxresult)
|
|||
*
|
||||
* Description: Run unit test like this:
|
||||
*
|
||||
* rm a.exe ; gcc tt_text.c -DTT_MAIN -DDEBUG aprs_tt.c latlong.c strtok_r.o utm/LatLong-UTMconversion.c ; ./a.exe
|
||||
*
|
||||
* Bugs: No automatic checking.
|
||||
* Just eyeball it to see if things look right.
|
||||
* rm a.exe ; gcc tt_text.c -DTT_MAIN -Igeotranz aprs_tt.c latlong.o textcolor.o geotranz.a misc.a ; ./a.exe
|
||||
* or
|
||||
* make ttest
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
// TODO: add this to "make check"
|
||||
|
||||
|
||||
#if TT_MAIN
|
||||
|
||||
/*
|
||||
* Regression test for the parsing.
|
||||
* It does not maintain any history so abbreviation will not invoke previous full call.
|
||||
*/
|
||||
|
||||
void text_color_set (dw_color_t c) { return; }
|
||||
static const struct {
|
||||
char *toneseq; /* Tone sequence in. */
|
||||
|
||||
int dw_printf (const char *fmt, ...)
|
||||
char *callsign; /* Expected results... */
|
||||
char *ssid;
|
||||
char *symbol;
|
||||
char *freq;
|
||||
char *comment;
|
||||
char *lat;
|
||||
char *lon;
|
||||
char *dao;
|
||||
} testcases[] = {
|
||||
|
||||
/* Callsigns & abbreviations. */
|
||||
|
||||
{ "A9A2B42A7A7C71#", "WB4APR", "12", "7A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* WB4APR/7 */
|
||||
{ "A27773#", "277", "12", "7A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* abbreviated form */
|
||||
/* Example in http://www.aprs.org/aprstt/aprstt-coding24.txt has a bad checksum! */
|
||||
/* Bad checksum for "2777". Expected 3 but received 6. */
|
||||
{ "A27776#", "", "12", "\\A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* Expect error message. */
|
||||
|
||||
/* Bad checksum for "2A7A7C7". E xpected 5 but received 1. */
|
||||
{ "A2A7A7C71#", "", "12", "\\A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* Spelled suffix, overlay, checksum */
|
||||
{ "A27773#", "277", "12", "7A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* Suffix digits, overlay, checksum */
|
||||
|
||||
{ "A9A2B26C7D9D71#", "WB2OSZ", "12", "7A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* WB2OSZ/7 numeric overlay */
|
||||
{ "A67979#", "679", "12", "7A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* abbreviated form */
|
||||
|
||||
{ "A9A2B26C7D9D5A9#", "WB2OSZ", "12", "JA", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* WB2OSZ/J letter overlay */
|
||||
{ "A6795A7#", "679", "12", "JA", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* abbreviated form */
|
||||
|
||||
{ "A277#", "277", "12", "\\A", "", "", "-999999.0000", "-999999.0000", "!T !" }, /* Tactical call "277" no overlay and no checksum */
|
||||
|
||||
/* Locations */
|
||||
|
||||
{ "B01*A67979#", "679", "12", "7A", "", "", "12.2500", "56.2500", "!T1 !" },
|
||||
{ "B988*A67979#", "679", "12", "7A", "", "", "12.5000", "56.5000", "!T88!" },
|
||||
|
||||
{ "B51000125*A67979#", "679", "12", "7A", "", "", "52.7907", "0.8309", "!TB5!" }, /* expect about 52.79 +0.83 */
|
||||
|
||||
{ "B5206070*A67979#", "679", "12", "7A", "", "", "37.9137", "-81.1366", "!TB5!" }, /* Try to get from Hilltop Tower to Archery & Target Range. */
|
||||
/* Latitude comes out ok, 37.9137 -> 55.82 min. */
|
||||
/* Longitude -81.1254 -> 8.20 min */
|
||||
{ "B21234*A67979#", "679", "12", "7A", "", "", "12.3400", "56.1200", "!TB2!" },
|
||||
{ "B533686*A67979#", "679", "12", "7A", "", "", "37.9222", "81.1143", "!TB5!" },
|
||||
|
||||
/* Comments */
|
||||
|
||||
{ "C1", "", "12", "\\A", "", "", "-999999.0000", "-999999.0000", "!T !" },
|
||||
{ "C2", "", "12", "\\A", "", "", "-999999.0000", "-999999.0000", "!T !" },
|
||||
{ "C146520", "", "12", "\\A", "146.520MHz", "", "-999999.0000", "-999999.0000", "!T !" },
|
||||
{ "C7788444222550227776669660333666990122223333",
|
||||
"", "12", "\\A", "", "QUICK BROWN FOX 123", "-999999.0000", "-999999.0000", "!T !" },
|
||||
/* Macros */
|
||||
|
||||
{ "88345", "BIKE 345", "0", "/b", "", "", "12.5000", "56.5000", "!T88!" },
|
||||
|
||||
/* 10 digit representation for callsign & satellite grid. WB4APR near 39.5, -77 */
|
||||
|
||||
{ "AC9242771558*BA1819", "WB4APR", "12", "\\A", "", "", "39.5000", "-77.0000", "!TBA!" },
|
||||
{ "18199242771558", "WB4APR", "12", "\\A", "", "", "39.5000", "-77.0000", "!TBA!" },
|
||||
};
|
||||
|
||||
|
||||
static int test_num;
|
||||
static int error_count;
|
||||
|
||||
static void check_result (void)
|
||||
{
|
||||
va_list args;
|
||||
int len;
|
||||
char stemp[32];
|
||||
|
||||
va_start (args, fmt);
|
||||
len = vprintf (fmt, args);
|
||||
va_end (args);
|
||||
return (len);
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("callsign=\"%s\", ssid=%d, symbol=\"%c%c\", freq=\"%s\", comment=\"%s\", lat=%.4f, lon=%.4f, dao=\"%s\"\n",
|
||||
m_callsign, m_ssid, m_symtab_or_overlay, m_symbol_code, m_freq, m_comment, m_latitude, m_longitude, m_dao);
|
||||
|
||||
|
||||
if (strcmp(m_callsign, testcases[test_num].callsign) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for callsign.\n", testcases[test_num].callsign);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
snprintf (stemp, sizeof(stemp), "%d", m_ssid);
|
||||
if (strcmp(stemp, testcases[test_num].ssid) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for SSID.\n", testcases[test_num].ssid);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
stemp[0] = m_symtab_or_overlay;
|
||||
stemp[1] = m_symbol_code;
|
||||
stemp[2] = '\0';
|
||||
if (strcmp(stemp, testcases[test_num].symbol) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for Symbol.\n", testcases[test_num].symbol);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (strcmp(m_freq, testcases[test_num].freq) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for Freq.\n", testcases[test_num].freq);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (strcmp(m_comment, testcases[test_num].comment) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for Comment.\n", testcases[test_num].comment);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
snprintf (stemp, sizeof(stemp), "%.4f", m_latitude);
|
||||
if (strcmp(stemp, testcases[test_num].lat) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for Latitude.\n", testcases[test_num].lat);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
snprintf (stemp, sizeof(stemp), "%.4f", m_longitude);
|
||||
if (strcmp(stemp, testcases[test_num].lon) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for Longitude.\n", testcases[test_num].lon);
|
||||
error_count++;
|
||||
}
|
||||
|
||||
if (strcmp(m_dao, testcases[test_num].dao) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR: Expected \"%s\" for DAO.\n", testcases[test_num].dao);
|
||||
error_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char text[256], buttons[256];
|
||||
int n;
|
||||
|
||||
dw_printf ("Hello, world!\n");
|
||||
|
||||
aprs_tt_init (NULL);
|
||||
|
||||
//if (argc < 2) {
|
||||
//dw_printf ("Supply text string on command line.\n");
|
||||
//exit (1);
|
||||
//}
|
||||
error_count = 0;
|
||||
|
||||
/* Callsigns & abbreviations. */
|
||||
for (test_num = 0; test_num < sizeof(testcases) / sizeof(testcases[0]); test_num++) {
|
||||
|
||||
aprs_tt_sequence (0, "A9A2B42A7A7C71#"); /* WB4APR/7 */
|
||||
aprs_tt_sequence (0, "A27773#"); /* abbreviated form */
|
||||
/* Example in http://www.aprs.org/aprstt/aprstt-coding24.txt has a bad checksum! */
|
||||
aprs_tt_sequence (0, "A27776#"); /* Expect error message. */
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("\nTest case %d: %s\n", test_num, testcases[test_num].toneseq);
|
||||
|
||||
aprs_tt_sequence (0, "A2A7A7C71#"); /* Spelled suffix, overlay, checksum */
|
||||
aprs_tt_sequence (0, "A27773#"); /* Suffix digits, overlay, checksum */
|
||||
aprs_tt_sequence (0, testcases[test_num].toneseq);
|
||||
}
|
||||
|
||||
aprs_tt_sequence (0, "A9A2B26C7D9D71#"); /* WB2OSZ/7 numeric overlay */
|
||||
aprs_tt_sequence (0, "A67979#"); /* abbreviated form */
|
||||
if (error_count != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n\nTEST FAILED, Total of %d errors.\n", error_count);
|
||||
return (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
aprs_tt_sequence (0, "A9A2B26C7D9D5A9#"); /* WB2OSZ/J letter overlay */
|
||||
aprs_tt_sequence (0, "A6795A7#"); /* abbreviated form */
|
||||
|
||||
aprs_tt_sequence (0, "A277#"); /* Tactical call "277" no overlay and no checksum */
|
||||
|
||||
/* Locations */
|
||||
|
||||
aprs_tt_sequence (0, "B01*A67979#");
|
||||
aprs_tt_sequence (0, "B988*A67979#");
|
||||
|
||||
/* expect about 52.79 +0.83 */
|
||||
aprs_tt_sequence (0, "B51000125*A67979#");
|
||||
|
||||
/* Try to get from Hilltop Tower to Archery & Target Range. */
|
||||
/* Latitude comes out ok, 37.9137 -> 55.82 min. */
|
||||
/* Longitude -81.1254 -> 8.20 min */
|
||||
|
||||
aprs_tt_sequence (0, "B5206070*A67979#");
|
||||
|
||||
aprs_tt_sequence (0, "B21234*A67979#");
|
||||
aprs_tt_sequence (0, "B533686*A67979#");
|
||||
|
||||
|
||||
/* Comments */
|
||||
|
||||
aprs_tt_sequence (0, "C1");
|
||||
aprs_tt_sequence (0, "C2");
|
||||
aprs_tt_sequence (0, "C146520");
|
||||
aprs_tt_sequence (0, "C7788444222550227776669660333666990122223333");
|
||||
|
||||
/* Macros */
|
||||
|
||||
aprs_tt_sequence (0, "88345");
|
||||
|
||||
/* 10 digit representation for callsign & satellite grid. WB4APR near 39.5, -77 */
|
||||
|
||||
aprs_tt_sequence (0, "AC9242771558*BA1819");
|
||||
aprs_tt_sequence (0, "18199242771558");
|
||||
|
||||
|
||||
return(0);
|
||||
text_color_set(DW_COLOR_REC);
|
||||
dw_printf ("\n\nAll tests passed.\n");
|
||||
return (EXIT_SUCCESS);
|
||||
|
||||
} /* end main */
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* end aprs_tt.c */
|
||||
|
|
|
@ -176,7 +176,7 @@ void aprs_tt_dao_to_desc (char *dao, char *str);
|
|||
|
||||
void aprs_tt_sequence (int chan, char *msg);
|
||||
|
||||
int dw_run_cmd (char *cmd, int oneline, char *result, int maxresult);
|
||||
int dw_run_cmd (char *cmd, int oneline, char *result, size_t resultsiz);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
74
atest.c
74
atest.c
|
@ -141,7 +141,11 @@ static int decimate = 0; /* Reduce that sampling rate if set. */
|
|||
|
||||
static struct audio_s my_audio_config;
|
||||
|
||||
static int error_if_less_than = 0; /* Exit with error status if this minimum not reached. */
|
||||
static int error_if_less_than = -1; /* Exit with error status if this minimum not reached. */
|
||||
/* Can be used to check that performance has not decreased. */
|
||||
|
||||
static int error_if_greater_than = -1; /* Exit with error status if this maximum exceeded. */
|
||||
/* Can be used to check that duplicate removal is not broken. */
|
||||
|
||||
|
||||
|
||||
|
@ -161,6 +165,8 @@ extern float space_gain[MAX_SUBCHANS];
|
|||
static void usage (void);
|
||||
|
||||
|
||||
static int decode_only = 0; /* Set to 0 or 1 to decode only one channel. 2 for both. */
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
@ -171,7 +177,6 @@ int main (int argc, char *argv[])
|
|||
time_t start_time;
|
||||
|
||||
|
||||
|
||||
#if defined(EXPERIMENT_G) || defined(EXPERIMENT_H)
|
||||
int j;
|
||||
|
||||
|
@ -245,7 +250,7 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.achan[channel].space_freq = DEFAULT_SPACE_FREQ;
|
||||
my_audio_config.achan[channel].baud = DEFAULT_BAUD;
|
||||
|
||||
strcpy (my_audio_config.achan[channel].profiles, "E");
|
||||
strlcpy (my_audio_config.achan[channel].profiles, "E", sizeof(my_audio_config.achan[channel].profiles));
|
||||
|
||||
my_audio_config.achan[channel].num_freq = 1;
|
||||
my_audio_config.achan[channel].offset = 0;
|
||||
|
@ -261,7 +266,7 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
|
||||
while (1) {
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
//int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"future1", 1, 0, 0},
|
||||
|
@ -272,7 +277,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
/* ':' following option character means arg is required. */
|
||||
|
||||
c = getopt_long(argc, argv, "B:P:D:F:e:",
|
||||
c = getopt_long(argc, argv, "B:P:D:F:L:G:012",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -297,12 +302,13 @@ int main (int argc, char *argv[])
|
|||
my_audio_config.achan[0].modem_type = MODEM_AFSK;
|
||||
my_audio_config.achan[0].mark_freq = 1600;
|
||||
my_audio_config.achan[0].space_freq = 1800;
|
||||
strcpy (my_audio_config.achan[0].profiles, "D"); }
|
||||
strlcpy (my_audio_config.achan[0].profiles, "D", sizeof(my_audio_config.achan[0].profiles));
|
||||
}
|
||||
else if (my_audio_config.achan[0].baud > 2400) {
|
||||
my_audio_config.achan[0].modem_type = MODEM_SCRAMBLE;
|
||||
my_audio_config.achan[0].mark_freq = 0;
|
||||
my_audio_config.achan[0].space_freq = 0;
|
||||
strcpy (my_audio_config.achan[0].profiles, " "); // avoid getting default later.
|
||||
strlcpy (my_audio_config.achan[0].profiles, " ", sizeof(my_audio_config.achan[0].profiles)); // avoid getting default later.
|
||||
dw_printf ("Using scrambled baseband signal rather than AFSK.\n");
|
||||
}
|
||||
else {
|
||||
|
@ -315,7 +321,7 @@ int main (int argc, char *argv[])
|
|||
case 'P': /* -P for modem profile. */
|
||||
|
||||
dw_printf ("Demodulator profile set to \"%s\"\n", optarg);
|
||||
strcpy (my_audio_config.achan[0].profiles, optarg);
|
||||
strlcpy (my_audio_config.achan[0].profiles, optarg, sizeof(my_audio_config.achan[0].profiles));
|
||||
break;
|
||||
|
||||
case 'D': /* -D reduce sampling rate for lower CPU usage. */
|
||||
|
@ -343,11 +349,31 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
break;
|
||||
|
||||
case 'e': /* -e error if less than this number decoded. */
|
||||
case 'L': /* -L error if less than this number decoded. */
|
||||
|
||||
error_if_less_than = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'G': /* -G error if greater than this number decoded. */
|
||||
|
||||
error_if_greater_than = atoi(optarg);
|
||||
break;
|
||||
|
||||
case '0': /* channel 0, left from stereo */
|
||||
|
||||
decode_only = 0;
|
||||
break;
|
||||
|
||||
case '1': /* channel 1, right from stereo */
|
||||
|
||||
decode_only = 1;
|
||||
break;
|
||||
|
||||
case '2': /* decode both from stereo */
|
||||
|
||||
decode_only = 2;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
|
||||
/* Unknown option message was already printed. */
|
||||
|
@ -363,6 +389,9 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
memcpy (&my_audio_config.achan[1], &my_audio_config.achan[0], sizeof(my_audio_config.achan[0]));
|
||||
|
||||
|
||||
if (optind >= argc) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Specify .WAV file name on command line.\n");
|
||||
|
@ -386,6 +415,7 @@ int main (int argc, char *argv[])
|
|||
*/
|
||||
|
||||
err= fread (&header, (size_t)12, (size_t)1, fp);
|
||||
(void)(err);
|
||||
|
||||
if (strncmp(header.riff, "RIFF", 4) != 0 || strncmp(header.wave, "WAVE", 4) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -421,6 +451,7 @@ int main (int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
|
||||
// TODO: Should have proper message, not abort.
|
||||
assert (format.nchannels == 1 || format.nchannels == 2);
|
||||
assert (format.wbitspersample == 8 || format.wbitspersample == 16);
|
||||
|
||||
|
@ -464,11 +495,8 @@ int main (int argc, char *argv[])
|
|||
if (audio_sample >= 256 * 256)
|
||||
e_o_f = 1;
|
||||
|
||||
#define ONE_CHAN 1 /* only use one audio channel. */
|
||||
|
||||
#if ONE_CHAN
|
||||
if (c != 0) continue;
|
||||
#endif
|
||||
if (decode_only == 0 && c != 0) continue;
|
||||
if (decode_only == 1 && c != 1) continue;
|
||||
|
||||
multi_modem_process_sample(c,audio_sample);
|
||||
}
|
||||
|
@ -495,9 +523,14 @@ int main (int argc, char *argv[])
|
|||
#endif
|
||||
dw_printf ("%d packets decoded in %d seconds.\n", packets_decoded, (int)(time(NULL) - start_time));
|
||||
|
||||
if (packets_decoded < error_if_less_than) {
|
||||
if (error_if_less_than != -1 && packets_decoded < error_if_less_than) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n * * * TEST FAILED to achieve minimum of %d * * * \n", error_if_less_than);
|
||||
dw_printf ("\n * * * TEST FAILED: number decoded is less than %d * * * \n", error_if_less_than);
|
||||
exit (1);
|
||||
}
|
||||
if (error_if_greater_than != -1 && packets_decoded > error_if_greater_than) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\n * * * TEST FAILED: number decoded is greater than %d * * * \n", error_if_greater_than);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
@ -564,12 +597,11 @@ void dlq_append (dlq_type_t type, int chan, int subchan, packet_t pp, alevel_t a
|
|||
unsigned char *pinfo;
|
||||
int info_len;
|
||||
int h;
|
||||
char heard[20];
|
||||
char heard[AX25_MAX_ADDR_LEN];
|
||||
char alevel_text[AX25_ALEVEL_TO_TEXT_SIZE];
|
||||
|
||||
packets_decoded++;
|
||||
|
||||
|
||||
ax25_format_addrs (pp, stemp);
|
||||
|
||||
info_len = ax25_get_info (pp, &pinfo);
|
||||
|
@ -585,7 +617,7 @@ void dlq_append (dlq_type_t type, int chan, int subchan, packet_t pp, alevel_t a
|
|||
if (ax25_get_num_addr(pp) == 0) {
|
||||
/* Not AX.25. No station to display below. */
|
||||
h = -1;
|
||||
strcpy (heard, "");
|
||||
strlcpy (heard, "", sizeof(heard));
|
||||
}
|
||||
else {
|
||||
h = ax25_get_heard(pp);
|
||||
|
@ -676,6 +708,10 @@ static void usage (void) {
|
|||
dw_printf (" -P m Select the demodulator type such as A, B, C, D (default for 300 baud),\n");
|
||||
dw_printf (" E (default for 1200 baud), F, A+, B+, C+, D+, E+, F+.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" -0 Use channel 0 (left) of stereo audio (default).\n");
|
||||
dw_printf (" -1 use channel 1 (right) of stereo audio.\n");
|
||||
dw_printf (" -1 decode both channels of stereo audio.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf (" wav-file-in is a WAV format audio file.\n");
|
||||
dw_printf ("\n");
|
||||
dw_printf ("Examples:\n");
|
||||
|
|
25
audio.c
25
audio.c
|
@ -661,6 +661,16 @@ static int set_alsa_params (int a, snd_pcm_t *handle, struct audio_s *pa, char *
|
|||
dw_printf ("audio buffer size = %d (bytes per frame) x %d (frames per period) = %d \n", adev[a].bytes_per_frame, (int)fpp, buf_size_in_bytes);
|
||||
#endif
|
||||
|
||||
/* Version 1.3 - after a report of this situation for Mac OSX version. */
|
||||
if (buf_size_in_bytes < 256 || buf_size_in_bytes > 32768) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio buffer has unexpected extreme size of %d bytes.\n", buf_size_in_bytes);
|
||||
dw_printf ("Detected at %s, line %d.\n", __FILE__, __LINE__);
|
||||
dw_printf ("This might be caused by unusual audio device configuration values.\n");
|
||||
buf_size_in_bytes = 2048;
|
||||
dw_printf ("Using %d to attempt recovery.\n", buf_size_in_bytes);
|
||||
}
|
||||
|
||||
return (buf_size_in_bytes);
|
||||
|
||||
|
||||
|
@ -787,9 +797,20 @@ static int set_oss_params (int fd, struct audio_s *pa)
|
|||
dw_printf ("audio_open(): using block size of %d\n", ossbuf_size_in_bytes);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* Original - dies without good explanation. */
|
||||
assert (ossbuf_size_in_bytes >= 256 && ossbuf_size_in_bytes <= 32768);
|
||||
|
||||
|
||||
#else
|
||||
/* Version 1.3 - after a report of this situation for Mac OSX version. */
|
||||
if (ossbuf_size_in_bytes < 256 || ossbuf_size_in_bytes > 32768) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio buffer has unexpected extreme size of %d bytes.\n", ossbuf_size_in_bytes);
|
||||
dw_printf ("Detected at %s, line %d.\n", __FILE__, __LINE__);
|
||||
dw_printf ("This might be caused by unusual audio device configuration values.\n");
|
||||
ossbuf_size_in_bytes = 2048;
|
||||
dw_printf ("Using %d to attempt recovery.\n", ossbuf_size_in_bytes);
|
||||
}
|
||||
#endif
|
||||
return (ossbuf_size_in_bytes);
|
||||
|
||||
} /* end set_oss_params */
|
||||
|
|
|
@ -714,6 +714,27 @@ int audio_open (struct audio_s *pa)
|
|||
* Finally allocate buffer for each direction.
|
||||
*/
|
||||
|
||||
/* Version 1.3 - Add sanity check on buffer size. */
|
||||
/* There was a reported case of assert failure on buffer size in audio_get(). */
|
||||
|
||||
if (adev[a].inbuf_size_in_bytes < 256 || adev[a].inbuf_size_in_bytes > 32768) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio input buffer has unexpected extreme size of %d bytes.\n", adev[a].inbuf_size_in_bytes);
|
||||
dw_printf ("Detected at %s, line %d.\n", __FILE__, __LINE__);
|
||||
dw_printf ("This might be caused by unusual audio device configuration values.\n");
|
||||
adev[a].inbuf_size_in_bytes = 2048;
|
||||
dw_printf ("Using %d to attempt recovery.\n", adev[a].inbuf_size_in_bytes);
|
||||
}
|
||||
|
||||
if (adev[a].outbuf_size_in_bytes < 256 || adev[a].outbuf_size_in_bytes > 32768) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio output buffer has unexpected extreme size of %d bytes.\n", adev[a].outbuf_size_in_bytes);
|
||||
dw_printf ("Detected at %s, line %d.\n", __FILE__, __LINE__);
|
||||
dw_printf ("This might be caused by unusual audio device configuration values.\n");
|
||||
adev[a].outbuf_size_in_bytes = 2048;
|
||||
dw_printf ("Using %d to attempt recovery.\n", adev[a].outbuf_size_in_bytes);
|
||||
}
|
||||
|
||||
adev[a].inbuf_ptr = malloc(adev[a].inbuf_size_in_bytes);
|
||||
assert (adev[a].inbuf_ptr != NULL);
|
||||
adev[a].inbuf_len = 0;
|
||||
|
|
11
audio_win.c
11
audio_win.c
|
@ -113,6 +113,17 @@ static int calcbufsize(int rate, int chans, int bits)
|
|||
dw_printf ("audio_open: calcbufsize (rate=%d, chans=%d, bits=%d) calc size=%d, round up to %d\n",
|
||||
rate, chans, bits, size1, size2);
|
||||
#endif
|
||||
|
||||
/* Version 1.3 - add a sanity check. */
|
||||
if (size2 < 256 || size2 > 32768) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Audio buffer has unexpected extreme size of %d bytes.\n", size2);
|
||||
dw_printf ("Detected at %s, line %d.\n", __FILE__, __LINE__);
|
||||
dw_printf ("This might be caused by unusual audio device configuration values.\n");
|
||||
size2 = 2048;
|
||||
dw_printf ("Using %d to attempt recovery.\n", size2);
|
||||
}
|
||||
|
||||
return (size2);
|
||||
}
|
||||
|
||||
|
|
80
ax25_pad.c
80
ax25_pad.c
|
@ -44,22 +44,27 @@
|
|||
* Description:
|
||||
*
|
||||
*
|
||||
* A UI frame starts with 2-10 addressses (14-70 octets):
|
||||
* APRS uses only UI frames.
|
||||
* Each starts with 2-10 addressses (14-70 octets):
|
||||
*
|
||||
* * Destination Address (note: opposite order in printed format)
|
||||
*
|
||||
* * Destination Address
|
||||
* * Source Address
|
||||
*
|
||||
* * 0-8 Digipeater Addresses (Could there ever be more as a result of
|
||||
* digipeaters inserting their own call
|
||||
* and decrementing the remaining count in
|
||||
* WIDEn-n, TRACEn-n, etc.?
|
||||
* NO. The limit is 8 when transmitting AX.25 over the radio.
|
||||
* However, communication with an IGate server could have
|
||||
* a longer VIA path but that is only in text form, not here.)
|
||||
* digipeaters inserting their own call for
|
||||
* the tracing feature?
|
||||
* NO. The limit is 8 when transmitting AX.25 over the
|
||||
* radio.
|
||||
* Communication with an IGate server could
|
||||
* have a longer VIA path but that is only in text form,
|
||||
* not as an AX.25 frame.)
|
||||
*
|
||||
* Each address is composed of:
|
||||
*
|
||||
* * 6 upper case letters or digits, blank padded.
|
||||
* These are shifted left one bit, leaving the the LSB always 0.
|
||||
* These are shifted left one bit, leaving the LSB always 0.
|
||||
*
|
||||
* * a 7th octet containing the SSID and flags.
|
||||
* The LSB is always 0 except for the last octet of the address field.
|
||||
*
|
||||
|
@ -96,8 +101,12 @@
|
|||
* have the "H" bit set to 1.
|
||||
* The "H" bit would be set to 1 in the repeated frame.
|
||||
*
|
||||
* When monitoring, an asterisk is displayed after the last digipeater with
|
||||
* the "H" bit set. No asterisk means the source is being heard directly.
|
||||
* In standard monitoring format, an asterisk is displayed after the last
|
||||
* digipeater with the "H" bit set. That indicates who you are hearing
|
||||
* over the radio.
|
||||
* (That is if digipeaters update the via path properly. Some don't so
|
||||
* we don't know who we are hearing. This is discussed in the User Guide.)
|
||||
* No asterisk means the source is being heard directly.
|
||||
*
|
||||
* Example, if we can hear all stations involved,
|
||||
*
|
||||
|
@ -118,6 +127,10 @@
|
|||
*
|
||||
* And, of course, the 2 byte CRC.
|
||||
*
|
||||
* The descriptions above, for the C, H, and RR bits, are for APRS usage.
|
||||
* When operating as a KISS TNC we just pass everything along and don't
|
||||
* interpret or change them.
|
||||
*
|
||||
*
|
||||
* Constructors: ax25_init - Clear everything.
|
||||
* ax25_from_text - Tear apart a text string
|
||||
|
@ -569,11 +582,11 @@ packet_t ax25_from_frame_debug (unsigned char *fbuf, int flen, alevel_t alevel,
|
|||
packet_t ax25_from_frame (unsigned char *fbuf, int flen, alevel_t alevel)
|
||||
#endif
|
||||
{
|
||||
unsigned char *pf;
|
||||
//unsigned char *pf;
|
||||
packet_t this_p;
|
||||
|
||||
int a;
|
||||
int addr_bytes;
|
||||
//int a;
|
||||
//int addr_bytes;
|
||||
|
||||
/*
|
||||
* First make sure we have an acceptable length:
|
||||
|
@ -908,7 +921,6 @@ void ax25_set_addr (packet_t this_p, int n, char *ad)
|
|||
|
||||
void ax25_insert_addr (packet_t this_p, int n, char *ad)
|
||||
{
|
||||
int k;
|
||||
int ssid_temp, heard_temp;
|
||||
char atemp[AX25_MAX_ADDR_LEN];
|
||||
int i;
|
||||
|
@ -979,7 +991,6 @@ void ax25_insert_addr (packet_t this_p, int n, char *ad)
|
|||
|
||||
void ax25_remove_addr (packet_t this_p, int n)
|
||||
{
|
||||
int k;
|
||||
int expect;
|
||||
|
||||
assert (this_p->magic1 == MAGIC);
|
||||
|
@ -1025,7 +1036,7 @@ void ax25_remove_addr (packet_t this_p, int n)
|
|||
|
||||
int ax25_get_num_addr (packet_t this_p)
|
||||
{
|
||||
unsigned char *pf;
|
||||
//unsigned char *pf;
|
||||
int a;
|
||||
int addr_bytes;
|
||||
|
||||
|
@ -1178,7 +1189,6 @@ void ax25_get_addr_with_ssid (packet_t this_p, int n, char *station)
|
|||
|
||||
void ax25_get_addr_no_ssid (packet_t this_p, int n, char *station)
|
||||
{
|
||||
int ssid;
|
||||
int i;
|
||||
|
||||
assert (this_p->magic1 == MAGIC);
|
||||
|
@ -1801,23 +1811,23 @@ static void hex_dump (unsigned char *p, int len)
|
|||
|
||||
// TODO: use ax25_frame_type() instead.
|
||||
|
||||
static void ctrl_to_text (int c, char *out)
|
||||
static void ctrl_to_text (int c, char *out, size_t outsiz)
|
||||
{
|
||||
if ((c & 1) == 0) { sprintf (out, "I frame: n(r)=%d, p=%d, n(s)=%d", (c>>5)&7, (c>>4)&1, (c>>1)&7); }
|
||||
else if ((c & 0xf) == 0x01) { sprintf (out, "S frame RR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x05) { sprintf (out, "S frame RNR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x09) { sprintf (out, "S frame REJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x0D) { sprintf (out, "S frame sREJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x6f) { sprintf (out, "U frame SABME: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x2f) { sprintf (out, "U frame SABM: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x43) { sprintf (out, "U frame DISC: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x0f) { sprintf (out, "U frame DM: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x63) { sprintf (out, "U frame UA: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x87) { sprintf (out, "U frame FRMR: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x03) { sprintf (out, "U frame UI: p/f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0xAF) { sprintf (out, "U frame XID: p/f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0xe3) { sprintf (out, "U frame TEST: p/f=%d", (c>>4)&1); }
|
||||
else { sprintf (out, "Unknown frame type for control = 0x%02x", c); }
|
||||
if ((c & 1) == 0) { snprintf (out, outsiz, "I frame: n(r)=%d, p=%d, n(s)=%d", (c>>5)&7, (c>>4)&1, (c>>1)&7); }
|
||||
else if ((c & 0xf) == 0x01) { snprintf (out, outsiz, "S frame RR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x05) { snprintf (out, outsiz, "S frame RNR: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x09) { snprintf (out, outsiz, "S frame REJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xf) == 0x0D) { snprintf (out, outsiz, "S frame sREJ: n(r)=%d, p/f=%d", (c>>5)&7, (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x6f) { snprintf (out, outsiz, "U frame SABME: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x2f) { snprintf (out, outsiz, "U frame SABM: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x43) { snprintf (out, outsiz, "U frame DISC: p=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x0f) { snprintf (out, outsiz, "U frame DM: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x63) { snprintf (out, outsiz, "U frame UA: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x87) { snprintf (out, outsiz, "U frame FRMR: f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0x03) { snprintf (out, outsiz, "U frame UI: p/f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0xAF) { snprintf (out, outsiz, "U frame XID: p/f=%d", (c>>4)&1); }
|
||||
else if ((c & 0xef) == 0xe3) { snprintf (out, outsiz, "U frame TEST: p/f=%d", (c>>4)&1); }
|
||||
else { snprintf (out, outsiz, "Unknown frame type for control = 0x%02x", c); }
|
||||
}
|
||||
|
||||
/* Text description of protocol id octet. */
|
||||
|
@ -1864,7 +1874,7 @@ void ax25_hex_dump (packet_t this_p)
|
|||
c = fptr[this_p->num_addr*7];
|
||||
p = fptr[this_p->num_addr*7+1];
|
||||
|
||||
ctrl_to_text (c, cp_text); // TODO: use ax25_frame_type() instead.
|
||||
ctrl_to_text (c, cp_text, sizeof(cp_text)); // TODO: use ax25_frame_type() instead.
|
||||
|
||||
if ( (c & 0x01) == 0 || /* I xxxx xxx0 */
|
||||
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
|
||||
|
|
550
beacon.c
550
beacon.c
|
@ -1,7 +1,3 @@
|
|||
//#define DEBUG 1
|
||||
//#define DEBUG_SIM 1
|
||||
|
||||
|
||||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
|
@ -32,17 +28,17 @@
|
|||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
//#define DEBUG 1
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <time.h>
|
||||
#if __WIN32__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "ax25_pad.h"
|
||||
|
@ -51,7 +47,6 @@
|
|||
#include "tq.h"
|
||||
#include "xmit.h"
|
||||
#include "config.h"
|
||||
#include "digipeater.h"
|
||||
#include "version.h"
|
||||
#include "encode_aprs.h"
|
||||
#include "beacon.h"
|
||||
|
@ -62,14 +57,25 @@
|
|||
#include "aprs_tt.h" // for dw_run_cmd - should relocate someday.
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
/*
|
||||
* Are we using GPS data?
|
||||
* Incremented if tracker beacons configured.
|
||||
* Cleared if dwgps_init fails.
|
||||
* Windows doesn't have localtime_r.
|
||||
* It should have the equivalent localtime_s, with opposite parameter
|
||||
* order, but I get undefined reference when trying to use it.
|
||||
*/
|
||||
|
||||
static int g_using_gps = 0;
|
||||
struct tm *localtime_r(time_t *clock, struct tm *res)
|
||||
{
|
||||
struct tm *tm;
|
||||
|
||||
tm = localtime (clock);
|
||||
memcpy (res, tm, sizeof(struct tm));
|
||||
return (res);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Save pointers to configuration settings.
|
||||
|
@ -77,8 +83,6 @@ static int g_using_gps = 0;
|
|||
|
||||
static struct audio_s *g_modem_config_p;
|
||||
static struct misc_config_s *g_misc_config_p;
|
||||
static struct digi_config_s *g_digi_config_p;
|
||||
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
@ -97,6 +101,11 @@ void beacon_tracker_set_debug (int level)
|
|||
g_tracker_debug_level = level;
|
||||
}
|
||||
|
||||
static time_t sb_calculate_next_time (time_t now,
|
||||
float current_speed_mph, float current_course,
|
||||
time_t last_xmit_time, float last_xmit_course);
|
||||
|
||||
static void beacon_send (int j, dwgps_info_t *gpsinfo);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -105,26 +114,24 @@ void beacon_tracker_set_debug (int level)
|
|||
*
|
||||
* Purpose: Initialize the beacon process.
|
||||
*
|
||||
* Inputs: pmodem - Aduio device and modem configuration.
|
||||
* Used only to find valide channels.
|
||||
* Inputs: pmodem - Audio device and modem configuration.
|
||||
* Used only to find valid channels.
|
||||
*
|
||||
* pconfig - misc. configuration from config file.
|
||||
* pdigi - digipeater configuration from config file.
|
||||
* TODO: Is this needed?
|
||||
*
|
||||
*
|
||||
* Outputs: Remember required information for future use.
|
||||
*
|
||||
* Description: Initialize the queue to be empty and set up other
|
||||
* mechanisms for sharing it between different threads.
|
||||
* Description: Do some validity checking on the beacon configuration.
|
||||
*
|
||||
* Start up xmit_thread to actually send the packets
|
||||
* Start up beacon_thread to actually send the packets
|
||||
* at the appropriate time.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct digi_config_s *pdigi)
|
||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig)
|
||||
{
|
||||
time_t now;
|
||||
int j;
|
||||
|
@ -149,7 +156,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
*/
|
||||
g_modem_config_p = pmodem;
|
||||
g_misc_config_p = pconfig;
|
||||
g_digi_config_p = pdigi;
|
||||
|
||||
/*
|
||||
* Precompute the packet contents so any errors are
|
||||
|
@ -164,7 +170,9 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
|
||||
if (g_modem_config_p->achan[chan].valid) {
|
||||
|
||||
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 && strcasecmp(g_modem_config_p->achan[chan].mycall, "NOCALL") != 0) {
|
||||
if (strlen(g_modem_config_p->achan[chan].mycall) > 0 &&
|
||||
strcasecmp(g_modem_config_p->achan[chan].mycall, "N0CALL") != 0 &&
|
||||
strcasecmp(g_modem_config_p->achan[chan].mycall, "NOCALL") != 0) {
|
||||
|
||||
switch (g_misc_config_p->beacon[j].btype) {
|
||||
|
||||
|
@ -194,14 +202,18 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
|
||||
case BEACON_TRACKER:
|
||||
|
||||
#if defined(ENABLE_GPS) || defined(DEBUG_SIM)
|
||||
g_using_gps++;
|
||||
#else
|
||||
{
|
||||
dwgps_info_t gpsinfo;
|
||||
dwfix_t fix;
|
||||
|
||||
fix = dwgps_read (&gpsinfo);
|
||||
if (fix == DWFIX_NOT_INIT) {
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: GPS tracker feature is not enabled.\n", g_misc_config_p->beacon[j].lineno);
|
||||
dw_printf ("Config file, line %d: GPS must be configured to use TBEACON.\n", g_misc_config_p->beacon[j].lineno);
|
||||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BEACON_CUSTOM:
|
||||
|
@ -234,7 +246,7 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
}
|
||||
|
||||
/*
|
||||
* Calculate next time for each beacon.
|
||||
* Calculate first time for each beacon from the 'delay' value.
|
||||
*/
|
||||
|
||||
now = time(NULL);
|
||||
|
@ -253,37 +265,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Connect to GPS receiver if any tracker beacons are configured.
|
||||
* If open fails, disable all tracker beacons.
|
||||
*/
|
||||
|
||||
#if DEBUG_SIM
|
||||
|
||||
g_using_gps = 1;
|
||||
|
||||
#elif ENABLE_GPS
|
||||
|
||||
if (g_using_gps > 0) {
|
||||
int err;
|
||||
|
||||
err = dwgps_init();
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("All tracker beacons disabled.\n");
|
||||
g_using_gps = 0;
|
||||
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||
g_misc_config_p->beacon[j].btype = BEACON_IGNORE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Start up thread for processing only if at least one is valid.
|
||||
*/
|
||||
|
@ -342,18 +323,6 @@ void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct
|
|||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
|
||||
/* Difference between two angles. */
|
||||
|
||||
static inline float heading_change (float a, float b)
|
||||
{
|
||||
float diff;
|
||||
|
||||
diff = fabs(a - b);
|
||||
if (diff <= 180.)
|
||||
return (diff);
|
||||
else
|
||||
return (360. - diff);
|
||||
}
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
@ -362,29 +331,17 @@ static unsigned __stdcall beacon_thread (void *arg)
|
|||
static void * beacon_thread (void *arg)
|
||||
#endif
|
||||
{
|
||||
int j;
|
||||
int j; /* Index into array of beacons. */
|
||||
time_t earliest;
|
||||
time_t now;
|
||||
time_t now; /* Current time. */
|
||||
int number_of_tbeacons; /* Number of tracker beacons. */
|
||||
|
||||
/*
|
||||
* Information from GPS.
|
||||
*/
|
||||
int fix = 0; /* 0 = none, 2 = 2D, 3 = 3D */
|
||||
double my_lat = 0; /* degrees */
|
||||
double my_lon = 0;
|
||||
float my_course = 0; /* degrees */
|
||||
float my_speed_knots = 0;
|
||||
float my_speed_mph = 0;
|
||||
float my_alt_m = G_UNKNOWN; /* meters */
|
||||
int my_alt_ft = G_UNKNOWN;
|
||||
|
||||
/*
|
||||
* SmartBeaconing state.
|
||||
*/
|
||||
time_t sb_prev_time = 0; /* Time of most recent transmission. */
|
||||
float sb_prev_course = 0; /* Most recent course reported. */
|
||||
//float sb_prev_speed_mph; /* Most recent speed reported. */
|
||||
int sb_every; /* Calculated time between transmissions. */
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
@ -392,30 +349,45 @@ static void * beacon_thread (void *arg)
|
|||
char hms[20];
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
localtime_r (&now, &tm);
|
||||
|
||||
strftime (hms, sizeof(hms), "%H:%M:%S", &tm);
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("beacon_thread: started %s\n", hms);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See if any tracker beacons are configured.
|
||||
* No need to obtain GPS data if none.
|
||||
*/
|
||||
|
||||
number_of_tbeacons = 0;
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||
number_of_tbeacons++;
|
||||
}
|
||||
}
|
||||
|
||||
now = time(NULL);
|
||||
|
||||
while (1) {
|
||||
|
||||
assert (g_misc_config_p->num_beacons >= 1);
|
||||
dwgps_info_t gpsinfo;
|
||||
|
||||
/*
|
||||
* Sleep until time for the earliest scheduled or
|
||||
* the soonest we could transmit due to corner pegging.
|
||||
*/
|
||||
|
||||
earliest = g_misc_config_p->beacon[0].next;
|
||||
for (j=1; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_IGNORE)
|
||||
continue;
|
||||
earliest = now + 60 * 60;
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype != BEACON_IGNORE) {
|
||||
earliest = MIN(g_misc_config_p->beacon[j].next, earliest);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_misc_config_p->sb_configured && g_using_gps) {
|
||||
if (g_misc_config_p->sb_configured && number_of_tbeacons > 0) {
|
||||
earliest = MIN(now + g_misc_config_p->sb_turn_time, earliest);
|
||||
earliest = MIN(now + g_misc_config_p->sb_fast_rate, earliest);
|
||||
}
|
||||
|
@ -442,128 +414,57 @@ static void * beacon_thread (void *arg)
|
|||
* beacon because corner pegging make it sooner.
|
||||
*/
|
||||
|
||||
#if DEBUG_SIM
|
||||
FILE *fp;
|
||||
char cs[40];
|
||||
if (number_of_tbeacons > 0) {
|
||||
|
||||
fp = fopen ("c:\\cygwin\\tmp\\cs", "r");
|
||||
if (fp != NULL) {
|
||||
fscanf (fp, "%f %f", &my_course, &my_speed_knots);
|
||||
fclose (fp);
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "Can't read /tmp/cs.\n");
|
||||
}
|
||||
fix = 3;
|
||||
my_speed_mph = DW_KNOTS_TO_MPH(my_speed_knots);
|
||||
my_lat = 42.99;
|
||||
my_lon = 71.99;
|
||||
my_alt_m = 100;
|
||||
#else
|
||||
if (g_using_gps) {
|
||||
|
||||
fix = dwgps_read (&my_lat, &my_lon, &my_speed_knots, &my_course, &my_alt_m);
|
||||
my_speed_mph = DW_KNOTS_TO_MPH(my_speed_knots);
|
||||
dwfix_t fix = dwgps_read (&gpsinfo);
|
||||
float my_speed_mph = DW_KNOTS_TO_MPH(gpsinfo.speed_knots);
|
||||
|
||||
if (g_tracker_debug_level >= 1) {
|
||||
struct tm tm;
|
||||
char hms[20];
|
||||
|
||||
|
||||
localtime_r (&now, &tm);
|
||||
strftime (hms, sizeof(hms), "%H:%M:%S", &tm);
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
if (fix == 3) {
|
||||
dw_printf ("%s 3D, %.6f, %.6f, %.1f mph, %.0f\xc2\xb0, %.1f m\n", hms, my_lat, my_lon, my_speed_mph, my_course, my_alt_m);
|
||||
dw_printf ("%s 3D, %.6f, %.6f, %.1f mph, %.0f\xc2\xb0, %.1f m\n", hms, gpsinfo.dlat, gpsinfo.dlon, my_speed_mph, gpsinfo.track, gpsinfo.altitude);
|
||||
}
|
||||
else if (fix == 2) {
|
||||
dw_printf ("%s 2D, %.6f, %.6f, %.1f mph, %.0f\xc2\xb0\n", hms, my_lat, my_lon, my_speed_mph, my_course);
|
||||
dw_printf ("%s 2D, %.6f, %.6f, %.1f mph, %.0f\xc2\xb0\n", hms, gpsinfo.dlat, gpsinfo.dlon, my_speed_mph, gpsinfo.track);
|
||||
}
|
||||
else {
|
||||
dw_printf ("%s No GPS fix\n", hms);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transmit altitude only if 3D fix and user asked for it. */
|
||||
|
||||
my_alt_ft = G_UNKNOWN;
|
||||
if (fix >= 3 && my_alt_m != G_UNKNOWN && g_misc_config_p->beacon[j].alt_m != G_UNKNOWN) {
|
||||
my_alt_ft = DW_METERS_TO_FEET(my_alt_m);
|
||||
}
|
||||
|
||||
/* Don't complain here for no fix. */
|
||||
/* Possibly at the point where about to transmit. */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Run SmartBeaconing calculation if configured and GPS data available.
|
||||
*/
|
||||
if (g_misc_config_p->sb_configured && g_using_gps && fix >= 2) {
|
||||
if (g_misc_config_p->sb_configured && fix >= DWFIX_2D) {
|
||||
|
||||
if (my_speed_mph > g_misc_config_p->sb_fast_speed) {
|
||||
sb_every = g_misc_config_p->sb_fast_rate;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f > fast %d mph, interval = %d sec\n", my_speed_mph, g_misc_config_p->sb_fast_speed, sb_every);
|
||||
}
|
||||
}
|
||||
else if (my_speed_mph < g_misc_config_p->sb_slow_speed) {
|
||||
sb_every = g_misc_config_p->sb_slow_rate;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f < slow %d mph, interval = %d sec\n", my_speed_mph, g_misc_config_p->sb_slow_speed, sb_every);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Can't divide by 0 assuming sb_slow_speed > 0. */
|
||||
sb_every = ( g_misc_config_p->sb_fast_rate * g_misc_config_p->sb_fast_speed ) / my_speed_mph;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f mph, interval = %d sec\n", my_speed_mph, sb_every);
|
||||
}
|
||||
}
|
||||
time_t tnext = sb_calculate_next_time (now,
|
||||
DW_KNOTS_TO_MPH(gpsinfo.speed_knots), gpsinfo.track,
|
||||
sb_prev_time, sb_prev_course);
|
||||
|
||||
#if DEBUG_SIM
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("SB: fast %d %d slow %d %d speed=%.1f every=%d\n",
|
||||
g_misc_config_p->sb_fast_speed, g_misc_config_p->sb_fast_rate,
|
||||
g_misc_config_p->sb_slow_speed, g_misc_config_p->sb_slow_rate,
|
||||
my_speed_mph, sb_every);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Test for "Corner Pegging" if moving.
|
||||
*/
|
||||
if (my_speed_mph >= 1.0) {
|
||||
int turn_threshold = g_misc_config_p->sb_turn_angle +
|
||||
g_misc_config_p->sb_turn_slope / my_speed_mph;
|
||||
|
||||
#if DEBUG_SIM
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("SB-moving: course %.0f prev %.0f thresh %d\n",
|
||||
my_course, sb_prev_course, turn_threshold);
|
||||
#endif
|
||||
if (heading_change(my_course, sb_prev_course) > turn_threshold &&
|
||||
now >= sb_prev_time + g_misc_config_p->sb_turn_time) {
|
||||
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("heading change (%.0f, %.0f) > threshold %d and %d since last >= turn time %d\n",
|
||||
my_course, sb_prev_course, turn_threshold,
|
||||
(int)(now - sb_prev_time), g_misc_config_p->sb_turn_time);
|
||||
}
|
||||
|
||||
/* Send it now. */
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||
g_misc_config_p->beacon[j].next = now;
|
||||
/* Haven't thought about the consequences of SmartBeaconing */
|
||||
/* and having more than one tbeacon configured. */
|
||||
if (tnext < g_misc_config_p->beacon[j].next) {
|
||||
g_misc_config_p->beacon[j].next = tnext;
|
||||
}
|
||||
}
|
||||
} /* significant change in direction */
|
||||
} /* is moving */
|
||||
} /* Update next time if sooner. */
|
||||
} /* apply SmartBeaconing */
|
||||
} /* tbeacon(s) configured. */
|
||||
|
||||
|
||||
/*
|
||||
* Send if the time has arrived.
|
||||
*/
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_IGNORE)
|
||||
|
@ -571,13 +472,199 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
if (g_misc_config_p->beacon[j].next <= now) {
|
||||
|
||||
/* Send the beacon. */
|
||||
|
||||
beacon_send (j, &gpsinfo);
|
||||
|
||||
/* Calculate when the next one should be sent. */
|
||||
/* Easy for fixed interval. SmartBeaconing takes more effort. */
|
||||
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||
|
||||
if (gpsinfo.fix < DWFIX_2D) {
|
||||
/* Fix not available so beacon was not sent. */
|
||||
/* Try again in a couple seconds. */
|
||||
|
||||
g_misc_config_p->beacon[j].next = now + 2;
|
||||
}
|
||||
else if (g_misc_config_p->sb_configured) {
|
||||
|
||||
/* Remember most recent tracker beacon. */
|
||||
/* Compute next time if not turning. */
|
||||
|
||||
sb_prev_time = now;
|
||||
sb_prev_course = gpsinfo.track;
|
||||
|
||||
g_misc_config_p->beacon[j].next = sb_calculate_next_time (now,
|
||||
DW_KNOTS_TO_MPH(gpsinfo.speed_knots), gpsinfo.track,
|
||||
sb_prev_time, sb_prev_course);
|
||||
}
|
||||
else {
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* non-tracker beacons are at fixed spacing. */
|
||||
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
}
|
||||
|
||||
} /* if time to send it */
|
||||
|
||||
} /* for each configured beacon */
|
||||
|
||||
} /* do forever */
|
||||
|
||||
#if __WIN32__
|
||||
return(0); /* unreachable but warning if not here. */
|
||||
#else
|
||||
return(NULL);
|
||||
#endif
|
||||
|
||||
} /* end beacon_thread */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: sb_calculate_next_time
|
||||
*
|
||||
* Purpose: Calculate next transmission time using the SmartBeaconing algorithm.
|
||||
*
|
||||
* Inputs: now - Current time.
|
||||
*
|
||||
* current_speed_mph - Current speed from GPS.
|
||||
* Not expecting G_UNKNOWN but should check for it.
|
||||
*
|
||||
* current_course - Current direction of travel.
|
||||
* Could be G_UNKNOWN if stationary.
|
||||
*
|
||||
* last_xmit_time - Time of most recent transmission.
|
||||
*
|
||||
* last_xmit_course - Direction included in most recent transmission.
|
||||
*
|
||||
* Global In: g_misc_config_p->
|
||||
* sb_configured TRUE if SmartBeaconing is configured.
|
||||
* sb_fast_speed MPH
|
||||
* sb_fast_rate seconds
|
||||
* sb_slow_speed MPH
|
||||
* sb_slow_rate seconds
|
||||
* sb_turn_time seconds
|
||||
* sb_turn_angle degrees
|
||||
* sb_turn_slope degrees * MPH
|
||||
*
|
||||
* Returns: Time of next transmission.
|
||||
* Could vary from now to sb_slow_rate in the future.
|
||||
*
|
||||
* Caution: The algorithm is defined in MPH units. GPS uses knots.
|
||||
* The caller must be careful about using the proper conversions.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
/* Difference between two angles. */
|
||||
|
||||
static float heading_change (float a, float b)
|
||||
{
|
||||
float diff;
|
||||
|
||||
diff = fabs(a - b);
|
||||
if (diff <= 180.)
|
||||
return (diff);
|
||||
else
|
||||
return (360. - diff);
|
||||
}
|
||||
|
||||
static time_t sb_calculate_next_time (time_t now,
|
||||
float current_speed_mph, float current_course,
|
||||
time_t last_xmit_time, float last_xmit_course)
|
||||
{
|
||||
int beacon_rate;
|
||||
time_t next_time;
|
||||
|
||||
/*
|
||||
* Compute time between beacons for travelling in a straight line.
|
||||
*/
|
||||
|
||||
if (current_speed_mph == G_UNKNOWN) {
|
||||
beacon_rate = (int)roundf((g_misc_config_p->sb_fast_rate + g_misc_config_p->sb_slow_rate) / 2.);
|
||||
}
|
||||
else if (current_speed_mph > g_misc_config_p->sb_fast_speed) {
|
||||
beacon_rate = g_misc_config_p->sb_fast_rate;
|
||||
}
|
||||
else if (current_speed_mph < g_misc_config_p->sb_slow_speed) {
|
||||
beacon_rate = g_misc_config_p->sb_slow_rate;
|
||||
}
|
||||
else {
|
||||
/* Can't divide by 0 assuming sb_slow_speed > 0. */
|
||||
beacon_rate = (int)roundf(( g_misc_config_p->sb_fast_rate * g_misc_config_p->sb_fast_speed ) / current_speed_mph);
|
||||
}
|
||||
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("SmartBeaconing: Beacon Rate = %d seconds for %.1f MPH\n", beacon_rate, current_speed_mph);
|
||||
}
|
||||
|
||||
next_time = last_xmit_time + beacon_rate;
|
||||
|
||||
/*
|
||||
* Test for "Corner Pegging" if moving.
|
||||
*/
|
||||
if (current_speed_mph != G_UNKNOWN && current_speed_mph >= 1.0 &&
|
||||
current_course != G_UNKNOWN && last_xmit_course != G_UNKNOWN) {
|
||||
|
||||
float change = heading_change(current_course, last_xmit_course);
|
||||
float turn_threshold = g_misc_config_p->sb_turn_angle +
|
||||
g_misc_config_p->sb_turn_slope / current_speed_mph;
|
||||
|
||||
if (change > turn_threshold &&
|
||||
now >= last_xmit_time + g_misc_config_p->sb_turn_time) {
|
||||
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("SmartBeaconing: Send now for heading change of %.0f\n", change);
|
||||
}
|
||||
|
||||
next_time = now;
|
||||
}
|
||||
}
|
||||
|
||||
return (next_time);
|
||||
|
||||
} /* end sb_calculate_next_time */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: beacon_send
|
||||
*
|
||||
* Purpose: Transmit one beacon after it was determined to be time.
|
||||
*
|
||||
* Inputs: j Index into beacon configuration array below.
|
||||
*
|
||||
* gpsinfo Information from GPS. Used only for TBEACON.
|
||||
*
|
||||
* Global In: g_misc_config_p->beacon Array of beacon configurations.
|
||||
*
|
||||
* Outputs: Destination(s) specified:
|
||||
* - Transmit queue.
|
||||
* - IGate.
|
||||
* - Simulated reception.
|
||||
*
|
||||
* Description: Prepare text in monitor format.
|
||||
* Convert to packet object.
|
||||
* Send to desired destination(s).
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
static void beacon_send (int j, dwgps_info_t *gpsinfo)
|
||||
{
|
||||
|
||||
|
||||
int strict = 1; /* Strict packet checking because they will go over air. */
|
||||
char stemp[20];
|
||||
char info[AX25_MAX_INFO_LEN];
|
||||
char beacon_text[AX25_MAX_PACKET_LEN];
|
||||
packet_t pp = NULL;
|
||||
char mycall[AX25_MAX_ADDR_LEN];
|
||||
int alt_ft;
|
||||
|
||||
char super_comment[AX25_MAX_INFO_LEN]; // Fixed part + any dynamic part.
|
||||
|
||||
|
@ -600,7 +687,7 @@ static void * beacon_thread (void *arg)
|
|||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("MYCALL not set for beacon in config file line %d.\n", g_misc_config_p->beacon[j].lineno);
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -645,7 +732,7 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
/* Run given command to get variable part of comment. */
|
||||
|
||||
k = dw_run_cmd (g_misc_config_p->beacon[j].commentcmd, 2, var_comment, (int)sizeof(var_comment));
|
||||
k = dw_run_cmd (g_misc_config_p->beacon[j].commentcmd, 2, var_comment, sizeof(var_comment));
|
||||
if (k > 0) {
|
||||
strlcat (super_comment, var_comment, sizeof(super_comment));
|
||||
}
|
||||
|
@ -663,18 +750,16 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
case BEACON_POSITION:
|
||||
|
||||
alt_ft = DW_METERS_TO_FEET(g_misc_config_p->beacon[j].alt_m);
|
||||
|
||||
encode_position (g_misc_config_p->beacon[j].messaging,
|
||||
g_misc_config_p->beacon[j].compress, g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon, alt_ft,
|
||||
encode_position (g_misc_config_p->beacon[j].messaging, g_misc_config_p->beacon[j].compress,
|
||||
g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon,
|
||||
(int)roundf(DW_METERS_TO_FEET(g_misc_config_p->beacon[j].alt_m)),
|
||||
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||
0, 0, /* course, speed */
|
||||
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
||||
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset,
|
||||
super_comment,
|
||||
info, sizeof(info));
|
||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
break;
|
||||
|
||||
case BEACON_OBJECT:
|
||||
|
@ -682,48 +767,43 @@ static void * beacon_thread (void *arg)
|
|||
encode_object (g_misc_config_p->beacon[j].objname, g_misc_config_p->beacon[j].compress, 0, g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon,
|
||||
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||
0, 0, /* course, speed */
|
||||
G_UNKNOWN, G_UNKNOWN, /* course, speed */
|
||||
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset, super_comment,
|
||||
info, sizeof(info));
|
||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
break;
|
||||
|
||||
case BEACON_TRACKER:
|
||||
|
||||
if (fix >= 2) {
|
||||
int coarse; /* APRS encoder wants 1 - 360. */
|
||||
/* 0 means none or unknown. */
|
||||
if (gpsinfo->fix >= DWFIX_2D) {
|
||||
|
||||
coarse = (int)roundf(my_course);
|
||||
if (coarse == 0) {
|
||||
coarse = 360;
|
||||
int coarse; /* Round to nearest integer. retaining unknown state. */
|
||||
int my_alt_ft;
|
||||
|
||||
/* Transmit altitude only if user asked for it. */
|
||||
/* A positive altitude in the config file enables */
|
||||
/* transmission of altitude from GPS. */
|
||||
|
||||
my_alt_ft = G_UNKNOWN;
|
||||
if (gpsinfo->fix >= 3 && gpsinfo->altitude != G_UNKNOWN && g_misc_config_p->beacon[j].alt_m > 0) {
|
||||
my_alt_ft = (int)roundf(DW_METERS_TO_FEET(gpsinfo->altitude));
|
||||
}
|
||||
encode_position (g_misc_config_p->beacon[j].messaging,
|
||||
g_misc_config_p->beacon[j].compress,
|
||||
my_lat, my_lon, my_alt_ft,
|
||||
|
||||
coarse = G_UNKNOWN;
|
||||
if (gpsinfo->track != G_UNKNOWN) {
|
||||
coarse = (int)roundf(gpsinfo->track);
|
||||
}
|
||||
|
||||
encode_position (g_misc_config_p->beacon[j].messaging, g_misc_config_p->beacon[j].compress,
|
||||
gpsinfo->dlat, gpsinfo->dlon, my_alt_ft,
|
||||
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
||||
g_misc_config_p->beacon[j].power, g_misc_config_p->beacon[j].height, g_misc_config_p->beacon[j].gain, g_misc_config_p->beacon[j].dir,
|
||||
coarse, (int)roundf(my_speed_knots),
|
||||
coarse, (int)roundf(gpsinfo->speed_knots),
|
||||
g_misc_config_p->beacon[j].freq, g_misc_config_p->beacon[j].tone, g_misc_config_p->beacon[j].offset,
|
||||
super_comment,
|
||||
info, sizeof(info));
|
||||
strlcat (beacon_text, info, sizeof(beacon_text));
|
||||
|
||||
/* Remember most recent tracker beacon. */
|
||||
|
||||
sb_prev_time = now;
|
||||
sb_prev_course = my_course;
|
||||
//sb_prev_speed_mph = my_speed_mph;
|
||||
|
||||
/* Calculate time for next transmission. */
|
||||
if (g_misc_config_p->sb_configured) {
|
||||
g_misc_config_p->beacon[j].next = now + sb_every;
|
||||
}
|
||||
else {
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
}
|
||||
|
||||
/* Write to log file for testing. */
|
||||
/* The idea is to run log2gpx and map the result rather than */
|
||||
/* actually transmitting and relying on someone else to receive */
|
||||
|
@ -743,11 +823,11 @@ static void * beacon_thread (void *arg)
|
|||
strlcpy (A.g_src, mycall, sizeof(A.g_src));
|
||||
A.g_symbol_table = g_misc_config_p->beacon[j].symtab;
|
||||
A.g_symbol_code = g_misc_config_p->beacon[j].symbol;
|
||||
A.g_lat = my_lat;
|
||||
A.g_lon = my_lon;
|
||||
A.g_speed = DW_KNOTS_TO_MPH(my_speed_knots);
|
||||
A.g_lat = gpsinfo->dlat;
|
||||
A.g_lon = gpsinfo->dlon;
|
||||
A.g_speed_mph = DW_KNOTS_TO_MPH(gpsinfo->speed_knots);
|
||||
A.g_course = coarse;
|
||||
A.g_altitude = my_alt_ft;
|
||||
A.g_altitude_ft = DW_METERS_TO_FEET(gpsinfo->altitude);
|
||||
|
||||
/* Fake channel of 999 to distinguish from real data. */
|
||||
memset (&alevel, 0, sizeof(alevel));
|
||||
|
@ -755,8 +835,7 @@ static void * beacon_thread (void *arg)
|
|||
}
|
||||
}
|
||||
else {
|
||||
g_misc_config_p->beacon[j].next = now + 2;
|
||||
continue; /* No fix. Try again in a couple seconds. */
|
||||
return; /* No fix. Skip this time. */
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -770,12 +849,11 @@ static void * beacon_thread (void *arg)
|
|||
}
|
||||
else if (g_misc_config_p->beacon[j].custom_infocmd != NULL) {
|
||||
char info_part[AX25_MAX_INFO_LEN];
|
||||
char *p;
|
||||
int k;
|
||||
|
||||
/* Run given command to obtain the info part for packet. */
|
||||
|
||||
k = dw_run_cmd (g_misc_config_p->beacon[j].custom_infocmd, 2, info_part, (int)sizeof(info_part));
|
||||
k = dw_run_cmd (g_misc_config_p->beacon[j].custom_infocmd, 2, info_part, sizeof(info_part));
|
||||
if (k > 0) {
|
||||
strlcat (beacon_text, info_part, sizeof(beacon_text));
|
||||
}
|
||||
|
@ -790,7 +868,6 @@ static void * beacon_thread (void *arg)
|
|||
dw_printf ("Internal error. custom_info is null. %s %d\n", __FILE__, __LINE__);
|
||||
strlcpy (beacon_text, "", sizeof(beacon_text)); // abort!
|
||||
}
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
break;
|
||||
|
||||
case BEACON_IGNORE:
|
||||
|
@ -803,7 +880,7 @@ static void * beacon_thread (void *arg)
|
|||
* Parse monitor format into form for transmission.
|
||||
*/
|
||||
if (strlen(beacon_text) == 0) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
pp = ax25_from_text (beacon_text, strict);
|
||||
|
@ -819,11 +896,9 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
case SENDTO_IGATE:
|
||||
|
||||
|
||||
#if 1
|
||||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[ig] %s\n", beacon_text);
|
||||
#endif
|
||||
|
||||
igate_send_rec_packet (0, pp);
|
||||
ax25_delete (pp);
|
||||
break;
|
||||
|
@ -849,12 +924,7 @@ static void * beacon_thread (void *arg)
|
|||
dw_printf ("%s\n", beacon_text);
|
||||
}
|
||||
|
||||
} /* if time to send it */
|
||||
} /* end beacon_send */
|
||||
|
||||
} /* for each configured beacon */
|
||||
|
||||
} /* do forever */
|
||||
|
||||
} /* end beacon_thread */
|
||||
|
||||
/* end beacon.c */
|
||||
|
|
2
beacon.h
2
beacon.h
|
@ -1,6 +1,6 @@
|
|||
|
||||
/* beacon.h */
|
||||
|
||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig, struct digi_config_s *pdigi);
|
||||
void beacon_init (struct audio_s *pmodem, struct misc_config_s *pconfig);
|
||||
|
||||
void beacon_tracker_set_debug (int level);
|
||||
|
|
172
config.c
172
config.c
|
@ -42,10 +42,8 @@
|
|||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#if __WIN32__
|
||||
//#include "pthreads/pthread.h"
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#if ENABLE_GPSD
|
||||
#include <gps.h> /* for DEFAULT_GPSD_PORT (2947) */
|
||||
#endif
|
||||
|
||||
#include "ax25_pad.h"
|
||||
|
@ -184,13 +182,12 @@ static int alllettersorpm(char *p)
|
|||
/* Acceptable symbols to separate degrees & minutes. */
|
||||
/* Degree symbol is not in ASCII so documentation says to use "^" instead. */
|
||||
/* Some wise guy will try to use degree symbol. */
|
||||
/* UTF-8 is more difficult because it is a two byte sequence, c2 b0. */
|
||||
|
||||
#define DEG1 '^'
|
||||
#define DEG2 0xb0 /* ISO Latin1 */
|
||||
#define DEG3 0xf8 /* Microsoft code page 437 */
|
||||
|
||||
// TODO: recognize UTF-8 degree symbol.
|
||||
|
||||
|
||||
enum parse_ll_which_e { LAT, LON };
|
||||
|
||||
|
@ -484,7 +481,6 @@ static char *split (char *string, int rest_of_line)
|
|||
{
|
||||
static char cmd[MAXCMDLEN];
|
||||
static char token[MAXCMDLEN];
|
||||
static char *nextp = NULL;
|
||||
static char *c; // current position in cmd.
|
||||
char *s, *t;
|
||||
int in_quotes;
|
||||
|
@ -756,6 +752,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
//strlcpy (p_misc_config->nullmodem, DEFAULT_NULLMODEM, sizeof(p_misc_config->nullmodem));
|
||||
strlcpy (p_misc_config->nullmodem, "", sizeof(p_misc_config->nullmodem));
|
||||
strlcpy (p_misc_config->gpsnmea_port, "", sizeof(p_misc_config->gpsnmea_port));
|
||||
strlcpy (p_misc_config->nmea_port, "", sizeof(p_misc_config->nmea_port));
|
||||
strlcpy (p_misc_config->logdir, "", sizeof(p_misc_config->logdir));
|
||||
|
||||
|
@ -869,12 +866,12 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
/* First channel of device is valid. */
|
||||
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1;
|
||||
|
||||
strncpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in)-1);
|
||||
strncpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out)-1);
|
||||
strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
|
||||
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t != NULL) {
|
||||
strncpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out)-1);
|
||||
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -924,7 +921,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
/* First channel of device is valid. */
|
||||
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1;
|
||||
|
||||
strncpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in)-1);
|
||||
strlcpy (p_audio_config->adev[adevice].adevice_in, t, sizeof(p_audio_config->adev[adevice].adevice_in));
|
||||
}
|
||||
else if (strcasecmp(t, "PAODEVICE") == 0) {
|
||||
adevice = 0;
|
||||
|
@ -951,7 +948,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
/* First channel of device is valid. */
|
||||
p_audio_config->achan[ADEVFIRSTCHAN(adevice)].valid = 1;
|
||||
|
||||
strncpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out)-1);
|
||||
strlcpy (p_audio_config->adev[adevice].adevice_out, t, sizeof(p_audio_config->adev[adevice].adevice_out));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1074,7 +1071,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
char *p;
|
||||
|
||||
strncpy (p_audio_config->achan[c].mycall, t, sizeof(p_audio_config->achan[c].mycall)-1);
|
||||
strlcpy (p_audio_config->achan[c].mycall, t, sizeof(p_audio_config->achan[c].mycall));
|
||||
|
||||
for (p = p_audio_config->achan[c].mycall; *p != '\0'; p++) {
|
||||
if (islower(*p)) {
|
||||
|
@ -1082,6 +1079,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
}
|
||||
}
|
||||
// TODO: additional checks if valid.
|
||||
// Should have a function to check for valid callsign[-ssid]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1231,7 +1229,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
}
|
||||
}
|
||||
|
||||
strncpy (p_audio_config->achan[channel].profiles, t, sizeof(p_audio_config->achan[channel].profiles));
|
||||
strlcpy (p_audio_config->achan[channel].profiles, t, sizeof(p_audio_config->achan[channel].profiles));
|
||||
t = split(NULL,0);
|
||||
if (strlen(p_audio_config->achan[channel].profiles) > 1 && t != NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1328,7 +1326,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
else if (alllettersorpm(t)) { /* profile of letter(s) + - */
|
||||
|
||||
// Will be validated later.
|
||||
strncpy (p_audio_config->achan[channel].profiles, t, sizeof(p_audio_config->achan[channel].profiles));
|
||||
strlcpy (p_audio_config->achan[channel].profiles, t, sizeof(p_audio_config->achan[channel].profiles));
|
||||
}
|
||||
|
||||
else if (*t == '/') { /* /div */
|
||||
|
@ -1354,7 +1352,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
/* A later place catches disallowed combination of + and @. */
|
||||
/* A later place sets /n for 300 baud if not specified by user. */
|
||||
|
||||
//printf ("debug: div = %d\n", p_audio_config->achan[channel].decimate);
|
||||
//dw_printf ("debug: div = %d\n", p_audio_config->achan[channel].decimate);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1440,7 +1438,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
*/
|
||||
|
||||
else if (strcasecmp(t, "PTT") == 0 || strcasecmp(t, "DCD") == 0) {
|
||||
//int n;
|
||||
int ot;
|
||||
char otname[8];
|
||||
|
||||
|
@ -1729,7 +1726,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
*/
|
||||
|
||||
else if (strcasecmp(t, "SPEECH") == 0) {
|
||||
int n;
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -1895,8 +1892,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
else if (strcasecmp(t, "regen") == 0) {
|
||||
int from_chan, to_chan;
|
||||
int e;
|
||||
char message[100];
|
||||
|
||||
|
||||
t = split(NULL,0);
|
||||
|
@ -1957,8 +1952,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
else if (strcasecmp(t, "FILTER") == 0) {
|
||||
int from_chan, to_chan;
|
||||
int e;
|
||||
char message[100];
|
||||
|
||||
|
||||
t = split(NULL,0);
|
||||
|
@ -2036,7 +2029,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
*/
|
||||
|
||||
else if (strcasecmp(t, "TTCORRAL") == 0) {
|
||||
//int n;
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -2371,8 +2364,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
struct ttloc_s *tl;
|
||||
int j;
|
||||
int znum;
|
||||
char *zlet;
|
||||
double dlat, dlon;
|
||||
long lerr;
|
||||
|
||||
|
@ -2485,8 +2476,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
struct ttloc_s *tl;
|
||||
int j;
|
||||
int znum;
|
||||
char *zlet;
|
||||
int num_x, num_y;
|
||||
double lat, lon;
|
||||
long lerr;
|
||||
|
@ -2679,7 +2668,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
p_tt_config->ttloc_len--;
|
||||
continue;
|
||||
}
|
||||
if (tt_mhead_to_text(t, 0, mh) != 0) {
|
||||
if (tt_mhead_to_text(t, 0, mh, sizeof(mh)) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Line %d: TTMHEAD prefix not a valid DTMF sequence.\n", line);
|
||||
p_tt_config->ttloc_len--;
|
||||
|
@ -2802,7 +2791,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
struct ttloc_s *tl;
|
||||
int j;
|
||||
//char ch;
|
||||
int p_count[3], d_count[3];
|
||||
int tt_error = 0;
|
||||
|
||||
|
@ -2959,8 +2947,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
if (*pi == '}') {
|
||||
char symtab;
|
||||
char symbol;
|
||||
char overlay;
|
||||
char symdest[8];
|
||||
|
||||
*ps = '\0';
|
||||
|
||||
|
@ -2975,7 +2961,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
// Convert symtab(overlay) & symbol to tone sequence.
|
||||
|
||||
symbols_to_tones (symtab, symbol, ttemp);
|
||||
symbols_to_tones (symtab, symbol, ttemp, sizeof(ttemp));
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("DEBUG config file Line %d: AB{%s} -> %s\n", line, stemp, ttemp);
|
||||
|
@ -3129,7 +3115,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
if (t != NULL) {
|
||||
|
||||
// TODO: Should do some validity checking on the path.
|
||||
strncpy (p_tt_config->obj_xmit_via, t, sizeof(p_tt_config->obj_xmit_via));
|
||||
strlcpy (p_tt_config->obj_xmit_via, t, sizeof(p_tt_config->obj_xmit_via));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3246,9 +3232,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
while (*t == ' ' || *t == '\t') t++; // remove leading white space.
|
||||
|
||||
strncpy (p_tt_config->status[status_num], t, TT_MTEXT_LEN);
|
||||
p_tt_config->status[status_num][TT_MTEXT_LEN-1] = '\0';
|
||||
|
||||
strlcpy (p_tt_config->status[status_num], t, sizeof(p_tt_config->status[status_num]));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3260,7 +3244,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
*/
|
||||
|
||||
else if (strcasecmp(t, "TTCMD") == 0) {
|
||||
int status_num;
|
||||
|
||||
t = split(NULL,1);
|
||||
if (t == NULL) {
|
||||
|
@ -3269,9 +3252,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
continue;
|
||||
}
|
||||
|
||||
strncpy (p_tt_config->ttcmd, t, sizeof(p_tt_config->ttcmd));
|
||||
p_tt_config->ttcmd[sizeof(p_tt_config->ttcmd)-1] = '\0';
|
||||
|
||||
strlcpy (p_tt_config->ttcmd, t, sizeof(p_tt_config->ttcmd));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3294,7 +3275,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
dw_printf ("Line %d: Missing IGate server name for IGSERVER command.\n", line);
|
||||
continue;
|
||||
}
|
||||
strncpy (p_igate_config->t2_server_name, t, sizeof(p_igate_config->t2_server_name)-1);
|
||||
strlcpy (p_igate_config->t2_server_name, t, sizeof(p_igate_config->t2_server_name));
|
||||
|
||||
/* If there is a : in the name, split it out as the port number. */
|
||||
|
||||
|
@ -3329,7 +3310,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
line, p_igate_config->t2_server_port);
|
||||
}
|
||||
}
|
||||
//printf ("DEBUG server=%s port=%d\n", p_igate_config->t2_server_name, p_igate_config->t2_server_port);
|
||||
//dw_printf ("DEBUG server=%s port=%d\n", p_igate_config->t2_server_name, p_igate_config->t2_server_port);
|
||||
//exit (0);
|
||||
}
|
||||
|
||||
|
@ -3347,7 +3328,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
continue;
|
||||
}
|
||||
// TODO: Wouldn't hurt to do validity checking of format.
|
||||
strncpy (p_igate_config->t2_login, t, sizeof(p_igate_config->t2_login)-1);
|
||||
strlcpy (p_igate_config->t2_login, t, sizeof(p_igate_config->t2_login));
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t == NULL) {
|
||||
|
@ -3355,7 +3336,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
dw_printf ("Line %d: Missing passcode for IGLOGIN command.\n", line);
|
||||
continue;
|
||||
}
|
||||
strncpy (p_igate_config->t2_passcode, t, sizeof(p_igate_config->t2_passcode)-1);
|
||||
strlcpy (p_igate_config->t2_passcode, t, sizeof(p_igate_config->t2_passcode));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3387,7 +3368,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
if (t != NULL) {
|
||||
char *p;
|
||||
p_igate_config->tx_via[0] = ',';
|
||||
strncpy (p_igate_config->tx_via + 1, t, sizeof(p_igate_config->tx_via)-2);
|
||||
strlcpy (p_igate_config->tx_via + 1, t, sizeof(p_igate_config->tx_via)-1);
|
||||
for (p = p_igate_config->tx_via; *p != '\0'; p++) {
|
||||
if (islower(*p)) {
|
||||
*p = toupper(*p); /* silently force upper case. */
|
||||
|
@ -3403,7 +3384,6 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
*/
|
||||
|
||||
else if (strcasecmp(t, "IGFILTER") == 0) {
|
||||
//int n;
|
||||
|
||||
t = split(NULL,1); /* Take rest of line as one string. */
|
||||
|
||||
|
@ -3524,12 +3504,74 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
continue;
|
||||
}
|
||||
else {
|
||||
strncpy (p_misc_config->nullmodem, t, sizeof(p_misc_config->nullmodem)-1);
|
||||
strlcpy (p_misc_config->nullmodem, t, sizeof(p_misc_config->nullmodem));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GPSNMEA - Device name for reading from GPS receiver.
|
||||
*/
|
||||
else if (strcasecmp(t, "gpsnmea") == 0) {
|
||||
t = split(NULL,0);
|
||||
if (t == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Missing serial port name for GPS receiver.\n", line);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
strlcpy (p_misc_config->gpsnmea_port, t, sizeof(p_misc_config->gpsnmea_port));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GPSD - Use GPSD server.
|
||||
*
|
||||
* GPSD [ host [ port ] ]
|
||||
*/
|
||||
else if (strcasecmp(t, "gpsd") == 0) {
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: The GPSD interface is not available for Windows.\n", line);
|
||||
continue;
|
||||
|
||||
#elif ENABLE_GPSD
|
||||
|
||||
strlcpy (p_misc_config->gpsd_host, "localhost", sizeof(p_misc_config->gpsd_host));
|
||||
p_misc_config->gpsd_port = atoi(DEFAULT_GPSD_PORT);
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t != NULL) {
|
||||
strlcpy (p_misc_config->gpsd_host, t, sizeof(p_misc_config->gpsd_host));
|
||||
|
||||
t = split(NULL,0);
|
||||
if (t != NULL) {
|
||||
|
||||
int n = atoi(t);
|
||||
if ((n >= MIN_IP_PORT_NUMBER && n <= MAX_IP_PORT_NUMBER) || n == 0) {
|
||||
p_misc_config->gpsd_port = n;
|
||||
}
|
||||
else {
|
||||
p_misc_config->gpsd_port = atoi(DEFAULT_GPSD_PORT);
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Line %d: Invalid port number for GPSD Socket Interface. Using default of %d.\n",
|
||||
line, p_misc_config->gpsd_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: The GPSD interface has not been enabled.\n", line);
|
||||
dw_printf ("Install gpsd and libgps-dev packages then rebuild direwolf.\n");
|
||||
continue;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* NMEA - Device name for communication with NMEA device.
|
||||
* Wasn't documented will probably use WAYPOINT instead.
|
||||
*/
|
||||
else if (strcasecmp(t, "nmea") == 0) {
|
||||
t = split(NULL,0);
|
||||
|
@ -3539,7 +3581,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
continue;
|
||||
}
|
||||
else {
|
||||
strncpy (p_misc_config->nmea_port, t, sizeof(p_misc_config->nmea_port)-1);
|
||||
strlcpy (p_misc_config->nmea_port, t, sizeof(p_misc_config->nmea_port));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3554,7 +3596,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
continue;
|
||||
}
|
||||
else {
|
||||
strncpy (p_misc_config->logdir, t, sizeof(p_misc_config->logdir)-1);
|
||||
strlcpy (p_misc_config->logdir, t, sizeof(p_misc_config->logdir));
|
||||
}
|
||||
t = split(NULL,0);
|
||||
if (t != NULL) {
|
||||
|
@ -3591,21 +3633,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
strcasecmp(t, "OBEACON") == 0 ||
|
||||
strcasecmp(t, "TBEACON") == 0 ||
|
||||
strcasecmp(t, "CBEACON") == 0) {
|
||||
#if __WIN32__
|
||||
if (strcasecmp(t, "TBEACON") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: TBEACON is available only in Linux version.\n", line);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_GPS
|
||||
if (strcasecmp(t, "TBEACON") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Rebuild with GPS support for TBEACON to be available.\n", line);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (p_misc_config->num_beacons < MAX_BEACONS) {
|
||||
|
||||
memset (&(p_misc_config->beacon[p_misc_config->num_beacons]), 0, sizeof(struct beacon_s));
|
||||
|
@ -3638,7 +3666,9 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
|
||||
/*
|
||||
* SMARTBEACONING fast_speed fast_rate slow_speed slow_rate turn_time turn_angle turn_slope
|
||||
* SMARTBEACONING [ fast_speed fast_rate slow_speed slow_rate turn_time turn_angle turn_slope ]
|
||||
*
|
||||
* Parameters must be all or nothing.
|
||||
*/
|
||||
|
||||
else if (strcasecmp(t, "SMARTBEACON") == 0 ||
|
||||
|
@ -3649,6 +3679,10 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
#define SB_NUM(name,sbvar,minn,maxx,unit) \
|
||||
t = split(NULL,0); \
|
||||
if (t == NULL) { \
|
||||
if (strcmp(name, "fast speed") == 0) { \
|
||||
p_misc_config->sb_configured = 1; \
|
||||
continue; \
|
||||
} \
|
||||
text_color_set(DW_COLOR_ERROR); \
|
||||
dw_printf ("Line %d: Missing %s for SmartBeaconing.\n", line, name); \
|
||||
continue; \
|
||||
|
@ -3787,11 +3821,7 @@ void config_init (char *fname, struct audio_s *p_audio_config,
|
|||
|
||||
static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_s *p_audio_config)
|
||||
{
|
||||
char options[1000];
|
||||
char *o;
|
||||
char *t;
|
||||
char *p;
|
||||
int q;
|
||||
char temp_symbol[100];
|
||||
int ok;
|
||||
char zone[8];
|
||||
|
@ -3901,7 +3931,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
b->custom_infocmd = strdup(value);
|
||||
}
|
||||
else if (strcasecmp(keyword, "OBJNAME") == 0) {
|
||||
strncpy(b->objname, value, 9);
|
||||
strlcpy(b->objname, value, sizeof(b->objname));
|
||||
}
|
||||
else if (strcasecmp(keyword, "LAT") == 0) {
|
||||
b->lat = parse_ll (value, LAT, line);
|
||||
|
@ -3913,7 +3943,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
b->alt_m = atof(value);
|
||||
}
|
||||
else if (strcasecmp(keyword, "ZONE") == 0) {
|
||||
strncpy(zone, value, sizeof(zone));
|
||||
strlcpy(zone, value, sizeof(zone));
|
||||
}
|
||||
else if (strcasecmp(keyword, "EAST") == 0 || strcasecmp(keyword, "EASTING") == 0) {
|
||||
easting = atof(value);
|
||||
|
@ -3944,7 +3974,7 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line, struct audio_
|
|||
b->gain = atoi(value);
|
||||
}
|
||||
else if (strcasecmp(keyword, "DIR") == 0 || strcasecmp(keyword, "DIRECTION") == 0) {
|
||||
strncpy(b->dir, value, 2);
|
||||
strlcpy(b->dir, value, sizeof(b->dir));
|
||||
}
|
||||
else if (strcasecmp(keyword, "FREQ") == 0) {
|
||||
b->freq = atof(value);
|
||||
|
|
16
config.h
16
config.h
|
@ -38,11 +38,21 @@ struct misc_config_s {
|
|||
/* Want this to be off by default because it hangs */
|
||||
/* after a while if nothing is reading from other end. */
|
||||
|
||||
char nullmodem[40]; /* Serial port name for our end of the */
|
||||
char nullmodem[20]; /* Serial port name for our end of the */
|
||||
/* virtual null modem for native Windows apps. */
|
||||
|
||||
char nmea_port[40]; /* Serial port name for NMEA communication with GPS */
|
||||
/* receiver and/or mapping application. */
|
||||
char gpsnmea_port[20]; /* Serial port name for reading NMEA sentences from GPS. */
|
||||
/* e.g. COM22, /dev/ttyACM0 */
|
||||
|
||||
char gpsd_host[20]; /* Host for gpsd server. */
|
||||
/* e.g. localhost, 192.168.1.2 */
|
||||
|
||||
int gpsd_port; /* Port number for gpsd server. */
|
||||
/* Default is 2947. */
|
||||
|
||||
/* e.g. COM22, /dev/ttyACM0 */
|
||||
char nmea_port[20]; /* Serial port name for NMEA communication with GPS */
|
||||
/* receiver and/or mapping application. Change this. */
|
||||
|
||||
char logdir[80]; /* Directory for saving activity logs. */
|
||||
|
||||
|
|
391
decode_aprs.c
391
decode_aprs.c
|
@ -53,7 +53,7 @@
|
|||
#include "textcolor.h"
|
||||
#include "symbols.h"
|
||||
#include "latlong.h"
|
||||
//#include "nmea.h"
|
||||
#include "dwgpsnmea.h"
|
||||
#include "decode_aprs.h"
|
||||
#include "telemetry.h"
|
||||
|
||||
|
@ -143,7 +143,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen);
|
|||
*
|
||||
* Outputs: A-> g_symbol_table, g_symbol_code,
|
||||
* g_lat, g_lon,
|
||||
* g_speed, g_course, g_altitude,
|
||||
* g_speed_mph, g_course, g_altitude_ft,
|
||||
* g_comment
|
||||
* ... and many others...
|
||||
*
|
||||
|
@ -174,7 +174,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet)
|
|||
A->g_lat = G_UNKNOWN;
|
||||
A->g_lon = G_UNKNOWN;
|
||||
|
||||
A->g_speed = G_UNKNOWN;
|
||||
A->g_speed_mph = G_UNKNOWN;
|
||||
A->g_course = G_UNKNOWN;
|
||||
|
||||
A->g_power = G_UNKNOWN;
|
||||
|
@ -182,7 +182,7 @@ void decode_aprs (decode_aprs_t *A, packet_t pp, int quiet)
|
|||
A->g_gain = G_UNKNOWN;
|
||||
|
||||
A->g_range = G_UNKNOWN;
|
||||
A->g_altitude = G_UNKNOWN;
|
||||
A->g_altitude_ft = G_UNKNOWN;
|
||||
A->g_freq = G_UNKNOWN;
|
||||
A->g_tone = G_UNKNOWN;
|
||||
A->g_dcs = G_UNKNOWN;
|
||||
|
@ -416,6 +416,11 @@ void decode_aprs_print (decode_aprs_t *A) {
|
|||
if (A->g_power > 0) {
|
||||
char phg[100];
|
||||
|
||||
/* Protcol spec doesn't mention whether this is dBd or dBi. */
|
||||
/* Clarified later. */
|
||||
/* http://eng.usna.navy.mil/~bruninga/aprs/aprs11.html */
|
||||
/* "The Antenna Gain in the PHG format on page 28 is in dBi." */
|
||||
|
||||
snprintf (phg, sizeof(phg), ", %d W height=%d %ddBi %s", A->g_power, A->g_height, A->g_gain, A->g_directivity);
|
||||
strlcat (stemp, phg, sizeof(stemp));
|
||||
}
|
||||
|
@ -507,11 +512,11 @@ void decode_aprs_print (decode_aprs_t *A) {
|
|||
strlcat (stemp, A->g_aprstt_loc, sizeof(stemp));
|
||||
};
|
||||
|
||||
if (A->g_speed != G_UNKNOWN) {
|
||||
if (A->g_speed_mph != G_UNKNOWN) {
|
||||
char spd[20];
|
||||
|
||||
if (strlen(stemp) > 0) strlcat (stemp, ", ", sizeof(stemp));
|
||||
snprintf (spd, sizeof(spd), "%.0f MPH", A->g_speed);
|
||||
snprintf (spd, sizeof(spd), "%.0f MPH", A->g_speed_mph);
|
||||
strlcat (stemp, spd, sizeof(stemp));
|
||||
};
|
||||
|
||||
|
@ -523,11 +528,11 @@ void decode_aprs_print (decode_aprs_t *A) {
|
|||
strlcat (stemp, cse, sizeof(stemp));
|
||||
};
|
||||
|
||||
if (A->g_altitude != G_UNKNOWN) {
|
||||
if (A->g_altitude_ft != G_UNKNOWN) {
|
||||
char alt[20];
|
||||
|
||||
if (strlen(stemp) > 0) strlcat (stemp, ", ", sizeof(stemp));
|
||||
snprintf (alt, sizeof(alt), "alt %.0f ft", A->g_altitude);
|
||||
snprintf (alt, sizeof(alt), "alt %.0f ft", A->g_altitude_ft);
|
||||
strlcat (stemp, alt, sizeof(stemp));
|
||||
};
|
||||
|
||||
|
@ -662,7 +667,7 @@ void decode_aprs_print (decode_aprs_t *A) {
|
|||
* Inputs: info - Pointer to Information field.
|
||||
* ilen - Information field length.
|
||||
*
|
||||
* Outputs: A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed, A->g_course, A->g_altitude.
|
||||
* Outputs: A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed_mph, A->g_course, A->g_altitude_ft.
|
||||
*
|
||||
* Description: Type identifier '=' has APRS messaging.
|
||||
* Type identifier '!' does not have APRS messaging.
|
||||
|
@ -758,7 +763,7 @@ static void aprs_ll_pos (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
* Inputs: info - Pointer to Information field.
|
||||
* ilen - Information field length.
|
||||
*
|
||||
* Outputs: A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed, A->g_course, A->g_altitude.
|
||||
* Outputs: A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed_mph, A->g_course, A->g_altitude_ft.
|
||||
*
|
||||
* Description: Type identifier '@' has APRS messaging.
|
||||
* Type identifier '/' does not have APRS messaging.
|
||||
|
@ -850,6 +855,7 @@ static void aprs_ll_pos_time (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
}
|
||||
}
|
||||
|
||||
(void)(ts); // suppress 'set but not used' warning.
|
||||
}
|
||||
|
||||
|
||||
|
@ -862,7 +868,7 @@ static void aprs_ll_pos_time (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
* Inputs: info - Pointer to Information field.
|
||||
* ilen - Information field length.
|
||||
*
|
||||
* Outputs: ??? TBD
|
||||
* Outputs: A-> ...
|
||||
*
|
||||
* Description: APRS recognizes raw ASCII data strings conforming to the NMEA 0183
|
||||
* Version 2.0 specification, originating from navigation equipment such
|
||||
|
@ -875,286 +881,37 @@ static void aprs_ll_pos_time (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
* VTG Velocity and Track Data
|
||||
* WPL Way Point Location
|
||||
*
|
||||
* We presently recognize only RMC and GGA.
|
||||
*
|
||||
* Examples: $GPGGA,102705,5157.9762,N,00029.3256,W,1,04,2.0,75.7,M,47.6,M,,*62
|
||||
* $GPGLL,2554.459,N,08020.187,W,154027.281,A
|
||||
* $GPRMC,063909,A,3349.4302,N,11700.3721,W,43.022,89.3,291099,13.6,E*52
|
||||
* $GPVTG,318.7,T,,M,35.1,N,65.0,K*69
|
||||
*
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
static void nmea_checksum (decode_aprs_t *A, char *sent)
|
||||
{
|
||||
char *p;
|
||||
char *next;
|
||||
unsigned char cs;
|
||||
|
||||
|
||||
// Do we have valid checksum?
|
||||
|
||||
cs = 0;
|
||||
for (p = sent+1; *p != '*' && *p != '\0'; p++) {
|
||||
cs ^= *p;
|
||||
}
|
||||
|
||||
p = strchr (sent, '*');
|
||||
if (p == NULL) {
|
||||
if ( ! A->g_quiet) {
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
dw_printf("Missing GPS checksum.\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (cs != strtoul(p+1, NULL, 16)) {
|
||||
if ( ! A->g_quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("GPS checksum error. Expected %02x but found %s.\n", cs, p+1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
*p = '\0'; // Remove the checksum.
|
||||
}
|
||||
|
||||
static void aprs_raw_nmea (decode_aprs_t *A, unsigned char *info, int ilen)
|
||||
{
|
||||
char stemp[256];
|
||||
char *ptype;
|
||||
char *next;
|
||||
|
||||
|
||||
strlcpy (A->g_msg_type, "Raw NMEA", sizeof(A->g_msg_type));
|
||||
|
||||
strlcpy (stemp, (char *)info, sizeof(stemp));
|
||||
nmea_checksum (A, stemp);
|
||||
|
||||
next = stemp;
|
||||
ptype = strsep(&next, ",");
|
||||
|
||||
if (strcmp(ptype, "$GPGGA") == 0)
|
||||
if (strncmp((char*)info, "$GPRMC,", 7) == 0)
|
||||
{
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pquality; /* Fix Quality: 0=invalid, 1=GPS, 2=DGPS */
|
||||
char *pnsat; /* Number of satellites. */
|
||||
char *phdop; /* Horizontal dilution of precision. */
|
||||
char *paltitude; /* Altitude, meters above mean sea level. */
|
||||
char *pm; /* "M" = meters */
|
||||
/* Various other stuff... */
|
||||
float speed_knots = G_UNKNOWN;
|
||||
|
||||
|
||||
ptime = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pquality = strsep(&next, ",");
|
||||
pnsat = strsep(&next, ",");
|
||||
phdop = strsep(&next, ",");
|
||||
paltitude = strsep(&next, ",");
|
||||
pm = strsep(&next, ",");
|
||||
|
||||
/* Process time??? */
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
A->g_lat = latitude_from_nmea(plat, pns);
|
||||
(void) dwgpsnmea_gprmc ((char*)info, A->g_quiet, &(A->g_lat), &(A->g_lon), &speed_knots, &(A->g_course));
|
||||
A->g_speed_mph = DW_KNOTS_TO_MPH(speed_knots);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete latitude in sentence.\n");
|
||||
}
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
A->g_lon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete longitude in sentence.\n");
|
||||
}
|
||||
|
||||
if (paltitude != NULL && strlen(paltitude) > 0) {
|
||||
A->g_altitude = DW_METERS_TO_FEET(atof(paltitude));
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete altitude in sentence.\n");
|
||||
}
|
||||
|
||||
}
|
||||
else if (strcmp(ptype, "$GPGLL") == 0)
|
||||
else if (strncmp((char*)info, "$GPGGA,", 7) == 0)
|
||||
{
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
/* optional Time hhmmss[.sss] */
|
||||
/* optional 'A' for data valid */
|
||||
float alt_meters = G_UNKNOWN;
|
||||
int num_sat = 0;
|
||||
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
A->g_lat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete latitude in sentence.\n");
|
||||
(void) dwgpsnmea_gpgga ((char*)info, A->g_quiet, &(A->g_lat), &(A->g_lon), &alt_meters, &num_sat);
|
||||
A->g_altitude_ft = DW_METERS_TO_FEET(alt_meters);
|
||||
}
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
A->g_lon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete longitude in sentence.\n");
|
||||
}
|
||||
// TODO (low): add a few other sentence types.
|
||||
|
||||
}
|
||||
else if (strcmp(ptype, "$GPRMC") == 0)
|
||||
{
|
||||
//char *ptime, *pstatus, *plat, *pns, *plon, *pew, *pspeed, *ptrack, *pdate;
|
||||
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *pstatus; /* Status, A=Active (valid position), V=Void */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pknots; /* Speed over ground, knots. */
|
||||
char *pcourse; /* True course, degrees. */
|
||||
char *pdate; /* Date, ddmmyy */
|
||||
/* Magnetic variation */
|
||||
/* In version 3.00, mode is added: A D E N (see below) */
|
||||
/* Checksum */
|
||||
|
||||
ptime = strsep(&next, ",");
|
||||
pstatus = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pknots = strsep(&next, ",");
|
||||
pcourse = strsep(&next, ",");
|
||||
pdate = strsep(&next, ",");
|
||||
|
||||
/* process time ??? date ??? */
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
A->g_lat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete latitude in sentence.\n");
|
||||
}
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
A->g_lon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete longitude in sentence.\n");
|
||||
}
|
||||
|
||||
if (pknots != NULL && strlen(pknots) > 0) {
|
||||
A->g_speed = DW_KNOTS_TO_MPH(atof(pknots));
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete speed in sentence.\n");
|
||||
}
|
||||
|
||||
if (pcourse != NULL && strlen(pcourse) > 0) {
|
||||
A->g_course = atof(pcourse);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete course in sentence.\n");
|
||||
}
|
||||
|
||||
}
|
||||
else if (strcmp(ptype, "$GPVTG") == 0)
|
||||
{
|
||||
|
||||
/* Speed and direction but NO location! */
|
||||
|
||||
char *ptcourse; /* True course, degrees. */
|
||||
char *pt; /* "T" */
|
||||
char *pmcourse; /* Magnetic course, degrees. */
|
||||
char *pm; /* "M" */
|
||||
char *pknots; /* Ground speed, knots. */
|
||||
char *pn; /* "N" = Knots */
|
||||
char *pkmh; /* Ground speed, km/hr */
|
||||
char *pk; /* "K" = Kilometers per hour */
|
||||
char *pmode; /* New in NMEA 0183 version 3.0 */
|
||||
/* Mode: A=Autonomous, D=Differential, */
|
||||
|
||||
ptcourse = strsep(&next, ",");
|
||||
pt = strsep(&next, ",");
|
||||
pmcourse = strsep(&next, ",");
|
||||
pm = strsep(&next, ",");
|
||||
pknots = strsep(&next, ",");
|
||||
pn = strsep(&next, ",");
|
||||
pkmh = strsep(&next, ",");
|
||||
pk = strsep(&next, ",");
|
||||
pmode = strsep(&next, ",");
|
||||
|
||||
if (pknots != NULL && strlen(pknots) > 0) {
|
||||
A->g_speed = DW_KNOTS_TO_MPH(atof(pknots));
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete speed in sentence.\n");
|
||||
}
|
||||
|
||||
if (ptcourse != NULL && strlen(ptcourse) > 0) {
|
||||
A->g_course = atof(ptcourse);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete course in sentence.\n");
|
||||
}
|
||||
|
||||
}
|
||||
else if (strcmp(ptype, "$GPWPL") == 0)
|
||||
{
|
||||
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pident; /* Identifier for Waypoint. rules??? */
|
||||
/* checksum */
|
||||
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pident = strsep(&next, ",");
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
A->g_lat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete latitude in sentence.\n");
|
||||
}
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
A->g_lon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Incomplete longitude in sentence.\n");
|
||||
}
|
||||
|
||||
/* do something with identifier? */
|
||||
|
||||
}
|
||||
}
|
||||
} /* end aprs_raw_nmea */
|
||||
|
||||
|
||||
|
||||
|
@ -1535,7 +1292,7 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
n = ((p->speed_course[0] - 28) * 10) + ((p->speed_course[1] - 28) / 10);
|
||||
if (n >= 800) n -= 800;
|
||||
|
||||
A->g_speed = DW_KNOTS_TO_MPH(n);
|
||||
A->g_speed_mph = DW_KNOTS_TO_MPH(n);
|
||||
|
||||
n = ((p->speed_course[1] - 28) % 10) * 100 + (p->speed_course[2] - 28);
|
||||
if (n >= 400) n -= 400;
|
||||
|
@ -1627,16 +1384,16 @@ static void aprs_mic_e (decode_aprs_t *A, packet_t pp, unsigned char *info, int
|
|||
|
||||
if (plast > pfirst && pfirst[3] == '}') {
|
||||
|
||||
A->g_altitude = DW_METERS_TO_FEET((pfirst[0]-33)*91*91 + (pfirst[1]-33)*91 + (pfirst[2]-33) - 10000);
|
||||
A->g_altitude_ft = DW_METERS_TO_FEET((pfirst[0]-33)*91*91 + (pfirst[1]-33)*91 + (pfirst[2]-33) - 10000);
|
||||
|
||||
if ( ! isdigit91(pfirst[0]) || ! isdigit91(pfirst[1]) || ! isdigit91(pfirst[2]))
|
||||
{
|
||||
if ( ! A->g_quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("Invalid character in MIC-E altitude. Must be in range of '!' to '{'.\n");
|
||||
dw_printf("Bogus altitude of %.0f changed to unknown.\n", A->g_altitude);
|
||||
dw_printf("Bogus altitude of %.0f changed to unknown.\n", A->g_altitude_ft);
|
||||
}
|
||||
A->g_altitude = G_UNKNOWN;
|
||||
A->g_altitude_ft = G_UNKNOWN;
|
||||
}
|
||||
|
||||
pfirst += 4;
|
||||
|
@ -1776,7 +1533,7 @@ static void aprs_message (decode_aprs_t *A, unsigned char *info, int ilen, int q
|
|||
* Inputs: info - Pointer to Information field.
|
||||
* ilen - Information field length.
|
||||
*
|
||||
* Outputs: A->g_object_name, A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed, A->g_course, A->g_altitude.
|
||||
* Outputs: A->g_object_name, A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed_mph, A->g_course, A->g_altitude_ft.
|
||||
*
|
||||
* Description: Message has a 9 character object name which could be quite different than
|
||||
* the source station.
|
||||
|
@ -1878,7 +1635,9 @@ static void aprs_object (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
(void)(ts);
|
||||
|
||||
} /* end aprs_object */
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
|
@ -1890,7 +1649,7 @@ static void aprs_object (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
* Inputs: info - Pointer to Information field.
|
||||
* ilen - Information field length.
|
||||
*
|
||||
* Outputs: A->g_object_name, A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed, A->g_course, A->g_altitude.
|
||||
* Outputs: A->g_object_name, A->g_lat, A->g_lon, A->g_symbol_table, A->g_symbol_code, A->g_speed_mph, A->g_course, A->g_altitude_ft.
|
||||
*
|
||||
* Description: An "item" is very much like an "object" except
|
||||
*
|
||||
|
@ -1928,13 +1687,13 @@ static void aprs_item (decode_aprs_t *A, unsigned char *info, int ilen)
|
|||
} *q;
|
||||
|
||||
|
||||
time_t ts = 0;
|
||||
int i;
|
||||
char *ppos;
|
||||
|
||||
|
||||
p = (struct aprs_item_s *)info;
|
||||
q = (struct aprs_compressed_item_s *)info;
|
||||
(void)(q);
|
||||
|
||||
memset (A->g_name, 0, sizeof(A->g_name));
|
||||
i = 0;
|
||||
|
@ -2209,10 +1968,13 @@ static void aprs_status_report (decode_aprs_t *A, char *info, int ilen)
|
|||
erp = (p - '0') * (p - '0') * 10;
|
||||
}
|
||||
|
||||
// TODO: put result somewhere.
|
||||
// TODO (low): put result somewhere.
|
||||
// could use A->g_directivity and need new variable for erp.
|
||||
|
||||
*hp = '\0';
|
||||
|
||||
(void)(beam);
|
||||
(void)(erp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2406,10 +2168,10 @@ static void aprs_general_query (decode_aprs_t *A, char *info, int ilen, int quie
|
|||
|
||||
static void aprs_directed_station_query (decode_aprs_t *A, char *addressee, char *query, int quiet)
|
||||
{
|
||||
char query_type[20]; /* Does the query type always need to be exactly 5 characters? */
|
||||
//char query_type[20]; /* Does the query type always need to be exactly 5 characters? */
|
||||
/* If not, how would we know where the extra optional information starts? */
|
||||
|
||||
char callsign[AX25_MAX_ADDR_LEN];
|
||||
//char callsign[AX25_MAX_ADDR_LEN];
|
||||
|
||||
//if (strlen(query) < 5) ...
|
||||
|
||||
|
@ -2428,7 +2190,8 @@ static void aprs_directed_station_query (decode_aprs_t *A, char *addressee, char
|
|||
* ilen - Information field length.
|
||||
* quiet - suppress error messages.
|
||||
*
|
||||
* Outputs: ???
|
||||
* Outputs: A->g_telemetry
|
||||
* A->g_comment
|
||||
*
|
||||
* Description: TBD.
|
||||
*
|
||||
|
@ -2444,7 +2207,7 @@ static void aprs_telemetry (decode_aprs_t *A, char *info, int ilen, int quiet)
|
|||
|
||||
strlcpy (A->g_msg_type, "Telemetry", sizeof(A->g_msg_type));
|
||||
|
||||
telemetry_data_original (A->g_src, info, quiet, A->g_telemetry, A->g_comment);
|
||||
telemetry_data_original (A->g_src, info, quiet, A->g_telemetry, sizeof(A->g_telemetry), A->g_comment, sizeof(A->g_comment));
|
||||
|
||||
|
||||
} /* end aprs_telemetry */
|
||||
|
@ -2542,7 +2305,7 @@ static void aprs_positionless_weather_report (decode_aprs_t *A, unsigned char *i
|
|||
|
||||
strlcpy (A->g_msg_type, "Positionless Weather Report", sizeof(A->g_msg_type));
|
||||
|
||||
time_t ts = 0;
|
||||
//time_t ts = 0;
|
||||
|
||||
|
||||
p = (struct aprs_positionless_weather_s *)info;
|
||||
|
@ -2569,7 +2332,7 @@ static void aprs_positionless_weather_report (decode_aprs_t *A, unsigned char *i
|
|||
* TODO: call this context instead and have 3 enumerated values.
|
||||
*
|
||||
* Global In: A->g_course - Wind info for compressed location.
|
||||
* A->g_speed
|
||||
* A->g_speed_mph
|
||||
*
|
||||
* Outputs: A->g_weather
|
||||
*
|
||||
|
@ -2578,7 +2341,7 @@ static void aprs_positionless_weather_report (decode_aprs_t *A, unsigned char *i
|
|||
* For human-readable locations, we expect wind direction
|
||||
* and speed in a format like this: 999/999.
|
||||
* For compressed location, this has already been
|
||||
* processed and put in A->g_course and A->g_speed.
|
||||
* processed and put in A->g_course and A->g_speed_mph.
|
||||
* Otherwise, for positionless weather data, the
|
||||
* wind is in the form c999s999.
|
||||
*
|
||||
|
@ -2661,11 +2424,11 @@ static void weather_data (decode_aprs_t *A, char *wdata, int wind_prefix)
|
|||
}
|
||||
if (sscanf (wp+4, "%3d", &n))
|
||||
{
|
||||
A->g_speed = DW_KNOTS_TO_MPH(n); /* yes, in knots */
|
||||
A->g_speed_mph = DW_KNOTS_TO_MPH(n); /* yes, in knots */
|
||||
}
|
||||
wp += 7;
|
||||
}
|
||||
else if ( A->g_speed == G_UNKNOWN) {
|
||||
else if ( A->g_speed_mph == G_UNKNOWN) {
|
||||
|
||||
if ( ! getwdata (&wp, 'c', 3, &A->g_course)) {
|
||||
if ( ! A->g_quiet) {
|
||||
|
@ -2673,7 +2436,7 @@ static void weather_data (decode_aprs_t *A, char *wdata, int wind_prefix)
|
|||
dw_printf("Didn't find wind direction in form c999.\n");
|
||||
}
|
||||
}
|
||||
if ( ! getwdata (&wp, 's', 3, &A->g_speed)) { /* MPH here */
|
||||
if ( ! getwdata (&wp, 's', 3, &A->g_speed_mph)) { /* MPH here */
|
||||
if ( ! A->g_quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("Didn't find wind speed in form s999.\n");
|
||||
|
@ -2684,9 +2447,9 @@ static void weather_data (decode_aprs_t *A, char *wdata, int wind_prefix)
|
|||
// At this point, we should have the wind direction and speed
|
||||
// from one of three methods.
|
||||
|
||||
if (A->g_speed != G_UNKNOWN) {
|
||||
if (A->g_speed_mph != G_UNKNOWN) {
|
||||
|
||||
snprintf (A->g_weather, sizeof(A->g_weather), "wind %.1f mph", A->g_speed);
|
||||
snprintf (A->g_weather, sizeof(A->g_weather), "wind %.1f mph", A->g_speed_mph);
|
||||
if (A->g_course != G_UNKNOWN) {
|
||||
char ctemp[40];
|
||||
snprintf (ctemp, sizeof(ctemp), ", direction %.0f", A->g_course);
|
||||
|
@ -2695,7 +2458,7 @@ static void weather_data (decode_aprs_t *A, char *wdata, int wind_prefix)
|
|||
}
|
||||
|
||||
/* We don't want this to show up on the location line. */
|
||||
A->g_speed = G_UNKNOWN;
|
||||
A->g_speed_mph = G_UNKNOWN;
|
||||
A->g_course = G_UNKNOWN;
|
||||
|
||||
/*
|
||||
|
@ -3041,7 +2804,6 @@ static void aprs_ultimeter (decode_aprs_t *A, char *info, int ilen)
|
|||
|
||||
static void third_party_header (decode_aprs_t *A, char *info, int ilen)
|
||||
{
|
||||
int n;
|
||||
|
||||
strlcpy (A->g_msg_type, "Third Party Header", sizeof(A->g_msg_type));
|
||||
|
||||
|
@ -3095,7 +2857,7 @@ static void decode_position (decode_aprs_t *A, position_t *ppos)
|
|||
*
|
||||
* One of the following:
|
||||
* A->g_course & A->g_speeed
|
||||
* A->g_altitude
|
||||
* A->g_altitude_ft
|
||||
* A->g_range
|
||||
*
|
||||
* Description: The compressed position provides resolution of around ???
|
||||
|
@ -3169,7 +2931,7 @@ static void decode_compressed_position (decode_aprs_t *A, compressed_position_t
|
|||
; /* ignore other two bytes */
|
||||
}
|
||||
else if (((pcpos->t - 33) & 0x18) == 0x10) {
|
||||
A->g_altitude = pow(1.002, (pcpos->c - 33) * 91 + pcpos->s - 33);
|
||||
A->g_altitude_ft = pow(1.002, (pcpos->c - 33) * 91 + pcpos->s - 33);
|
||||
}
|
||||
else if (pcpos->c == '{')
|
||||
{
|
||||
|
@ -3179,7 +2941,7 @@ static void decode_compressed_position (decode_aprs_t *A, compressed_position_t
|
|||
{
|
||||
/* For a weather station, this is wind information. */
|
||||
A->g_course = (pcpos->c - 33) * 4;
|
||||
A->g_speed = DW_KNOTS_TO_MPH(pow(1.08, pcpos->s - 33) - 1.0);
|
||||
A->g_speed_mph = DW_KNOTS_TO_MPH(pow(1.08, pcpos->s - 33) - 1.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -3720,7 +3482,7 @@ int get_maidenhead (decode_aprs_t *A, char *p)
|
|||
* Outputs: One or more of the following, depending the data found:
|
||||
*
|
||||
* A->g_course
|
||||
* A->g_speed
|
||||
* A->g_speed_mph
|
||||
* A->g_power
|
||||
* A->g_height
|
||||
* A->g_gain
|
||||
|
@ -3771,7 +3533,7 @@ static int data_extension_comment (decode_aprs_t *A, char *pdext)
|
|||
}
|
||||
if (sscanf (pdext+4, "%3d", &n))
|
||||
{
|
||||
A->g_speed = DW_KNOTS_TO_MPH(n);
|
||||
A->g_speed_mph = DW_KNOTS_TO_MPH(n);
|
||||
}
|
||||
|
||||
/* Bearing and Number/Range/Quality? */
|
||||
|
@ -3878,8 +3640,11 @@ static const char *search_locations[] = {
|
|||
(const char *) NULL
|
||||
};
|
||||
|
||||
static int tocall_cmp (const struct tocalls_s *x, const struct tocalls_s *y)
|
||||
static int tocall_cmp (const void *px, const void *py)
|
||||
{
|
||||
const struct tocalls_s *x = (struct tocalls_s *)px;
|
||||
const struct tocalls_s *y = (struct tocalls_s *)py;
|
||||
|
||||
if (x->len != y->len) return (y->len - x->len);
|
||||
return (strcmp(x->prefix, y->prefix));
|
||||
}
|
||||
|
@ -3933,7 +3698,7 @@ static void decode_tocall (decode_aprs_t *A, char *dest)
|
|||
*p-- = '\0';
|
||||
}
|
||||
|
||||
// printf("debug: %s\n", stuff);
|
||||
// dw_printf("debug: %s\n", stuff);
|
||||
|
||||
if (stuff[0] == ' ' &&
|
||||
stuff[4] == ' ' &&
|
||||
|
@ -4065,7 +3830,7 @@ static void substr_se (char *dest, const char *src, int start, int endp1)
|
|||
* clen - Length of comment or -1 to take it all.
|
||||
*
|
||||
* Outputs: A->g_telemetry - Base 91 telemetry |ss1122|
|
||||
* A->g_altitude - from /A=123456
|
||||
* A->g_altitude_ft - from /A=123456
|
||||
* A->g_lat - Might be adjusted from !DAO!
|
||||
* A->g_lon - Might be adjusted from !DAO!
|
||||
* A->g_aprstt_loc - Private extension to !DAO!
|
||||
|
@ -4381,7 +4146,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
}
|
||||
else if (regexec (&std_toff_re, A->g_comment, MAXMATCH, match, 0) == 0) {
|
||||
|
||||
printf ("NO tone\n");
|
||||
dw_printf ("NO tone\n");
|
||||
A->g_tone = 0;
|
||||
|
||||
strlcpy (temp, A->g_comment + match[0].rm_eo, sizeof(temp));
|
||||
|
@ -4390,8 +4155,6 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
else if (regexec (&std_dcs_re, A->g_comment, MAXMATCH, match, 0) == 0) {
|
||||
|
||||
char sttemp[10]; /* three octal digits */
|
||||
int f;
|
||||
int i;
|
||||
|
||||
substr_se (sttemp, A->g_comment, match[1].rm_so, match[1].rm_eo);
|
||||
|
||||
|
@ -4403,7 +4166,6 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
else if (regexec (&std_offset_re, A->g_comment, MAXMATCH, match, 0) == 0) {
|
||||
|
||||
char sttemp[10]; /* includes leading sign */
|
||||
int f;
|
||||
|
||||
substr_se (sttemp, A->g_comment, match[1].rm_so, match[1].rm_eo);
|
||||
|
||||
|
@ -4416,7 +4178,6 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
|
||||
char sttemp[10]; /* should be two digits */
|
||||
char sutemp[10]; /* m for miles or k for km */
|
||||
int f;
|
||||
|
||||
substr_se (sttemp, A->g_comment, match[1].rm_so, match[1].rm_eo);
|
||||
substr_se (sutemp, A->g_comment, match[2].rm_so, match[2].rm_eo);
|
||||
|
@ -4453,7 +4214,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
|
||||
//dw_printf("compressed telemetry data = \"%s\"\n", tdata);
|
||||
|
||||
telemetry_data_base91 (A->g_src, tdata, A->g_telemetry);
|
||||
telemetry_data_base91 (A->g_src, tdata, A->g_telemetry, sizeof(A->g_telemetry));
|
||||
|
||||
strlcpy (temp, A->g_comment + match[0].rm_eo, sizeof(temp));
|
||||
strlcpy (A->g_comment + match[0].rm_so, temp, sizeof(A->g_comment)-match[0].rm_so);
|
||||
|
@ -4558,7 +4319,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
strlcpy (temp, A->g_comment + match[0].rm_eo, sizeof(temp));
|
||||
|
||||
A->g_comment[match[0].rm_eo] = '\0';
|
||||
A->g_altitude = atoi(A->g_comment + match[0].rm_so + 3);
|
||||
A->g_altitude_ft = atoi(A->g_comment + match[0].rm_so + 3);
|
||||
|
||||
strlcpy (A->g_comment + match[0].rm_so, temp, sizeof(A->g_comment)-match[0].rm_so);
|
||||
}
|
||||
|
@ -4586,7 +4347,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
(x >= 902 && x <= 928)) {
|
||||
|
||||
if ( ! A->g_quiet) {
|
||||
sprintf (good, "%07.3fMHz", x);
|
||||
snprintf (good, sizeof(good), "%07.3fMHz", x);
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("\"%s\" in comment looks like a frequency in non-standard format.\n", bad);
|
||||
dw_printf("For most systems to recognize it, use exactly this form \"%s\" at beginning of comment.\n", good);
|
||||
|
@ -4680,7 +4441,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
*
|
||||
* Description: Compile like this to make a standalone test program.
|
||||
*
|
||||
* gcc -o decode_aprs -DTEST decode_aprs.c ax25_pad.c
|
||||
* gcc -o decode_aprs -DDECAMAIN decode_aprs.c ax25_pad.c ...
|
||||
*
|
||||
* ./decode_aprs < decode_aprs.txt
|
||||
*
|
||||
|
@ -4709,7 +4470,7 @@ static void process_comment (decode_aprs_t *A, char *pstart, int clen)
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#if TEST
|
||||
#if DECAMAIN
|
||||
|
||||
/* Stub for stand-alone decoder. */
|
||||
|
||||
|
@ -4809,6 +4570,6 @@ int main (int argc, char *argv[])
|
|||
return (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* DECAMAIN */
|
||||
|
||||
/* end decode_aprs.c */
|
||||
|
|
|
@ -64,7 +64,7 @@ typedef struct decode_aprs_s {
|
|||
/* Also for Directed Station Query which is a */
|
||||
/* special case of message. */
|
||||
|
||||
float g_speed; /* Speed in MPH. */
|
||||
float g_speed_mph; /* Speed in MPH. */
|
||||
|
||||
float g_course; /* 0 = North, 90 = East, etc. */
|
||||
|
||||
|
@ -78,7 +78,7 @@ typedef struct decode_aprs_s {
|
|||
|
||||
float g_range; /* Precomputed radio range in miles. */
|
||||
|
||||
float g_altitude; /* Feet above median sea level. */
|
||||
float g_altitude_ft; /* Feet above median sea level. */
|
||||
|
||||
char g_mfr[80]; /* Manufacturer or application. */
|
||||
|
||||
|
|
24
demod.c
24
demod.c
|
@ -98,7 +98,7 @@ static int sample_count[MAX_CHANS][MAX_SUBCHANS];
|
|||
|
||||
int demod_init (struct audio_s *pa)
|
||||
{
|
||||
int j;
|
||||
//int j;
|
||||
int chan; /* Loop index over number of radio channels. */
|
||||
char profile;
|
||||
|
||||
|
@ -184,7 +184,7 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
/* This has been optimized for 300 baud. */
|
||||
|
||||
strcpy (just_letters, "D");
|
||||
strlcpy (just_letters, "D", sizeof(just_letters));
|
||||
|
||||
}
|
||||
else {
|
||||
|
@ -193,7 +193,7 @@ int demod_init (struct audio_s *pa)
|
|||
/* Previously we would use F if possible otherwise fall back to A. */
|
||||
|
||||
/* In version 1.2, new default is E+ /3. */
|
||||
strcpy (just_letters, "E"); // version 1.2 now E.
|
||||
strlcpy (just_letters, "E", sizeof(just_letters)); // version 1.2 now E.
|
||||
if (have_plus != -1) have_plus = 1; // Add as default for version 1.2
|
||||
// If not explicitly turned off.
|
||||
if (save_audio_config_p->achan[chan].decimate == 0) {
|
||||
|
@ -202,7 +202,7 @@ int demod_init (struct audio_s *pa)
|
|||
}
|
||||
}
|
||||
#else
|
||||
strcpy (just_letters, "E"); // version 1.2 changed C to E.
|
||||
strlcpy (just_letters, "E", sizeof(just_letters)); // version 1.2 changed C to E.
|
||||
if (have_plus != -1) have_plus = 1; // Add as default for version 1.2
|
||||
// If not explicitly turned off.
|
||||
#endif
|
||||
|
@ -223,12 +223,12 @@ int demod_init (struct audio_s *pa)
|
|||
|
||||
if (have_plus == -1) have_plus = 0;
|
||||
|
||||
strcpy (save_audio_config_p->achan[chan].profiles, just_letters);
|
||||
strlcpy (save_audio_config_p->achan[chan].profiles, just_letters, sizeof(save_audio_config_p->achan[chan].profiles));
|
||||
|
||||
assert (strlen(save_audio_config_p->achan[chan].profiles) >= 1);
|
||||
|
||||
if (have_plus) {
|
||||
strcat (save_audio_config_p->achan[chan].profiles, "+");
|
||||
strlcat (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
|
||||
}
|
||||
|
||||
/* These can be increased later for the multi-frequency case. */
|
||||
|
@ -250,7 +250,7 @@ int demod_init (struct audio_s *pa)
|
|||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Channel %d: Demodulator + option can't be combined with multiple letters.\n", chan);
|
||||
|
||||
strcpy (save_audio_config_p->achan[chan].profiles, "C+"); // Reduce to one letter.
|
||||
strlcpy (save_audio_config_p->achan[chan].profiles, "C+", sizeof(save_audio_config_p->achan[chan].profiles)); // Reduce to one letter.
|
||||
num_letters = 1;
|
||||
save_audio_config_p->achan[chan].num_demod = 1;
|
||||
save_audio_config_p->achan[chan].num_subchan = 1; // Will be set higher later.
|
||||
|
@ -478,7 +478,7 @@ int demod_init (struct audio_s *pa)
|
|||
/* Need to take a look at CPU usage and performance difference. */
|
||||
|
||||
#ifndef __arm__
|
||||
strcpy (save_audio_config_p->achan[chan].profiles, "+");
|
||||
strlcpy (save_audio_config_p->achan[chan].profiles, "+", sizeof(save_audio_config_p->achan[chan].profiles));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -641,7 +641,8 @@ int demod_get_sample (int a)
|
|||
__attribute__((hot))
|
||||
void demod_process_sample (int chan, int subchan, int sam)
|
||||
{
|
||||
float fsam, abs_fsam;
|
||||
float fsam;
|
||||
//float abs_fsam;
|
||||
int k;
|
||||
|
||||
|
||||
|
@ -650,8 +651,8 @@ void demod_process_sample (int chan, int subchan, int sam)
|
|||
static int seq = 0; /* for log file name */
|
||||
#endif
|
||||
|
||||
int j;
|
||||
int demod_data;
|
||||
//int j;
|
||||
//int demod_data;
|
||||
struct demodulator_state_s *D;
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
|
@ -786,7 +787,6 @@ alevel_t demod_get_audio_level (int chan, int subchan)
|
|||
{
|
||||
struct demodulator_state_s *D;
|
||||
alevel_t alevel;
|
||||
int pk;
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
assert (subchan >= 0 && subchan < MAX_SUBCHANS);
|
||||
|
|
33
demod_9600.c
33
demod_9600.c
|
@ -56,7 +56,7 @@ static float slice_point[MAX_SUBCHANS];
|
|||
|
||||
/* Add sample to buffer and shift the rest down. */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline void push_sample (float val, float *buff, int size)
|
||||
{
|
||||
memmove(buff+1,buff,(size-1)*sizeof(float));
|
||||
|
@ -66,7 +66,7 @@ static inline void push_sample (float val, float *buff, int size)
|
|||
|
||||
/* FIR filter kernel. */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline float convolve (const float *__restrict__ data, const float *__restrict__ filter, int filter_size)
|
||||
{
|
||||
float sum = 0.0f;
|
||||
|
@ -81,10 +81,12 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
float *d = __builtin_assume_aligned(data, 16);
|
||||
float *f = __builtin_assume_aligned(filter, 16);
|
||||
|
||||
#pragma GCC ivdep
|
||||
for (j=0; j<filter_size; j++) {
|
||||
sum += f[j] * d[j];
|
||||
}
|
||||
#else
|
||||
#pragma GCC ivdep // ignored until gcc 4.9
|
||||
for (j=0; j<filter_size; j++) {
|
||||
sum += filter[j] * data[j];
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
/* Automatic gain control. */
|
||||
/* Result should settle down to 1 unit peak to peak. i.e. -0.5 to +0.5 */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline float agc (float in, float fast_attack, float slow_decay, float *ppeak, float *pvalley)
|
||||
{
|
||||
if (in >= *ppeak) {
|
||||
|
@ -264,7 +266,7 @@ void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D
|
|||
{
|
||||
|
||||
float fsam;
|
||||
float abs_fsam;
|
||||
//float abs_fsam;
|
||||
float amp;
|
||||
float demod_out;
|
||||
|
||||
|
@ -273,7 +275,7 @@ void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D
|
|||
static int seq = 0; /* for log file name */
|
||||
#endif
|
||||
|
||||
int j;
|
||||
//int j;
|
||||
int subchan = 0;
|
||||
int demod_data; /* Still scrambled. */
|
||||
|
||||
|
@ -397,7 +399,6 @@ void demod_9600_process_sample (int chan, int sam, struct demodulator_state_s *D
|
|||
__attribute__((hot))
|
||||
static void nudge_pll (int chan, int subchan, int demod_data, struct demodulator_state_s *D)
|
||||
{
|
||||
int descram; /* Data bit de-scrambled. */
|
||||
|
||||
/*
|
||||
* Next, a PLL is used to sample near the centers of the data bits.
|
||||
|
@ -439,22 +440,12 @@ static void nudge_pll (int chan, int subchan, int demod_data, struct demodulator
|
|||
*
|
||||
* http://www.amsat.org/amsat/articles/g3ruh/109/fig03.gif
|
||||
*/
|
||||
|
||||
//assert (modem.modem_type[chan] == MODEM_SCRAMBLE);
|
||||
|
||||
//if (modem.modem_type[chan] == MODEM_SCRAMBLE) {
|
||||
|
||||
|
||||
descram = descramble (demod_data, &(D->slicer[subchan].lfsr));
|
||||
// Warning: 'descram' set but not used.
|
||||
// It's used in conditional debug code below.
|
||||
// descram =
|
||||
descramble (demod_data, &(D->slicer[subchan].lfsr));
|
||||
|
||||
hdlc_rec_bit (chan, subchan, demod_data, 1, D->slicer[subchan].lfsr);
|
||||
|
||||
//D->prev_descram = descram;
|
||||
//}
|
||||
//else {
|
||||
/* Baseband signal for completeness - not in common use. */
|
||||
//hdlc_rec_bit (chan, subchan, demod_data);
|
||||
//}
|
||||
}
|
||||
|
||||
if (demod_data != D->slicer[subchan].prev_demod_data) {
|
||||
|
@ -480,7 +471,7 @@ static void nudge_pll (int chan, int subchan, int demod_data, struct demodulator
|
|||
|
||||
if (demod_log_fp == NULL) {
|
||||
seq++;
|
||||
sprintf (fname, "demod96/%04d.csv", seq);
|
||||
snprintf (fname, sizeof(fname), "demod96/%04d.csv", seq);
|
||||
if (seq == 1) mkdir ("demod96"
|
||||
#ifndef __WIN32__
|
||||
, 0777
|
||||
|
|
19
demod_afsk.c
19
demod_afsk.c
|
@ -72,7 +72,7 @@
|
|||
/* Should help with microcomputer platform. */
|
||||
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline float z (float x, float y)
|
||||
{
|
||||
x = fabsf(x);
|
||||
|
@ -88,7 +88,7 @@ static inline float z (float x, float y)
|
|||
|
||||
/* Add sample to buffer and shift the rest down. */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline void push_sample (float val, float *buff, int size)
|
||||
{
|
||||
memmove(buff+1,buff,(size-1)*sizeof(float));
|
||||
|
@ -98,7 +98,7 @@ static inline void push_sample (float val, float *buff, int size)
|
|||
|
||||
/* FIR filter kernel. */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline float convolve (const float *__restrict__ data, const float *__restrict__ filter, int filter_size)
|
||||
{
|
||||
float sum = 0.0f;
|
||||
|
@ -113,10 +113,12 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
float *d = __builtin_assume_aligned(data, 16);
|
||||
float *f = __builtin_assume_aligned(filter, 16);
|
||||
|
||||
#pragma GCC ivdep
|
||||
for (j=0; j<filter_size; j++) {
|
||||
sum += f[j] * d[j];
|
||||
}
|
||||
#else
|
||||
#pragma GCC ivdep // ignored until gcc 4.9
|
||||
for (j=0; j<filter_size; j++) {
|
||||
sum += filter[j] * data[j];
|
||||
}
|
||||
|
@ -127,7 +129,7 @@ static inline float convolve (const float *__restrict__ data, const float *__res
|
|||
/* Automatic gain control. */
|
||||
/* Result should settle down to 1 unit peak to peak. i.e. -0.5 to +0.5 */
|
||||
|
||||
__attribute__((hot))
|
||||
__attribute__((hot)) __attribute__((always_inline))
|
||||
static inline float agc (float in, float fast_attack, float slow_decay, float *ppeak, float *pvalley)
|
||||
{
|
||||
if (in >= *ppeak) {
|
||||
|
@ -795,7 +797,8 @@ static void nudge_pll (int chan, int subchan, int demod_data, struct demodulator
|
|||
__attribute__((hot))
|
||||
void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulator_state_s *D)
|
||||
{
|
||||
float fsam, abs_fsam;
|
||||
float fsam;
|
||||
//float abs_fsam;
|
||||
float m_sum1, m_sum2, s_sum1, s_sum2;
|
||||
float m_amp, s_amp;
|
||||
float m_norm, s_norm;
|
||||
|
@ -806,7 +809,7 @@ void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulat
|
|||
#endif
|
||||
|
||||
|
||||
int j;
|
||||
//int j;
|
||||
int demod_data;
|
||||
|
||||
|
||||
|
@ -827,7 +830,7 @@ void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulat
|
|||
|
||||
fsam = sam / 16384.0f;
|
||||
|
||||
abs_fsam = fsam >= 0.0f ? fsam : -fsam;
|
||||
//abs_fsam = fsam >= 0.0f ? fsam : -fsam;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -1049,7 +1052,7 @@ void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulat
|
|||
|
||||
if (demod_log_fp == NULL) {
|
||||
seq++;
|
||||
sprintf (fname, "demod/%04d.csv", seq);
|
||||
snprintf (fname, sizeof(fname), "demod/%04d.csv", seq);
|
||||
if (seq == 1) mkdir ("demod", 0777);
|
||||
|
||||
demod_log_fp = fopen (fname, "w");
|
||||
|
|
30
digipeater.c
30
digipeater.c
|
@ -533,6 +533,9 @@ static packet_t digipeat_match (int from_chan, packet_t pp, char *mycall_rec, ch
|
|||
*
|
||||
* Description: TODO...
|
||||
*
|
||||
* Initial reports were favorable.
|
||||
* Should document what this is all about if there is still interest...
|
||||
*
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
void digi_regen (int from_chan, packet_t pp)
|
||||
|
@ -569,7 +572,7 @@ void digi_regen (int from_chan, packet_t pp)
|
|||
*
|
||||
*------------------------------------------------------------------------*/
|
||||
|
||||
#if TEST
|
||||
#if DIGITEST
|
||||
|
||||
static char mycall[] = "WB2OSZ-9";
|
||||
|
||||
|
@ -594,6 +597,7 @@ static void test (char *in, char *out)
|
|||
int info_len;
|
||||
unsigned char frame[AX25_MAX_PACKET_LEN];
|
||||
int frame_len;
|
||||
alevel_t alevel;
|
||||
|
||||
dw_printf ("\n");
|
||||
|
||||
|
@ -606,7 +610,7 @@ static void test (char *in, char *out)
|
|||
|
||||
ax25_format_addrs (pp, rec);
|
||||
info_len = ax25_get_info (pp, &pinfo);
|
||||
strcat (rec, (char*)pinfo);
|
||||
strlcat (rec, (char*)pinfo, sizeof(rec));
|
||||
|
||||
if (strcmp(in, rec) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -621,11 +625,15 @@ static void test (char *in, char *out)
|
|||
frame_len = ax25_pack (pp, frame);
|
||||
ax25_delete (pp);
|
||||
|
||||
pp = ax25_from_frame (frame, frame_len, 50);
|
||||
alevel.rec = 50;
|
||||
alevel.mark = 50;
|
||||
alevel.space = 50;
|
||||
|
||||
pp = ax25_from_frame (frame, frame_len, alevel);
|
||||
assert (pp != NULL);
|
||||
ax25_format_addrs (pp, rec);
|
||||
info_len = ax25_get_info (pp, &pinfo);
|
||||
strcat (rec, (char*)pinfo);
|
||||
strlcat (rec, (char*)pinfo, sizeof(rec));
|
||||
|
||||
if (strcmp(in, rec) != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -648,11 +656,11 @@ static void test (char *in, char *out)
|
|||
dedupe_remember (result, 0);
|
||||
ax25_format_addrs (result, xmit);
|
||||
info_len = ax25_get_info (result, &pinfo);
|
||||
strcat (xmit, (char*)pinfo);
|
||||
strlcat (xmit, (char*)pinfo, sizeof(xmit));
|
||||
ax25_delete (result);
|
||||
}
|
||||
else {
|
||||
strcpy (xmit, "");
|
||||
strlcpy (xmit, "", sizeof(xmit));
|
||||
}
|
||||
|
||||
text_color_set(DW_COLOR_XMIT);
|
||||
|
@ -894,7 +902,7 @@ int main (int argc, char *argv[])
|
|||
* Filtering integrated with rest of process...
|
||||
*/
|
||||
|
||||
strcpy (typefilter, "w");
|
||||
strlcpy (typefilter, "w", sizeof(typefilter));
|
||||
|
||||
test ( "N8VIM>APN391,WIDE2-1:$ULTW00000000010E097D2884FFF389DC000102430002033400000000",
|
||||
"N8VIM>APN391,WB2OSZ-9*:$ULTW00000000010E097D2884FFF389DC000102430002033400000000");
|
||||
|
@ -902,7 +910,7 @@ int main (int argc, char *argv[])
|
|||
test ( "AB1OC-10>APWW10,WIDE1-1,WIDE2-1:>FN42er/# Hollis, NH iGate Operational",
|
||||
"");
|
||||
|
||||
strcpy (typefilter, "s");
|
||||
strlcpy (typefilter, "s", sizeof(typefilter));
|
||||
|
||||
test ( "AB1OC-10>APWW10,WIDE1-1,WIDE2-1:>FN42er/# Hollis, NH iGate Operational",
|
||||
"AB1OC-10>APWW10,WB2OSZ-9*,WIDE2-1:>FN42er/# Hollis, NH iGate Operational");
|
||||
|
@ -910,12 +918,12 @@ int main (int argc, char *argv[])
|
|||
test ( "K1ABC-9>TR4R8R,WIDE1-1:`c6LlIb>/`\"4K}_%",
|
||||
"");
|
||||
|
||||
strcpy (typefilter, "up");
|
||||
strlcpy (typefilter, "up", sizeof(typefilter));
|
||||
|
||||
test ( "K1ABC-9>TR4R8R,WIDE1-1:`c6LlIb>/`\"4K}_%",
|
||||
"K1ABC-9>TR4R8R,WB2OSZ-9*:`c6LlIb>/`\"4K}_%");
|
||||
|
||||
strcpy (typefilter, "");
|
||||
strlcpy (typefilter, "", sizeof(typefilter));
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -934,6 +942,6 @@ int main (int argc, char *argv[])
|
|||
|
||||
} /* end main */
|
||||
|
||||
#endif /* if TEST */
|
||||
#endif /* if DIGITEST */
|
||||
|
||||
/* end digipeater.c */
|
||||
|
|
42
direwolf.c
42
direwolf.c
|
@ -164,7 +164,7 @@ static struct misc_config_s misc_config;
|
|||
int main (int argc, char *argv[])
|
||||
{
|
||||
int err;
|
||||
int eof;
|
||||
//int eof;
|
||||
int j;
|
||||
char config_file[100];
|
||||
int xmit_calibrate_option = 0;
|
||||
|
@ -180,6 +180,7 @@ int main (int argc, char *argv[])
|
|||
int d_k_opt = 0; /* "-d k" option for serial port KISS. Can be repeated for more detail. */
|
||||
int d_n_opt = 0; /* "-d n" option for Network KISS. Can be repeated for more detail. */
|
||||
int d_t_opt = 0; /* "-d t" option for Tracker. Can be repeated for more detail. */
|
||||
int d_g_opt = 0; /* "-d g" option for GPS. Can be repeated for more detail. */
|
||||
int d_o_opt = 0; /* "-d o" option for output control such as PTT and DCD. */
|
||||
int a_opt = 0; /* "-a n" interval, in seconds, for audio statistics report. 0 for none. */
|
||||
|
||||
|
@ -199,12 +200,6 @@ int main (int argc, char *argv[])
|
|||
//Restore on exit? oldcp = GetConsoleOutputCP();
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
|
||||
#elif __CYGWIN__
|
||||
|
||||
/*
|
||||
* Without this, the ISO Latin 1 characters are displayed as gray boxes.
|
||||
*/
|
||||
//setenv ("LANG", "C.ISO-8859-1", 1);
|
||||
#else
|
||||
|
||||
/*
|
||||
|
@ -230,16 +225,17 @@ int main (int argc, char *argv[])
|
|||
}
|
||||
|
||||
// TODO: control development/beta/release by version.h instead of changing here.
|
||||
// Print platform. This will provide more information when people send a copy the information displayed.
|
||||
|
||||
text_color_init(t_opt);
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "F", __DATE__);
|
||||
dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "G", __DATE__);
|
||||
//dw_printf ("Dire Wolf version %d.%d\n", MAJOR_VERSION, MINOR_VERSION);
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
SetConsoleCtrlHandler (cleanup_win, TRUE);
|
||||
SetConsoleCtrlHandler ((PHANDLER_ROUTINE)cleanup_win, TRUE);
|
||||
#else
|
||||
setlinebuf (stdout);
|
||||
signal (SIGINT, cleanup_linux);
|
||||
|
@ -278,19 +274,7 @@ int main (int argc, char *argv[])
|
|||
text_color_set(DW_COLOR_INFO);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This has not been very well tested in 64 bit mode.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
if (sizeof(int) != 4 || sizeof(long) != 4 || sizeof(char *) != 4) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("------------------------------------------------------------------\n");
|
||||
dw_printf ("This might not work properly when compiled for a 64 bit target.\n");
|
||||
dw_printf ("It is recommended that you rebuild it with gcc -m32 option.\n");
|
||||
dw_printf ("------------------------------------------------------------------\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Default location of configuration file is current directory.
|
||||
|
@ -307,7 +291,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
strlcpy (input_file, "", sizeof(input_file));
|
||||
while (1) {
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
//int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
int c;
|
||||
char *p;
|
||||
|
@ -448,6 +432,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
// separate out gps & waypoints.
|
||||
|
||||
case 'g': d_g_opt++; break;
|
||||
case 't': d_t_opt++; beacon_tracker_set_debug (d_t_opt); break;
|
||||
|
||||
case 'w': nmea_set_debug (1); break; // not documented yet.
|
||||
|
@ -685,7 +670,9 @@ int main (int argc, char *argv[])
|
|||
/*
|
||||
* Open port for communication with GPS.
|
||||
*/
|
||||
nmea_init (&misc_config);
|
||||
dwgps_init (&misc_config, d_g_opt);
|
||||
|
||||
nmea_init (&misc_config); // TODO: revisit.
|
||||
|
||||
/*
|
||||
* Create thread for trying to salvage frames with bad FCS.
|
||||
|
@ -695,8 +682,8 @@ int main (int argc, char *argv[])
|
|||
/*
|
||||
* Enable beaconing.
|
||||
*/
|
||||
beacon_init (&audio_config, &misc_config, &digi_config);
|
||||
|
||||
beacon_init (&audio_config, &misc_config);
|
||||
|
||||
log_init(misc_config.logdir);
|
||||
|
||||
|
@ -920,7 +907,7 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, alevel_t alevel
|
|||
if (A.g_lat != G_UNKNOWN && A.g_lon != G_UNKNOWN) {
|
||||
nmea_send_waypoint (strlen(A.g_name) > 0 ? A.g_name : A.g_src,
|
||||
A.g_lat, A.g_lon, A.g_symbol_table, A.g_symbol_code,
|
||||
DW_FEET_TO_METERS(A.g_altitude), A.g_course, DW_MPH_TO_KNOTS(A.g_speed),
|
||||
DW_FEET_TO_METERS(A.g_altitude_ft), A.g_course, DW_MPH_TO_KNOTS(A.g_speed_mph),
|
||||
A.g_comment);
|
||||
}
|
||||
}
|
||||
|
@ -947,7 +934,7 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, alevel_t alevel
|
|||
*/
|
||||
if (subchan == -1) {
|
||||
if (tt_config.gateway_enabled && info_len >= 2) {
|
||||
aprs_tt_sequence (chan, pinfo+1);
|
||||
aprs_tt_sequence (chan, (char*)(pinfo+1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -1048,7 +1035,8 @@ static void usage (char **argv)
|
|||
dw_printf (" n n = KISS network client.\n");
|
||||
dw_printf (" u u = Display non-ASCII text in hexadecimal.\n");
|
||||
dw_printf (" p p = dump Packets in hexadecimal.\n");
|
||||
dw_printf (" t t = gps Tracker.\n");
|
||||
dw_printf (" g g = GPS interface.\n");
|
||||
dw_printf (" t t = Tracker beacon.\n");
|
||||
dw_printf (" o o = output controls such as PTT and DCD.\n");
|
||||
dw_printf (" -q Quiet (suppress output) options:\n");
|
||||
dw_printf (" h h = Heard line with the audio level.\n");
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
# To use something other than the default, generally use plughw
|
||||
# and a card number reported by "arecord -l" command. Example:
|
||||
|
||||
# ADEVICE plughw:1,0
|
||||
ADEVICE "Realtek High"
|
||||
|
||||
# Starting with version 1.0, you can also use "-" or "stdin" to
|
||||
# pipe stdout from some other application such as a software defined
|
||||
|
@ -93,8 +93,7 @@ ACHANNELS 1
|
|||
# #
|
||||
#############################################################
|
||||
|
||||
#ADEVICE1 ...
|
||||
|
||||
#ADEVICE1 USB
|
||||
|
||||
#############################################################
|
||||
# #
|
||||
|
@ -129,7 +128,7 @@ CHANNEL 0
|
|||
# Example (don't use this unless you are me): MYCALL WB2OSZ-5
|
||||
#
|
||||
|
||||
MYCALL N0CALL
|
||||
MYCALL WB2OSZ-14
|
||||
|
||||
#
|
||||
# Pick a suitable modem speed based on your situation.
|
||||
|
@ -166,7 +165,7 @@ MODEM 1200
|
|||
# Uncomment line below to enable the DTMF decoder for this channel.
|
||||
#
|
||||
|
||||
#DTMF
|
||||
DTMF
|
||||
|
||||
#
|
||||
# If not using a VOX circuit, the transmitter Push to Talk (PTT)
|
||||
|
@ -181,7 +180,7 @@ MODEM 1200
|
|||
#
|
||||
|
||||
#PTT COM1 RTS
|
||||
#PTT COM1 RTS -DTR
|
||||
PTT COM1 RTS -DTR
|
||||
#PTT /dev/ttyUSB0 RTS
|
||||
|
||||
#
|
||||
|
@ -213,6 +212,8 @@ MODEM 1200
|
|||
# Specify MYCALL, MODEM, PTT, etc. configuration items for
|
||||
# CHANNEL 1. Repeat for any other channels.
|
||||
|
||||
#CHANNEL 2
|
||||
#DTMF
|
||||
|
||||
#############################################################
|
||||
# #
|
||||
|
@ -260,6 +261,11 @@ KISSPORT 8001
|
|||
# #
|
||||
#############################################################
|
||||
|
||||
GPSNMEA COM22
|
||||
|
||||
TBEACON delay=0:30 every=0:20 SYMBOL=car FREQ=146.955 OFFSET=-0.600 TONE=74.4
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Beaconing is configured with these two commands:
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#define DIREWOLF_H 1
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Previously, we could handle only a single audio device.
|
||||
* This meant we could have only two radio channels.
|
||||
|
@ -75,6 +74,10 @@
|
|||
|
||||
/* Prefix with DW_ because /usr/include/gps.h uses a couple of these names. */
|
||||
|
||||
#ifndef G_UNKNOWN
|
||||
#include "latlong.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define DW_METERS_TO_FEET(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 3.2808399)
|
||||
#define DW_FEET_TO_METERS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.3048)
|
||||
|
@ -163,8 +166,10 @@ typedef pthread_mutex_t dw_mutex_t;
|
|||
/* Platform differences for string functions. */
|
||||
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||
#endif
|
||||
|
||||
//#if __WIN32__
|
||||
|
|
10
dlq.c
10
dlq.c
|
@ -276,9 +276,9 @@ void dlq_append (dlq_type_t type, int chan, int subchan, packet_t pp, alevel_t a
|
|||
pnew->alevel = alevel;
|
||||
pnew->retries = retries;
|
||||
if (spectrum == NULL)
|
||||
strcpy(pnew->spectrum, "");
|
||||
strlcpy(pnew->spectrum, "", sizeof(pnew->spectrum));
|
||||
else
|
||||
strcpy(pnew->spectrum, spectrum);
|
||||
strlcpy(pnew->spectrum, spectrum, sizeof(pnew->spectrum));
|
||||
|
||||
#if DEBUG1
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -524,7 +524,7 @@ void dlq_wait_while_empty (void)
|
|||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum)
|
||||
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum, size_t spectrumsize)
|
||||
{
|
||||
|
||||
struct dlq_item_s *phead;
|
||||
|
@ -562,7 +562,7 @@ int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_
|
|||
memset (alevel, 0xff, sizeof(*alevel));
|
||||
|
||||
*retries = -1;
|
||||
strcpy(spectrum,"");
|
||||
strlcpy(spectrum, "", spectrumsize);
|
||||
result = 0;
|
||||
}
|
||||
else {
|
||||
|
@ -576,7 +576,7 @@ int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_
|
|||
*pp = phead->pp;
|
||||
*alevel = phead->alevel;
|
||||
*retries = phead->retries;
|
||||
strcpy (spectrum, phead->spectrum);
|
||||
strlcpy (spectrum, phead->spectrum, spectrumsize);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
|
|
2
dlq.h
2
dlq.h
|
@ -22,7 +22,7 @@ void dlq_append (dlq_type_t type, int chan, int subchan, packet_t pp, alevel_t a
|
|||
|
||||
void dlq_wait_while_empty (void);
|
||||
|
||||
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum);
|
||||
int dlq_remove (dlq_type_t *type, int *chan, int *subchan, packet_t *pp, alevel_t *alevel, retry_t *retries, char *spectrum, size_t spectrumsize);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "dtime_now.h"
|
||||
|
||||
|
@ -17,9 +17,7 @@
|
|||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#if __WIN32__
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
417
dwgps.c
417
dwgps.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
|
||||
// Copyright (C) 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,69 +22,67 @@
|
|||
*
|
||||
* Module: dwgps.c
|
||||
*
|
||||
* Purpose: Interface to location data, i.e. GPS receiver.
|
||||
* Purpose: Interface for obtaining location from GPS.
|
||||
*
|
||||
* Description: Tracker beacons need to know the current location.
|
||||
* At this time, I can't think of any other reason why
|
||||
* we would need this information.
|
||||
* Description: This is a wrapper for two different implementations:
|
||||
*
|
||||
* For Linux, we use gpsd and libgps.
|
||||
* This has the extra benefit that the system clock can
|
||||
* be set from the GPS signal.
|
||||
* (1) Read NMEA sentences from a serial port (or USB
|
||||
* that looks line one). Available for all platforms.
|
||||
*
|
||||
* Not yet implemented for Windows. Not sure how yet.
|
||||
* The Windows location API is new in Windows 7.
|
||||
* At the end of 2013, about 1/3 of Windows users are
|
||||
* still using XP so that still needs to be supported.
|
||||
* (2) Read from gpsd. Not available for Windows.
|
||||
* Including this is optional because it depends
|
||||
* on another external software component.
|
||||
*
|
||||
* Reference:
|
||||
*
|
||||
* API: dwgps_init Connect to data stream at start up time.
|
||||
*
|
||||
* dwgps_read Return most recent location to application.
|
||||
*
|
||||
* dwgps_print Print contents of structure for debugging.
|
||||
*
|
||||
* dwgps_term Shutdown on exit.
|
||||
*
|
||||
*
|
||||
* from below: dwgps_set_data Called from other two implementations to
|
||||
* save data until it is needed.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
#if TEST
|
||||
#define ENABLE_GPS 1
|
||||
#endif
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#if __WIN32__
|
||||
#include <windows.h>
|
||||
#else
|
||||
#if ENABLE_GPS
|
||||
#include <gps.h>
|
||||
|
||||
#if GPSD_API_MAJOR_VERSION != 5
|
||||
#error libgps API version might be incompatible.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "dwgps.h"
|
||||
#include "dwgpsnmea.h"
|
||||
#include "dwgpsd.h"
|
||||
|
||||
|
||||
/* Was init successful? */
|
||||
static int s_dwgps_debug = 0; /* Enable debug output. */
|
||||
/* >= 2 show updates from GPS. */
|
||||
/* >= 1 show results from dwgps_read. */
|
||||
|
||||
static enum { INIT_NOT_YET, INIT_SUCCESS, INIT_FAILED } init_status = INIT_NOT_YET;
|
||||
/*
|
||||
* The GPS reader threads deposit current data here when it becomes available.
|
||||
* dwgps_read returns it to the requesting application.
|
||||
*
|
||||
* A critical region to avoid inconsistency between fields.
|
||||
*/
|
||||
|
||||
#if __WIN32__
|
||||
#include <windows.h>
|
||||
#else
|
||||
#if ENABLE_GPS
|
||||
static dwgps_info_t s_dwgps_info = {
|
||||
.timestamp = 0,
|
||||
.fix = DWFIX_NOT_INIT, /* to detect read without init. */
|
||||
.dlat = G_UNKNOWN,
|
||||
.dlon = G_UNKNOWN,
|
||||
.speed_knots = G_UNKNOWN,
|
||||
.track = G_UNKNOWN,
|
||||
.altitude = G_UNKNOWN
|
||||
};
|
||||
|
||||
static struct gps_data_t gpsdata;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
static dw_mutex_t s_gps_mutex;
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -93,223 +91,125 @@ static struct gps_data_t gpsdata;
|
|||
*
|
||||
* Purpose: Intialize the GPS interface.
|
||||
*
|
||||
* Inputs: none.
|
||||
* Inputs: pconfig Configuration settings. This might include
|
||||
* serial port name for direct connect and host
|
||||
* name or address for network connection.
|
||||
*
|
||||
* Returns: 0 = success
|
||||
* -1 = failure
|
||||
* debug - If >= 1, print results when dwgps_read is called.
|
||||
* (In this file.)
|
||||
*
|
||||
* Description: For Linux, this maps into gps_open.
|
||||
* Not yet implemented for Windows.
|
||||
* If >= 2, location updates are also printed.
|
||||
* (In other two related files.)
|
||||
*
|
||||
* Returns: none
|
||||
*
|
||||
* Description: Call corresponding functions for implementations.
|
||||
* Normally we would expect someone to use either GPSNMEA or
|
||||
* GPSD but there is nothing to prevent use of both at the
|
||||
* same time.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
int dwgps_init (void)
|
||||
|
||||
void dwgps_init (struct misc_config_s *pconfig, int debug)
|
||||
{
|
||||
|
||||
#if __WIN32__
|
||||
s_dwgps_debug = debug;
|
||||
|
||||
/*
|
||||
* Windows version. Not implemented yet.
|
||||
*/
|
||||
dw_mutex_init (&s_gps_mutex);
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPS interface not yet available in Windows version.\n");
|
||||
init_status = INIT_FAILED;
|
||||
return (-1);
|
||||
dwgpsnmea_init (pconfig, debug);
|
||||
|
||||
#elif ENABLE_GPS
|
||||
#if ENABLE_GPSD
|
||||
|
||||
int err;
|
||||
|
||||
#if USE_GPS_SHM
|
||||
|
||||
/*
|
||||
* Linux - Shared memory interface to gpsd.
|
||||
*
|
||||
* I wanted to use this method because it is simpler and more efficient.
|
||||
*
|
||||
* The current version of gpsd, supplied with Raspian, is 3.6 from back in
|
||||
* May 2012, is missing support for the shared memory interface.
|
||||
* https://github.com/raspberrypi/linux/issues/523
|
||||
*
|
||||
* I tried to download a newer source and build with shared memory support
|
||||
* but ran into a couple other issues.
|
||||
*
|
||||
* sudo apt-get install libncurses5-dev
|
||||
* sudo apt-get install scons
|
||||
* cd ~
|
||||
* wget http://download-mirror.savannah.gnu.org/releases/gpsd/gpsd-3.11.tar.gz
|
||||
* tar xfz gpsd-3.11.tar.gz
|
||||
* cd gpsd-3.11
|
||||
* scons prefix=/usr libdir=lib/arm-linux-gnueabihf shm_export=True python=False
|
||||
* sudo scons udev-install
|
||||
*
|
||||
* For now, we will use the socket interface.
|
||||
* Maybe get back to this again someday.
|
||||
*/
|
||||
|
||||
err = gps_open (GPSD_SHARED_MEMORY, NULL, &gpsdata);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unable to connect to GPSD shared memory interface, status=%d.\n", err);
|
||||
if (err == NL_NOHOST) {
|
||||
// I don't think this is right but we are not using it anyhow.
|
||||
dw_printf ("Shared memory interface is not enabled in libgps.\n");
|
||||
dw_printf ("Download the gpsd source and build with 'shm_export=True' option.\n");
|
||||
}
|
||||
else {
|
||||
dw_printf ("%s\n", gps_errstr(errno));
|
||||
}
|
||||
init_status = INIT_FAILED;
|
||||
return (-1);
|
||||
}
|
||||
init_status = INIT_SUCCESS;
|
||||
return (0);
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Linux - Socket interface to gpsd.
|
||||
*/
|
||||
|
||||
err = gps_open ("localhost", DEFAULT_GPSD_PORT, &gpsdata);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unable to connect to GPSD stream, status%d.\n", err);
|
||||
dw_printf ("%s\n", gps_errstr(errno));
|
||||
init_status = INIT_FAILED;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
|
||||
init_status = INIT_SUCCESS;
|
||||
return (0);
|
||||
dwgpsd_init (pconfig, debug);
|
||||
|
||||
#endif
|
||||
|
||||
#else /* end ENABLE_GPS */
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPS interface not enabled in this version.\n");
|
||||
dw_printf ("See documentation on how to rebuild with ENABLE_GPS.\n");
|
||||
init_status = INIT_FAILED;
|
||||
return (-1);
|
||||
|
||||
#endif
|
||||
SLEEP_MS(500); /* So receive thread(s) can clear the */
|
||||
/* not init status before it gets checked. */
|
||||
|
||||
} /* end dwgps_init */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgps_clear
|
||||
*
|
||||
* Purpose: Clear the gps info structure.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
void dwgps_clear (dwgps_info_t *gpsinfo)
|
||||
{
|
||||
gpsinfo->timestamp = 0;
|
||||
gpsinfo->fix = DWFIX_NOT_SEEN;
|
||||
gpsinfo->dlat = G_UNKNOWN;
|
||||
gpsinfo->dlon = G_UNKNOWN;
|
||||
gpsinfo->speed_knots = G_UNKNOWN;
|
||||
gpsinfo->track = G_UNKNOWN;
|
||||
gpsinfo->altitude = G_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgps_read
|
||||
*
|
||||
* Purpose: Obtain current location from GPS receiver.
|
||||
* Purpose: Return most recent location data available.
|
||||
*
|
||||
* Outputs: *plat - Latitude.
|
||||
* *plon - Longitude.
|
||||
* *pspeed - Speed, knots.
|
||||
* *pcourse - Course over ground, degrees.
|
||||
* *palt - Altitude, meters.
|
||||
* Outputs: gpsinfo - Structure with latitude, longitude, etc.
|
||||
*
|
||||
* Returns: Position fix quality. Same as in structure.
|
||||
*
|
||||
* Returns: -1 = error
|
||||
* 0 = location currently not available (no fix)
|
||||
* 2 = 2D fix, lat/lon, speed, and course are set.
|
||||
* 3 - 3D fix, altitude is also set.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float *palt)
|
||||
dwfix_t dwgps_read (dwgps_info_t *gpsinfo)
|
||||
{
|
||||
#if __WIN32__
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
||||
return (-1);
|
||||
dw_mutex_lock (&s_gps_mutex);
|
||||
|
||||
#elif ENABLE_GPS
|
||||
memcpy (gpsinfo, &s_dwgps_info, sizeof(*gpsinfo));
|
||||
|
||||
int err;
|
||||
dw_mutex_unlock (&s_gps_mutex);
|
||||
|
||||
if (init_status != INIT_SUCCESS) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Internal error, dwgps_read without successful init.\n");
|
||||
return (-1);
|
||||
if (s_dwgps_debug >= 1) {
|
||||
text_color_set (DW_COLOR_DEBUG);
|
||||
dwgps_print ("gps_read: ", gpsinfo);
|
||||
}
|
||||
|
||||
#if USE_GPS_SHM
|
||||
// TODO: Should we check timestamp and complain if very stale?
|
||||
// or should we leave that up to the caller?
|
||||
|
||||
/*
|
||||
* Shared memory version.
|
||||
*/
|
||||
return (s_dwgps_info.fix);
|
||||
}
|
||||
|
||||
err = gps_read (&gpsdata);
|
||||
|
||||
#if DEBUG
|
||||
dw_printf ("gps_read returns %d bytes\n", err);
|
||||
#endif
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgps_print
|
||||
*
|
||||
* Purpose: Print gps information for debugging.
|
||||
*
|
||||
* Inputs: msg - Message for prefix on line.
|
||||
* gpsinfo - Structure with latitude, longitude, etc.
|
||||
*
|
||||
* Description: Caller is responsible for setting text color.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#else
|
||||
void dwgps_print (char *msg, dwgps_info_t *gpsinfo)
|
||||
{
|
||||
|
||||
/*
|
||||
* Socket version.
|
||||
*/
|
||||
dw_printf ("%stime=%d fix=%d lat=%.6f lon=%.6f trk=%.0f spd=%.1f alt=%.0f\n",
|
||||
msg,
|
||||
(int)gpsinfo->timestamp, (int)gpsinfo->fix,
|
||||
gpsinfo->dlat, gpsinfo->dlon,
|
||||
gpsinfo->track, gpsinfo->speed_knots,
|
||||
gpsinfo->altitude);
|
||||
|
||||
// Wait for up to 1000 milliseconds.
|
||||
// This should only happen in the beaconing thread so
|
||||
// I'm not worried about other functions hanging.
|
||||
|
||||
if (gps_waiting(&gpsdata, 1000)) {
|
||||
|
||||
err = gps_read (&gpsdata);
|
||||
}
|
||||
else {
|
||||
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (err > 0) {
|
||||
/* Data is available. */
|
||||
|
||||
if (gpsdata.status >= STATUS_FIX && gpsdata.fix.mode >= MODE_2D) {
|
||||
|
||||
*plat = gpsdata.fix.latitude;
|
||||
*plon = gpsdata.fix.longitude;
|
||||
*pcourse = gpsdata.fix.track;
|
||||
*pspeed = MPS_TO_KNOTS * gpsdata.fix.speed; /* libgps uses meters/sec */
|
||||
|
||||
if (gpsdata.fix.mode >= MODE_3D) {
|
||||
*palt = gpsdata.fix.altitude;
|
||||
return (3);
|
||||
}
|
||||
return (2);
|
||||
}
|
||||
|
||||
/* No fix. Probably temporary condition. */
|
||||
return (0);
|
||||
}
|
||||
else if (err == 0) {
|
||||
|
||||
/* No data available at the present time. */
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
|
||||
/* More serious error. */
|
||||
return (-1);
|
||||
}
|
||||
#else
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
||||
return (-1);
|
||||
#endif
|
||||
|
||||
} /* end dwgps_read */
|
||||
} /* end dwgps_set_data */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -326,19 +226,10 @@ int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float
|
|||
|
||||
void dwgps_term (void) {
|
||||
|
||||
#if __WIN32__
|
||||
|
||||
#elif ENABLE_GPS
|
||||
|
||||
if (init_status == INIT_SUCCESS) {
|
||||
|
||||
#ifndef USE_GPS_SHM
|
||||
gps_stream(&gpsdata, WATCH_DISABLE, NULL);
|
||||
#endif
|
||||
gps_close (&gpsdata);
|
||||
}
|
||||
#else
|
||||
dwgpsnmea_term ();
|
||||
|
||||
#if ENABLE_GPSD
|
||||
dwgpsd_term ();
|
||||
#endif
|
||||
|
||||
} /* end dwgps_term */
|
||||
|
@ -348,69 +239,27 @@ void dwgps_term (void) {
|
|||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: main
|
||||
* Name: dwgps_set_data
|
||||
*
|
||||
* Purpose: Simple unit test for other functions in this file.
|
||||
* Purpose: Called by the GPS interfaces when new data is available.
|
||||
*
|
||||
* Description: Compile with -DTEST option.
|
||||
*
|
||||
* gcc -DTEST dwgps.c textcolor.c -lgps
|
||||
* ./a.out
|
||||
* Inputs: gpsinfo - Structure with latitude, longitude, etc.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#if TEST
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
void dwgps_set_data (dwgps_info_t *gpsinfo)
|
||||
{
|
||||
|
||||
#if __WIN32__
|
||||
/* Debug print is handled by the two callers so */
|
||||
/* we can distinguish the source. */
|
||||
|
||||
printf ("Not in win32 version yet.\n");
|
||||
dw_mutex_lock (&s_gps_mutex);
|
||||
|
||||
#elif ENABLE_GPS
|
||||
int err;
|
||||
int fix;
|
||||
double lat;
|
||||
double lon;
|
||||
float speed;
|
||||
float course;
|
||||
float alt;
|
||||
memcpy (&s_dwgps_info, gpsinfo, sizeof(s_dwgps_info));
|
||||
|
||||
err = dwgps_init ();
|
||||
|
||||
if (err != 0) exit(1);
|
||||
|
||||
while (1) {
|
||||
fix = dwgps_read (&lat, &lon, &speed, &course, &alt)
;
|
||||
switch (fix) {
|
||||
case 3:
|
||||
case 2:
|
||||
dw_printf ("%.6f %.6f", lat, lon);
|
||||
dw_printf (" %.1f knots %.0f degrees", speed, course);
|
||||
if (fix==3) dw_printf (" altitude = %.1f meters", alt);
|
||||
dw_printf ("\n");
|
||||
break;
|
||||
case 0:
|
||||
dw_printf ("location currently not available.\n");
|
||||
break;
|
||||
default:
|
||||
dw_printf ("ERROR getting GPS information.\n");
|
||||
}
|
||||
sleep (3);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
printf ("Test: Shouldn't be here.\n");
|
||||
#endif
|
||||
|
||||
} /* end main */
|
||||
|
||||
|
||||
#endif
|
||||
dw_mutex_unlock (&s_gps_mutex);
|
||||
|
||||
} /* end dwgps_set_data */
|
||||
|
||||
|
||||
/* end dwgps.c */
|
||||
|
|
50
dwgps.h
50
dwgps.h
|
@ -1,13 +1,59 @@
|
|||
|
||||
/* dwgps.h */
|
||||
|
||||
#ifndef DWGPS_H
|
||||
#define DWGPS_H 1
|
||||
|
||||
int dwgps_init (void);
|
||||
|
||||
int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float *palt);
|
||||
#include <time.h>
|
||||
#include "config.h" /* for struct misc_config_s */
|
||||
|
||||
|
||||
/*
|
||||
* Values for fix, equivalent to values from libgps.
|
||||
* -2 = not initialized.
|
||||
* -1 = error communicating with GPS receiver.
|
||||
* 0 = nothing heard yet.
|
||||
* 1 = had signal but lost it.
|
||||
* 2 = 2D.
|
||||
* 3 = 3D.
|
||||
*
|
||||
* Undefined float & double values are set to G_UNKNOWN.
|
||||
*
|
||||
*/
|
||||
|
||||
enum dwfix_e { DWFIX_NOT_INIT= -2, DWFIX_ERROR= -1, DWFIX_NOT_SEEN=0, DWFIX_NO_FIX=1, DWFIX_2D=2, DWFIX_3D=3 };
|
||||
|
||||
typedef enum dwfix_e dwfix_t;
|
||||
|
||||
typedef struct dwgps_info_s {
|
||||
time_t timestamp; /* When last updated. System time. */
|
||||
dwfix_t fix; /* Quality of position fix. */
|
||||
double dlat; /* Latitude. Valid if fix >= 2. */
|
||||
double dlon; /* Longitude. Valid if fix >= 2. */
|
||||
float speed_knots; /* libgps uses meters/sec but we use GPS usual knots. */
|
||||
float track; /* What is difference between track and course? */
|
||||
float altitude; /* meters above mean sea level. Valid if fix == 3. */
|
||||
} dwgps_info_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void dwgps_init (struct misc_config_s *pconfig, int debug);
|
||||
|
||||
void dwgps_clear (dwgps_info_t *gpsinfo);
|
||||
|
||||
dwfix_t dwgps_read (dwgps_info_t *gpsinfo);
|
||||
|
||||
void dwgps_print (char *msg, dwgps_info_t *gpsinfo);
|
||||
|
||||
void dwgps_term (void);
|
||||
|
||||
void dwgps_set_data (dwgps_info_t *gpsinfo);
|
||||
|
||||
|
||||
#endif /* DWGPS_H 1 */
|
||||
|
||||
/* end dwgps.h */
|
||||
|
||||
|
|
|
@ -0,0 +1,434 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013, 2014, 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Module: dwgps.c
|
||||
*
|
||||
* Purpose: Interface to location data, i.e. GPS receiver.
|
||||
*
|
||||
* Description: For Linux, we would normally want to use gpsd and libgps.
|
||||
* This allows multiple applications to access the GPS data,
|
||||
* without fighting over the same serial port, and has the
|
||||
* extra benefit that the system clock can be set from the GPS signal.
|
||||
*
|
||||
* Reference: http://www.catb.org/gpsd/
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#if __WIN32__
|
||||
#error Not for Windows
|
||||
#endif
|
||||
|
||||
#if ENABLE_GPSD
|
||||
#include <gps.h>
|
||||
|
||||
// Debian bug report: direwolf (1.2-1) FTBFS with libgps22 as part of the gpsd transition (#803605):
|
||||
// dwgps.c claims to only support GPSD_API_MAJOR_VERSION 5, but also builds successfully with
|
||||
// GPSD_API_MAJOR_VERSION 6 provided by libgps22 when the attached patch is applied.
|
||||
#if GPSD_API_MAJOR_VERSION < 5 || GPSD_API_MAJOR_VERSION > 6
|
||||
#error libgps API version might be incompatible.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "dwgps.h"
|
||||
#include "dwgpsd.h"
|
||||
|
||||
|
||||
|
||||
static int s_debug = 0; /* Enable debug output. */
|
||||
/* >= 1 show results from dwgps_read. */
|
||||
/* >= 2 show updates from GPS. */
|
||||
|
||||
static void * read_gpsd_thread (void *arg);
|
||||
|
||||
/*
|
||||
* Information for interface to gpsd daemon.
|
||||
*/
|
||||
|
||||
static struct gps_data_t gpsdata;
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsd_init
|
||||
*
|
||||
* Purpose: Intialize the GPS interface.
|
||||
*
|
||||
* Inputs: pconfig Configuration settings. This includes
|
||||
* host name or address for network connection.
|
||||
*
|
||||
* debug - If >= 1, print results when dwgps_read is called.
|
||||
* (In different file.)
|
||||
*
|
||||
* If >= 2, location updates are also printed.
|
||||
* (In this file.)
|
||||
*
|
||||
* Returns: 1 = success
|
||||
* 0 = nothing to do (no host specified in config)
|
||||
* -1 = failure
|
||||
*
|
||||
* Description: - Establish socket connection with gpsd.
|
||||
* - Start up thread to process incoming data.
|
||||
* It reads from the daemon and deposits into
|
||||
* shared region via dwgps_put_data.
|
||||
*
|
||||
* The application calls dwgps_read to get the most
|
||||
8 recent information.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Historical notes:
|
||||
*
|
||||
* Originally, I wanted to use the shared memory interface to gpsd
|
||||
* because it is simpler and more efficient. Just access it when we
|
||||
* actually need the data and we don't have a lot of extra unnecessary
|
||||
* busy work going on.
|
||||
*
|
||||
* The current version of gpsd, supplied with Raspian, is 3.6 from back in
|
||||
* May 2012, is missing support for the shared memory interface.
|
||||
*
|
||||
* I tried to download a newer source and build with shared memory support
|
||||
* but ran into a couple other issues.
|
||||
*
|
||||
* sudo apt-get install libncurses5-dev
|
||||
* sudo apt-get install scons
|
||||
* cd ~
|
||||
* wget http://download-mirror.savannah.gnu.org/releases/gpsd/gpsd-3.11.tar.gz
|
||||
* tar xfz gpsd-3.11.tar.gz
|
||||
* cd gpsd-3.11
|
||||
* scons prefix=/usr libdir=lib/arm-linux-gnueabihf shm_export=True python=False
|
||||
* sudo scons udev-install
|
||||
*
|
||||
* For now, we will use the socket interface. Maybe get back to this again someday.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int dwgpsd_init (struct misc_config_s *pconfig, int debug)
|
||||
{
|
||||
|
||||
#if ENABLE_GPSD
|
||||
|
||||
pthread_t read_gps_tid;
|
||||
int e;
|
||||
int err;
|
||||
int arg = 0;
|
||||
char sport[12];
|
||||
dwgps_info_t info;
|
||||
|
||||
s_debug = debug;
|
||||
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dwgpsd_init()\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket interface to gpsd.
|
||||
*/
|
||||
|
||||
if (strlen(pconfig->gpsd_host) == 0) {
|
||||
|
||||
/* Nothing to do. Leave initial fix value of errror. */
|
||||
return (0);
|
||||
}
|
||||
|
||||
snprintf (sport, sizeof(sport), "%d", pconfig->gpsd_port);
|
||||
err = gps_open (pconfig->gpsd_host, sport, &gpsdata);
|
||||
if (err != 0) {
|
||||
dwgps_info_t info;
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unable to connect to GPSD stream.\n");
|
||||
dw_printf ("%s\n", gps_errstr(errno));
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
|
||||
e = pthread_create (&read_gps_tid, NULL, read_gpsd_thread, (void *)(long)arg);
|
||||
if (e != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Could not create GPS reader thread");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* success */
|
||||
|
||||
return (1);
|
||||
|
||||
|
||||
#else /* end ENABLE_GPSD */
|
||||
|
||||
// Shouldn't be here.
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPSD interface not enabled in this version.\n");
|
||||
dw_printf ("See documentation on how to rebuild with ENABLE_GPSD.\n");
|
||||
|
||||
return (-1);
|
||||
|
||||
#endif
|
||||
|
||||
} /* end dwgps_init */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: read_gpsd_thread
|
||||
*
|
||||
* Purpose: Read information from GPSD, as it becomes available, and
|
||||
* store in memory shared with dwgps_read.
|
||||
*
|
||||
* Inputs: arg - not used
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#define TIMEOUT 30
|
||||
|
||||
#if ENABLE_GPSD
|
||||
|
||||
static void * read_gpsd_thread (void *arg)
|
||||
{
|
||||
dwgps_info_t info;
|
||||
|
||||
if (s_debug >= 1) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("starting read_gpsd_thread (%d)\n", (int)(long)arg);
|
||||
}
|
||||
|
||||
dwgps_clear (&info);
|
||||
info.fix = DWFIX_NOT_SEEN; /* clear not init state. */
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSD: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
|
||||
while (1) {
|
||||
|
||||
if ( ! gps_waiting(&gpsdata, TIMEOUT * 1000000)) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPSD: Timeout waiting for GPS data.\n");
|
||||
/* Fall thru to read which should get error and bail out. */
|
||||
}
|
||||
|
||||
if (gps_read (&gpsdata) == -1) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
||||
dw_printf ("------------------------------------------\n");
|
||||
dw_printf ("GPSD: Lost communication with gpsd server.\n");
|
||||
dw_printf ("------------------------------------------\n");
|
||||
|
||||
info.fix = DWFIX_ERROR;
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSD: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
|
||||
break; // Jump out of loop and terminate thread.
|
||||
}
|
||||
|
||||
switch (gpsdata.fix.mode) {
|
||||
default:
|
||||
case MODE_NOT_SEEN:
|
||||
if (info.fix >= DWFIX_2D) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSD: Lost location fix.\n");
|
||||
}
|
||||
info.fix = DWFIX_NOT_SEEN;
|
||||
break;
|
||||
|
||||
case MODE_NO_FIX:
|
||||
if (info.fix >= DWFIX_2D) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSD: Lost location fix.\n");
|
||||
}
|
||||
info.fix = DWFIX_NO_FIX;
|
||||
break;
|
||||
|
||||
case MODE_2D:
|
||||
if (info.fix != DWFIX_2D) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSD: Location fix is now 2D.\n");
|
||||
}
|
||||
info.fix = DWFIX_2D;
|
||||
break;
|
||||
|
||||
case MODE_3D:
|
||||
if (info.fix != DWFIX_3D) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSD: Location fix is now 3D.\n");
|
||||
}
|
||||
info.fix = DWFIX_3D;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Data is available. */
|
||||
// TODO: what is gpsdata.status?
|
||||
|
||||
|
||||
if (gpsdata.status >= STATUS_FIX && gpsdata.fix.mode >= MODE_2D) {
|
||||
|
||||
info.dlat = isnan(gpsdata.fix.latitude) ? G_UNKNOWN : gpsdata.fix.latitude;
|
||||
info.dlon = isnan(gpsdata.fix.longitude) ? G_UNKNOWN : gpsdata.fix.longitude;
|
||||
info.track = isnan(gpsdata.fix.track) ? G_UNKNOWN : gpsdata.fix.track;
|
||||
info.speed_knots = isnan(gpsdata.fix.speed) ? G_UNKNOWN : (MPS_TO_KNOTS * gpsdata.fix.speed);
|
||||
|
||||
if (gpsdata.fix.mode >= MODE_3D) {
|
||||
info.altitude = isnan(gpsdata.fix.altitude) ? G_UNKNOWN : gpsdata.fix.altitude;
|
||||
}
|
||||
}
|
||||
|
||||
info.timestamp = time(NULL);
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSD: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
}
|
||||
|
||||
return(0); // Terminate thread on serious error.
|
||||
|
||||
} /* end read_gps_thread */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsd_term
|
||||
*
|
||||
* Purpose: Shut down GPS interface before exiting from application.
|
||||
*
|
||||
* Inputs: none.
|
||||
*
|
||||
* Returns: none.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void dwgpsd_term (void) {
|
||||
|
||||
#if ENABLE_GPSD
|
||||
|
||||
gps_close (&gpsdata);
|
||||
|
||||
#endif
|
||||
|
||||
} /* end dwgpsd_term */
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: main
|
||||
*
|
||||
* Purpose: Simple unit test for other functions in this file.
|
||||
*
|
||||
* Description: Compile with -DGPSTEST option.
|
||||
*
|
||||
* gcc -DGPSTEST -DENABLE_GPSD dwgpsd.c dwgps.c textcolor.o latlong.o misc.a -lm -lpthread -lgps
|
||||
* ./a.out
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#if GPSTEST
|
||||
|
||||
|
||||
int dwgpsnmea_init (struct misc_config_s *pconfig, int debug)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
void dwgpsnmea_term (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct misc_config_s config;
|
||||
dwgps_info_t info;
|
||||
|
||||
|
||||
memset (&config, 0, sizeof(config));
|
||||
strlcpy (config.gpsd_host, "localhost", sizeof(config.gpsd_host));
|
||||
config.gpsd_port = atoi(DEFAULT_GPSD_PORT);
|
||||
|
||||
dwgps_init (&config, 3);
|
||||
|
||||
while (1) {
|
||||
dwfix_t fix;
|
||||
|
||||
fix = dwgps_read (&info)
;
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
switch (fix) {
|
||||
case DWFIX_2D:
|
||||
case DWFIX_3D:
|
||||
dw_printf ("%.6f %.6f", info.dlat, info.dlon);
|
||||
dw_printf (" %.1f knots %.0f degrees", info.speed_knots, info.track);
|
||||
if (fix==3) dw_printf (" altitude = %.1f meters", info.altitude);
|
||||
dw_printf ("\n");
|
||||
break;
|
||||
case DWFIX_NOT_SEEN:
|
||||
case DWFIX_NO_FIX:
|
||||
dw_printf ("Location currently not available.\n");
|
||||
break;
|
||||
case DWFIX_NOT_INIT:
|
||||
dw_printf ("GPS Init failed.\n");
|
||||
exit (1);
|
||||
case DWFIX_ERROR:
|
||||
default:
|
||||
dw_printf ("ERROR getting GPS information.\n");
|
||||
break;
|
||||
}
|
||||
SLEEP_SEC (3);
|
||||
}
|
||||
|
||||
} /* end main */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* end dwgpsd.c */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/* dwgpsd.h - For communicating with daemon */
|
||||
|
||||
|
||||
|
||||
#ifndef DWGPSD_H
|
||||
#define DWGPSD_H 1
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
int dwgpsd_init (struct misc_config_s *pconfig, int debug);
|
||||
|
||||
void dwgpsd_term (void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* end dwgpsd.h */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,800 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013, 2014, 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Module: dwgpsnmea.c
|
||||
*
|
||||
* Purpose: process NMEA sentences from a GPS receiver.
|
||||
*
|
||||
* Description: This version is available for all operating systems.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "dwgps.h"
|
||||
#include "dwgpsnmea.h"
|
||||
#include "serial_port.h"
|
||||
|
||||
|
||||
static int s_debug = 0; /* Enable debug output. */
|
||||
/* See dwgpsnmea_init description for values. */
|
||||
|
||||
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
static unsigned __stdcall read_gpsnmea_thread (void *arg);
|
||||
#else
|
||||
static void * read_gpsnmea_thread (void *arg);
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsnmea_init
|
||||
*
|
||||
* Purpose: Open serial port for the GPS receiver.
|
||||
*
|
||||
* Inputs: pconfig Configuration settings. This includes
|
||||
* serial port name for direct connect.
|
||||
*
|
||||
* debug - If >= 1, print results when dwgps_read is called.
|
||||
* (In different file.)
|
||||
*
|
||||
* If >= 2, location updates are also printed.
|
||||
* (In this file.)
|
||||
* Why not do it in dwgps_set_data() ?
|
||||
* Here, we can prefix it with GPSNMEA to
|
||||
* distinguish it from GPSD.
|
||||
*
|
||||
* If >= 3, Also the NMEA sentences.
|
||||
* (In this file.)
|
||||
*
|
||||
* Returns: 1 = success
|
||||
* 0 = nothing to do (no serial port specified in config)
|
||||
* -1 = failure
|
||||
*
|
||||
* Description: When talking directly to GPS receiver (any operating system):
|
||||
*
|
||||
* - Open the appropriate serial port.
|
||||
* - Start up thread to process incoming data.
|
||||
* It reads from the serial port and deposits into
|
||||
* dwgps_info, above.
|
||||
*
|
||||
* The application calls dwgps_read to get the most recent information.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
/* Make this static and available to all functions so term function can access it. */
|
||||
|
||||
static MYFDTYPE s_gpsnmea_port_fd = MYFDERROR; /* Handle for serial port. */
|
||||
|
||||
|
||||
int dwgpsnmea_init (struct misc_config_s *pconfig, int debug)
|
||||
{
|
||||
//dwgps_info_t info;
|
||||
#if __WIN32__
|
||||
HANDLE read_gps_th;
|
||||
#else
|
||||
pthread_t read_gps_tid;
|
||||
int e;
|
||||
#endif
|
||||
|
||||
s_debug = debug;
|
||||
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("dwgpsnmea_init()\n");
|
||||
}
|
||||
|
||||
if (strlen(pconfig->gpsnmea_port) == 0) {
|
||||
|
||||
/* Nothing to do. Leave initial fix value for not init. */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open serial port connection.
|
||||
* 4800 baud is standard for GPS.
|
||||
* Should add an option to allow changing someday.
|
||||
*/
|
||||
|
||||
s_gpsnmea_port_fd = serial_port_open (pconfig->gpsnmea_port, 4800);
|
||||
|
||||
if (s_gpsnmea_port_fd != MYFDERROR) {
|
||||
#if __WIN32__
|
||||
read_gps_th = (HANDLE)_beginthreadex (NULL, 0, read_gpsnmea_thread, (void*)(long)s_gpsnmea_port_fd, 0, NULL);
|
||||
if (read_gps_th == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create GPS NMEA listening thread.\n");
|
||||
return (-1);
|
||||
}
|
||||
#else
|
||||
int e;
|
||||
e = pthread_create (&read_gps_tid, NULL, read_gpsnmea_thread, (void*)(long)s_gpsnmea_port_fd);
|
||||
if (e != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Could not create GPS NMEA listening thread.");
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not open serial port %s for GPS receiver.\n", pconfig->gpsnmea_port);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* success */
|
||||
|
||||
return (1);
|
||||
|
||||
} /* end dwgpsnmea_init */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: read_gpsnmea_thread
|
||||
*
|
||||
* Purpose: Read information from GPS, as it becomes available, and
|
||||
* store it for later retrieval by dwgps_read.
|
||||
*
|
||||
* Inputs: fd - File descriptor for serial port.
|
||||
*
|
||||
* Description: This version reads from serial port and parses the
|
||||
* NMEA sentences.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#define TIMEOUT 5
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
static unsigned __stdcall read_gpsnmea_thread (void *arg)
|
||||
#else
|
||||
static void * read_gpsnmea_thread (void *arg)
|
||||
#endif
|
||||
{
|
||||
MYFDTYPE fd = (MYFDTYPE)(long)arg;
|
||||
|
||||
// Maximum length of message from GPS receiver is 82 according to some people.
|
||||
// Make buffer considerably larger to be safe.
|
||||
|
||||
#define NMEA_MAX_LEN 160
|
||||
|
||||
char gps_msg[NMEA_MAX_LEN];
|
||||
int gps_msg_len = 0;
|
||||
dwgps_info_t info;
|
||||
|
||||
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("read_gpsnmea_thread (%d)\n", (int)(long)arg);
|
||||
}
|
||||
|
||||
dwgps_clear (&info);
|
||||
info.fix = DWFIX_NOT_SEEN; /* clear not init state. */
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSNMEA: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
|
||||
|
||||
while (1) {
|
||||
int ch;
|
||||
|
||||
ch = serial_port_get1(fd);
|
||||
|
||||
if (ch < 0) {
|
||||
|
||||
/* This might happen if a USB device is unplugged. */
|
||||
/* I can't imagine anything that would cause it with */
|
||||
/* a normal serial port. */
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("----------------------------------------------\n");
|
||||
dw_printf ("GPSNMEA: Lost communication with GPS receiver.\n");
|
||||
dw_printf ("----------------------------------------------\n");
|
||||
|
||||
info.fix = DWFIX_ERROR;
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSNMEA: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
|
||||
// TODO: doesn't exist yet - serial_port_close(fd);
|
||||
s_gpsnmea_port_fd = MYFDERROR;
|
||||
|
||||
break; /* terminate thread. */
|
||||
}
|
||||
|
||||
if (ch == '$') {
|
||||
// Start of new sentence.
|
||||
gps_msg_len = 0;
|
||||
gps_msg[gps_msg_len++] = ch;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
else if (ch == '\r' || ch == '\n') {
|
||||
if (gps_msg_len >= 6 && gps_msg[0] == '$') {
|
||||
|
||||
dwfix_t f;
|
||||
|
||||
if (s_debug >= 3) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("%s\n", gps_msg);
|
||||
}
|
||||
|
||||
/* Process sentence. */
|
||||
|
||||
if (strncmp(gps_msg, "$GPRMC", 6) == 0) {
|
||||
|
||||
f = dwgpsnmea_gprmc (gps_msg, 0, &info.dlat, &info.dlon, &info.speed_knots, &info.track);
|
||||
|
||||
if (f == DWFIX_ERROR) {
|
||||
|
||||
/* Parse error. Shouldn't happen. Better luck next time. */
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSNMEA: Error parsing $GPRMC sentence.\n");
|
||||
dw_printf ("%s\n", gps_msg);
|
||||
}
|
||||
else if (f == DWFIX_2D) {
|
||||
|
||||
if (info.fix != DWFIX_2D && info.fix != DWFIX_3D) {
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSNMEA: Location fix is now available.\n");
|
||||
|
||||
info.fix = DWFIX_2D; // Don't know if 2D or 3D. Take minimum.
|
||||
}
|
||||
info.timestamp = time(NULL);
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSNMEA: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
}
|
||||
else {
|
||||
|
||||
if (info.fix == DWFIX_2D || info.fix == DWFIX_3D) {
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSNMEA: Lost location fix.\n");
|
||||
}
|
||||
info.fix = f; /* lost it. */
|
||||
info.timestamp = time(NULL);
|
||||
if (s_debug >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dwgps_print ("GPSNMEA: ", &info);
|
||||
}
|
||||
dwgps_set_data (&info);
|
||||
}
|
||||
|
||||
}
|
||||
else if (strncmp(gps_msg, "$GPGGA", 6) == 0) {
|
||||
int nsat;
|
||||
|
||||
f = dwgpsnmea_gpgga (gps_msg, 0, &info.dlat, &info.dlon, &info.altitude, &nsat);
|
||||
|
||||
/* Only switch between 2D & 3D. */
|
||||
/* Let GPRMC handle other changes in fix state and data transfer. */
|
||||
|
||||
if (f == DWFIX_ERROR) {
|
||||
|
||||
/* Parse error. Shouldn't happen. Better luck next time. */
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSNMEA: Error parsing $GPGGA sentence.\n");
|
||||
dw_printf ("%s\n", gps_msg);
|
||||
}
|
||||
else if ((f == DWFIX_3D && info.fix == DWFIX_2D) ||
|
||||
(f == DWFIX_2D && info.fix == DWFIX_3D)) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("GPSNMEA: Location fix is now %dD.\n", (int)f);
|
||||
info.fix = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gps_msg_len = 0;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
else {
|
||||
if (gps_msg_len < NMEA_MAX_LEN-1) {
|
||||
gps_msg[gps_msg_len++] = ch;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
}
|
||||
} /* while (1) */
|
||||
|
||||
#if __WIN32__
|
||||
return (0);
|
||||
#else
|
||||
return (NULL);
|
||||
#endif
|
||||
|
||||
} /* end read_gpsnmea_thread */
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: remove_checksum
|
||||
*
|
||||
* Purpose: Validate checksum and remove before further processing.
|
||||
*
|
||||
* Inputs: sentence
|
||||
* quiet suppress printing of error messages.
|
||||
*
|
||||
* Outputs: sentence modified in place.
|
||||
*
|
||||
* Returns: 0 = good checksum.
|
||||
* -1 = error. missing or wrong.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static int remove_checksum (char *sent, int quiet)
|
||||
{
|
||||
char *p;
|
||||
unsigned char cs;
|
||||
|
||||
|
||||
// Do we have valid checksum?
|
||||
|
||||
cs = 0;
|
||||
for (p = sent+1; *p != '*' && *p != '\0'; p++) {
|
||||
cs ^= *p;
|
||||
}
|
||||
|
||||
p = strchr (sent, '*');
|
||||
if (p == NULL) {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
dw_printf("Missing GPS checksum.\n");
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
if (cs != strtoul(p+1, NULL, 16)) {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("GPS checksum error. Expected %02x but found %s.\n", cs, p+1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
*p = '\0'; // Remove the checksum.
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsnmea_gprmc
|
||||
*
|
||||
* Purpose: Parse $GPRMC sentence and extract interesing parts.
|
||||
*
|
||||
* Inputs: sentence NMEA sentence.
|
||||
*
|
||||
* quiet suppress printing of error messages.
|
||||
*
|
||||
* Outputs: odlat latitude
|
||||
* odlon longitude
|
||||
* oknots speed
|
||||
* ocourse direction of travel.
|
||||
*
|
||||
* Left undefined if not valid.
|
||||
*
|
||||
* Returns: DWFIX_ERROR Parse error.
|
||||
* DWFIX_NO_FIX GPS is there but Position unknown. Could be temporary.
|
||||
* DWFIX_2D Valid position. We don't know if it is really 2D or 3D.
|
||||
*
|
||||
* Examples: $GPRMC,001431.00,V,,,,,,,121015,,,N*7C
|
||||
* $GPRMC,212404.000,V,4237.1505,N,07120.8602,W,,,150614,,*0B
|
||||
* $GPRMC,000029.020,V,,,,,,,080810,,,N*45
|
||||
* $GPRMC,003413.710,A,4237.1240,N,07120.8333,W,5.07,291.42,160614,,,A*7F
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
dwfix_t dwgpsnmea_gprmc (char *sentence, int quiet, double *odlat, double *odlon, float *oknots, float *ocourse)
|
||||
{
|
||||
char stemp[NMEA_MAX_LEN]; /* Make copy because parsing is destructive. */
|
||||
|
||||
char *next;
|
||||
|
||||
char *ptype; /* Should be $GPRMC */
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *pstatus; /* Status, A=Active (valid position), V=Void */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pknots; /* Speed over ground, knots. */
|
||||
char *pcourse; /* True course, degrees. */
|
||||
char *pdate; /* Date, ddmmyy */
|
||||
/* Magnetic variation */
|
||||
/* In version 3.00, mode is added: A D E N (see below) */
|
||||
/* Checksum */
|
||||
|
||||
strlcpy (stemp, sentence, sizeof(stemp));
|
||||
|
||||
if (remove_checksum (stemp, quiet) < 0) {
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
next = stemp;
|
||||
ptype = strsep(&next, ",");
|
||||
ptime = strsep(&next, ",");
|
||||
pstatus = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pknots = strsep(&next, ",");
|
||||
pcourse = strsep(&next, ",");
|
||||
pdate = strsep(&next, ",");
|
||||
|
||||
/* Suppress the 'set but not used' warnings. */
|
||||
/* Alternatively, we might use __attribute__((unused)) */
|
||||
|
||||
(void)(ptype);
|
||||
(void)(ptime);
|
||||
(void)(pdate);
|
||||
|
||||
if (pstatus != NULL && strlen(pstatus) == 1) {
|
||||
if (*pstatus != 'A') {
|
||||
return (DWFIX_NO_FIX); /* Not "Active." Don't parse. */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("No status in GPRMC sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
*odlat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get latitude from GPRMC sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
*odlon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get longitude from GPRMC sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (pknots != NULL && strlen(pknots) > 0) {
|
||||
*oknots = atof(pknots);
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get speed from GPRMC sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (pcourse != NULL) {
|
||||
if (strlen(pcourse) > 0) {
|
||||
*ocourse = atof(pcourse);
|
||||
}
|
||||
else {
|
||||
/* When stationary, this field might be empty. */
|
||||
*ocourse = G_UNKNOWN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get course from GPRMC sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
//text_color_set (DW_COLOR_INFO);
|
||||
//dw_printf("%.6f %.6f %.1f %.0f\n", *odlat, *odlon, *oknots, *ocourse);
|
||||
|
||||
return (DWFIX_2D);
|
||||
|
||||
} /* end dwgpsnmea_gprmc */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsnmea_gpgga
|
||||
*
|
||||
* Purpose: Parse $GPGGA sentence and extract interesing parts.
|
||||
*
|
||||
* Inputs: sentence NMEA sentence.
|
||||
*
|
||||
* quiet suppress printing of error messages.
|
||||
*
|
||||
* Outputs: odlat latitude
|
||||
* odlon longitude
|
||||
* oalt altitude in meters
|
||||
* onsat number of satellites.
|
||||
*
|
||||
* Left undefined if not valid.
|
||||
*
|
||||
* Returns: DWFIX_ERROR Parse error.
|
||||
* DWFIX_NO_FIX GPS is there but Position unknown. Could be temporary.
|
||||
* DWFIX_2D Valid position. We don't know if it is really 2D or 3D.
|
||||
* Take more cautious value so we don't try using altitude.
|
||||
*
|
||||
* Examples: $GPGGA,001429.00,,,,,0,00,99.99,,,,,,*68
|
||||
* $GPGGA,212407.000,4237.1505,N,07120.8602,W,0,00,,,M,,M,,*58
|
||||
* $GPGGA,000409.392,,,,,0,00,,,M,0.0,M,,0000*53
|
||||
* $GPGGA,003518.710,4237.1250,N,07120.8327,W,1,03,5.9,33.5,M,-33.5,M,,0000*5B
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// TODO: in progress...
|
||||
|
||||
dwfix_t dwgpsnmea_gpgga (char *sentence, int quiet, double *odlat, double *odlon, float *oalt, int *onsat)
|
||||
{
|
||||
char stemp[NMEA_MAX_LEN]; /* Make copy because parsing is destructive. */
|
||||
|
||||
char *next;
|
||||
|
||||
char *ptype; /* Should be $GPGGA */
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pfix; /* 0=invalid, 1=GPS fix, 2=DGPS fix */
|
||||
char *pnum_sat; /* Number of satellites */
|
||||
char *phdop; /* Horiz. Dilution fo Precision */
|
||||
char *paltitude; /* Altitude, above mean sea level */
|
||||
char *palt_u; /* Units for Altitude, typically M for meters. */
|
||||
char *pheight; /* Height above ellipsoid */
|
||||
char *pheight_u; /* Units for height, typically M for meters. */
|
||||
char *psince; /* Time since last DGPS update. */
|
||||
char *pdsta; /* DGPS reference station id. */
|
||||
|
||||
|
||||
strlcpy (stemp, sentence, sizeof(stemp));
|
||||
|
||||
if (remove_checksum (stemp, quiet) < 0) {
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
next = stemp;
|
||||
ptype = strsep(&next, ",");
|
||||
ptime = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pfix = strsep(&next, ",");
|
||||
pnum_sat = strsep(&next, ",");
|
||||
phdop = strsep(&next, ",");
|
||||
paltitude = strsep(&next, ",");
|
||||
palt_u = strsep(&next, ",");
|
||||
pheight = strsep(&next, ",");
|
||||
pheight_u = strsep(&next, ",");
|
||||
psince = strsep(&next, ",");
|
||||
pdsta = strsep(&next, ",");
|
||||
|
||||
/* Suppress the 'set but not used' warnings. */
|
||||
/* Alternatively, we might use __attribute__((unused)) */
|
||||
|
||||
(void)(ptype);
|
||||
(void)(ptime);
|
||||
(void)(pnum_sat);
|
||||
(void)(phdop);
|
||||
(void)(palt_u);
|
||||
(void)(pheight);
|
||||
(void)(pheight_u);
|
||||
(void)(psince);
|
||||
(void)(pdsta);
|
||||
|
||||
if (pfix != NULL && strlen(pfix) == 1) {
|
||||
if (*pfix == '0') {
|
||||
return (DWFIX_NO_FIX); /* No Fix. Don't parse the rest. */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("No fix in GPGGA sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0 && pns != NULL && strlen(pns) > 0) {
|
||||
*odlat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get latitude from GPGGA sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
if (plon != NULL && strlen(plon) > 0 && pew != NULL && strlen(pew) > 0) {
|
||||
*odlon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get longitude from GPGGA sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
// TODO: num sat...
|
||||
|
||||
/*
|
||||
* We can distinguish between 2D & 3D fix by presence
|
||||
* of altitude or an empty field.
|
||||
*/
|
||||
|
||||
if (paltitude != NULL) {
|
||||
|
||||
if (strlen(paltitude) > 0) {
|
||||
*oalt = atof(paltitude);
|
||||
return (DWFIX_3D);
|
||||
}
|
||||
else {
|
||||
return (DWFIX_2D);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( ! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("Can't get altitude from GPGGA sentence.\n");
|
||||
}
|
||||
return (DWFIX_ERROR);
|
||||
}
|
||||
|
||||
} /* end dwgpsnmea_gpgga */
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: dwgpsnmea_term
|
||||
*
|
||||
* Purpose: Shut down GPS interface before exiting from application.
|
||||
*
|
||||
* Inputs: none.
|
||||
*
|
||||
* Returns: none.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
void dwgpsnmea_term (void) {
|
||||
|
||||
// Should probably kill reader thread before closing device to avoid
|
||||
// message about read error.
|
||||
|
||||
// serial_port_close (s_gpsnmea_port_fd);
|
||||
|
||||
} /* end dwgps_term */
|
||||
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: main
|
||||
*
|
||||
* Purpose: Simple unit test for other functions in this file.
|
||||
*
|
||||
* Description: Compile with -DGPSTEST option.
|
||||
*
|
||||
* Windows:
|
||||
* gcc -DGPSTEST -Iregex dwgpsnmea.c dwgps.c textcolor.o serial_port.o latlong.o misc.a
|
||||
* a.exe
|
||||
*
|
||||
* Linux:
|
||||
* gcc -DGPSTEST dwgpsnmea.c dwgps.c textcolor.o serial_port.o latlong.o misc.a -lm -lpthread
|
||||
* ./a.out
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
#if GPSTEST
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
struct misc_config_s config;
|
||||
dwgps_info_t info;
|
||||
|
||||
|
||||
memset (&config, 0, sizeof(config));
|
||||
strlcpy (config.gpsnmea_port, "COM22", sizeof(config.gpsnmea_port));
|
||||
|
||||
dwgps_init (&config, 3);
|
||||
|
||||
while (1) {
|
||||
dwfix_t fix;
|
||||
|
||||
fix = dwgps_read (&info)
;
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
switch (fix) {
|
||||
case DWFIX_2D:
|
||||
case DWFIX_3D:
|
||||
dw_printf ("%.6f %.6f", info.dlat, info.dlon);
|
||||
dw_printf (" %.1f knots %.0f degrees", info.speed_knots, info.track);
|
||||
if (fix==3) dw_printf (" altitude = %.1f meters", info.altitude);
|
||||
dw_printf ("\n");
|
||||
break;
|
||||
case DWFIX_NOT_SEEN:
|
||||
case DWFIX_NO_FIX:
|
||||
dw_printf ("Location currently not available.\n");
|
||||
break;
|
||||
case DWFIX_NOT_INIT:
|
||||
dw_printf ("GPS Init failed.\n");
|
||||
exit (1);
|
||||
case DWFIX_ERROR:
|
||||
default:
|
||||
dw_printf ("ERROR getting GPS information.\n");
|
||||
break;
|
||||
}
|
||||
SLEEP_SEC (3);
|
||||
}
|
||||
|
||||
} /* end main */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* end dwgpsnmea.c */
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/* dwgpsnmea.h - For NMEA sentences over serial port */
|
||||
|
||||
|
||||
|
||||
#ifndef DWGPSNMEA_H
|
||||
#define DWGPSNMEA_H 1
|
||||
|
||||
#include "dwgps.h" /* for dwfix_t */
|
||||
#include "config.h"
|
||||
|
||||
|
||||
int dwgpsnmea_init (struct misc_config_s *pconfig, int debug);
|
||||
|
||||
void dwgpsnmea_term (void);
|
||||
|
||||
|
||||
dwfix_t dwgpsnmea_gprmc (char *sentence, int quiet, double *odlat, double *odlon, float *oknots, float *ocourse);
|
||||
|
||||
dwfix_t dwgpsnmea_gpgga (char *sentence, int quiet, double *odlat, double *odlon, float *oalt, int *onsat);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* end dwgpsnmea.h */
|
||||
|
||||
|
||||
|
139
encode_aprs.c
139
encode_aprs.c
|
@ -116,7 +116,8 @@ static int set_norm_position (char symtab, char symbol, double dlat, double dlon
|
|||
* height - Feet.
|
||||
* gain - dBi.
|
||||
*
|
||||
* course - Degress, 1 - 360. 0 means none or unknown.
|
||||
* course - Degress, 0 - 360 (360 equiv. to 0).
|
||||
* Use G_UNKNOWN for none or unknown.
|
||||
* speed - knots.
|
||||
*
|
||||
*
|
||||
|
@ -130,6 +131,9 @@ static int set_norm_position (char symtab, char symbol, double dlat, double dlon
|
|||
* radio range - calculated from PHG
|
||||
* altitude - not implemented yet.
|
||||
*
|
||||
* Some conversion must be performed for course from
|
||||
* the API definition to what is sent over the air.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
/* Compressed position & symbol fields common to several message formats. */
|
||||
|
@ -198,13 +202,18 @@ static int set_comp_position (char symtab, char symbol, double dlat, double dlon
|
|||
* When c is '{', s is range ...
|
||||
*/
|
||||
|
||||
if (course || speed) {
|
||||
if (speed > 0) {
|
||||
int c;
|
||||
int s;
|
||||
|
||||
c = (course + 1) / 4;
|
||||
if (course != G_UNKNOWN) {
|
||||
c = (course + 2) / 4;
|
||||
if (c < 0) c += 90;
|
||||
if (c >= 90) c -= 90;
|
||||
}
|
||||
else {
|
||||
c = 0;
|
||||
}
|
||||
presult->c = c + '!';
|
||||
|
||||
s = (int)round(log(speed+1.0) / log(1.08));
|
||||
|
@ -251,7 +260,10 @@ static int set_comp_position (char symtab, char symbol, double dlat, double dlon
|
|||
*
|
||||
* Inputs: power - Watts.
|
||||
* height - Feet.
|
||||
* gain - dB. Not clear if it is dBi or dBd.
|
||||
* gain - dB. Protocol spec doesn't mention whether it is dBi or dBd.
|
||||
* This says dBi:
|
||||
* http://www.tapr.org/pipermail/aprssig/2008-September/027034.html
|
||||
|
||||
* dir - Directivity: N, NE, etc., omni.
|
||||
*
|
||||
* Outputs: presult - Stored here.
|
||||
|
@ -260,6 +272,11 @@ static int set_comp_position (char symtab, char symbol, double dlat, double dlon
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
// TODO (bug): Doesn't check for G_UNKNOWN.
|
||||
// could have a case where some, but not all, values were specified.
|
||||
// Callers originally checked for any not zero.
|
||||
// now they check for any > 0.
|
||||
|
||||
|
||||
typedef struct phg_s {
|
||||
char P;
|
||||
|
@ -317,13 +334,19 @@ static int phg_data_extension (int power, int height, int gain, char *dir, char
|
|||
*
|
||||
* Purpose: Fill in parts of the course & speed data extension.
|
||||
*
|
||||
* Inputs: course - Degress, 1 - 360.
|
||||
* Inputs: course - Degress, 0 - 360 (360 equiv. to 0).
|
||||
* Use G_UNKNOWN for none or unknown.
|
||||
*
|
||||
* speed - knots.
|
||||
*
|
||||
* Outputs: presult - Stored here.
|
||||
*
|
||||
* Returns: Number of characters in result.
|
||||
*
|
||||
* Description: Over the air we use:
|
||||
* 0 for unknown or not relevant.
|
||||
* 1 - 360 for valid course. (360 for north)
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
@ -340,16 +363,23 @@ static int cse_spd_data_extension (int course, int speed, char *presult)
|
|||
char stemp[8];
|
||||
int x;
|
||||
|
||||
if (course != G_UNKNOWN) {
|
||||
x = course;
|
||||
if (x < 0) x = 0;
|
||||
if (x > 360) x = 360;
|
||||
while (x < 1) x += 360;
|
||||
while (x > 360) x -= 360;
|
||||
// Should now be in range of 1 - 360. */
|
||||
// Original value of 0 for north is transmitted as 360. */
|
||||
}
|
||||
else {
|
||||
x = 0;
|
||||
}
|
||||
snprintf (stemp, sizeof(stemp), "%03d", x);
|
||||
memcpy (r->cse, stemp, 3);
|
||||
|
||||
r->slash = '/';
|
||||
|
||||
x = speed;
|
||||
if (x < 0) x = 0;
|
||||
if (x < 0) x = 0; // would include G_UNKNOWN
|
||||
if (x > 999) x = 999;
|
||||
snprintf (stemp, sizeof(stemp), "%03d", x);
|
||||
memcpy (r->spd, stemp, 3);
|
||||
|
@ -459,8 +489,9 @@ static int frequency_spec (float freq, float tone, float offset, char *presult)
|
|||
* gain - dB. Not clear if it is dBi or dBd.
|
||||
* dir - Directivity: N, NE, etc., omni.
|
||||
*
|
||||
* course - Degress, 1 - 360. 0 means none or unknown.
|
||||
* speed - knots.
|
||||
* course - Degress, 0 - 360 (360 equiv. to 0).
|
||||
* Use G_UNKNOWN for none or unknown.
|
||||
* speed - knots. // TODO: should distinguish unknown(not revevant) vs. known zero.
|
||||
*
|
||||
* freq - MHz.
|
||||
* tone - Hz.
|
||||
|
@ -487,6 +518,7 @@ static int frequency_spec (float freq, float tone, float offset, char *presult)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
typedef struct aprs_ll_pos_s {
|
||||
char dti; /* ! or = */
|
||||
position_t pos;
|
||||
|
@ -533,10 +565,10 @@ int encode_position (int messaging, int compressed, double lat, double lon, int
|
|||
/* Optional data extension. (singular) */
|
||||
/* Can't have both course/speed and PHG. Former gets priority. */
|
||||
|
||||
if (course || speed) {
|
||||
if (course != G_UNKNOWN || speed > 0) {
|
||||
result_len += cse_spd_data_extension (course, speed, presult + result_len);
|
||||
}
|
||||
else if (power || height || gain) {
|
||||
else if (power > 0 || height > 0 || gain > 0) {
|
||||
result_len += phg_data_extension (power, height, gain, dir, presult + result_len);
|
||||
}
|
||||
}
|
||||
|
@ -598,7 +630,8 @@ int encode_position (int messaging, int compressed, double lat, double lon, int
|
|||
* gain - dB. Not clear if it is dBi or dBd.
|
||||
* dir - Direction: N, NE, etc., omni.
|
||||
*
|
||||
* course - Degress, 1 - 360. 0 means none or unknown.
|
||||
* course - Degress, 0 - 360 (360 equiv. to 0).
|
||||
* Use G_UNKNOWN for none or unknown.
|
||||
* speed - knots.
|
||||
*
|
||||
* freq - MHz.
|
||||
|
@ -614,7 +647,7 @@ int encode_position (int messaging, int compressed, double lat, double lon, int
|
|||
* 36 for fixed part,
|
||||
* 7 for optional extended data,
|
||||
* ~20 for freq, etc.,
|
||||
* comment ...
|
||||
* comment could be very long...
|
||||
*
|
||||
* Returns: Number of characters in result.
|
||||
*
|
||||
|
@ -694,10 +727,10 @@ int encode_object (char *name, int compressed, time_t thyme, double lat, double
|
|||
/* Optional data extension. (singular) */
|
||||
/* Can't have both course/speed and PHG. Former gets priority. */
|
||||
|
||||
if (course || speed) {
|
||||
if (course != G_UNKNOWN || speed > 0) {
|
||||
result_len += cse_spd_data_extension (course, speed, presult + result_len);
|
||||
}
|
||||
else if (power || height || gain) {
|
||||
else if (power > 0 || height > 0 || gain > 0) {
|
||||
result_len += phg_data_extension (power, height, gain, dir, presult + result_len);
|
||||
}
|
||||
}
|
||||
|
@ -746,93 +779,97 @@ int encode_object (char *name, int compressed, time_t thyme, double lat, double
|
|||
int main (int argc, char *argv[])
|
||||
{
|
||||
char result[100];
|
||||
|
||||
int errors = 0;
|
||||
|
||||
|
||||
/*********** Position ***********/
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, G_UNKNOWN, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* with PHG. */
|
||||
// TODO: Need to test specifying some but not all.
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
50, 100, 6, "N", 0, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
50, 100, 6, "N", G_UNKNOWN, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&PHG7368") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&PHG7368") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* with freq. */
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 0, 0, 146.955, 74.4, -0.6, NULL, result, sizeof(result));
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, G_UNKNOWN, 0, 146.955, 74.4, -0.6, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&146.955MHz T074 -060 ") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&146.955MHz T074 -060 ") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* with course/speed, freq, and comment! */
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 180, 55, 146.955, 74.4, -0.6, "River flooding", result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz T074 -060 River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz T074 -060 River flooding") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* Course speed, no tone, + offset */
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 180, 55, 146.955, 0, 0.6, "River flooding", result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 River flooding") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* Course speed, no tone, + offset + altitude */
|
||||
|
||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 12345, 'D', '&',
|
||||
encode_position (0, 0, 42+34.61/60, -(71+26.47/60), 12345, 'D', '&',
|
||||
0, 0, 0, NULL, 180, 55, 146.955, 0, 0.6, "River flooding", result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 /A=012345River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 /A=012345River flooding") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
// TODO: try boundary conditions of course = 0, 359, 360
|
||||
|
||||
/*********** Compressed position. ***********/
|
||||
|
||||
encode_position (1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
encode_position (0, 1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, G_UNKNOWN, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!D8yKC<Hn[& !") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!D8yKC<Hn[& !") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
|
||||
/* with PHG. In this case it is converted to precomputed radio range. TODO: check on this. Is 27.4 correct? */
|
||||
|
||||
encode_position (1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
50, 100, 6, "N", 0, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
encode_position (0, 1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
50, 100, 6, "N", G_UNKNOWN, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!D8yKC<Hn[&{CG") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, "!D8yKC<Hn[&{CG") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
/* with course/speed, freq, and comment! TODO: check on this 55 knots should be 63 MPH. we get 62. */
|
||||
/* with course/speed, freq, and comment! Roundoff. 55 knots should be 63 MPH. we get 62. */
|
||||
|
||||
encode_position (1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
encode_position (0, 1, 42+34.61/60, -(71+26.47/60), G_UNKNOWN, 'D', '&',
|
||||
0, 0, 0, NULL, 180, 55, 146.955, 74.4, -0.6, "River flooding", result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, "!D8yKC<Hn[& !146.955MHz T074 -060 River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
|
||||
//$ echo 'A>B:!D8yKC<Hn[&NUG146.955MHz T074 -060 River flooding' | decode_aprs
|
||||
|
||||
//A>B:!D8yKC<Hn[&NUG146.955MHz T074 -060 River flooding
|
||||
//Position, I=Igte IGate R=RX T=1hopTX 2=2hopTX w/overlay D
|
||||
//N 42 34.6100, W 071 26.4700, 62 MPH, course 180, 146.955 MHz, -600k, PL 74.4
|
||||
// River flooding
|
||||
if (strcmp(result, "!D8yKC<Hn[&NUG146.955MHz T074 -060 River flooding") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
// TODO: test alt; cs+alt
|
||||
|
||||
|
||||
/*********** Object. ***********/
|
||||
|
||||
encode_object ("WB1GOF-C", 0, 0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
||||
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
0, 0, 0, NULL, G_UNKNOWN, 0, 0, 0, 0, NULL, result, sizeof(result));
|
||||
dw_printf ("%s\n", result);
|
||||
if (strcmp(result, ";WB1GOF-C *111111z4234.61ND07126.47W&") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||
if (strcmp(result, ";WB1GOF-C *111111z4234.61ND07126.47W&") != 0) { dw_printf ("ERROR! line %d\n", __LINE__); errors++; }
|
||||
|
||||
// TODO: need more tests.
|
||||
|
||||
return(0);
|
||||
if (errors > 0) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Encode APRS test FAILED with %d errors.\n", errors);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
text_color_set (DW_COLOR_REC);
|
||||
dw_printf ("Encode APRS test PASSED with no errors.\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
} /* end main */
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
int encode_position (int messaging, int compressed, double lat, double lon, int alt_ft,
|
||||
char symtab, char symbol,
|
||||
int power, int height, int gain, char *dir,
|
||||
int course, int speed,
|
||||
int course, int speed_knots,
|
||||
float freq, float tone, float offset,
|
||||
char *comment,
|
||||
char *presult, size_t result_size);
|
||||
|
@ -10,7 +10,7 @@ int encode_position (int messaging, int compressed, double lat, double lon, int
|
|||
int encode_object (char *name, int compressed, time_t thyme, double lat, double lon,
|
||||
char symtab, char symbol,
|
||||
int power, int height, int gain, char *dir,
|
||||
int course, int speed,
|
||||
int course, int speed_knots,
|
||||
float freq, float tone, float offset, char *comment,
|
||||
char *presult, size_t result_size);
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ static void send_packet (char *str)
|
|||
int main(int argc, char **argv)
|
||||
{
|
||||
int c;
|
||||
int digit_optind = 0;
|
||||
//int digit_optind = 0;
|
||||
int err;
|
||||
int packet_count = 0;
|
||||
int i;
|
||||
|
@ -156,14 +156,14 @@ int main(int argc, char **argv)
|
|||
char output_file[256]; /* -o option */
|
||||
FILE *input_fp = NULL; /* File or NULL for built-in message */
|
||||
|
||||
strcpy (output_file, "");
|
||||
strlcpy (output_file, "", sizeof(output_file));
|
||||
|
||||
/*
|
||||
* Parse the command line options.
|
||||
*/
|
||||
|
||||
while (1) {
|
||||
int this_option_optind = optind ? optind : 1;
|
||||
//int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"future1", 1, 0, 0},
|
||||
|
@ -333,7 +333,7 @@ int main(int argc, char **argv)
|
|||
|
||||
case 'o': /* -o for Output file */
|
||||
|
||||
strcpy (output_file, optarg);
|
||||
strlcpy (output_file, optarg, sizeof(output_file));
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Output file set to %s\n", output_file);
|
||||
break;
|
||||
|
@ -399,9 +399,6 @@ int main(int argc, char **argv)
|
|||
assert (modem.adev[0].num_channels == 1 || modem.adev[0].num_channels == 2);
|
||||
assert (modem.adev[0].samples_per_sec >= MIN_SAMPLES_PER_SEC && modem.adev[0].samples_per_sec <= MAX_SAMPLES_PER_SEC);
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Get user packets(s) from file or stdin if specified.
|
||||
* "-n" option is ignored in this case.
|
||||
|
@ -472,12 +469,16 @@ int main(int argc, char **argv)
|
|||
if (modem.achan[0].modem_type == MODEM_SCRAMBLE) {
|
||||
g_noise_level = 0.33 * (amplitude / 200.0) * ((float)i / packet_count);
|
||||
}
|
||||
else if (modem.achan[0].baud < 600) {
|
||||
/* About 2/3 should be decoded properly. */
|
||||
g_noise_level = amplitude *.0048 * ((float)i / packet_count);
|
||||
}
|
||||
else {
|
||||
/* About 2/3 should be decoded properly. */
|
||||
g_noise_level = amplitude *.0023 * ((float)i / packet_count);
|
||||
}
|
||||
|
||||
sprintf (stemp, "WB2OSZ-15>TEST:,The quick brown fox jumps over the lazy dog! %04d of %04d", i, packet_count);
|
||||
snprintf (stemp, sizeof(stemp), "WB2OSZ-15>TEST:,The quick brown fox jumps over the lazy dog! %04d of %04d", i, packet_count);
|
||||
|
||||
send_packet (stemp);
|
||||
|
||||
|
@ -689,6 +690,14 @@ static int audio_file_open (char *fname, struct audio_s *pa)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
#define MY_RAND_MAX 0x7fffffff
|
||||
|
||||
static int seed = 1;
|
||||
|
||||
static int my_rand (void) {
|
||||
seed = ((seed * 1103515245) + 12345) & MY_RAND_MAX;
|
||||
return (seed);
|
||||
}
|
||||
|
||||
int audio_put (int a, int c)
|
||||
{
|
||||
|
@ -712,7 +721,12 @@ int audio_put (int a, int c)
|
|||
/* Add random noise to the signal. */
|
||||
/* r should be in range of -1 .. +1. */
|
||||
|
||||
r = (rand() - RAND_MAX/2.0) / (RAND_MAX/2.0);
|
||||
/* Use own function instead of rand() from the C library. */
|
||||
/* Windows and Linux have different results, messing up my self test procedure. */
|
||||
/* No idea what Mac OSX and BSD might do. */
|
||||
|
||||
|
||||
r = (my_rand() - MY_RAND_MAX/2.0) / (MY_RAND_MAX/2.0);
|
||||
|
||||
s += 5 * r * g_noise_level * 32767;
|
||||
|
||||
|
|
|
@ -426,8 +426,8 @@ int main ()
|
|||
/* one channel. 2 times: one second of each tone. */
|
||||
|
||||
memset (&my_audio_config, 0, sizeof(my_audio_config));
|
||||
strcpy (my_audio_config.adev[0].adevice_in, DEFAULT_ADEVICE);
|
||||
strcpy (my_audio_config.adev[0].adevice_out, DEFAULT_ADEVICE);
|
||||
strlcpy (my_audio_config.adev[0].adevice_in, DEFAULT_ADEVICE, sizeof(my_audio_config.adev[0].adevice_in));
|
||||
strlcpy (my_audio_config.adev[0].adevice_out, DEFAULT_ADEVICE, sizeof(my_audio_config.adev[0].adevice_out));
|
||||
|
||||
audio_open (&my_audio_config);
|
||||
gen_tone_init (&my_audio_config, 100);
|
||||
|
@ -448,8 +448,8 @@ int main ()
|
|||
/* Now try stereo. */
|
||||
|
||||
memset (&my_audio_config, 0, sizeof(my_audio_config));
|
||||
strcpy (my_audio_config.adev[0].adevice_in, DEFAULT_ADEVICE);
|
||||
strcpy (my_audio_config.adev[0].adevice_out, DEFAULT_ADEVICE);
|
||||
strlcpy (my_audio_config.adev[0].adevice_in, DEFAULT_ADEVICE, sizeof(my_audio_config.adev[0].adevice_in));
|
||||
strlcpy (my_audio_config.adev[0].adevice_out, DEFAULT_ADEVICE, , sizeof(my_audio_config.adev[0].adevice_out));
|
||||
my_audio_config.adev[0].num_channels = 2;
|
||||
|
||||
audio_open (&my_audio_config);
|
||||
|
|
|
@ -178,7 +178,7 @@ long Set_Polar_Stereographic_Parameters (double a,
|
|||
double essin;
|
||||
double one_PLUS_es, one_MINUS_es;
|
||||
double pow_es;
|
||||
double temp, temp_northing;
|
||||
double temp, temp_northing = 0;
|
||||
double inv_f = 1 / f;
|
||||
double mc;
|
||||
// const double epsilon = 1.0e-2;
|
||||
|
|
|
@ -634,8 +634,6 @@ void dcd_change (int chan, int subchan, int state)
|
|||
|
||||
int hdlc_rec_data_detect_any (int chan)
|
||||
{
|
||||
int subchan;
|
||||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
|
||||
return (composite_dcd[chan] != 0);
|
||||
|
|
|
@ -226,7 +226,6 @@ void hdlc_rec2_block (rrbb_t block)
|
|||
retry_t fix_bits = save_audio_config_p->achan[chan].fix_bits;
|
||||
int passall = save_audio_config_p->achan[chan].passall;
|
||||
int ok;
|
||||
int n;
|
||||
|
||||
#if DEBUGx
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -332,7 +331,7 @@ static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, alevel_t a
|
|||
int ok;
|
||||
int len, i,j;
|
||||
retry_t fix_bits = save_audio_config_p->achan[chan].fix_bits;
|
||||
int passall = save_audio_config_p->achan[chan].passall;
|
||||
//int passall = save_audio_config_p->achan[chan].passall;
|
||||
|
||||
|
||||
len = rrbb_get_len(block);
|
||||
|
@ -881,7 +880,9 @@ static int try_decode (rrbb_t block, int chan, int subchan, alevel_t alevel, ret
|
|||
int blen; /* Block length in bits. */
|
||||
int i;
|
||||
unsigned int raw; /* From demodulator. */
|
||||
#if DEBUGx
|
||||
int crc_failed = 1;
|
||||
#endif
|
||||
int retry_conf_mode = retry_conf.mode;
|
||||
int retry_conf_type = retry_conf.type;
|
||||
int retry_conf_retry = retry_conf.retry;
|
||||
|
@ -1119,7 +1120,9 @@ static int try_decode (rrbb_t block, int chan, int subchan, alevel_t alevel, ret
|
|||
goto failure;
|
||||
}
|
||||
} else {
|
||||
#if DEBUGx
|
||||
crc_failed = 0;
|
||||
#endif
|
||||
goto failure;
|
||||
}
|
||||
failure:
|
||||
|
@ -1151,8 +1154,8 @@ failure:
|
|||
}
|
||||
dw_printf ("\n");
|
||||
}
|
||||
#endif
|
||||
end:
|
||||
#endif
|
||||
return 0; /* failure. */
|
||||
|
||||
} /* end try_decode */
|
||||
|
|
3
igate.c
3
igate.c
|
@ -377,7 +377,6 @@ void igate_init (struct audio_s *p_audio_config, struct igate_config_s *p_igate_
|
|||
pthread_t cmd_listen_tid;
|
||||
int e;
|
||||
#endif
|
||||
int j;
|
||||
|
||||
#if DEBUGx
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -924,6 +923,7 @@ void igate_send_rec_packet (int chan, packet_t recv_pp)
|
|||
*/
|
||||
|
||||
info_len = ax25_get_info (pp, &pinfo);
|
||||
(void)(info_len);
|
||||
|
||||
if ((p = strchr ((char*)pinfo, '\r')) != NULL) {
|
||||
#if DEBUGx
|
||||
|
@ -1314,6 +1314,7 @@ static void xmit_packet (char *message)
|
|||
|
||||
ax25_format_addrs (pp3, payload);
|
||||
info_len = ax25_get_info (pp3, (unsigned char **)(&pinfo));
|
||||
(void)(info_len);
|
||||
strlcat (payload, pinfo, sizeof(payload));
|
||||
#if DEBUGx
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
|
12
kiss.c
12
kiss.c
|
@ -303,7 +303,7 @@ void kiss_init (struct misc_config_s *mc)
|
|||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Converted nullmodem device '%s'", mc->nullmodem);
|
||||
if (n < 1) n = 1;
|
||||
sprintf (mc->nullmodem, "/dev/ttyS%d", n-1);
|
||||
snprintf (mc->nullmodem, sizeof(mc->nullmodem), "/dev/ttyS%d", n-1);
|
||||
dw_printf (" to Linux equivalent '%s'\n", mc->nullmodem);
|
||||
}
|
||||
#endif
|
||||
|
@ -374,7 +374,7 @@ static MYFDTYPE kiss_open_pt (void)
|
|||
return (MYFDERROR);
|
||||
}
|
||||
|
||||
strcpy (pt_slave_name, pts);
|
||||
strlcpy (pt_slave_name, pts, sizeof(pt_slave_name));
|
||||
|
||||
e = tcgetattr (fd, &ts);
|
||||
if (e != 0) {
|
||||
|
@ -512,13 +512,13 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
|||
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
|
||||
// http://support.microsoft.com/kb/115831
|
||||
|
||||
strcpy (bettername, devicename);
|
||||
strlcpy (bettername, devicename, sizeof(bettername));
|
||||
if (strncasecmp(devicename, "COM", 3) == 0) {
|
||||
int n;
|
||||
n = atoi(devicename+3);
|
||||
if (n >= 10) {
|
||||
strcpy (bettername, "\\\\.\\");
|
||||
strcat (bettername, devicename);
|
||||
strlcpy (bettername, "\\\\.\\", sizeof(bettername));
|
||||
strlcat (bettername, devicename, sizeof(bettername));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -667,7 +667,7 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
|||
if (kiss_debug) {
|
||||
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
|
||||
}
|
||||
strcpy ((char *)kiss_buff, (char *)fbuf);
|
||||
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
|
||||
kiss_len = strlen((char *)kiss_buff);
|
||||
}
|
||||
else {
|
||||
|
|
15
kiss_frame.c
15
kiss_frame.c
|
@ -70,10 +70,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -91,7 +89,7 @@ void hex_dump (unsigned char *p, int len);
|
|||
static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug);
|
||||
|
||||
|
||||
#if TEST
|
||||
#if KISSTEST
|
||||
|
||||
#define dw_printf printf
|
||||
|
||||
|
@ -275,7 +273,7 @@ static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
|
|||
} /* end kiss_unwrap */
|
||||
|
||||
|
||||
#ifndef TEST
|
||||
#ifndef KISSTEST
|
||||
|
||||
|
||||
|
||||
|
@ -326,7 +324,7 @@ static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
|
|||
void kiss_rec_byte (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int))
|
||||
{
|
||||
|
||||
//printf ("kiss_frame ( %c %02x ) \n", ch, ch);
|
||||
//dw_printf ("kiss_frame ( %c %02x ) \n", ch, ch);
|
||||
|
||||
switch (kf->state) {
|
||||
|
||||
|
@ -625,11 +623,11 @@ void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int
|
|||
|
||||
/* Quick unit test for encapsulate & unwrap */
|
||||
|
||||
// $ gcc -DTEST kiss_frame.c ; ./a
|
||||
// $ gcc -DKISSTEST kiss_frame.c ; ./a
|
||||
// Quick KISS test passed OK.
|
||||
|
||||
|
||||
#if TEST
|
||||
#if KISSTEST
|
||||
|
||||
|
||||
main ()
|
||||
|
@ -661,7 +659,8 @@ main ()
|
|||
assert (dlen == 512);
|
||||
assert (memcmp(din, dout, 512) == 0);
|
||||
|
||||
printf ("Quick KISS test passed OK.\n");
|
||||
dw_printf ("Quick KISS test passed OK.\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -275,7 +275,7 @@ static void * connect_listen_thread (void *arg)
|
|||
SOCKET listen_sock;
|
||||
WSADATA wsadata;
|
||||
|
||||
sprintf (kiss_port_str, "%d", (int)(long)arg);
|
||||
snprintf (kiss_port_str, sizeof(kiss_port_str), "%d", (int)(long)arg);
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("DEBUG: kissnet port = %d = '%s'\n", (int)(long)arg, kiss_port_str);
|
||||
|
@ -493,7 +493,7 @@ void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
|||
if (kiss_debug) {
|
||||
kiss_debug_print (TO_CLIENT, "Fake command prompt", fbuf, flen);
|
||||
}
|
||||
strcpy ((char *)kiss_buff, (char *)fbuf);
|
||||
strlcpy ((char *)kiss_buff, (char *)fbuf, sizeof(kiss_buff));
|
||||
kiss_len = strlen((char *)kiss_buff);
|
||||
}
|
||||
else {
|
||||
|
|
229
latlong.c
229
latlong.c
|
@ -55,6 +55,7 @@
|
|||
* ambiguity - If 1, 2, 3, or 4, blank out that many trailing digits.
|
||||
*
|
||||
* Outputs: slat - String in format ddmm.mm[NS]
|
||||
* Should always be exactly 8 characters + NUL.
|
||||
*
|
||||
* Returns: None
|
||||
*
|
||||
|
@ -89,7 +90,7 @@ void latitude_to_str (double dlat, int ambiguity, char *slat)
|
|||
ideg = (int)dlat;
|
||||
dmin = (dlat - ideg) * 60.;
|
||||
|
||||
sprintf (smin, "%05.2f", dmin);
|
||||
snprintf (smin, sizeof(smin), "%05.2f", dmin);
|
||||
/* Due to roundoff, 59.9999 could come out as "60.00" */
|
||||
if (smin[0] == '6') {
|
||||
smin[0] = '0';
|
||||
|
@ -124,6 +125,7 @@ void latitude_to_str (double dlat, int ambiguity, char *slat)
|
|||
* ambiguity - If 1, 2, 3, or 4, blank out that many trailing digits.
|
||||
*
|
||||
* Outputs: slat - String in format dddmm.mm[NS]
|
||||
* Should always be exactly 9 characters + NUL.
|
||||
*
|
||||
* Returns: None
|
||||
*
|
||||
|
@ -158,7 +160,7 @@ void longitude_to_str (double dlong, int ambiguity, char *slong)
|
|||
ideg = (int)dlong;
|
||||
dmin = (dlong - ideg) * 60.;
|
||||
|
||||
sprintf (smin, "%05.2f", dmin);
|
||||
snprintf (smin, sizeof(smin), "%05.2f", dmin);
|
||||
/* Due to roundoff, 59.9999 could come out as "60.00" */
|
||||
if (smin[0] == '6') {
|
||||
smin[0] = '0';
|
||||
|
@ -197,6 +199,7 @@ void longitude_to_str (double dlong, int ambiguity, char *slong)
|
|||
* Inputs: dlat - Floating point degrees.
|
||||
*
|
||||
* Outputs: slat - String in format yyyy.
|
||||
* Exactly 4 bytes, no nul terminator.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
@ -243,6 +246,7 @@ void latitude_to_comp_str (double dlat, char *clat)
|
|||
* Inputs: dlong - Floating point degrees.
|
||||
*
|
||||
* Outputs: slat - String in format xxxx.
|
||||
* Exactly 4 bytes, no nul terminator.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
@ -330,7 +334,7 @@ void latitude_to_nmea (double dlat, char *slat, char *hemi)
|
|||
ideg = (int)dlat;
|
||||
dmin = (dlat - ideg) * 60.;
|
||||
|
||||
sprintf (smin, "%07.4f", dmin);
|
||||
snprintf (smin, sizeof(smin), "%07.4f", dmin);
|
||||
/* Due to roundoff, 59.99999 could come out as "60.0000" */
|
||||
if (smin[0] == '6') {
|
||||
smin[0] = '0';
|
||||
|
@ -391,7 +395,7 @@ void longitude_to_nmea (double dlong, char *slong, char *hemi)
|
|||
ideg = (int)dlong;
|
||||
dmin = (dlong - ideg) * 60.;
|
||||
|
||||
sprintf (smin, "%07.4f", dmin);
|
||||
snprintf (smin, sizeof(smin), "%07.4f", dmin);
|
||||
/* Due to roundoff, 59.99999 could come out as "60.0000" */
|
||||
if (smin[0] == '6') {
|
||||
smin[0] = '0';
|
||||
|
@ -426,7 +430,6 @@ void longitude_to_nmea (double dlong, char *slong, char *hemi)
|
|||
* Bugs: Very little validation of data.
|
||||
*
|
||||
* Errors: Return constant G_UNKNOWN for any type of error.
|
||||
* Could we use special "NaN" code?
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
|
@ -490,7 +493,6 @@ double latitude_from_nmea (char *pstr, char *phemi)
|
|||
* Bugs: Very little validation of data.
|
||||
*
|
||||
* Errors: Return constant G_UNKNOWN for any type of error.
|
||||
* Could we use special "NaN" code?
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
|
@ -559,16 +561,14 @@ double ll_distance_km (double lat1, double lon1, double lat2, double lon2)
|
|||
*
|
||||
* Purpose: Convert Maidenhead locator to latitude and longitude.
|
||||
*
|
||||
* Inputs: maidenhead - 2, 4, 6, or 8 character grid square locator.
|
||||
* Inputs: maidenhead - 2, 4, 6, 8, 10, or 12 character grid square locator.
|
||||
*
|
||||
* Outputs: dlat, dlon - Latitude and longitude.
|
||||
* Original values unchanged if error.
|
||||
*
|
||||
* Returns: 1 for success, 0 if error.
|
||||
*
|
||||
* Bug: This does not check for invalid values.
|
||||
*
|
||||
* Reference: A good converter for spot checking:
|
||||
* Reference: A good converter for spot checking. Only handles 4 or 6 characters :-(
|
||||
* http://home.arcor.de/waldemar.kebsch/The_Makrothen_Contest/fmaidenhead.html
|
||||
*
|
||||
* Rambling: What sort of resolution does this provide?
|
||||
|
@ -577,14 +577,87 @@ double ll_distance_km (double lat1, double lon1, double lat2, double lon2)
|
|||
* 6371 km * 2 * pi * 0.25 / 60 / 360 = 0.463 km. Is that right?
|
||||
*
|
||||
* Using this calculator, http://www.earthpoint.us/Convert.aspx
|
||||
* It gives lower left corner of square rather than the middle. :-(
|
||||
*
|
||||
* FN42MA00 --> 19T 334361mE 4651711mN
|
||||
* FN42MA11 --> 19T 335062mE 4652157mN
|
||||
* ------ -------
|
||||
* 701 446 meters difference.
|
||||
*
|
||||
* With another two pairs, we are down around 2 meters for latitude.
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#define MH_MIN_PAIR 1
|
||||
#define MH_MAX_PAIR 6
|
||||
#define MH_UNITS ( 18 * 10 * 24 * 10 * 24 * 10 * 2 )
|
||||
|
||||
static const struct {
|
||||
char *position;
|
||||
char min_ch;
|
||||
char max_ch;
|
||||
int value;
|
||||
} mh_pair[MH_MAX_PAIR] = {
|
||||
{ "first", 'A', 'R', 10 * 24 * 10 * 24 * 10 * 2 },
|
||||
{ "second", '0', '9', 24 * 10 * 24 * 10 * 2 },
|
||||
{ "third", 'A', 'X', 10 * 24 * 10 * 2 },
|
||||
{ "fourth", '0', '9', 24 * 10 * 2 },
|
||||
{ "fifth", 'A', 'X', 10 * 2 },
|
||||
{ "sixth", '0', '9', 2 } }; // Even so we can get center of square.
|
||||
|
||||
|
||||
|
||||
#if 1
|
||||
|
||||
int ll_from_grid_square (char *maidenhead, double *dlat, double *dlon)
|
||||
{
|
||||
char mh[16]; /* Local copy, changed to upper case. */
|
||||
int ilat = 0, ilon = 0; /* In units in table above. */
|
||||
char *p;
|
||||
int n;
|
||||
|
||||
int np = strlen(maidenhead) / 2; /* Number of pairs of characters. */
|
||||
|
||||
if (strlen(maidenhead) %2 != 0 || np < MH_MIN_PAIR || np > MH_MAX_PAIR) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("Maidenhead locator \"%s\" must from 1 to %d pairs of characters.\n", maidenhead, MH_MAX_PAIR);
|
||||
return (0);
|
||||
}
|
||||
|
||||
strlcpy (mh, maidenhead, sizeof(mh));
|
||||
for (p = mh; *p != '\0'; p++) {
|
||||
if (islower(*p)) *p = toupper(*p);
|
||||
}
|
||||
|
||||
for (n = 0; n < np; n++) {
|
||||
|
||||
if (mh[2*n] < mh_pair[n].min_ch || mh[2*n] > mh_pair[n].max_ch ||
|
||||
mh[2*n+1] < mh_pair[n].min_ch || mh[2*n+1] > mh_pair[n].max_ch) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("The %s pair of characters in Maidenhead locator \"%s\" must be in range of %c thru %c.\n",
|
||||
mh_pair[n].position, maidenhead, mh_pair[n].min_ch, mh_pair[n].max_ch);
|
||||
return (0);
|
||||
}
|
||||
|
||||
ilon += ( mh[2*n] - mh_pair[n].min_ch ) * mh_pair[n].value;
|
||||
ilat += ( mh[2*n+1] - mh_pair[n].min_ch ) * mh_pair[n].value;
|
||||
|
||||
if (n == np-1) { // If last pair, take center of square.
|
||||
ilon += mh_pair[n].value / 2;
|
||||
ilat += mh_pair[n].value / 2;
|
||||
}
|
||||
}
|
||||
|
||||
*dlat = (double)ilat / MH_UNITS * 180. - 90.;
|
||||
*dlon = (double)ilon / MH_UNITS * 360. - 180.;
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf("DEBUG: Maidenhead conversion \"%s\" -> %.6f %.6f\n", maidenhead, *dlat, *dlon);
|
||||
|
||||
return (1);
|
||||
}
|
||||
#else
|
||||
|
||||
int ll_from_grid_square (char *maidenhead, double *dlat, double *dlon)
|
||||
{
|
||||
double lat, lon;
|
||||
|
@ -687,6 +760,142 @@ int ll_from_grid_square (char *maidenhead, double *dlat, double *dlon)
|
|||
return (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* end ll_from_grid_square */
|
||||
|
||||
|
||||
#if LLTEST
|
||||
|
||||
/* gcc -o lltest -DLLTEST latlong.c textcolor.o misc.a && lltest */
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
char result[20];
|
||||
int errors = 0;
|
||||
int ok;
|
||||
double dlat, dlon;
|
||||
|
||||
/* Latitude to APRS format. */
|
||||
|
||||
latitude_to_str (45.25, 0, result);
|
||||
if (strcmp(result, "4515.00N") != 0) { errors++; dw_printf ("Error 1.1: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_str (-45.25, 0, result);
|
||||
if (strcmp(result, "4515.00S") != 0) { errors++; dw_printf ("Error 1.2: Did not expect \"%s\"\n", result); }
|
||||
|
||||
|
||||
latitude_to_str (45.999830, 0, result);
|
||||
if (strcmp(result, "4559.99N") != 0) { errors++; dw_printf ("Error 1.3: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_str (45.99999, 0, result);
|
||||
if (strcmp(result, "4600.00N") != 0) { errors++; dw_printf ("Error 1.4: Did not expect \"%s\"\n", result); }
|
||||
|
||||
|
||||
latitude_to_str (45.999830, 1, result);
|
||||
if (strcmp(result, "4559.9 N") != 0) { errors++; dw_printf ("Error 1.5: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_str (45.999830, 2, result);
|
||||
if (strcmp(result, "4559. N") != 0) { errors++; dw_printf ("Error 1.6: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_str (45.999830, 3, result);
|
||||
if (strcmp(result, "455 . N") != 0) { errors++; dw_printf ("Error 1.7: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_str (45.999830, 4, result);
|
||||
if (strcmp(result, "45 . N") != 0) { errors++; dw_printf ("Error 1.8: Did not expect \"%s\"\n", result); }
|
||||
|
||||
/* Longitude to APRS format. */
|
||||
|
||||
longitude_to_str (45.25, 0, result);
|
||||
if (strcmp(result, "04515.00E") != 0) { errors++; dw_printf ("Error 2.1: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_str (-45.25, 0, result);
|
||||
if (strcmp(result, "04515.00W") != 0) { errors++; dw_printf ("Error 2.2: Did not expect \"%s\"\n", result); }
|
||||
|
||||
|
||||
longitude_to_str (45.999830, 0, result);
|
||||
if (strcmp(result, "04559.99E") != 0) { errors++; dw_printf ("Error 2.3: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_str (45.99999, 0, result);
|
||||
if (strcmp(result, "04600.00E") != 0) { errors++; dw_printf ("Error 2.4: Did not expect \"%s\"\n", result); }
|
||||
|
||||
|
||||
longitude_to_str (45.999830, 1, result);
|
||||
if (strcmp(result, "04559.9 E") != 0) { errors++; dw_printf ("Error 2.5: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_str (45.999830, 2, result);
|
||||
if (strcmp(result, "04559. E") != 0) { errors++; dw_printf ("Error 2.6: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_str (45.999830, 3, result);
|
||||
if (strcmp(result, "0455 . E") != 0) { errors++; dw_printf ("Error 2.7: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_str (45.999830, 4, result);
|
||||
if (strcmp(result, "045 . E") != 0) { errors++; dw_printf ("Error 2.8: Did not expect \"%s\"\n", result); }
|
||||
|
||||
/* Compressed format. */
|
||||
/* Protocol spec example has <*e7 but I got <*e8 due to rounding rather than truncation to integer. */
|
||||
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
latitude_to_comp_str (-90.0, result);
|
||||
if (strcmp(result, "{{!!") != 0) { errors++; dw_printf ("Error 3.1: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_comp_str (49.5, result);
|
||||
if (strcmp(result, "5L!!") != 0) { errors++; dw_printf ("Error 3.2: Did not expect \"%s\"\n", result); }
|
||||
|
||||
latitude_to_comp_str (90.0, result);
|
||||
if (strcmp(result, "!!!!") != 0) { errors++; dw_printf ("Error 3.3: Did not expect \"%s\"\n", result); }
|
||||
|
||||
|
||||
longitude_to_comp_str (-180.0, result);
|
||||
if (strcmp(result, "!!!!") != 0) { errors++; dw_printf ("Error 3.4: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_comp_str (-72.75, result);
|
||||
if (strcmp(result, "<*e8") != 0) { errors++; dw_printf ("Error 3.5: Did not expect \"%s\"\n", result); }
|
||||
|
||||
longitude_to_comp_str (180.0, result);
|
||||
if (strcmp(result, "{{!!") != 0) { errors++; dw_printf ("Error 3.6: Did not expect \"%s\"\n", result); }
|
||||
|
||||
// to be continued for others... NMEA...
|
||||
|
||||
|
||||
/* Maidenhead locator to lat/long. */
|
||||
|
||||
|
||||
ok = ll_from_grid_square ("BL11", &dlat, &dlon);
|
||||
if (!ok || dlat < 20.4999999 || dlat > 21.5000001 || dlon < -157.0000001 || dlon > -156.9999999) { errors++; dw_printf ("Error 7.1: Did not expect %.6f %.6f\n", dlat, dlon); }
|
||||
|
||||
ok = ll_from_grid_square ("BL11BH", &dlat, &dlon);
|
||||
if (!ok || dlat < 21.31249 || dlat > 21.31251 || dlon < -157.87501 || dlon > -157.87499) { errors++; dw_printf ("Error 7.2: Did not expect %.6f %.6f\n", dlat, dlon); }
|
||||
|
||||
#if 0 // TODO: add more test cases after comparing results with other cconverters.
|
||||
// Many other converters are limited to smaller number of characters,
|
||||
// or return corner rather than center of square, or return 3 decimal places for degrees.
|
||||
|
||||
ok = ll_from_grid_square ("BL11BH16", &dlat, &dlon);
|
||||
if (!ok || dlat < 21.? || dlat > 21.? || dlon < -157.? || dlon > -157.?) { errors++; dw_printf ("Error 7.3: Did not expect %.6f %.6f\n", dlat, dlon); }
|
||||
|
||||
ok = ll_from_grid_square ("BL11BH16oo", &dlat, &dlon);
|
||||
if (!ok || dlat < 21.? || dlat > 21.? || dlon < -157.? || dlon > -157.?) { errors++; dw_printf ("Error 7.4: Did not expect %.6f %.6f\n", dlat, dlon); }
|
||||
|
||||
ok = ll_from_grid_square ("BL11BH16oo66", &dlat, &dlon);
|
||||
if (!ok || dlat < 21.? || dlat > 21.? || dlon < -157.? || dlon > -157.?) { errors++; dw_printf ("Error 7.5: Did not expect %.6f %.6f\n", dlat, dlon); }
|
||||
#endif
|
||||
if (errors > 0) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("\nLocation Coordinate Conversion Test - FAILED!\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
text_color_set (DW_COLOR_REC);
|
||||
dw_printf ("\nLocation Coordinate Conversion Test - SUCCESS!\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* end latlong.c */
|
74
log.c
74
log.c
|
@ -54,7 +54,7 @@
|
|||
* CSV format needs quotes if value contains comma or quote.
|
||||
*/
|
||||
|
||||
static void quote_for_csv (char *out, const char *in) {
|
||||
static void quote_for_csv (char *out, size_t outsize, const char *in) {
|
||||
const char *p;
|
||||
char *q = out;
|
||||
int need_quote = 0;
|
||||
|
@ -66,6 +66,8 @@ static void quote_for_csv (char *out, const char *in) {
|
|||
}
|
||||
}
|
||||
|
||||
// BUG: need to avoid buffer overflow on "out". *strcpy*
|
||||
|
||||
if (need_quote) {
|
||||
*q++ = '"';
|
||||
for (p = in; *p != '\0'; p++) {
|
||||
|
@ -78,7 +80,7 @@ static void quote_for_csv (char *out, const char *in) {
|
|||
*q = '\0';
|
||||
}
|
||||
else {
|
||||
strcpy (out, in);
|
||||
strlcpy (out, in, outsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,9 +110,9 @@ void log_init (char *path)
|
|||
{
|
||||
struct stat st;
|
||||
|
||||
strcpy (g_log_dir, "");
|
||||
strlcpy (g_log_dir, "", sizeof(g_log_dir));
|
||||
g_log_fp = NULL;
|
||||
strcpy (g_open_fname, "");
|
||||
strlcpy (g_open_fname, "", sizeof(g_open_fname));
|
||||
|
||||
if (strlen(path) == 0) {
|
||||
return;
|
||||
|
@ -120,13 +122,13 @@ void log_init (char *path)
|
|||
// Exists, but is it a directory?
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
// Specified directory exists.
|
||||
strcpy (g_log_dir, path);
|
||||
strlcpy (g_log_dir, path, sizeof(g_log_dir));
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Log file location \"%s\" is not a directory.\n", path);
|
||||
dw_printf ("Using current working directory \".\" instead.\n");
|
||||
strcpy (g_log_dir, ".");
|
||||
strlcpy (g_log_dir, ".", sizeof(g_log_dir));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -141,14 +143,14 @@ void log_init (char *path)
|
|||
// Success.
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Log file location \"%s\" has been created.\n", path);
|
||||
strcpy (g_log_dir, path);
|
||||
strlcpy (g_log_dir, path, sizeof(g_log_dir));
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Failed to create log file location \"%s\".\n", path);
|
||||
dw_printf ("%s\n", strerror(errno));
|
||||
dw_printf ("Using current working directory \".\" instead.\n");
|
||||
strcpy (g_log_dir, ".");
|
||||
strlcpy (g_log_dir, ".", sizeof(g_log_dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +187,7 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
// Generate the file name from current date, UTC.
|
||||
|
||||
now = time(NULL);
|
||||
gmtime_r (&now, &tm);
|
||||
(void)gmtime_r (&now, &tm);
|
||||
|
||||
// Microsoft doesn't recognize %F as equivalent to %Y-%m-%d
|
||||
|
||||
|
@ -204,13 +206,13 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
struct stat st;
|
||||
int already_there;
|
||||
|
||||
strcpy (full_path, g_log_dir);
|
||||
strlcpy (full_path, g_log_dir, sizeof(full_path));
|
||||
#if __WIN32__
|
||||
strcat (full_path, "\\");
|
||||
strlcat (full_path, "\\", sizeof(full_path));
|
||||
#else
|
||||
strcat (full_path, "/");
|
||||
strlcat (full_path, "/", sizeof(full_path));
|
||||
#endif
|
||||
strcat (full_path, fname);
|
||||
strlcat (full_path, fname, sizeof(full_path));
|
||||
|
||||
// See if it already exists.
|
||||
// This is used later to write a header if it did not exist already.
|
||||
|
@ -223,13 +225,13 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
g_log_fp = fopen (full_path, "a");
|
||||
|
||||
if (g_log_fp != NULL) {
|
||||
strcpy (g_open_fname, fname);
|
||||
strlcpy (g_open_fname, fname, sizeof(g_open_fname));
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("Can't open log file \"%s\" for write.\n", full_path);
|
||||
dw_printf ("%s\n", strerror(errno));
|
||||
strcpy (g_open_fname, "");
|
||||
strlcpy (g_open_fname, "", sizeof(g_open_fname));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -267,12 +269,12 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
/* Who are we hearing? Original station or digipeater? */
|
||||
/* Similar code in direwolf.c. Combine into one function? */
|
||||
|
||||
strcpy(heard, "");
|
||||
strlcpy(heard, "", sizeof(heard));
|
||||
if (pp != NULL) {
|
||||
if (ax25_get_num_addr(pp) == 0) {
|
||||
/* Not AX.25. No station to display below. */
|
||||
h = -1;
|
||||
strcpy (heard, "");
|
||||
strlcpy (heard, "", sizeof(heard));
|
||||
}
|
||||
else {
|
||||
h = ax25_get_heard(pp);
|
||||
|
@ -285,7 +287,7 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
heard[5] == '\0') {
|
||||
|
||||
ax25_get_addr_with_ssid(pp, h-1, heard);
|
||||
strcat (heard, "?");
|
||||
strlcat (heard, "?", sizeof(heard));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,35 +296,35 @@ void log_write (int chan, decode_aprs_t *A, packet_t pp, alevel_t alevel, retry_
|
|||
|
||||
// Might need to quote anything that could contain comma or quote.
|
||||
|
||||
strcpy(sdti, "");
|
||||
strlcpy(sdti, "", sizeof(sdti));
|
||||
if (pp != NULL) {
|
||||
stemp[0] = ax25_get_dti(pp);
|
||||
stemp[1] = '\0';
|
||||
quote_for_csv (sdti, stemp);
|
||||
quote_for_csv (sdti, sizeof(sdti), stemp);
|
||||
}
|
||||
|
||||
quote_for_csv (sname, (strlen(A->g_name) > 0) ? A->g_name : A->g_src);
|
||||
quote_for_csv (sname, sizeof(sname), (strlen(A->g_name) > 0) ? A->g_name : A->g_src);
|
||||
|
||||
stemp[0] = A->g_symbol_table;
|
||||
stemp[1] = A->g_symbol_code;
|
||||
stemp[2] = '\0';
|
||||
quote_for_csv (ssymbol, stemp);
|
||||
quote_for_csv (ssymbol, sizeof(ssymbol), stemp);
|
||||
|
||||
quote_for_csv (smfr, A->g_mfr);
|
||||
quote_for_csv (sstatus, A->g_mic_e_status);
|
||||
quote_for_csv (stelemetry, A->g_telemetry);
|
||||
quote_for_csv (scomment, A->g_comment);
|
||||
quote_for_csv (smfr, sizeof(smfr), A->g_mfr);
|
||||
quote_for_csv (sstatus, sizeof(sstatus), A->g_mic_e_status);
|
||||
quote_for_csv (stelemetry, sizeof(stelemetry), A->g_telemetry);
|
||||
quote_for_csv (scomment, sizeof(scomment), A->g_comment);
|
||||
|
||||
strcpy (slat, ""); if (A->g_lat != G_UNKNOWN) sprintf (slat, "%.6f", A->g_lat);
|
||||
strcpy (slon, ""); if (A->g_lon != G_UNKNOWN) sprintf (slon, "%.6f", A->g_lon);
|
||||
strcpy (sspd, ""); if (A->g_speed != G_UNKNOWN) sprintf (sspd, "%.1f", DW_MPH_TO_KNOTS(A->g_speed));
|
||||
strcpy (scse, ""); if (A->g_course != G_UNKNOWN) sprintf (scse, "%.1f", A->g_course);
|
||||
strcpy (salt, ""); if (A->g_altitude != G_UNKNOWN) sprintf (salt, "%.1f", DW_FEET_TO_METERS(A->g_altitude));
|
||||
strlcpy (slat, "", sizeof(slat)); if (A->g_lat != G_UNKNOWN) snprintf (slat, sizeof(slat), "%.6f", A->g_lat);
|
||||
strlcpy (slon, "", sizeof(slon)); if (A->g_lon != G_UNKNOWN) snprintf (slon, sizeof(slon), "%.6f", A->g_lon);
|
||||
strlcpy (sspd, "", sizeof(sspd)); if (A->g_speed_mph != G_UNKNOWN) snprintf (sspd, sizeof(sspd), "%.1f", DW_MPH_TO_KNOTS(A->g_speed_mph));
|
||||
strlcpy (scse, "", sizeof(scse)); if (A->g_course != G_UNKNOWN) snprintf (scse, sizeof(scse), "%.1f", A->g_course);
|
||||
strlcpy (salt, "", sizeof(salt)); if (A->g_altitude_ft != G_UNKNOWN) snprintf (salt, sizeof(salt), "%.1f", DW_FEET_TO_METERS(A->g_altitude_ft));
|
||||
|
||||
strcpy (sfreq, ""); if (A->g_freq != G_UNKNOWN) sprintf (sfreq, "%.3f", A->g_freq);
|
||||
strcpy (soffs, ""); if (A->g_offset != G_UNKNOWN) sprintf (soffs, "%+d", A->g_offset);
|
||||
strcpy (stone, ""); if (A->g_tone != G_UNKNOWN) sprintf (stone, "%.1f", A->g_tone);
|
||||
if (A->g_dcs != G_UNKNOWN) sprintf (stone, "D%03o", A->g_dcs);
|
||||
strlcpy (sfreq, "", sizeof(sfreq)); if (A->g_freq != G_UNKNOWN) snprintf (sfreq, sizeof(sfreq), "%.3f", A->g_freq);
|
||||
strlcpy (soffs, "", sizeof(soffs)); if (A->g_offset != G_UNKNOWN) snprintf (soffs, sizeof(soffs), "%+d", A->g_offset);
|
||||
strlcpy (stone, "", sizeof(stone)); if (A->g_tone != G_UNKNOWN) snprintf (stone, sizeof(stone), "%.1f", A->g_tone);
|
||||
if (A->g_dcs != G_UNKNOWN) snprintf (stone, sizeof(stone), "D%03o", A->g_dcs);
|
||||
|
||||
fprintf (g_log_fp, "%d,%d,%s,%s,%s,%s,%d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||
chan, (int)now, itime,
|
||||
|
@ -359,7 +361,7 @@ void log_term (void)
|
|||
fclose (g_log_fp);
|
||||
|
||||
g_log_fp = NULL;
|
||||
strcpy (g_open_fname, "");
|
||||
strlcpy (g_open_fname, "", sizeof(g_open_fname));
|
||||
}
|
||||
|
||||
} /* end log_term */
|
||||
|
|
44
log2gpx.c
44
log2gpx.c
|
@ -27,6 +27,8 @@
|
|||
char *strsep(char **stringp, const char *delim);
|
||||
#endif
|
||||
|
||||
#include "direwolf.h"
|
||||
|
||||
|
||||
/*
|
||||
* Information we gather for each thing.
|
||||
|
@ -228,6 +230,20 @@ static void read_csv(FILE *fp)
|
|||
ptelemetry = strsep(&next,"\t"); /* Currently unused. Add to description? */
|
||||
pcomment = strsep(&next,"\t");
|
||||
|
||||
/* Suppress the 'set but not used' warnings. */
|
||||
/* Alternatively, we might use __attribute__((unused)) */
|
||||
|
||||
(void)(ptelemetry);
|
||||
(void)(psystem);
|
||||
(void)(psymbol);
|
||||
(void)(pdti);
|
||||
(void)(perror);
|
||||
(void)(plevel);
|
||||
(void)(pheard);
|
||||
(void)(psource);
|
||||
(void)(putime);
|
||||
|
||||
|
||||
/*
|
||||
* Skip header line with names of fields.
|
||||
*/
|
||||
|
@ -265,42 +281,42 @@ static void read_csv(FILE *fp)
|
|||
|
||||
if (pfreq != NULL && strlen(pfreq) > 0) {
|
||||
freq = atof(pfreq);
|
||||
sprintf (desc, "%.3f MHz", freq);
|
||||
snprintf (desc, sizeof(desc), "%.3f MHz", freq);
|
||||
}
|
||||
else {
|
||||
strcpy (desc, "");
|
||||
strlcpy (desc, "", sizeof(desc));
|
||||
}
|
||||
|
||||
if (poffset != NULL && strlen(poffset) > 0) {
|
||||
offset = atoi(poffset);
|
||||
if (offset != 0 && offset % 1000 == 0) {
|
||||
sprintf (stemp, "%+dM", offset / 1000);
|
||||
snprintf (stemp, sizeof(stemp), "%+dM", offset / 1000);
|
||||
}
|
||||
else {
|
||||
sprintf (stemp, "%+dk", offset);
|
||||
snprintf (stemp, sizeof(stemp), "%+dk", offset);
|
||||
}
|
||||
if (strlen(desc) > 0) strcat (desc, " ");
|
||||
strcat (desc, stemp);
|
||||
if (strlen(desc) > 0) strlcat (desc, " ", sizeof(desc));
|
||||
strlcat (desc, stemp, sizeof(desc));
|
||||
}
|
||||
|
||||
if (ptone != NULL && strlen(ptone) > 0) {
|
||||
if (*ptone == 'D') {
|
||||
sprintf (stemp, "DCS %s", ptone+1);
|
||||
snprintf (stemp, sizeof(stemp), "DCS %s", ptone+1);
|
||||
}
|
||||
else {
|
||||
sprintf (stemp, "PL %s", ptone);
|
||||
snprintf (stemp, sizeof(stemp), "PL %s", ptone);
|
||||
}
|
||||
if (strlen(desc) > 0) strcat (desc, " ");
|
||||
strcat (desc, stemp);
|
||||
if (strlen(desc) > 0) strlcat (desc, " ", sizeof(desc));
|
||||
strlcat (desc, stemp, sizeof(desc));
|
||||
}
|
||||
|
||||
strcpy (comment, "");
|
||||
strlcpy (comment, "", sizeof(comment));
|
||||
if (pstatus != NULL && strlen(pstatus) > 0) {
|
||||
strcpy (comment, pstatus);
|
||||
strlcpy (comment, pstatus, sizeof(comment));
|
||||
}
|
||||
if (pcomment != NULL && strlen(pcomment) > 0) {
|
||||
if (strlen(comment) > 0) strcat (comment, ", ");
|
||||
strcat (comment, pcomment);
|
||||
if (strlen(comment) > 0) strlcat (comment, ", ", sizeof(comment));
|
||||
strlcat (comment, pcomment, sizeof(comment));
|
||||
}
|
||||
|
||||
if (num_things == max_things) {
|
||||
|
|
|
@ -77,7 +77,9 @@ u = Display non-ASCII text in hexadecimal.
|
|||
.P
|
||||
p = Packet dump in hexadecimal.
|
||||
.P
|
||||
t = GPS Tracker.
|
||||
g = GPS interface.
|
||||
.P
|
||||
t = Tracker beacon.
|
||||
.P
|
||||
o = Output controls such as PTT and DCD.
|
||||
.RE
|
||||
|
|
2
morse.c
2
morse.c
|
@ -36,7 +36,7 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
|
328
nmea.c
328
nmea.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2014 John Langner, WB2OSZ
|
||||
// Copyright (C) 2014, 2015 John Langner, WB2OSZ
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,6 +20,9 @@
|
|||
|
||||
//#define DEBUG 1
|
||||
|
||||
|
||||
// TODO: rename this to waypoint & integrate.
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
*
|
||||
* Module: nmea.c
|
||||
|
@ -73,13 +76,9 @@ static MYFDTYPE nmea_port_fd = MYFDERROR;
|
|||
|
||||
static void nmea_send_sentence (char *sent);
|
||||
|
||||
#if __WIN32__
|
||||
static unsigned __stdcall nmea_listen_thread (void *arg);
|
||||
#else
|
||||
static void * nmea_listen_thread (void *arg);
|
||||
#endif
|
||||
|
||||
static void nmea_parse_gps (char *sentence);
|
||||
|
||||
//static void nmea_parse_gps (char *sentence);
|
||||
|
||||
|
||||
static int nmea_debug = 0; /* Print information flowing from and to attached device. */
|
||||
|
@ -102,7 +101,6 @@ void nmea_set_debug (int n)
|
|||
*
|
||||
*
|
||||
* Description: (1) Open serial port device.
|
||||
* (2) Start a new thread to listen for GPS receiver.
|
||||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
|
@ -110,12 +108,6 @@ void nmea_set_debug (int n)
|
|||
void nmea_init (struct misc_config_s *mc)
|
||||
{
|
||||
|
||||
#if __WIN32__
|
||||
HANDLE nmea_listen_th;
|
||||
#else
|
||||
pthread_t nmea_listen_tid;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Open serial port connection.
|
||||
* 4800 baud is standard for GPS.
|
||||
|
@ -125,25 +117,8 @@ void nmea_init (struct misc_config_s *mc)
|
|||
|
||||
nmea_port_fd = serial_port_open (mc->nmea_port, 4800);
|
||||
|
||||
if (nmea_port_fd != MYFDERROR) {
|
||||
#if __WIN32__
|
||||
nmea_listen_th = (HANDLE)_beginthreadex (NULL, 0, nmea_listen_thread, (void*)(long)nmea_port_fd, 0, NULL);
|
||||
if (nmea_listen_th == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create NMEA listening thread.\n");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int e;
|
||||
e = pthread_create (&nmea_listen_tid, NULL, nmea_listen_thread, (void*)(long)nmea_port_fd);
|
||||
if (e != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Could not create NMEA listening thread.");
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
@ -231,7 +206,7 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
char sspeed[12]; /* speed as string, empty if unknown */
|
||||
char scourse[12]; /* course as string, empty if unknown */
|
||||
int grm_sym; /* Garmin symbol code. */
|
||||
char sicon[4]; /* Magellan icon string */
|
||||
char sicon[5]; /* Magellan icon string */
|
||||
char stime[8];
|
||||
char sdate[8];
|
||||
char *p;
|
||||
|
@ -265,7 +240,7 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
* *99 is checksum
|
||||
*/
|
||||
|
||||
sprintf (sentence, "$GPWPL,%s,%s,%s,%s,%s", slat, slat_ns, slong, slong_ew, wname);
|
||||
snprintf (sentence, sizeof(sentence), "$GPWPL,%s,%s,%s,%s,%s", slat, slat_ns, slong, slong_ew, wname);
|
||||
append_checksum (sentence);
|
||||
nmea_send_sentence (sentence);
|
||||
|
||||
|
@ -291,11 +266,11 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
strcpy (salt, "");
|
||||
}
|
||||
else {
|
||||
sprintf (salt, "%.1f", alt);
|
||||
snprintf (salt, sizeof(salt), "%.1f", alt);
|
||||
}
|
||||
grm_sym = 0x1234; // TODO
|
||||
|
||||
sprintf (sentence, "$PGRMW,%s,%s,%04X,%s", wname, salt, grm_sym, comment);
|
||||
snprintf (sentence, sizeof(sentence), "$PGRMW,%s,%s,%04X,%s", wname, salt, grm_sym, comment);
|
||||
append_checksum (sentence);
|
||||
nmea_send_sentence (sentence);
|
||||
|
||||
|
@ -319,8 +294,8 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
|
||||
// TODO: icon
|
||||
|
||||
sprintf (sicon, "??");
|
||||
sprintf (sentence, "$PMGNWPL,%s,%s,%s,%s,%s,M,%s,%s,%s",
|
||||
snprintf (sicon, sizeof(sicon), "??");
|
||||
snprintf (sentence, sizeof(sentence), "$PMGNWPL,%s,%s,%s,%s,%s,M,%s,%s,%s",
|
||||
slat, slat_ns, slong, slong_ew, salt, wname, comment, sicon);
|
||||
append_checksum (sentence);
|
||||
nmea_send_sentence (sentence);
|
||||
|
@ -357,13 +332,13 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
strcpy (sspeed, "");
|
||||
}
|
||||
else {
|
||||
sprintf (sspeed, "%.1f", speed);
|
||||
snprintf (sspeed, sizeof(sspeed), "%.1f", speed);
|
||||
}
|
||||
if (course == G_UNKNOWN) {
|
||||
strcpy (scourse, "");
|
||||
}
|
||||
else {
|
||||
sprintf (scourse, "%.1f", course);
|
||||
snprintf (scourse, sizeof(scourse), "%.1f", course);
|
||||
}
|
||||
|
||||
// TODO: how to handle time & date ???
|
||||
|
@ -371,7 +346,7 @@ void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab,
|
|||
strcpy (stime, "123456");
|
||||
strcpy (sdate, "123456");
|
||||
|
||||
sprintf (sentence, "$PKWDWPL,%s,V,%s,%s,%s,%s,%s,%s,%s,%s,%s,%c%c",
|
||||
snprintf (sentence, sizeof(sentence), "$PKWDWPL,%s,V,%s,%s,%s,%s,%s,%s,%s,%s,%s,%c%c",
|
||||
stime, slat, slat_ns, slong, slong_ew,
|
||||
sspeed, scourse, sdate, salt, wname, symtab, symbol);
|
||||
append_checksum (sentence);
|
||||
|
@ -434,7 +409,7 @@ http://gpsbabel.sourcearchive.com/documentation/1.3.7~cvs1/magproto_8c-source.ht
|
|||
&lngdeg,&lngdir,
|
||||
&alt,&altunits,shortname,descr); then icon
|
||||
|
||||
sprintf(obuf, "PMGNWPL,%4.3f,%c,%09.3f,%c,%07.0f,M,%-.*s,%-.46s,%s",
|
||||
snprintf(obuf, sizeof(), "PMGNWPL,%4.3f,%c,%09.3f,%c,%07.0f,M,%-.*s,%-.46s,%s",
|
||||
lat, ilat < 0 ? 'S' : 'N',
|
||||
lon, ilon < 0 ? 'W' : 'E',
|
||||
waypointp->altitude == unknown_alt ?
|
||||
|
@ -485,277 +460,6 @@ static void nmea_send_sentence (char *sent)
|
|||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: nmea_listen_thread
|
||||
*
|
||||
* Purpose: Wait for messages from GPS receiver.
|
||||
*
|
||||
* Inputs: arg - File descriptor for reading.
|
||||
*
|
||||
* Outputs: pt_slave_fd - File descriptor for communicating with client app.
|
||||
*
|
||||
* Description: Process messages from the client application.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Maximum length of message from GPS receiver.
|
||||
// 82 according to some people. Larger to be safe.
|
||||
|
||||
#define NMEA_MAX_LEN 120
|
||||
|
||||
static char gps_msg[NMEA_MAX_LEN];
|
||||
int gps_msg_len = 0;
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
static unsigned __stdcall nmea_listen_thread (void *arg)
|
||||
#else
|
||||
static void * nmea_listen_thread (void *arg)
|
||||
#endif
|
||||
{
|
||||
MYFDTYPE fd = (MYFDTYPE)(long)arg;
|
||||
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("nmea_listen_thread ( %d )\n", fd);
|
||||
#endif
|
||||
|
||||
|
||||
while (1) {
|
||||
int ch;
|
||||
|
||||
ch = serial_port_get1(fd);
|
||||
|
||||
|
||||
// TODO: if ch < 0, terminate thread ...
|
||||
|
||||
//CloseHandle (fd);
|
||||
//fd = MYFDERROR;
|
||||
//pthread_exit (NULL);
|
||||
|
||||
//text_color_set(DW_COLOR_ERROR);
|
||||
//dw_printf ("\nError trying to read from GPS receiver. Closing connection %d.\n\n", fd);
|
||||
|
||||
//close (fd); -> serial_port_close(fd)
|
||||
|
||||
//fd = MYFDERROR;
|
||||
//pthread_exit (NULL);
|
||||
|
||||
|
||||
if (ch == '$') {
|
||||
// Start of new sentence.
|
||||
gps_msg_len = 0;
|
||||
gps_msg[gps_msg_len++] = ch;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
else if (ch == '\r' || ch == '\n') {
|
||||
if (gps_msg_len >= 6 && gps_msg[0] == '$') {
|
||||
nmea_parse_gps (gps_msg);
|
||||
text_color_set(DW_COLOR_REC);
|
||||
dw_printf ("%s\n", gps_msg);
|
||||
}
|
||||
gps_msg_len = 0;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
else {
|
||||
if (gps_msg_len < NMEA_MAX_LEN-1) {
|
||||
gps_msg[gps_msg_len++] = ch;
|
||||
gps_msg[gps_msg_len] = '\0';
|
||||
}
|
||||
}
|
||||
} /* while (1) */
|
||||
|
||||
return (NULL); /* Unreachable but avoids compiler warning. */
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
*
|
||||
* Name: ...
|
||||
*
|
||||
* Purpose: ...
|
||||
*
|
||||
* Inputs: ...
|
||||
*
|
||||
* Outputs: ...
|
||||
*
|
||||
* Description: ...
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
||||
static void remove_checksum (char *sent)
|
||||
{
|
||||
char *p;
|
||||
char *next;
|
||||
unsigned char cs;
|
||||
|
||||
|
||||
// Do we have valid checksum?
|
||||
|
||||
cs = 0;
|
||||
for (p = sent+1; *p != '*' && *p != '\0'; p++) {
|
||||
cs ^= *p;
|
||||
}
|
||||
|
||||
p = strchr (sent, '*');
|
||||
if (p == NULL) {
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
dw_printf("Missing GPS checksum.\n");
|
||||
return;
|
||||
}
|
||||
if (cs != strtoul(p+1, NULL, 16)) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf("GPS checksum error. Expected %02x but found %s.\n", cs, p+1);
|
||||
return;
|
||||
}
|
||||
*p = '\0'; // Remove the checksum.
|
||||
}
|
||||
|
||||
static void nmea_parse_gps (char *sentence)
|
||||
{
|
||||
|
||||
char stemp[NMEA_MAX_LEN];
|
||||
char *ptype;
|
||||
char *next;
|
||||
double g_lat, g_lon;
|
||||
float g_speed, g_course;
|
||||
static float g_alt = G_UNKNOWN;
|
||||
int fix; /* 0=none, 2=2D, 3=3D */
|
||||
|
||||
strcpy (stemp, sentence);
|
||||
|
||||
// TODO: process only if good.
|
||||
remove_checksum (stemp);
|
||||
|
||||
next = stemp;
|
||||
ptype = strsep(&next, ",");
|
||||
|
||||
|
||||
// $GPRMC has everything we care about except altitude.
|
||||
//
|
||||
// Examples: $GPRMC,212404.000,V,4237.1505,N,07120.8602,W,,,150614,,*0B
|
||||
// $GPRMC,000029.020,V,,,,,,,080810,,,N*45
|
||||
// $GPRMC,003413.710,A,4237.1240,N,07120.8333,W,5.07,291.42,160614,,,A*7F
|
||||
|
||||
if (strcmp(ptype, "$GPRMC") == 0)
|
||||
{
|
||||
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *pstatus; /* Status, A=Active (valid position), V=Void */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pknots; /* Speed over ground, knots. */
|
||||
char *pcourse; /* True course, degrees. */
|
||||
char *pdate; /* Date, ddmmyy */
|
||||
/* Magnetic variation */
|
||||
/* In version 3.00, mode is added: A D E N (see below) */
|
||||
/* Checksum */
|
||||
|
||||
ptime = strsep(&next, ",");
|
||||
pstatus = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pknots = strsep(&next, ",");
|
||||
pcourse = strsep(&next, ",");
|
||||
pdate = strsep(&next, ",");
|
||||
|
||||
|
||||
g_lat = G_UNKNOWN;
|
||||
g_lon = G_UNKNOWN;
|
||||
g_speed = G_UNKNOWN;
|
||||
g_course = G_UNKNOWN;
|
||||
|
||||
if (plat != NULL && strlen(plat) > 0) {
|
||||
g_lat = latitude_from_nmea(plat, pns);
|
||||
}
|
||||
if (plon != NULL && strlen(plon) > 0) {
|
||||
g_lon = longitude_from_nmea(plon, pew);
|
||||
}
|
||||
if (pknots != NULL && strlen(pknots) > 0) {
|
||||
g_speed = atof(pknots);
|
||||
}
|
||||
if (pcourse != NULL && strlen(pcourse) > 0) {
|
||||
g_course = atof(pcourse);
|
||||
}
|
||||
|
||||
if (*pstatus == 'A') {
|
||||
if (g_alt != G_UNKNOWN) {
|
||||
fix = 3;
|
||||
}
|
||||
else {
|
||||
fix = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fix = 0;
|
||||
}
|
||||
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
dw_printf("%d %.6f %.6f %.1f %.0f %.1f\n", fix, g_lat, g_lon, g_speed, g_course, g_alt);
|
||||
|
||||
#if WALK96
|
||||
// TODO: Need to design a proper interface.
|
||||
|
||||
extern void walk96 (int fix, double lat, double lon, float knots, float course, float alt);
|
||||
|
||||
walk96 (fix, g_lat, g_lon, g_speed, g_course, g_alt);
|
||||
#endif
|
||||
}
|
||||
|
||||
// $GPGGA has altitude.
|
||||
//
|
||||
// Examples: $GPGGA,212407.000,4237.1505,N,07120.8602,W,0,00,,,M,,M,,*58
|
||||
// $GPGGA,000409.392,,,,,0,00,,,M,0.0,M,,0000*53
|
||||
// $GPGGA,003518.710,4237.1250,N,07120.8327,W,1,03,5.9,33.5,M,-33.5,M,,0000*5B
|
||||
|
||||
else if (strcmp(ptype, "$GPGGA") == 0)
|
||||
{
|
||||
|
||||
char *ptime; /* Time, hhmmss[.sss] */
|
||||
char *plat; /* Latitude */
|
||||
char *pns; /* North/South */
|
||||
char *plon; /* Longitude */
|
||||
char *pew; /* East/West */
|
||||
char *pfix; /* 0=invalid, 1=GPS fix, 2=DGPS fix */
|
||||
char *pnum_sat; /* Number of satellites */
|
||||
char *phdop; /* Horiz. Dilution fo Precision */
|
||||
char *paltitude; /* Altitude, above mean sea level */
|
||||
char *palt_u; /* Units for Altitude, typically M for meters. */
|
||||
char *pheight; /* Height above ellipsoid */
|
||||
char *pheight_u; /* Units for height, typically M for meters. */
|
||||
char *psince; /* Time since last DGPS update. */
|
||||
char *pdsta; /* DGPS reference station id. */
|
||||
|
||||
ptime = strsep(&next, ",");
|
||||
plat = strsep(&next, ",");
|
||||
pns = strsep(&next, ",");
|
||||
plon = strsep(&next, ",");
|
||||
pew = strsep(&next, ",");
|
||||
pfix = strsep(&next, ",");
|
||||
pnum_sat = strsep(&next, ",");
|
||||
phdop = strsep(&next, ",");
|
||||
paltitude = strsep(&next, ",");
|
||||
palt_u = strsep(&next, ",");
|
||||
pheight = strsep(&next, ",");
|
||||
pheight_u = strsep(&next, ",");
|
||||
psince = strsep(&next, ",");
|
||||
pdsta = strsep(&next, ",");
|
||||
|
||||
g_alt = G_UNKNOWN;
|
||||
|
||||
if (paltitude != NULL && strlen(paltitude) > 0) {
|
||||
g_alt = atof(paltitude);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* end nmea_parse_gps */
|
||||
|
||||
/* end nmea.c */
|
||||
|
|
17
pfilter.c
17
pfilter.c
|
@ -919,7 +919,7 @@ static void print_error (pfstate_t *pf, char *msg)
|
|||
|
||||
|
||||
|
||||
#if TEST
|
||||
#if PFTEST
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -928,7 +928,7 @@ static void print_error (pfstate_t *pf, char *msg)
|
|||
*
|
||||
* Purpose: Unit test for packet filtering.
|
||||
*
|
||||
* Usage: gcc -Wall -o pftest -DTEST pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o latlong.o symbols.o telemetry.o tt_text.c misc.a regex.a && ./pftest
|
||||
* Usage: gcc -Wall -o pftest -DPFTEST pfilter.c ax25_pad.o textcolor.o fcs_calc.o decode_aprs.o latlong.o symbols.o telemetry.o tt_text.c misc.a regex.a && ./pftest
|
||||
*
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
@ -940,6 +940,9 @@ static void pftest (int test_num, char *filter, char *packet, int expected);
|
|||
int main ()
|
||||
{
|
||||
|
||||
dw_printf ("Quick test for packet filtering.\n");
|
||||
dw_printf ("Some error messages are normal. Look at the final success/fail message.\n");
|
||||
|
||||
pftest (1, "", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
||||
pftest (2, "0", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 0);
|
||||
pftest (3, "1", "WB2OSZ-5>APDW12,WIDE1-1,WIDE2-1:!4237.14NS07120.83W#PHG7140Chelmsford MA", 1);
|
||||
|
@ -1057,12 +1060,12 @@ int main ()
|
|||
|
||||
if (error_count > 0) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Packet Filtering Test - FAILED!\n");
|
||||
exit (1);
|
||||
dw_printf ("\nPacket Filtering Test - FAILED!\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
text_color_set (DW_COLOR_DEBUG );
|
||||
dw_printf ("Packet Filtering Test - SUCCESS!\n");
|
||||
exit (0);
|
||||
text_color_set (DW_COLOR_REC);
|
||||
dw_printf ("\nPacket Filtering Test - SUCCESS!\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
}
|
||||
|
||||
|
|
100
ptt.c
100
ptt.c
|
@ -50,12 +50,48 @@
|
|||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Idea for future enhancement:
|
||||
|
||||
A couple people have asked about support for the DMK URI.
|
||||
This uses a C-Media CM108/CM119 with one interesting addition, a GPIO
|
||||
pin is used to drive PTT. Here is some related information.
|
||||
|
||||
DMK URI:
|
||||
|
||||
http://www.dmkeng.com/URI_Order_Page.htm
|
||||
http://dmkeng.com/images/URI%20Schematic.pdf
|
||||
http://www.repeater-builder.com/voip/pdf/cm119-datasheet.pdf
|
||||
|
||||
Homebrew versions of the same idea:
|
||||
|
||||
http://images.ohnosec.org/usbfob.pdf
|
||||
http://www.qsl.net/kb9mwr/projects/voip/usbfob-119.pdf
|
||||
http://rtpdir.weebly.com/uploads/1/6/8/7/1687703/usbfob.pdf
|
||||
http://www.repeater-builder.com/projects/fob/USB-Fob-Construction.pdf
|
||||
|
||||
Applications that have support for this:
|
||||
|
||||
http://docs.allstarlink.org/drupal/
|
||||
http://soundmodem.sourcearchive.com/documentation/0.16-1/ptt_8c_source.html
|
||||
https://github.com/N0NB/hamlib/blob/master/src/cm108.c#L190
|
||||
|
||||
Information about the "hidraw" device:
|
||||
|
||||
http://unix.stackexchange.com/questions/85379/dev-hidraw-read-permissions
|
||||
http://www.signal11.us/oss/udev/
|
||||
http://www.signal11.us/oss/hidapi/
|
||||
https://github.com/signal11/hidapi/blob/master/libusb/hid.c
|
||||
http://stackoverflow.com/questions/899008/howto-write-to-the-gpio-pin-of-the-cm108-chip-in-linux
|
||||
https://www.kernel.org/doc/Documentation/hid/hidraw.txt
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#if __WIN32__
|
||||
#include <windows.h>
|
||||
|
@ -164,7 +200,7 @@ static char otnames[NUM_OCTYPES][8];
|
|||
void ptt_init (struct audio_s *audio_config_p)
|
||||
{
|
||||
int ch;
|
||||
HANDLE fd;
|
||||
HANDLE fd = INVALID_HANDLE_VALUE;
|
||||
#if __WIN32__
|
||||
#else
|
||||
int using_gpio;
|
||||
|
@ -177,9 +213,9 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
|
||||
save_audio_config_p = audio_config_p;
|
||||
|
||||
strcpy (otnames[OCTYPE_PTT], "PTT");
|
||||
strcpy (otnames[OCTYPE_DCD], "DCD");
|
||||
strcpy (otnames[OCTYPE_FUTURE], "FUTURE");
|
||||
strlcpy (otnames[OCTYPE_PTT], "PTT", sizeof(otnames[OCTYPE_PTT]));
|
||||
strlcpy (otnames[OCTYPE_DCD], "DCD", sizeof(otnames[OCTYPE_DCD]));
|
||||
strlcpy (otnames[OCTYPE_FUTURE], "FUTURE", sizeof(otnames[OCTYPE_FUTURE]));
|
||||
|
||||
|
||||
for (ch = 0; ch < MAX_CHANS; ch++) {
|
||||
|
@ -228,7 +264,7 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Converted %s device '%s'", audio_config_p->achan[ch].octrl[ot].ptt_device, otnames[ot]);
|
||||
if (n < 1) n = 1;
|
||||
sprintf (audio_config_p->achan[ch].octrl[ot].ptt_device, "/dev/ttyS%d", n-1);
|
||||
snprintf (audio_config_p->achan[ch].octrl[ot].ptt_device, sizeof(audio_config_p->achan[ch].octrl[ot].ptt_device), "/dev/ttyS%d", n-1);
|
||||
dw_printf (" to Linux equivalent '%s'\n", audio_config_p->achan[ch].octrl[ot].ptt_device);
|
||||
}
|
||||
#endif
|
||||
|
@ -259,13 +295,13 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
|
||||
// http://support.microsoft.com/kb/115831
|
||||
|
||||
strcpy (bettername, audio_config_p->achan[ch].octrl[ot].ptt_device);
|
||||
strlcpy (bettername, audio_config_p->achan[ch].octrl[ot].ptt_device, sizeof(bettername));
|
||||
if (strncasecmp(bettername, "COM", 3) == 0) {
|
||||
int n;
|
||||
n = atoi(bettername+3);
|
||||
if (n >= 10) {
|
||||
strcpy (bettername, "\\\\.\\");
|
||||
strcat (bettername, audio_config_p->achan[ch].octrl[ot].ptt_device);
|
||||
strlcpy (bettername, "\\\\.\\", sizeof(bettername));
|
||||
strlcat (bettername, audio_config_p->achan[ch].octrl[ot].ptt_device, sizeof(bettername));
|
||||
}
|
||||
}
|
||||
fd = CreateFile(bettername,
|
||||
|
@ -410,7 +446,7 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
dw_printf (" chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport\n");
|
||||
exit (1);
|
||||
}
|
||||
sprintf (stemp, "%d", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "%d", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
if (write (fd, stemp, strlen(stemp)) != strlen(stemp)) {
|
||||
int e = errno;
|
||||
/* Ignore EBUSY error which seems to mean */
|
||||
|
@ -424,16 +460,36 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
}
|
||||
close (fd);
|
||||
|
||||
/*
|
||||
Idea for future:
|
||||
|
||||
On the RPi, the device path for GPIO number XX is /sys/class/gpio/gpioXX.
|
||||
There was a report that it is different for the Cubieboard. For instance
|
||||
GPIO 61 has gpio61_pi13 in the path. This indicates connector "i" pin 13.
|
||||
|
||||
For another similar single board computer, we find the same thing:
|
||||
https://www.olimex.com/wiki/A20-OLinuXino-LIME#GPIO_under_Linux
|
||||
|
||||
How should we deal with this? Some possibilities:
|
||||
|
||||
(1) The user might explicitly mention the name in direwolf.conf.
|
||||
(2) We might be able to find the names in some system device config file.
|
||||
(3) Get a directory listing of /sys/class/gpio then search for a
|
||||
matching name. Suppose we wanted GPIO 61. First look for an exact
|
||||
match to "gpio61". If that is not found, look for something
|
||||
matching the pattern "gpio61_*".
|
||||
*/
|
||||
|
||||
/*
|
||||
* We will have the same permission problem if not root.
|
||||
* We only care about "direction" and "value".
|
||||
*/
|
||||
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
err = system (stemp);
|
||||
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "sudo chmod go+rw /sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
err = system (stemp);
|
||||
|
||||
sprintf (stemp, "/sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
|
||||
if (stat(stemp, &finfo) < 0) {
|
||||
int e = errno;
|
||||
|
@ -458,7 +514,7 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
* Set output direction with initial state off.
|
||||
*/
|
||||
|
||||
sprintf (stemp, "/sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/direction", audio_config_p->achan[ch].octrl[ot].ptt_gpio);
|
||||
fd = open(stemp, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
int e = errno;
|
||||
|
@ -470,10 +526,10 @@ void ptt_init (struct audio_s *audio_config_p)
|
|||
|
||||
char hilo[8];
|
||||
if (audio_config_p->achan[ch].octrl[ot].ptt_invert) {
|
||||
strcpy (hilo, "high");
|
||||
strlcpy (hilo, "high", sizeof(hilo));
|
||||
}
|
||||
else {
|
||||
strcpy (hilo, "low");
|
||||
strlcpy (hilo, "low", sizeof(hilo));
|
||||
}
|
||||
if (write (fd, hilo, strlen(hilo)) != strlen(hilo)) {
|
||||
int e = errno;
|
||||
|
@ -702,7 +758,7 @@ void ptt_set (int ot, int chan, int ptt_signal)
|
|||
int fd;
|
||||
char stemp[80];
|
||||
|
||||
sprintf (stemp, "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].octrl[ot].ptt_gpio);
|
||||
snprintf (stemp, sizeof(stemp), "/sys/class/gpio/gpio%d/value", save_audio_config_p->achan[chan].octrl[ot].ptt_gpio);
|
||||
|
||||
fd = open(stemp, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
|
@ -713,7 +769,7 @@ void ptt_set (int ot, int chan, int ptt_signal)
|
|||
return;
|
||||
}
|
||||
|
||||
sprintf (stemp, "%d", ptt);
|
||||
snprintf (stemp, sizeof(stemp), "%d", ptt);
|
||||
|
||||
if (write (fd, stemp, 1) != 1) {
|
||||
int e = errno;
|
||||
|
@ -840,14 +896,14 @@ main ()
|
|||
|
||||
my_audio_config.valid[0] = 1;
|
||||
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
|
||||
//strcpy (my_audio_config.ptt_device, "COM1");
|
||||
strcpy (my_audio_config.ptt_device, "/dev/ttyUSB0");
|
||||
//strlcpy (my_audio_config.ptt_device, "COM1", sizeof(my_audio_config.ptt_device));
|
||||
strlcpy (my_audio_config.ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.ptt_device));
|
||||
my_audio_config.adev[0].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_RTS;
|
||||
|
||||
my_audio_config.valid[1] = 1;
|
||||
my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_method = PTT_METHOD_SERIAL;
|
||||
//strcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "COM1");
|
||||
strcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0");
|
||||
//strlcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "COM1", sizeof(my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device));
|
||||
strlcpy (my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device, "/dev/ttyUSB0", sizeof(my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_device));
|
||||
my_audio_config.adev[1].octrl[OCTYPE_PTT].ptt_line = PTT_LINE_DTR;
|
||||
|
||||
|
||||
|
|
2
recv.c
2
recv.c
|
@ -302,7 +302,7 @@ void recv_process (void)
|
|||
#endif
|
||||
|
||||
|
||||
ok = dlq_remove (&type, &chan, &subchan, &pp, &alevel, &retries, spectrum);
|
||||
ok = dlq_remove (&type, &chan, &subchan, &pp, &alevel, &retries, spectrum, sizeof(spectrum));
|
||||
#if DEBUG
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("recv_process: dlq_remove() returned ok=%d, type=%d, chan=%d, pp=%p\n",
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
//#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#if __WIN32__
|
||||
|
|
|
@ -108,13 +108,13 @@ MYFDTYPE serial_port_open (char *devicename, int baud)
|
|||
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
|
||||
// http://support.microsoft.com/kb/115831
|
||||
|
||||
strcpy (bettername, devicename);
|
||||
strlcpy (bettername, devicename, sizeof(bettername));
|
||||
if (strncasecmp(devicename, "COM", 3) == 0) {
|
||||
int n;
|
||||
n = atoi(devicename+3);
|
||||
if (n >= 10) {
|
||||
strcpy (bettername, "\\\\.\\");
|
||||
strcat (bettername, devicename);
|
||||
strlcpy (bettername, "\\\\.\\", sizeof(bettername));
|
||||
strlcat (bettername, devicename, sizeof(bettername));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,14 +201,14 @@ MYFDTYPE serial_port_open (char *devicename, int baud)
|
|||
/* Translate Windows device name into Linux name. */
|
||||
/* COM1 -> /dev/ttyS0, etc. */
|
||||
|
||||
strcpy (linuxname, devicename);
|
||||
strlcpy (linuxname, devicename, sizeof(linuxname));
|
||||
|
||||
if (strncasecmp(devicename, "COM", 3) == 0) {
|
||||
int n = atoi (devicename + 3);
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("Converted serial port name '%s'", devicename);
|
||||
if (n < 1) n = 1;
|
||||
sprintf (linuxname, "/dev/ttyS%d", n-1);
|
||||
snprintf (linuxname, sizeof(linuxname), "/dev/ttyS%d", n-1);
|
||||
dw_printf (" to Linux equivalent '%s'\n", linuxname);
|
||||
}
|
||||
|
||||
|
|
92
server.c
92
server.c
|
@ -364,8 +364,8 @@ void server_init (struct audio_s *audio_config_p, struct misc_config_s *mc)
|
|||
#else
|
||||
pthread_t connect_listen_tid;
|
||||
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
|
||||
#endif
|
||||
int e;
|
||||
#endif
|
||||
int server_port = mc->agwpe_port; /* Usually 8000 but can be changed. */
|
||||
|
||||
|
||||
|
@ -475,7 +475,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("WSAStartup failed: %d\n", err);
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
|
||||
|
@ -483,7 +483,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
dw_printf("Could not find a usable version of Winsock.dll\n");
|
||||
WSACleanup();
|
||||
//sleep (1);
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
memset (&hints, 0, sizeof(hints));
|
||||
|
@ -498,14 +498,14 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
dw_printf("getaddrinfo failed: %d\n", err);
|
||||
//sleep (1);
|
||||
WSACleanup();
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
listen_sock= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (listen_sock == INVALID_SOCKET) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("connect_listen_thread: Socket creation failed, err=%d", WSAGetLastError());
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
@ -522,7 +522,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
freeaddrinfo(ai);
|
||||
closesocket(listen_sock);
|
||||
WSACleanup();
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
freeaddrinfo(ai);
|
||||
|
@ -553,7 +553,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("Listen failed with error: %d\n", WSAGetLastError());
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
@ -566,7 +566,7 @@ static THREAD_F connect_listen_thread (void *arg)
|
|||
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
||||
closesocket(listen_sock);
|
||||
WSACleanup();
|
||||
return (NULL); // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
@ -779,7 +779,7 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
|||
struct tm *tm;
|
||||
|
||||
clock = time(NULL);
|
||||
tm = localtime(&clock);
|
||||
tm = localtime(&clock); // TODO: should use localtime_r
|
||||
|
||||
memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
|
||||
|
||||
|
@ -1017,7 +1017,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
close (client_sock[client]);
|
||||
#endif
|
||||
client_sock[client] = -1;
|
||||
return NULL; // TODO: what should this be for Windows?
|
||||
return (0);
|
||||
}
|
||||
|
||||
cmd.data[0] = '\0';
|
||||
|
@ -1035,7 +1035,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
close (client_sock[client]);
|
||||
#endif
|
||||
client_sock[client] = -1;
|
||||
return NULL;
|
||||
return (0);
|
||||
}
|
||||
if (n > 0) {
|
||||
cmd.data[cmd.hdr.data_len] = '\0';
|
||||
|
@ -1196,7 +1196,7 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
case 'H': /* Ask about recently heard stations. */
|
||||
|
||||
{
|
||||
#if 0
|
||||
#if 0 /* This information is not being collected. */
|
||||
struct {
|
||||
struct agwpe_s hdr;
|
||||
char info[100];
|
||||
|
@ -1239,23 +1239,21 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
break;
|
||||
|
||||
|
||||
case 'V': /* Transmit UI data frame */
|
||||
case 'V': /* Transmit UI data frame (with digipeater path) */
|
||||
{
|
||||
// Data format is:
|
||||
// 1 byte for number of digipeaters.
|
||||
// 10 bytes for each digipeater.
|
||||
// data part of message.
|
||||
|
||||
char stemp[512];
|
||||
char stemp[AX25_MAX_PACKET_LEN+2];
|
||||
char *p;
|
||||
int ndigi;
|
||||
int k;
|
||||
|
||||
packet_t pp;
|
||||
//unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
||||
//int flen;
|
||||
|
||||
// We have already assured these do not exceed 9 characters.
|
||||
// We have already verified these do not exceed 9 characters. (?)
|
||||
|
||||
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
|
||||
strlcat (stemp, ">", sizeof(stemp));
|
||||
|
@ -1396,13 +1394,13 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case 'M': /* Send UNPROTO Information */
|
||||
|
||||
Not sure what we might want to do here.
|
||||
case 'M': /* Send UNPROTO Information (no digipeater path) */
|
||||
|
||||
/*
|
||||
Added in version 1.3.
|
||||
This is the same as 'V' except there is no provision for digipeaters.
|
||||
AGWterminal sends this for beacon or ask QRA.
|
||||
None of the other tested applications use it.
|
||||
|
||||
|
||||
<<< Send UNPROTO Information from AGWPE client application 0, total length = 253
|
||||
portx = 0, port_hi_reserved = 0
|
||||
|
@ -1420,32 +1418,56 @@ static THREAD_F cmd_listen_thread (void *arg)
|
|||
data_len = 1, user_reserved = 32218432, data =
|
||||
000: 0d .
|
||||
|
||||
There is also a report of it coming from UISS.
|
||||
|
||||
<<< Send UNPROTO Information from AGWPE client application 0, total length = 50
|
||||
portx = 0, port_hi_reserved = 0
|
||||
kind_lo = 77 = 'M', kind_hi = 0
|
||||
call_from = "JH4XSY", call_to = "APRS"
|
||||
data_len = 14, user_reserved = 0, data =
|
||||
000: 21 22 3c 43 2e 74 71 6c 48 72 71 21 21 5f !"<C.tqlHrq!!_
|
||||
*/
|
||||
{
|
||||
|
||||
packet_t pp;
|
||||
int pid = cmd.datakind_hi & 0xff;
|
||||
int pid = cmd.hdr.kind_hi & 0xff;
|
||||
(void)(pid);
|
||||
/* The AGW protocol spec says, */
|
||||
/* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
|
||||
|
||||
/* BUG: In theory, the AX.25 PID octet should be set from this. */
|
||||
/* All examples seen (above) have 0. */
|
||||
/* The AX.25 protocol spec doesn't list 0 as a valid value. */
|
||||
/* We always send 0xf0, meaning no layer 3. */
|
||||
/* Maybe we should have an ax25_set_pid function for cases when */
|
||||
/* it is neither 0 nor 0xf0. */
|
||||
|
||||
This is not right.
|
||||
It needs to be more like "V" Transmit UI data frame
|
||||
except there are no digipeaters involved.
|
||||
char stemp[AX25_MAX_PACKET_LEN];
|
||||
packet_t pp;
|
||||
|
||||
pp = ax25_from_frame ((unsigned char *)cmd.data, cmd.hdr.data_len, -1);
|
||||
strlcpy (stemp, cmd.hdr.call_from, sizeof(stemp));
|
||||
strlcat (stemp, ">", sizeof(stemp));
|
||||
strlcat (stemp, cmd.hdr.call_to, sizeof(stemp));
|
||||
|
||||
if (pp != NULL) {
|
||||
tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
|
||||
ax25_set_pid (pp, pid);
|
||||
}
|
||||
else {
|
||||
cmd.data[cmd.hdr.data_len] = '\0';
|
||||
|
||||
strlcat (stemp, ":", sizeof(stemp));
|
||||
strlcat (stemp, cmd.data, sizeof(stemp));
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("Transmit '%s'\n", stemp);
|
||||
|
||||
pp = ax25_from_text (stemp, 1);
|
||||
|
||||
if (pp == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Failed to create frame from AGW 'M' message.\n");
|
||||
}
|
||||
else {
|
||||
tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
case 'y': /* Ask Outstanding frames waiting on a Port */
|
||||
|
||||
|
|
237
symbols-new.txt
237
symbols-new.txt
|
@ -1,15 +1,18 @@
|
|||
APRS SYMBOL OVERLAY and EXTENSION TABLES in APRS 1.2 28 Aug 2014
|
||||
APRS SYMBOL OVERLAY and EXTENSION TABLES in APRS 1.2 29 Oct 2015
|
||||
---------------------------------------------------------------------
|
||||
|
||||
BACKGROUND: This file addresses new additions proposals (OVERLAYS)
|
||||
to the APRS symbol set after 1 October 2007. The master symbol
|
||||
document remains on the www.aprs.org/symbols/symbolsX.txt page.
|
||||
document remains on the www.aprs.org/symbols/symbolsX.txt page, but
|
||||
only has one line per symbol character. Since each of the symbols
|
||||
can have up to 36 overlays, this gives us thousands of symbols codes.
|
||||
|
||||
|
||||
NOTE: There was confusion with different copies of this file on
|
||||
different web pages and links. THIS file is now assumed to be the
|
||||
CORRECT one.
|
||||
|
||||
Update 29 Oct 2015: Reorgainized list to Alphabetical Order.
|
||||
+ Added many new Balloons (due to lost DoD radar Blimp yesterday)
|
||||
+ Confirmed D^ for Drones was already in there since 2014
|
||||
+ Added R^ type aircraft for remotely piloted
|
||||
+ Added S^ Solar Powered Aircraft
|
||||
|
||||
UPDATES/REVISIONS/CORRECTIONS:
|
||||
|
||||
|
@ -26,12 +29,16 @@ UPDATES/REVISIONS/CORRECTIONS:
|
|||
04 Jan 10 added #A to the table (correcting earlier omission)
|
||||
12 Oct 09 Added W0 for Yaesu WIRES nodes
|
||||
09 Apr 09 Changed APRStt symbol to overlayed BOX (#A)
|
||||
21 Aug 08 Added RFID R=, Stroller B], Radios#Y, & skull&Xbones (XH)
|
||||
27 Apr 08 Added some definitions of the numbered circle #0.
|
||||
25 Mar 08 Added these new definitions of overlays:
|
||||
21 Aug 08 Added RFID R=, Babystroller B], Radio#Y, skull&Xbones XH
|
||||
|
||||
Original Alternate Symbol codes being modified for new Overlay Use:
|
||||
|
||||
25 Mar 08 Modified these Alternate Symbol codes for expanded Overlays.
|
||||
Prior to this, each Alternate Table basic symbol had a unique defini-
|
||||
tion, but this was every restrictive. SO the following alternate
|
||||
base symbols were redefined so that the basic symbol could take on
|
||||
dozens of unique overlay definitions:
|
||||
|
||||
\0 - Several overlays for the numbered Circle
|
||||
\A - (BOX symbol) APRStt(DTMF), RFID users, XO (OLPC)
|
||||
\' - Was Crash Site. Now expanded to be INCIDENT sites
|
||||
\% - is an overlayed Powerplant. See definitions below
|
||||
|
@ -114,20 +121,28 @@ letting that define a new graphic just for that combination.
|
|||
The following tables will attempt to keep track of these and
|
||||
any other useful generic applications of overlay characters.
|
||||
|
||||
AMPLIFIED some existing ALTERNATE SYMBOL Overlays: (new Aug 2014)
|
||||
change Flooding #W to include Avalanche, Mudslide/Landslide
|
||||
change \' to crash & incident sites
|
||||
change \D to DEPOT family
|
||||
change overlayed car to generic with (1-9 overlays)
|
||||
Update #' name to crash & incident sites
|
||||
Update \D (was available) to DEPOT family
|
||||
change overlayed car to generic Vehicle with (1-9 overlays)
|
||||
|
||||
ADVISORIES: #< (new expansion possibilities)
|
||||
/< = motorcycle
|
||||
\< = Advisory (single gale flag)
|
||||
|
||||
AIRCRAFT
|
||||
/^ = LARGE Aircraft
|
||||
\^ = top-view originally intended to point in direction of flight
|
||||
A^ = Autonomous (2015)
|
||||
D^ = Drone (new may 2014)
|
||||
E^ = Enemy aircraft (too bad I cant use the original Hostile)
|
||||
E^ = Electric aircraft (2015)
|
||||
H^ = Hovercraft (new may 2014)
|
||||
J^ = JET (new may 2014)
|
||||
M^ = Missle (new may 2014)
|
||||
P^ = Prop (new Aug 2014)
|
||||
R^ = Remotely Piloted (new 2015)
|
||||
S^ = Solar Powered (new 2015)
|
||||
V^ = Vertical takeoff (new may 2014)
|
||||
X^ = Experimental (new Aug 2014)
|
||||
|
||||
|
@ -138,6 +153,60 @@ U$ = US dollars
|
|||
L$ = Brittish Pound
|
||||
Y$ = Japanese Yen
|
||||
|
||||
ARRL or DIAMOND: #a
|
||||
/a = Ambulance
|
||||
Aa = ARES
|
||||
Da = DSTAR (had been ARES Dutch)
|
||||
Ga = RSGB Radio Society of Great Brittan
|
||||
Ra = RACES
|
||||
Sa = SATERN Salvation Army
|
||||
Wa = WinLink
|
||||
|
||||
BALLOONS and lighter than air #O (All new Oct 2015)
|
||||
/O = Original Balloon (think Ham balloon)
|
||||
\O = ROCKET (amateur)(2007)
|
||||
BO = Blimp (2015)
|
||||
MO = Manned Balloon (2015)
|
||||
TO = Teathered (2015)
|
||||
CO = Constant Pressure - Long duration (2015)
|
||||
RO = Rocket bearing Balloon (Rockoon) (2015)
|
||||
|
||||
BOX SYMBOL: #A (and other system inputted symbols)
|
||||
/A = Aid station
|
||||
\A = numbered box
|
||||
9A = Mobile DTMF user
|
||||
7A = HT DTMF user
|
||||
HA = House DTMF user
|
||||
EA = Echolink DTMF report
|
||||
IA = IRLP DTMF report
|
||||
RA = RFID report
|
||||
AA = AllStar DTMF report
|
||||
DA = D-Star report
|
||||
XA = OLPC Laptop XO
|
||||
etc
|
||||
|
||||
BUILDINGS: #h
|
||||
/h = Hospital
|
||||
\h = Ham Store ** <= now used for HAMFESTS
|
||||
Fh = HamFest (new Aug 2014)
|
||||
Hh = Home Dept etc..
|
||||
|
||||
CARS: #> (Vehicles)
|
||||
/> = normal car (side view)
|
||||
\> = Top view and symbol POINTS in direction of travel
|
||||
#> = Reserve overlays 1-9 for numbered cars (new Aug 2014)
|
||||
E> = Electric
|
||||
H> = Hybrid
|
||||
S> = Solar powered
|
||||
V> = GM Volt
|
||||
|
||||
CIVIL DEFENSE or TRIANGLE: #c
|
||||
/c = Incident Command Post
|
||||
\c = Civil Defense
|
||||
Dc = Decontamination (new Aug 2014)
|
||||
Rc = RACES
|
||||
Sc = SATERN mobile canteen
|
||||
|
||||
DEPOT
|
||||
/D = was originally undefined
|
||||
\D = was drizzle (moved to ' ovlyD)
|
||||
|
@ -155,17 +224,14 @@ EMERGENCY: #!
|
|||
E! = ELT or EPIRB (new Aug 2014)
|
||||
V! = Volcanic Eruption or Lava (new Aug 2014)
|
||||
|
||||
POWER PLANT: #%
|
||||
/% = DX cluster <= the original primary table definition
|
||||
C% = Coal
|
||||
E% = Emergency (new Aug 2014)
|
||||
G% = Geothermal
|
||||
H% = Hydroelectric
|
||||
N% = Nuclear
|
||||
P% = Portable (new Aug 2014)
|
||||
S% = Solar
|
||||
T% = Turbine
|
||||
W% = Wind
|
||||
EYEBALL (EVENT) and VISIBILITY #E
|
||||
/E = Eyeball for special live events
|
||||
\E = (existing smoke) the symbol with no overlay
|
||||
HE = (H overlay) Haze
|
||||
SE = (S overlay) Smoke
|
||||
BE = (B overlay) Blowing Snow was \B
|
||||
DE = (D overlay) blowing Dust or sand was \b
|
||||
FE = (F overlay) Fog was \{
|
||||
|
||||
GATEWAYS: #&
|
||||
/& = HF Gateway <= the original primary table definition
|
||||
|
@ -174,14 +240,17 @@ R& = Receive only IGate (do not send msgs back to RF)
|
|||
T& = TX igate with path set to 1 hop only)
|
||||
2& = TX igate with path set to 2 hops (not generally good idea)
|
||||
|
||||
INCIDENT SITES: #'
|
||||
/' = Small Aircraft (original primary symbol)
|
||||
\' = Airplane Crash Site <= the original alternate deifinition
|
||||
A' = Automobile crash site
|
||||
H' = Hazardous incident
|
||||
M' = Multi-Vehicle crash site
|
||||
P' = Pileup
|
||||
T' = Truck wreck
|
||||
GPS devices: #\
|
||||
/\ = Triangle DF primary symbol
|
||||
\\ = was undefined alternate symbol
|
||||
A\ = Avmap G5 * <= Recommend special symbol
|
||||
|
||||
HAZARDS: #H
|
||||
/H = hotel
|
||||
\H = Haze
|
||||
RH = Radiation detector (new mar 2011)
|
||||
WH = Hazardous Waste
|
||||
XH = Skull&Crossbones
|
||||
|
||||
HUMAN SYMBOL: #[
|
||||
/[ = Human
|
||||
|
@ -205,6 +274,15 @@ O- = Operator Present
|
|||
S- = Solar Powered
|
||||
W- = Wind powered
|
||||
|
||||
INCIDENT SITES: #'
|
||||
/' = Small Aircraft (original primary symbol)
|
||||
\' = Airplane Crash Site <= the original alternate deifinition
|
||||
A' = Automobile crash site
|
||||
H' = Hazardous incident
|
||||
M' = Multi-Vehicle crash site
|
||||
P' = Pileup
|
||||
T' = Truck wreck
|
||||
|
||||
NUMBERED CIRCLES: #0
|
||||
E0 = Echolink Node (E0)
|
||||
I0 = IRLP repeater (I0)
|
||||
|
@ -223,48 +301,17 @@ I; = Islands on the air
|
|||
S; = Summits on the air
|
||||
W; = WOTA
|
||||
|
||||
ADVISORIES: #< (new expansion possibilities)
|
||||
/< = motorcycle
|
||||
\< = Advisory (single gale flag)
|
||||
|
||||
CARS: #> (Vehicles)
|
||||
/> = normal car (side view)
|
||||
\> = Top view and symbol POINTS in direction of travel
|
||||
#> = Reserve overlays 1-9 for numbered cars (new Aug 2014)
|
||||
E> = Electric
|
||||
H> = Hybrid
|
||||
S> = Solar powered
|
||||
V> = GM Volt
|
||||
|
||||
BOX SYMBOL: #A (and other system inputted symbols)
|
||||
/A = Aid station
|
||||
\A = numbered box
|
||||
9A = Mobile DTMF user
|
||||
7A = HT DTMF user
|
||||
HA = House DTMF user
|
||||
EA = Echolink DTMF report
|
||||
IA = IRLP DTMF report
|
||||
RA = RFID report
|
||||
AA = AllStar DTMF report
|
||||
DA = D-Star report
|
||||
XA = OLPC Laptop XO
|
||||
etc
|
||||
|
||||
EYEBALL and VISIBILITY #E
|
||||
/E = Eyeball for special live events
|
||||
\E = (existing smoke) the symbol with no overlay
|
||||
HE = (H overlay) Haze
|
||||
SE = (S overlay) Smoke
|
||||
BE = (B overlay) Blowing Snow was \B
|
||||
DE = (D overlay) blowing Dust or sand was \b
|
||||
FE = (F overlay) Fog was \{
|
||||
|
||||
HAZARDS: #H
|
||||
/H = hotel
|
||||
\H = Haze
|
||||
RH = Radiation detector (new mar 2011)
|
||||
WH = Hazardous Waste
|
||||
XH = Skull&Crossbones
|
||||
POWER or ENERGY: #%
|
||||
/% = DX cluster <= the original primary table definition
|
||||
C% = Coal
|
||||
E% = Emergency (new Aug 2014)
|
||||
G% = Geothermal
|
||||
H% = Hydroelectric
|
||||
N% = Nuclear
|
||||
P% = Portable (new Aug 2014)
|
||||
S% = Solar
|
||||
T% = Turbine
|
||||
W% = Wind
|
||||
|
||||
RESTAURANTS: #R
|
||||
\R = Restaurant (generic)
|
||||
|
@ -282,35 +329,6 @@ IY = Icom
|
|||
KY = Kenwood * <= Recommend special symbol
|
||||
YY = Yaesu/Standard* <= Recommend special symbol
|
||||
|
||||
GPS devices: #\
|
||||
/\ = Triangle DF primary symbol
|
||||
\\ = was undefined alternate symbol
|
||||
A\ = Avmap G5 * <= Recommend special symbol
|
||||
|
||||
ARRL or DIAMOND: #a
|
||||
/a = Ambulance
|
||||
Aa = ARES
|
||||
Da = DSTAR (had been ARES Dutch)
|
||||
Ga = RSGB Radio Society of Great Brittan
|
||||
Ra = RACES
|
||||
Sa = SATERN Salvation Army
|
||||
Wa = WinLink
|
||||
|
||||
CIVIL DEFENSE or TRIANGLE: #c
|
||||
/c = Incident Command Post
|
||||
\c = Civil Defense
|
||||
Dc = Decontamination (new Aug 2014)
|
||||
Rc = RACES
|
||||
Sc = SATERN mobile canteen
|
||||
|
||||
BUILDINGS: #h
|
||||
/h = Hospital
|
||||
\h = Ham Store ** <= now used for HAMFESTS
|
||||
Fh = HamFest (new Aug 2014)
|
||||
Hh = Home Dept etc..
|
||||
Mh = Morgue
|
||||
Ch = Clinic
|
||||
Th = Triage
|
||||
|
||||
SPECIAL VEHICLES: #k
|
||||
/k = truck
|
||||
|
@ -318,6 +336,14 @@ SPECIAL VEHICLES: #k
|
|||
4k = 4x4
|
||||
Ak = ATV (all terrain vehicle)
|
||||
|
||||
SHELTERS: #z
|
||||
/z = was available
|
||||
\z = overlayed shelter
|
||||
Cz = Clinic (new Aug 2014)
|
||||
Gz = Government building (new Aug 2014)
|
||||
Mz = Morgue (new Aug 2014)
|
||||
Tz = Triage (new Aug 2014)
|
||||
|
||||
SHIPS: #s
|
||||
/s = Power boat (ship) side view
|
||||
\s = Overlay Boat (Top view)
|
||||
|
@ -341,11 +367,10 @@ Ws = Wing-in-Ground effect (or Hovercraft)
|
|||
Xs = Passenger (paX)(ferry)
|
||||
Ys = Sailing (large ship)
|
||||
|
||||
|
||||
TRUCKS: #u
|
||||
/u = Truck (18 wheeler)
|
||||
\u = truck with overlay
|
||||
Bu = Buldozer/construction (new Aug 2014)
|
||||
Bu = Buldozer/construction/Backhoe (new Aug 2014)
|
||||
Gu = Gas
|
||||
Pu = Plow or SnowPlow (new Aug 2014)
|
||||
Tu = Tanker
|
||||
|
|
14
symbols.c
14
symbols.c
|
@ -35,6 +35,8 @@
|
|||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "symbols.h"
|
||||
#include "tt_text.h"
|
||||
|
||||
|
||||
//#if __WIN32__
|
||||
char *strcasestr(const char *S, const char *FIND);
|
||||
|
@ -460,7 +462,7 @@ void symbols_list (void)
|
|||
int symbol = new_sym_ptr[n].symbol;
|
||||
char tones[12];
|
||||
|
||||
symbols_to_tones (overlay, symbol, tones);
|
||||
symbols_to_tones (overlay, symbol, tones, sizeof(tones));
|
||||
|
||||
if (overlay == '/') {
|
||||
|
||||
|
@ -900,6 +902,7 @@ int symbols_code_from_description (char overlay, char *description, char *symtab
|
|||
*
|
||||
* Inputs: symtab/overlay
|
||||
* symbol
|
||||
* tonessiz - Amount of space available for result.
|
||||
*
|
||||
* Output: tones - string of AB...
|
||||
*
|
||||
|
@ -912,13 +915,12 @@ int symbols_code_from_description (char overlay, char *description, char *symtab
|
|||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
void symbols_to_tones (char symtab, char symbol, char *tones)
|
||||
void symbols_to_tones (char symtab, char symbol, char *tones, size_t tonessiz)
|
||||
{
|
||||
|
||||
if (symtab == '/') {
|
||||
|
||||
// TODO: potential buffer overflow.
|
||||
sprintf (tones, "AB1%02d", symbol - ' ');
|
||||
snprintf (tones, tonessiz, "AB1%02d", symbol - ' ');
|
||||
}
|
||||
else if (isupper(symtab) || isdigit(symtab)) {
|
||||
|
||||
|
@ -930,11 +932,11 @@ void symbols_to_tones (char symtab, char symbol, char *tones)
|
|||
|
||||
tt_text_to_two_key (text, 0, tt);
|
||||
|
||||
sprintf (tones, "AB0%02d%s", symbol - ' ', tt);
|
||||
snprintf (tones, tonessiz, "AB0%02d%s", symbol - ' ', tt);
|
||||
}
|
||||
else {
|
||||
|
||||
sprintf (tones, "AB2%02d", symbol - ' ');
|
||||
snprintf (tones, tonessiz, "AB2%02d", symbol - ' ');
|
||||
}
|
||||
|
||||
} /* end symbols_to_tones */
|
||||
|
|
|
@ -13,7 +13,7 @@ void symbols_get_description (char symtab, char symbol, char *description, size_
|
|||
|
||||
int symbols_code_from_description (char overlay, char *description, char *symtab, char *symbol);
|
||||
|
||||
void symbols_to_tones (char symtab, char symbol, char *tones);
|
||||
void symbols_to_tones (char symtab, char symbol, char *tones, size_t tonessize);
|
||||
|
||||
|
||||
/* end symbols.h */
|
||||
|
|
31
symbolsX.txt
31
symbolsX.txt
|
@ -1,4 +1,4 @@
|
|||
APRS SYMBOLS (Icons) 28 Aug 2014
|
||||
APRS SYMBOLS (Icons) 23 Jun 2015
|
||||
-----------------------------------------------------------------------
|
||||
WB4APR
|
||||
|
||||
|
@ -28,6 +28,7 @@ http://aprs.org/symbols/symbols-background.txt
|
|||
|
||||
UPDATE CHRONOLOGY:
|
||||
|
||||
23 Jun 15: Changed Aircraft to SSID-11 and Human to SSID-7
|
||||
28 Aug 14: Added notation on newly availble BASE codes (begun in 2007)
|
||||
Old WX versions of these: Bb{*:DFegJp were moved to ovlays
|
||||
Expanded #w Flooding to include Avalanches, Mud/Landslides
|
||||
|
@ -178,7 +179,7 @@ for the stand-alone trackers described above.
|
|||
/$ BE PHONE \$ OEO Bank or ATM (green box)
|
||||
/% BF DX CLUSTER \% OFO Power Plant with overlay
|
||||
/& BG HF GATEway \& OG# I=Igte R=RX T=1hopTX 2=2hopTX
|
||||
/' BH Small AIRCRAFT (SSID = 7) \' OHO Crash (& now Incident sites)
|
||||
/' BH Small AIRCRAFT (SSID-11) \' OHO Crash (& now Incident sites)
|
||||
/( BI Mobile Satellite Station \( OIO CLOUDY (other clouds w ovrly)
|
||||
/) BJ Wheelchair (handicapped) \) OJO Firenet MEO, MODIS Earth Obs.
|
||||
/* BK SnowMobile \* OK AVAIL (SNOW moved to ` ovly S)
|
||||
|
@ -203,9 +204,9 @@ for the stand-alone trackers described above.
|
|||
/9 P9 TBD (as mobiles at events)\9 A9 Gas Station (blue pump)
|
||||
/: MR FIRE \: NR AVAIL (Hail ==> ` ovly H)
|
||||
/; MS Campground (Portable ops) \; NSO Park/Picnic + overlay events
|
||||
/< MT Motorcycle (SSID =10) \< NTO ADVISORY (one WX flag)
|
||||
/< MT Motorcycle (SSID-10) \< NTO ADVISORY (one WX flag)
|
||||
/= MU RAILROAD ENGINE \= NUO APRStt Touchtone (DTMF users)
|
||||
/> MV CAR (SSID = 9) \> NV# OVERLAYED CARs & Vehicles
|
||||
/> MV CAR (SSID-9) \> NV# OVERLAYED CARs & Vehicles
|
||||
/? MW SERVER for Files \? NW INFO Kiosk (Blue box with ?)
|
||||
/@ MX HC FUTURE predict (dot) \@ NX HURICANE/Trop-Storm
|
||||
/A PA Aid Station \A AA# overlayBOX DTMF & RFID & XO
|
||||
|
@ -222,19 +223,19 @@ for the stand-alone trackers described above.
|
|||
/L PL PC user (Jan 03) \L AL Lighthouse
|
||||
/M PM MacAPRS \M AMO MARS (A=Army,N=Navy,F=AF)
|
||||
/N PN NTS Station \N AN Navigation Buoy
|
||||
/O PO BALLOON (SSID =11) \O AO Overlay Balloon (Rocket = \O)
|
||||
/O PO BALLOON (SSID-11) \O AO Overlay Balloon (Rocket = \O)
|
||||
/P PP Police \P AP Parking
|
||||
/Q PQ TBD \Q AQ QUAKE
|
||||
/R PR REC. VEHICLE (SSID =13) \R ARO Restaurant
|
||||
/R PR REC. VEHICLE (SSID-13) \R ARO Restaurant
|
||||
/S PS SHUTTLE \S AS Satellite/Pacsat
|
||||
/T PT SSTV \T AT Thunderstorm
|
||||
/U PU BUS (SSID = 2) \U AU SUNNY
|
||||
/U PU BUS (SSID-2) \U AU SUNNY
|
||||
/V PV ATV \V AV VORTAC Nav Aid
|
||||
/W PW National WX Service Site \W AW# # NWS site (NWS options)
|
||||
/X PX HELO (SSID = 6) \X AX Pharmacy Rx (Apothicary)
|
||||
/Y PY YACHT (sail) (SSID = 5) \Y AYO Radios and devices
|
||||
/X PX HELO (SSID-6) \X AX Pharmacy Rx (Apothicary)
|
||||
/Y PY YACHT (sail) (SSID-5) \Y AYO Radios and devices
|
||||
/Z PZ WinAPRS \Z AZ AVAIL
|
||||
/[ HS Human/Person (HT) \[ DSO W.Cloud (& humans w Ovrly)
|
||||
/[ HS Human/Person (SSID-7) \[ DSO W.Cloud (& humans w Ovrly)
|
||||
/\ HT TRIANGLE(DF station) \\ DTO New overlayable GPS symbol
|
||||
/] HU MAIL/PostOffice(was PBBS) \] DU AVAIL
|
||||
/^ HV LARGE AIRCRAFT \^ DV# other Aircraft ovrlys (2014)
|
||||
|
@ -243,17 +244,17 @@ for the stand-alone trackers described above.
|
|||
|
||||
/$ XYZ LOWER CASE SYMBOL TABLE \$ XYZ SECONDARY SYMBOL TABLE (\)
|
||||
-- --- ------------------------ -- --- --------------------------
|
||||
/a LA AMBULANCE (SSID = 1) \a SA#O ARRL,ARES,WinLINK,Dstar, etc
|
||||
/b LB BIKE (SSID = 4) \b SB AVAIL(Blwng Dst/Snd => E ovly)
|
||||
/a LA AMBULANCE (SSID-1) \a SA#O ARRL,ARES,WinLINK,Dstar, etc
|
||||
/b LB BIKE (SSID-4) \b SB AVAIL(Blwng Dst/Snd => E ovly)
|
||||
/c LC Incident Command Post \c SC#O CD triangle RACES/SATERN/etc
|
||||
/d LD Fire dept \d SD DX spot by callsign
|
||||
/e LE HORSE (equestrian) \e SE Sleet (& future ovrly codes)
|
||||
/f LF FIRE TRUCK (SSID = 3) \f SF Funnel Cloud
|
||||
/f LF FIRE TRUCK (SSID-3) \f SF Funnel Cloud
|
||||
/g LG Glider \g SG Gale Flags
|
||||
/h LH HOSPITAL \h SHO Store. or HAMFST Hh=HAM store
|
||||
/i LI IOTA (islands on the air) \i SI# BOX or points of Interest
|
||||
/j LJ JEEP (SSID-12) \j SJ WorkZone (Steam Shovel)
|
||||
/k LK TRUCK (SSID = 14) \k SKO Special Vehicle SUV,ATV,4x4
|
||||
/k LK TRUCK (SSID-14) \k SKO Special Vehicle SUV,ATV,4x4
|
||||
/l LL Laptop (Jan 03) (Feb 07) \l SL Areas (box,circles,etc)
|
||||
/m LM Mic-E Repeater \m SM Value Sign (3 digit display)
|
||||
/n LN Node (black bulls-eye) \n SN# OVERLAY TRIANGLE
|
||||
|
@ -264,7 +265,7 @@ for the stand-alone trackers described above.
|
|||
/s LS SHIP (pwr boat) (SSID-8) \s SS# OVERLAY SHIP/boats
|
||||
/t LT TRUCK STOP \t ST Tornado
|
||||
/u LU TRUCK (18 wheeler) \u SU# OVERLAYED TRUCK
|
||||
/v LV VAN (SSID = 15) \v SV# OVERLAYED Van
|
||||
/v LV VAN (SSID-15) \v SV# OVERLAYED Van
|
||||
/w LW WATER station \w SWO Flooding (Avalanches/Slides)
|
||||
/x LX xAPRS (Unix) \x SX Wreck or Obstruction ->X<-
|
||||
/y LY YAGI @ QTH \y SY Skywarn
|
||||
|
|
368
telemetry.c
368
telemetry.c
|
@ -57,10 +57,6 @@
|
|||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if __WIN32__
|
||||
char *strsep(char **stringp, const char *delim);
|
||||
#endif
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "ax25_pad.h" // for packet_t, AX25_MAX_ADDR_LEN
|
||||
#include "decode_aprs.h" // for decode_aprs_t, G_UNKNOWN
|
||||
|
@ -117,7 +113,7 @@ struct t_metadata_s {
|
|||
|
||||
static struct t_metadata_s * md_list_head = NULL;
|
||||
|
||||
static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_ANALOG], int ndp[T_NUM_ANALOG], int draw[T_NUM_DIGITAL], char *output);
|
||||
static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_ANALOG], int ndp[T_NUM_ANALOG], int draw[T_NUM_DIGITAL], char *output, size_t outputsize);
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -136,7 +132,7 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
static struct t_metadata_s * t_get_metadata (char *station)
|
||||
{
|
||||
struct t_metadata_s *p;
|
||||
int n, j;
|
||||
int n;
|
||||
|
||||
#if DEBUG3
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -158,13 +154,13 @@ static struct t_metadata_s * t_get_metadata (char *station)
|
|||
|
||||
p->magic1 = MAGIC1;
|
||||
|
||||
strncpy (p->station, station, sizeof(p->station)-1);
|
||||
strlcpy (p->station, station, sizeof(p->station));
|
||||
|
||||
for (n = 0; n < T_NUM_ANALOG; n++) {
|
||||
sprintf (p->name[n], "A%d", n+1);
|
||||
snprintf (p->name[n], sizeof(p->name[n]), "A%d", n+1);
|
||||
}
|
||||
for (n = 0; n < T_NUM_DIGITAL; n++) {
|
||||
sprintf (p->name[T_NUM_ANALOG+n], "D%d", n+1);
|
||||
snprintf (p->name[T_NUM_ANALOG+n], sizeof(p->name[T_NUM_ANALOG+n]), "D%d", n+1);
|
||||
}
|
||||
|
||||
for (n = 0; n < T_NUM_ANALOG; n++) {
|
||||
|
@ -259,7 +255,7 @@ static int t_ndp (char *str)
|
|||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
void telemetry_data_original (char *station, char *info, int quiet, char *output, char *comment)
|
||||
void telemetry_data_original (char *station, char *info, int quiet, char *output, size_t outputsize, char *comment, size_t commentsize)
|
||||
{
|
||||
int n;
|
||||
int seq;
|
||||
|
@ -280,6 +276,9 @@ void telemetry_data_original (char *station, char *info, int quiet, char *output
|
|||
dw_printf ("\n%s\n\n", info);
|
||||
#endif
|
||||
|
||||
strlcpy (output, "", outputsize);
|
||||
strlcpy (comment, "", commentsize);
|
||||
|
||||
pm = t_get_metadata(station);
|
||||
|
||||
assert (pm->magic1 == MAGIC1);
|
||||
|
@ -307,8 +306,7 @@ void telemetry_data_original (char *station, char *info, int quiet, char *output
|
|||
* Remove any trailing CR/LF.
|
||||
*/
|
||||
|
||||
memset (stemp, 0, sizeof(stemp));
|
||||
strncpy (stemp, info+2, sizeof(stemp)-1);
|
||||
strlcpy (stemp, info+2, sizeof(stemp));
|
||||
|
||||
for (p = stemp + strlen(stemp) - 1; p >= stemp && (*p == '\r' || *p == '\n') ; p--) {
|
||||
*p = '\0';
|
||||
|
@ -352,7 +350,7 @@ void telemetry_data_original (char *station, char *info, int quiet, char *output
|
|||
|
||||
// TODO: test this!
|
||||
if (strlen(next) > 8) {
|
||||
strlcpy (comment, next+8, sizeof(comment));
|
||||
strlcpy (comment, next+8, commentsize);
|
||||
next[8] = '\0';
|
||||
}
|
||||
for (k = 0; k < strlen(next); k++) {
|
||||
|
@ -394,7 +392,7 @@ void telemetry_data_original (char *station, char *info, int quiet, char *output
|
|||
|
||||
#endif
|
||||
|
||||
t_data_process (pm, seq, araw, ndp, draw, output);
|
||||
t_data_process (pm, seq, araw, ndp, draw, output, outputsize);
|
||||
|
||||
} /* end telemtry_data_original */
|
||||
|
||||
|
@ -436,6 +434,7 @@ static int two_base91_to_i (char *c)
|
|||
else {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\"%c\" is not a valid character for base 91 telemetry data.\n", c[0]);
|
||||
return (G_UNKNOWN);
|
||||
}
|
||||
|
||||
if (isdigit91(c[1])) {
|
||||
|
@ -444,11 +443,12 @@ static int two_base91_to_i (char *c)
|
|||
else {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\"%c\" is not a valid character for base 91 telemetry data.\n", c[1]);
|
||||
return (G_UNKNOWN);
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
void telemetry_data_base91 (char *station, char *cdata, char *output)
|
||||
void telemetry_data_base91 (char *station, char *cdata, char *output, size_t outputsize)
|
||||
{
|
||||
int n;
|
||||
int seq;
|
||||
|
@ -465,6 +465,8 @@ void telemetry_data_base91 (char *station, char *cdata, char *output)
|
|||
dw_printf ("\n%s\n\n", cdata);
|
||||
#endif
|
||||
|
||||
strlcpy (output, "", outputsize);
|
||||
|
||||
pm = t_get_metadata(station);
|
||||
|
||||
assert (pm->magic1 == MAGIC1);
|
||||
|
@ -516,7 +518,7 @@ void telemetry_data_base91 (char *station, char *cdata, char *output)
|
|||
|
||||
#endif
|
||||
|
||||
t_data_process (pm, seq, araw, ndp, draw, output);
|
||||
t_data_process (pm, seq, araw, ndp, draw, output, outputsize);
|
||||
|
||||
} /* end telemtry_data_base91 */
|
||||
|
||||
|
@ -566,8 +568,7 @@ void telemetry_name_message (char *station, char *msg)
|
|||
* Remove any trailing CR LF.
|
||||
*/
|
||||
|
||||
memset (stemp, 0, sizeof(stemp));
|
||||
strncpy (stemp, msg, sizeof(stemp)-1);
|
||||
strlcpy (stemp, msg, sizeof(stemp));
|
||||
|
||||
for (p = stemp + strlen(stemp) - 1; p >= stemp && (*p == '\r' || *p == '\n') ; p--) {
|
||||
*p = '\0';
|
||||
|
@ -583,8 +584,7 @@ void telemetry_name_message (char *station, char *msg)
|
|||
while ((p = strsep(&next,",")) != NULL) {
|
||||
if (n < T_NUM_ANALOG + T_NUM_DIGITAL) {
|
||||
if (strlen(p) > 0 && strcmp(p,"-") != 0) {
|
||||
memset (pm->name[n], 0, T_STR_LEN);
|
||||
strncpy (pm->name[n], p, T_STR_LEN-1);
|
||||
strlcpy (pm->name[n], p, sizeof(pm->name[n]));
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
@ -644,8 +644,7 @@ void telemetry_unit_label_message (char *station, char *msg)
|
|||
* Remove any trailing CR LF.
|
||||
*/
|
||||
|
||||
memset (stemp, 0, sizeof(stemp));
|
||||
strncpy (stemp, msg, sizeof(stemp)-1);
|
||||
strlcpy (stemp, msg, sizeof(stemp));
|
||||
|
||||
for (p = stemp + strlen(stemp) - 1; p >= stemp && (*p == '\r' || *p == '\n') ; p--) {
|
||||
*p = '\0';
|
||||
|
@ -661,8 +660,7 @@ void telemetry_unit_label_message (char *station, char *msg)
|
|||
while ((p = strsep(&next,",")) != NULL) {
|
||||
if (n < T_NUM_ANALOG + T_NUM_DIGITAL) {
|
||||
if (strlen(p) > 0) {
|
||||
memset (pm->unit[n], 0, T_STR_LEN);
|
||||
strncpy (pm->unit[n], p, T_STR_LEN-1);
|
||||
strlcpy (pm->unit[n], p, sizeof(pm->unit[n]));
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
@ -723,8 +721,7 @@ void telemetry_coefficents_message (char *station, char *msg, int quiet)
|
|||
* Remove any trailing CR LF.
|
||||
*/
|
||||
|
||||
memset (stemp, 0, sizeof(stemp));
|
||||
strncpy (stemp, msg, sizeof(stemp)-1);
|
||||
strlcpy (stemp, msg, sizeof(stemp));
|
||||
|
||||
for (p = stemp + strlen(stemp) - 1; p >= stemp && (*p == '\r' || *p == '\n') ; p--) {
|
||||
*p = '\0';
|
||||
|
@ -841,7 +838,7 @@ void telemetry_bit_sense_message (char *station, char *msg, int quiet)
|
|||
|
||||
if (msg[n] == ',') n++;
|
||||
|
||||
strncpy (pm->project, msg+n, sizeof(pm->project)-1);
|
||||
strlcpy (pm->project, msg+n, sizeof(pm->project));
|
||||
|
||||
#if DEBUG3
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -905,7 +902,7 @@ static void ival_to_str (int x, char str[VAL_STR_SIZE])
|
|||
}
|
||||
}
|
||||
|
||||
static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_ANALOG], int ndp[T_NUM_ANALOG], int draw[T_NUM_DIGITAL], char *output)
|
||||
static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_ANALOG], int ndp[T_NUM_ANALOG], int draw[T_NUM_DIGITAL], char *output, size_t outputsize)
|
||||
{
|
||||
int n;
|
||||
char val_str[VAL_STR_SIZE];
|
||||
|
@ -915,16 +912,16 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
assert (pm->magic1 == MAGIC1);
|
||||
assert (pm->magic2 == MAGIC2);
|
||||
|
||||
strcpy (output, "");
|
||||
strlcpy (output, "", outputsize);
|
||||
|
||||
if (strlen(pm->project) > 0) {
|
||||
strcpy (output, pm->project);
|
||||
strcat (output, ": ");
|
||||
strlcpy (output, pm->project, outputsize);
|
||||
strlcat (output, ": ", outputsize);
|
||||
}
|
||||
|
||||
ival_to_str (seq, val_str);
|
||||
strcat (output, "Seq=");
|
||||
strcat (output, val_str);
|
||||
strlcat (output, "Seq=", outputsize);
|
||||
strlcat (output, val_str, outputsize);
|
||||
|
||||
for (n = 0; n < T_NUM_ANALOG; n++) {
|
||||
|
||||
|
@ -934,10 +931,10 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
float fval;
|
||||
int fndp;
|
||||
|
||||
strcat (output, ", ");
|
||||
strlcat (output, ", ", outputsize);
|
||||
|
||||
strcat (output, pm->name[n]);
|
||||
strcat (output, "=");
|
||||
strlcat (output, pm->name[n], outputsize);
|
||||
strlcat (output, "=", outputsize);
|
||||
|
||||
// Scaling and suitable number of decimal places for display.
|
||||
|
||||
|
@ -956,10 +953,10 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
fndp = MAX (z, MAX(pm->coeff_ndp[n][C_B] + ndp[n], pm->coeff_ndp[n][C_C]));
|
||||
}
|
||||
fval_to_str (fval, fndp, val_str);
|
||||
strcat (output, val_str);
|
||||
strlcat (output, val_str, outputsize);
|
||||
if (strlen(pm->unit[n]) > 0) {
|
||||
strcat (output, " ");
|
||||
strcat (output, pm->unit[n]);
|
||||
strlcat (output, " ", outputsize);
|
||||
strlcat (output, pm->unit[n], outputsize);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -972,10 +969,10 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
if (draw[n] != G_UNKNOWN) {
|
||||
int dval;
|
||||
|
||||
strcat (output, ", ");
|
||||
strlcat (output, ", ", outputsize);
|
||||
|
||||
strcat (output, pm->name[T_NUM_ANALOG+n]);
|
||||
strcat (output, "=");
|
||||
strlcat (output, pm->name[T_NUM_ANALOG+n], outputsize);
|
||||
strlcat (output, "=", outputsize);
|
||||
|
||||
// Possible inverting for bit sense.
|
||||
|
||||
|
@ -989,10 +986,10 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
ival_to_str (dval, val_str);
|
||||
|
||||
if (strlen(pm->unit[T_NUM_ANALOG+n]) > 0) {
|
||||
strcat (output, " ");
|
||||
strcat (output, pm->unit[T_NUM_ANALOG+n]);
|
||||
strlcat (output, " ", outputsize);
|
||||
strlcat (output, pm->unit[T_NUM_ANALOG+n], outputsize);
|
||||
}
|
||||
strcat (output, val_str);
|
||||
strlcat (output, val_str, outputsize);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1011,7 +1008,8 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
*
|
||||
* Unit test. Run with:
|
||||
*
|
||||
* make -f Makefile.? etest
|
||||
* make etest
|
||||
*
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
@ -1019,14 +1017,14 @@ static void t_data_process (struct t_metadata_s *pm, int seq, float araw[T_NUM_A
|
|||
#if TEST
|
||||
|
||||
|
||||
|
||||
int main ( )
|
||||
{
|
||||
char result[256];
|
||||
char comment[256];
|
||||
char result[120];
|
||||
char comment[40];
|
||||
int errors = 0;
|
||||
|
||||
strcpy (result, "");
|
||||
strcpy (comment, "");
|
||||
strlcpy (result, "", sizeof(result));
|
||||
strlcpy (comment, "", sizeof(comment));
|
||||
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
@ -1039,24 +1037,69 @@ int main ( )
|
|||
|
||||
// From protocol spec.
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101001", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101001", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A4=73, A5=123, D1=0, D2=1, D3=1, D4=0, D5=1, D6=0, D7=0, D8=1") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 101\n");
|
||||
}
|
||||
|
||||
// Try adding a comment.
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101001Comment,with,commas", 0, result, comment);
|
||||
strcpy (comment, "");
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101001Comment,with,commas", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
// Try shortening or omitting parts.
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A4=73, A5=123, D1=0, D2=1, D3=1, D4=0, D5=1, D6=0, D7=0, D8=1") != 0 ||
|
||||
strcmp(comment, "Comment,with,commas") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 102\n");
|
||||
}
|
||||
|
||||
|
||||
// Error handling - Try shortening or omitting parts.
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T005,199,000,255,073,123,0110", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 103\n");
|
||||
}
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,0110", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A4=73, A5=123, D1=0, D2=1, D3=1, D4=0") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 104\n");
|
||||
}
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A4=73, A5=123") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 105\n");
|
||||
}
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,,123,01101001", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A5=123, D1=0, D2=1, D3=1, D4=0, D5=1, D6=0, D7=0, D8=1") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 106\n");
|
||||
}
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101009", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=5, A1=199, A2=0, A3=255, A4=73, A5=123, D1=0, D2=1, D3=1, D4=0, D5=1, D6=0, D7=0") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 107\n");
|
||||
}
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T005,199,000,255,073,123,0110", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,0110", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,,123,01101001", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#005,199,000,255,073,123,01101009", 0, result, comment);
|
||||
|
||||
// Local observation.
|
||||
|
||||
telemetry_data_original ("WB2OSZ", "T#491,4.9,0.3,25.0,0.0,1.0,00000000", 0, result, comment);
|
||||
telemetry_data_original ("WB2OSZ", "T#491,4.9,0.3,25.0,0.0,1.0,00000000", 0, result, sizeof(result), comment, sizeof(comment));
|
||||
|
||||
if (strcmp(result, "Seq=491, A1=4.9, A2=0.3, A3=25.0, A4=0.0, A5=1.0, D1=0, D2=0, D3=0, D4=0, D5=0, D6=0, D7=0, D8=0") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 108\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -1067,43 +1110,187 @@ int main ( )
|
|||
|
||||
// From protocol spec.
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11", result);
|
||||
dw_printf ("expect 7544: 1472 above.\n");
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11", result, sizeof(result));
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!\"", result);
|
||||
dw_printf ("expect 7544: 1472, 1564, 1656, 1748, 8280, 10000000 above.\n");
|
||||
if (strcmp(result, "Seq=7544, A1=1472") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 201\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!\"", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "Seq=7544, A1=1472, A2=1564, A3=1656, A4=1748, A5=8280, D1=1, D2=0, D3=0, D4=0, D5=0, D6=0, D7=0, D8=0") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 202\n");
|
||||
}
|
||||
|
||||
// Error cases. Should not happen in practice because function
|
||||
// should be called only with valid data that matches the pattern.
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!\"x", result);
|
||||
telemetry_data_base91 ("WB2OSZ", "ss1", result);
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!", result);
|
||||
telemetry_data_base91 ("WB2OSZ", "s |1", result);
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!\"x", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 203\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss1", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 204\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "ss11223344{{!", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 205\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("WB2OSZ", "s |1", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "Seq=?") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 206\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if DEBUG3
|
||||
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("part 3\n");
|
||||
|
||||
telemetry_name_message ("N0QBF-11", "Battery,Btemp,ATemp,Pres,Alt,Camra,Chut,Sun,10m,ATV");
|
||||
|
||||
struct t_metadata_s *pm;
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
|
||||
if (strcmp(pm->name[0], "Battery") != 0 ||
|
||||
strcmp(pm->name[1], "Btemp") != 0 ||
|
||||
strcmp(pm->name[2], "ATemp") != 0 ||
|
||||
strcmp(pm->name[3], "Pres") != 0 ||
|
||||
strcmp(pm->name[4], "Alt") != 0 ||
|
||||
strcmp(pm->name[5], "Camra") != 0 ||
|
||||
strcmp(pm->name[6], "Chut") != 0 ||
|
||||
strcmp(pm->name[7], "Sun") != 0 ||
|
||||
strcmp(pm->name[8], "10m") != 0 ||
|
||||
strcmp(pm->name[9], "ATV") != 0 ||
|
||||
strcmp(pm->name[10], "D6") != 0 ||
|
||||
strcmp(pm->name[11], "D7") != 0 ||
|
||||
strcmp(pm->name[12], "D8") != 0 ) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 301\n");
|
||||
}
|
||||
|
||||
telemetry_unit_label_message ("N0QBF-11", "v/100,deg.F,deg.F,Mbar,Kft,Click,OPEN,on,on,hi");
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
|
||||
if (strcmp(pm->unit[0], "v/100") != 0 ||
|
||||
strcmp(pm->unit[1], "deg.F") != 0 ||
|
||||
strcmp(pm->unit[2], "deg.F") != 0 ||
|
||||
strcmp(pm->unit[3], "Mbar") != 0 ||
|
||||
strcmp(pm->unit[4], "Kft") != 0 ||
|
||||
strcmp(pm->unit[5], "Click") != 0 ||
|
||||
strcmp(pm->unit[6], "OPEN") != 0 ||
|
||||
strcmp(pm->unit[7], "on") != 0 ||
|
||||
strcmp(pm->unit[8], "on") != 0 ||
|
||||
strcmp(pm->unit[9], "hi") != 0 ||
|
||||
strcmp(pm->unit[10], "") != 0 ||
|
||||
strcmp(pm->unit[11], "") != 0 ||
|
||||
strcmp(pm->unit[12], "") != 0 ) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 302\n");
|
||||
}
|
||||
|
||||
telemetry_coefficents_message ("N0QBF-11", "0,5.2,0,0,.53,-32,3,4.39,49,-32,3,18,1,2,3", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
|
||||
if (pm->coeff[0][0] != 0 || pm->coeff[0][1] < 5.1999 || pm->coeff[0][1] > 5.2001 || pm->coeff[0][2] != 0 ||
|
||||
pm->coeff[1][0] != 0 || pm->coeff[1][1] < .52999 || pm->coeff[1][1] > .53001 || pm->coeff[1][2] != -32 ||
|
||||
pm->coeff[2][0] != 3 || pm->coeff[2][1] < 4.3899 || pm->coeff[2][1] > 4.3901 || pm->coeff[2][2] != 49 ||
|
||||
pm->coeff[3][0] != -32 || pm->coeff[3][1] != 3 || pm->coeff[3][2] != 18 ||
|
||||
pm->coeff[4][0] != 1 || pm->coeff[4][1] != 2 || pm->coeff[4][2] != 3) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 303c\n");
|
||||
}
|
||||
|
||||
if (pm->coeff_ndp[0][0] != 0 || pm->coeff_ndp[0][1] != 1 || pm->coeff_ndp[0][2] != 0 ||
|
||||
pm->coeff_ndp[1][0] != 0 || pm->coeff_ndp[1][1] != 2 || pm->coeff_ndp[1][2] != 0 ||
|
||||
pm->coeff_ndp[2][0] != 0 || pm->coeff_ndp[2][1] != 2 || pm->coeff_ndp[2][2] != 0 ||
|
||||
pm->coeff_ndp[3][0] != 0 || pm->coeff_ndp[3][1] != 0 || pm->coeff_ndp[3][2] != 0 ||
|
||||
pm->coeff_ndp[4][0] != 0 || pm->coeff_ndp[4][1] != 0 || pm->coeff_ndp[4][2] != 0 ) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 303n\n");
|
||||
}
|
||||
|
||||
// Error if less than 15 or empty field.
|
||||
// Notice that we keep the previous value in this case.
|
||||
|
||||
telemetry_coefficents_message ("N0QBF-11", "0,5.2,0,0,.53,-32,3,4.39,49,-32,3,18,1,2", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
|
||||
if (pm->coeff[0][0] != 0 || pm->coeff[0][1] < 5.1999 || pm->coeff[0][1] > 5.2001 || pm->coeff[0][2] != 0 ||
|
||||
pm->coeff[1][0] != 0 || pm->coeff[1][1] < .52999 || pm->coeff[1][1] > .53001 || pm->coeff[1][2] != -32 ||
|
||||
pm->coeff[2][0] != 3 || pm->coeff[2][1] < 4.3899 || pm->coeff[2][1] > 4.3901 || pm->coeff[2][2] != 49 ||
|
||||
pm->coeff[3][0] != -32 || pm->coeff[3][1] != 3 || pm->coeff[3][2] != 18 ||
|
||||
pm->coeff[4][0] != 1 || pm->coeff[4][1] != 2 || pm->coeff[4][2] != 3) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 304c\n");
|
||||
}
|
||||
|
||||
if (pm->coeff_ndp[0][0] != 0 || pm->coeff_ndp[0][1] != 1 || pm->coeff_ndp[0][2] != 0 ||
|
||||
pm->coeff_ndp[1][0] != 0 || pm->coeff_ndp[1][1] != 2 || pm->coeff_ndp[1][2] != 0 ||
|
||||
pm->coeff_ndp[2][0] != 0 || pm->coeff_ndp[2][1] != 2 || pm->coeff_ndp[2][2] != 0 ||
|
||||
pm->coeff_ndp[3][0] != 0 || pm->coeff_ndp[3][1] != 0 || pm->coeff_ndp[3][2] != 0 ||
|
||||
pm->coeff_ndp[4][0] != 0 || pm->coeff_ndp[4][1] != 0 || pm->coeff_ndp[4][2] != 0 ) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 304n\n");
|
||||
}
|
||||
|
||||
telemetry_coefficents_message ("N0QBF-11", "0,5.2,0,0,.53,-32,3,4.39,49,-32,3,18,1,,3", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
|
||||
if (pm->coeff[0][0] != 0 || pm->coeff[0][1] < 5.1999 || pm->coeff[0][1] > 5.2001 || pm->coeff[0][2] != 0 ||
|
||||
pm->coeff[1][0] != 0 || pm->coeff[1][1] < .52999 || pm->coeff[1][1] > .53001 || pm->coeff[1][2] != -32 ||
|
||||
pm->coeff[2][0] != 3 || pm->coeff[2][1] < 4.3899 || pm->coeff[2][1] > 4.3901 || pm->coeff[2][2] != 49 ||
|
||||
pm->coeff[3][0] != -32 || pm->coeff[3][1] != 3 || pm->coeff[3][2] != 18 ||
|
||||
pm->coeff[4][0] != 1 || pm->coeff[4][1] != 2 || pm->coeff[4][2] != 3) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 305c\n");
|
||||
}
|
||||
|
||||
if (pm->coeff_ndp[0][0] != 0 || pm->coeff_ndp[0][1] != 1 || pm->coeff_ndp[0][2] != 0 ||
|
||||
pm->coeff_ndp[1][0] != 0 || pm->coeff_ndp[1][1] != 2 || pm->coeff_ndp[1][2] != 0 ||
|
||||
pm->coeff_ndp[2][0] != 0 || pm->coeff_ndp[2][1] != 2 || pm->coeff_ndp[2][2] != 0 ||
|
||||
pm->coeff_ndp[3][0] != 0 || pm->coeff_ndp[3][1] != 0 || pm->coeff_ndp[3][2] != 0 ||
|
||||
pm->coeff_ndp[4][0] != 0 || pm->coeff_ndp[4][1] != 0 || pm->coeff_ndp[4][2] != 0 ) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 305n\n");
|
||||
}
|
||||
|
||||
|
||||
telemetry_bit_sense_message ("N0QBF-11", "10110000,N0QBF's Big Balloon", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
if (pm->sense[0] != 1 || pm->sense[1] != 0 || pm->sense[2] != 1 || pm->sense[3] != 1 ||
|
||||
pm->sense[4] != 0 || pm->sense[5] != 0 || pm->sense[6] != 0 || pm->sense[7] != 0 ||
|
||||
strcmp(pm->project, "N0QBF's Big Balloon") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 306\n");
|
||||
}
|
||||
|
||||
// Too few and invalid digits.
|
||||
telemetry_bit_sense_message ("N0QBF-11", "1011000", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
if (pm->sense[0] != 1 || pm->sense[1] != 0 || pm->sense[2] != 1 || pm->sense[3] != 1 ||
|
||||
pm->sense[4] != 0 || pm->sense[5] != 0 || pm->sense[6] != 0 || pm->sense[7] != 0 ||
|
||||
strcmp(pm->project, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 307\n");
|
||||
}
|
||||
|
||||
telemetry_bit_sense_message ("N0QBF-11", "10110008", 0);
|
||||
|
||||
pm = t_get_metadata("N0QBF-11");
|
||||
if (pm->sense[0] != 1 || pm->sense[1] != 0 || pm->sense[2] != 1 || pm->sense[3] != 1 ||
|
||||
pm->sense[4] != 0 || pm->sense[5] != 0 || pm->sense[6] != 0 || pm->sense[7] != 0 ||
|
||||
strcmp(pm->project, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 308\n");
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
|
@ -1114,15 +1301,46 @@ int main ( )
|
|||
telemetry_name_message ("M0XER-3", "Vbat,Vsolar,Temp,Sat");
|
||||
telemetry_unit_label_message ("M0XER-3", "V,V,C,,m");
|
||||
|
||||
telemetry_data_base91 ("M0XER-3", "DyR.&^<A!.", result);
|
||||
telemetry_data_base91 ("M0XER-3", "cNOv'C?=!-", result);
|
||||
telemetry_data_base91 ("M0XER-3", "n0RS(:>b!+", result);
|
||||
telemetry_data_base91 ("M0XER-3", "x&G=!(8s!,", result);
|
||||
telemetry_data_base91 ("M0XER-3", "DyR.&^<A!.", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "10mW research balloon: Seq=3273, Vbat=4.472 V, Vsolar=0.516 V, Temp=-24.3 C, Sat=13") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 401\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("M0XER-3", "cNOv'C?=!-", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "10mW research balloon: Seq=6051, Vbat=4.271 V, Vsolar=0.580 V, Temp=2.6 C, Sat=12") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 402\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("M0XER-3", "n0RS(:>b!+", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "10mW research balloon: Seq=7022, Vbat=4.509 V, Vsolar=0.662 V, Temp=-2.8 C, Sat=10") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 403\n");
|
||||
}
|
||||
|
||||
telemetry_data_base91 ("M0XER-3", "x&G=!(8s!,", result, sizeof(result));
|
||||
|
||||
if (strcmp(result, "10mW research balloon: Seq=7922, Vbat=3.486 V, Vsolar=0.007 V, Temp=-55.7 C, Sat=11") != 0 ||
|
||||
strcmp(comment, "") != 0) {
|
||||
errors++; text_color_set(DW_COLOR_ERROR); dw_printf ("Wrong result, test 404\n");
|
||||
}
|
||||
|
||||
|
||||
// TODO: Should return success/fail so visual inspection is not needed.
|
||||
/* final score. */
|
||||
|
||||
exit (0);
|
||||
if (errors != 0) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("\nTEST FAILED with %d errors.\n", errors);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
text_color_set (DW_COLOR_REC);
|
||||
dw_printf ("\nTEST WAS SUCCESSFUL.\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
/* telemetry.h */
|
||||
|
||||
void telemetry_data_original (char *station, char *info, int quiet, char *output, char *comment);
|
||||
void telemetry_data_original (char *station, char *info, int quiet, char *output, size_t outputsize, char *comment, size_t commentsize);
|
||||
|
||||
void telemetry_data_base91 (char *station, char *cdata, char *output);
|
||||
void telemetry_data_base91 (char *station, char *cdata, char *output, size_t outputsize);
|
||||
|
||||
void telemetry_name_message (char *station, char *msg);
|
||||
|
||||
|
|
29
tocalls.txt
29
tocalls.txt
|
@ -1,6 +1,9 @@
|
|||
APRS TO-CALL VERSION NUMBERS 27 Apr 2015
|
||||
APRS TO-CALL VERSION NUMBERS 26 Oct 2015
|
||||
-------------------------------------------------------------------
|
||||
WB4APR
|
||||
26 Oct 15 added APZ247 for UPRS
|
||||
09 Sep 15 added APHTxx for HMTracker by IU0AAC
|
||||
06 Aug 15 added APMTxx for LZ1PPL for tracker
|
||||
27 Apr 15 added APZMAJ for Martyn M1MAJ DeLorme inReach Tracker
|
||||
21 Apr 15 added APB2MF & APR2MF DL2MF - MF2APRS Radiosonde
|
||||
06 Apr 15 added APAVT5 SainSonic AP510 - a 1watt tracker
|
||||
|
@ -9,26 +12,7 @@ APRS TO-CALL VERSION NUMBERS 27 Apr 2015
|
|||
21 Aug 14 added APSMSx Paul Defrusne's SMS gateway
|
||||
11 Aug 14 added APCWP8 John GM7HHB, WinphoneAPRS
|
||||
18 Dec 13 added APZWKR GM1WKR NetSked application
|
||||
22 Oct 13 added APFIxx APRS.FI OH7LZB, Hessu
|
||||
23 Aug 13 added APOxxx OSCAR satellites for AMSAT-LU by LU9DO
|
||||
22 Feb 13 added APNWxx SQ3FYK.com & SQ3PLX http://microsat.com.pl/
|
||||
and APMIxx SQ3PLX http://microsat.com.pl/
|
||||
29 Jan 13 added APICxx for HA9MCQ Pic IGate
|
||||
23 Jan 13 added APWAxx APRSISCE Android version
|
||||
18 Jan 13 added APDGxx,APDHxx,APDOxx,APDDxx,APDKxx,APD4xx for Dstar
|
||||
13 Jan 13 added APLMxx WA0TQG transceiver controller
|
||||
17 Dec 12 added APAMxx Altus Metrum GPS trackers
|
||||
03 Dec 12 added APUDRx NW Digital Radio's UDR (APRS/Dstar)
|
||||
03 Nov 12 added APHAXn SM2APRS by PY2UEP
|
||||
17 Sep 12 added APSCxx aprsc APRS-IS core server (OH7LZB, OH2MQK)
|
||||
12 Sep 12 added APSARx for ZL4FOX's SARTRACK
|
||||
02 Jul 12 added APDGxx D-Star Gateways by G4KLX
|
||||
28 Jun 12 added APDInn DIXPRS - Bela, HA5DI
|
||||
27 jun 12 added APMGxx MiniGate - Alex, AB0TJ
|
||||
17 Feb 12 added APJYnn KA2DDO yet another APRS system
|
||||
20 Jan 12 added APDSXX SP9UOB for dsDigi and ds-tracker
|
||||
APBPQx John G8BPQ Digipeater/IGate
|
||||
APLQRU Charlie - QRU Server
|
||||
|
||||
11 Jan 12 added APYTxx for YagTracker and updated Yaesu APY008/350
|
||||
|
||||
In APRS, the AX.25 Destination address is not used for packet
|
||||
|
@ -92,6 +76,7 @@ a TOCALL number series:
|
|||
APGOxx for AA3NJ PDA application
|
||||
APH APHKxx for LA1BR tracker/digipeater
|
||||
APHAXn SM2APRS by PY2UEP
|
||||
APHTxx HMTracker by IU0AAC
|
||||
API APICQx for ICQ
|
||||
APICxx for HA9MCQ Pic IGate
|
||||
APJ APJAxx JavAPRS
|
||||
|
@ -109,6 +94,7 @@ a TOCALL number series:
|
|||
APM APMxxx MacAPRS,
|
||||
APMGxx MiniGate - Alex, AB0TJ
|
||||
APMIxx SQ3PLX http://microsat.com.pl/
|
||||
APMTxx LZ1PPL for tracker
|
||||
APN APNxxx Network nodes, digis, etc
|
||||
APN3xx Kantronics KPC-3 rom versions
|
||||
APN9xx Kantronics KPC-9612 Roms
|
||||
|
@ -180,6 +166,7 @@ a TOCALL number series:
|
|||
APY350 Yaesu FTM-350 series
|
||||
APYTxx for YagTracker
|
||||
APZ APZxxx Experimental
|
||||
APZ247 for UPRS NR0Q
|
||||
APZ0xx Xastir (old versions. See APX)
|
||||
APZMAJ Martyn M1MAJ DeLorme inReach Tracker
|
||||
APZMDR for HaMDR trackers - hessu * hes.iki.fi]
|
||||
|
|
407
tt_text.c
407
tt_text.c
|
@ -162,6 +162,7 @@ static const char grid[10][10][3] =
|
|||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "textcolor.h"
|
||||
#include "tt_text.h"
|
||||
|
||||
|
@ -202,9 +203,9 @@ int dw_printf (const char *fmt, ...)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_text_to_multipress (char *text, int quiet, char *buttons)
|
||||
int tt_text_to_multipress (const char *text, int quiet, char *buttons)
|
||||
{
|
||||
char *t = text;
|
||||
const char *t = text;
|
||||
char *b = buttons;
|
||||
char c;
|
||||
int row, col;
|
||||
|
@ -305,9 +306,9 @@ int tt_text_to_multipress (char *text, int quiet, char *buttons)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_text_to_two_key (char *text, int quiet, char *buttons)
|
||||
int tt_text_to_two_key (const char *text, int quiet, char *buttons)
|
||||
{
|
||||
char *t = text;
|
||||
const char *t = text;
|
||||
char *b = buttons;
|
||||
char c;
|
||||
int row, col;
|
||||
|
@ -382,6 +383,7 @@ int tt_text_to_two_key (char *text, int quiet, char *buttons)
|
|||
* "00" for error because this is probably
|
||||
* being used to build up a fixed length
|
||||
* string where positions are signficant.
|
||||
* Must be at least 3 bytes.
|
||||
*
|
||||
* Returns: Number of errors detected.
|
||||
*
|
||||
|
@ -390,14 +392,13 @@ int tt_text_to_two_key (char *text, int quiet, char *buttons)
|
|||
|
||||
// TODO: need to test this.
|
||||
|
||||
int tt_letter_to_two_digits (char c, int quiet, char *buttons)
|
||||
int tt_letter_to_two_digits (char c, int quiet, char buttons[3])
|
||||
{
|
||||
char *b = buttons;
|
||||
int row, col;
|
||||
int errors = 0;
|
||||
int found;
|
||||
|
||||
*b = '\0';
|
||||
strlcpy(buttons, "", 3);
|
||||
|
||||
if (islower(c)) {
|
||||
c = toupper(c);
|
||||
|
@ -409,7 +410,7 @@ int tt_letter_to_two_digits (char c, int quiet, char *buttons)
|
|||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Letter to two digits: \"%c\" found where a letter is required.\n", c);
|
||||
}
|
||||
strcpy (buttons, "00");
|
||||
strlcpy (buttons, "00", 3);
|
||||
return (errors);
|
||||
}
|
||||
|
||||
|
@ -420,9 +421,9 @@ int tt_letter_to_two_digits (char c, int quiet, char *buttons)
|
|||
for (row=0; row<10 && ! found; row++) {
|
||||
for (col=0; col<4 && ! found; col++) {
|
||||
if (c == translate[row][col]) {
|
||||
*b++ = '0' + row;
|
||||
*b++ = '1' + col;
|
||||
*b = '\0';
|
||||
buttons[0] = '0' + row;
|
||||
buttons[1] = '1' + col;
|
||||
buttons[2] = '\0';
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +432,7 @@ int tt_letter_to_two_digits (char c, int quiet, char *buttons)
|
|||
errors++;
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Letter to two digits: INTERNAL ERROR. Should not be here.\n");
|
||||
strcpy (buttons, "00");
|
||||
strlcpy (buttons, "00", 3);
|
||||
}
|
||||
|
||||
return (errors);
|
||||
|
@ -457,9 +458,9 @@ int tt_letter_to_two_digits (char c, int quiet, char *buttons)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_text_to_call10 (char *text, int quiet, char *buttons)
|
||||
int tt_text_to_call10 (const char *text, int quiet, char *buttons)
|
||||
{
|
||||
char *t;
|
||||
const char *t;
|
||||
char *b;
|
||||
char c;
|
||||
int packed; /* two bits per character */
|
||||
|
@ -538,7 +539,7 @@ int tt_text_to_call10 (char *text, int quiet, char *buttons)
|
|||
|
||||
/* Binary to decimal for the columns. */
|
||||
|
||||
sprintf (stemp, "%04d", packed);
|
||||
snprintf (stemp, sizeof(stemp), "%04d", packed);
|
||||
strcat (buttons, stemp);
|
||||
|
||||
return (errors);
|
||||
|
@ -568,7 +569,7 @@ int tt_text_to_call10 (char *text, int quiet, char *buttons)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_text_to_satsq (char *text, int quiet, char *buttons)
|
||||
int tt_text_to_satsq (const char *text, int quiet, char *buttons, size_t buttonsize)
|
||||
{
|
||||
|
||||
int row, col;
|
||||
|
@ -577,7 +578,7 @@ int tt_text_to_satsq (char *text, int quiet, char *buttons)
|
|||
char uc[3];
|
||||
|
||||
|
||||
strcpy (buttons, "");
|
||||
strlcpy (buttons, "", buttonsize);
|
||||
|
||||
/* Quick validity check. */
|
||||
|
||||
|
@ -625,11 +626,16 @@ int tt_text_to_satsq (char *text, int quiet, char *buttons)
|
|||
for (row=0; row<10 && ! found; row++) {
|
||||
for (col=0; col<10 && ! found; col++) {
|
||||
if (strcmp(uc,grid[row][col]) == 0) {
|
||||
buttons[0] = row + '0';
|
||||
buttons[1] = col + '0';
|
||||
buttons[2] = text[2];
|
||||
buttons[3] = text[3];
|
||||
buttons[4] = '\0';
|
||||
|
||||
char btemp[8];
|
||||
|
||||
btemp[0] = row + '0';
|
||||
btemp[1] = col + '0';
|
||||
btemp[2] = text[2];
|
||||
btemp[3] = text[3];
|
||||
btemp[4] = '\0';
|
||||
|
||||
strlcpy (buttons, btemp, buttonsize);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
@ -667,9 +673,9 @@ int tt_text_to_satsq (char *text, int quiet, char *buttons)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_multipress_to_text (char *buttons, int quiet, char *text)
|
||||
int tt_multipress_to_text (const char *buttons, int quiet, char *text)
|
||||
{
|
||||
char *b = buttons;
|
||||
const char *b = buttons;
|
||||
char *t = text;
|
||||
char c;
|
||||
int row, col;
|
||||
|
@ -766,9 +772,9 @@ int tt_multipress_to_text (char *buttons, int quiet, char *text)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_two_key_to_text (char *buttons, int quiet, char *text)
|
||||
int tt_two_key_to_text (const char *buttons, int quiet, char *text)
|
||||
{
|
||||
char *b = buttons;
|
||||
const char *b = buttons;
|
||||
char *t = text;
|
||||
char c;
|
||||
int row, col;
|
||||
|
@ -847,24 +853,24 @@ int tt_two_key_to_text (char *buttons, int quiet, char *text)
|
|||
*
|
||||
* quiet - True to suppress error messages.
|
||||
*
|
||||
* textsiz - Size of result storage. Typically 2.
|
||||
*
|
||||
* Outputs: text - Converted to string which should contain one upper case letter.
|
||||
* If error, use 'x' as a placeholder because we are probably
|
||||
* dealing with fixed length strings where position matters.
|
||||
* Empty string on error.
|
||||
*
|
||||
* Returns: Number of errors detected.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
// TODO: need to test
|
||||
|
||||
int tt_two_digits_to_letter (char *buttons, int quiet, char *text)
|
||||
int tt_two_digits_to_letter (const char *buttons, int quiet, char *text, size_t textsiz)
|
||||
{
|
||||
char c1 = buttons[0];
|
||||
char c2 = buttons[1];
|
||||
int row, col;
|
||||
int errors = 0;
|
||||
char stemp2[2];
|
||||
|
||||
strcpy (text, "x");
|
||||
strlcpy (text, "", textsiz);
|
||||
|
||||
if (c1 >= '2' && c1 <= '9') {
|
||||
|
||||
|
@ -874,12 +880,14 @@ int tt_two_digits_to_letter (char *buttons, int quiet, char *text)
|
|||
col = c2 - '1';
|
||||
|
||||
if (translate[row][col] != 0) {
|
||||
text[0] = translate[row][col];
|
||||
text[1] = '\0';
|
||||
|
||||
stemp2[0] = translate[row][col];
|
||||
stemp2[1] = '\0';
|
||||
strlcpy (text, stemp2, textsiz);
|
||||
}
|
||||
else {
|
||||
errors++;
|
||||
strcpy (text, "x");
|
||||
strlcpy (text, "", textsiz);
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Two digits to letter: Invalid combination \"%c%c\".\n", c1, c2);
|
||||
|
@ -888,7 +896,7 @@ int tt_two_digits_to_letter (char *buttons, int quiet, char *text)
|
|||
}
|
||||
else {
|
||||
errors++;
|
||||
strcpy (text, "x");
|
||||
strlcpy (text, "", textsiz);
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Two digits to letter: Second character \"%c\" must be in range of 1 through 4.\n", c2);
|
||||
|
@ -897,7 +905,7 @@ int tt_two_digits_to_letter (char *buttons, int quiet, char *text)
|
|||
}
|
||||
else {
|
||||
errors++;
|
||||
strcpy (text, "x");
|
||||
strlcpy (text, "", textsiz);
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Two digits to letter: First character \"%c\" must be in range of 2 through 9.\n", c1);
|
||||
|
@ -926,9 +934,9 @@ int tt_two_digits_to_letter (char *buttons, int quiet, char *text)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_call10_to_text (char *buttons, int quiet, char *text)
|
||||
int tt_call10_to_text (const char *buttons, int quiet, char *text)
|
||||
{
|
||||
char *b;
|
||||
const char *b;
|
||||
char *t;
|
||||
char c;
|
||||
int packed; /* from last 4 digits */
|
||||
|
@ -1010,39 +1018,57 @@ int tt_call10_to_text (char *buttons, int quiet, char *text)
|
|||
*
|
||||
* Name: tt_mhead_to_text
|
||||
*
|
||||
* Purpose: Convert the 4, 6, 10, or 12 digit DTMF representation of Maidenhead
|
||||
* Grid Square Locator to normal text representation.
|
||||
* Purpose: Convert the DTMF representation of
|
||||
* Maidenhead Grid Square Locator to normal text representation.
|
||||
*
|
||||
* Inputs: buttons - Input string.
|
||||
* Must contain 4, 6, 10, or 12 digits.
|
||||
* Must contain 4, 6, 10, or 12, 16, or 18 digits.
|
||||
*
|
||||
* quiet - True to suppress error messages.
|
||||
*
|
||||
* Outputs: text - Converted to gridsquare with upper case letters and digits.
|
||||
* Length should be 2, 4, 6, or 8 with alternating letter or digit pairs.
|
||||
* Zero length if any error.
|
||||
*
|
||||
* Returns: Number of errors detected.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
#define MAXMHPAIRS 6
|
||||
|
||||
int tt_mhead_to_text (char *buttons, int quiet, char *text)
|
||||
static const struct {
|
||||
char *position;
|
||||
char min_ch;
|
||||
char max_ch;
|
||||
} mhpair[MAXMHPAIRS] = {
|
||||
{ "first", 'A', 'R' },
|
||||
{ "second", '0', '9' },
|
||||
{ "third", 'A', 'X' },
|
||||
{ "fourth", '0', '9' },
|
||||
{ "fifth", 'A', 'X' },
|
||||
{ "sixth", '0', '9' }
|
||||
};
|
||||
|
||||
|
||||
int tt_mhead_to_text (const char *buttons, int quiet, char *text, size_t textsiz)
|
||||
{
|
||||
char *b;
|
||||
char *t;
|
||||
const char *b;
|
||||
int errors = 0;
|
||||
|
||||
strcpy (text, "");
|
||||
strlcpy (text, "", textsiz);
|
||||
|
||||
/* Validity check. */
|
||||
|
||||
if (strlen(buttons) != 4 && strlen(buttons) != 6 && strlen(buttons) != 10 && strlen(buttons) != 12) {
|
||||
if (strlen(buttons) != 4 && strlen(buttons) != 6 &&
|
||||
strlen(buttons) != 10 && strlen(buttons) != 12 &&
|
||||
strlen(buttons) != 16 && strlen(buttons) != 18) {
|
||||
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("DTMF to Maidenhead Gridsquare Locator: Input \"%s\" must be exactly 4, 6, 10, or 12 digits.\n", buttons);
|
||||
}
|
||||
errors++;
|
||||
strlcpy (text, "", textsiz);
|
||||
return (errors);
|
||||
}
|
||||
|
||||
|
@ -1054,46 +1080,48 @@ int tt_mhead_to_text (char *buttons, int quiet, char *text)
|
|||
dw_printf ("DTMF to Maidenhead Gridsquare Locator: Input \"%s\" can contain only digits.\n", buttons);
|
||||
}
|
||||
errors++;
|
||||
strlcpy (text, "", textsiz);
|
||||
return (errors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Convert DTMF to normal representation. */
|
||||
|
||||
b = buttons;
|
||||
t = text;
|
||||
|
||||
errors += tt_two_digits_to_letter (b, quiet, t);
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 6 && b < buttons+strlen(buttons); n++) {
|
||||
if ((n % 2) == 0) {
|
||||
|
||||
/* Convert pairs of digits to letter. */
|
||||
|
||||
char t2[2];
|
||||
|
||||
errors += tt_two_digits_to_letter (b, quiet, t2, sizeof(t2));
|
||||
strlcat (text, t2, textsiz);
|
||||
b += 2;
|
||||
t++;
|
||||
|
||||
errors += tt_two_digits_to_letter (b, quiet, t);
|
||||
errors += tt_two_digits_to_letter (b, quiet, t2, sizeof(t2));
|
||||
strlcat (text, t2, textsiz);
|
||||
b += 2;
|
||||
t++;
|
||||
}
|
||||
else {
|
||||
|
||||
if (strlen(buttons) > 4) {
|
||||
/* Copy the digits. */
|
||||
|
||||
*t++ = *b++;
|
||||
*t++ = *b++;
|
||||
*t = '\0';
|
||||
|
||||
if (strlen(buttons) > 6) {
|
||||
|
||||
errors += tt_two_digits_to_letter (b, quiet, t);
|
||||
b += 2;
|
||||
t++;
|
||||
|
||||
errors += tt_two_digits_to_letter (b, quiet, t);
|
||||
b += 2;
|
||||
t++;
|
||||
|
||||
if (strlen(buttons) > 10) {
|
||||
|
||||
*t++ = *b++;
|
||||
*t++ = *b++;
|
||||
*t = '\0';
|
||||
}
|
||||
char d3[3];
|
||||
d3[0] = *b++;
|
||||
d3[1] = *b++;
|
||||
d3[2] = '\0';
|
||||
strlcat (text, d3, textsiz);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors != 0) {
|
||||
strlcpy (text, "", textsiz);
|
||||
}
|
||||
return (errors);
|
||||
|
||||
} /* end tt_mhead_to_text */
|
||||
|
@ -1103,113 +1131,92 @@ int tt_mhead_to_text (char *buttons, int quiet, char *text)
|
|||
*
|
||||
* Name: tt_text_to_mhead
|
||||
*
|
||||
* Purpose: Convert the 2, 4, 6, or 8 character Maidenhead
|
||||
* Grid Square Locator to DTMF representation.
|
||||
* Purpose: Convert normal text Maidenhead Grid Square Locator to DTMF representation.
|
||||
*
|
||||
* Outputs: text - Maidenhead Grid Square locator in usual format.
|
||||
* Length should be 2, 4, 6, or 8 with alternating letter or digit pairs.
|
||||
*
|
||||
* Inputs: buttons - Result with 4, 6, 10, or 12 digits.
|
||||
* Each letter is replaced by two digits.
|
||||
* Inputs: text - Maidenhead Grid Square locator in usual format.
|
||||
* Length should be 1 to 6 pairs with alternating letter or digit pairs.
|
||||
*
|
||||
* quiet - True to suppress error messages.
|
||||
*
|
||||
* buttonsize - space available for 'buttons' result.
|
||||
*
|
||||
* Outputs: buttons - Result with 4, 6, 10, 12, 16, 18 digits.
|
||||
* Each letter is replaced by two digits.
|
||||
* Digits are simply copied.
|
||||
*
|
||||
* Returns: Number of errors detected.
|
||||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
|
||||
int tt_text_to_mhead (char *text, int quiet, char *buttons)
|
||||
int tt_text_to_mhead (const char *text, int quiet, char *buttons, size_t buttonsize)
|
||||
{
|
||||
char *b;
|
||||
char *t;
|
||||
int errors = 0;
|
||||
int np, i;
|
||||
|
||||
strcpy (buttons, "");
|
||||
strlcpy (buttons, "", buttonsize);
|
||||
|
||||
np = strlen(text) / 2;
|
||||
|
||||
if (strlen(text) != 2 && strlen(text) != 4 && strlen(text) != 6 && strlen(text) != 8) {
|
||||
if ((strlen(text) % 2) != 0) {
|
||||
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Maidenhead Gridsquare Locator to DTMF: Input \"%s\" must be exactly 2, 4, 6, or 8 characters.\n", text);
|
||||
dw_printf ("Maidenhead Gridsquare Locator to DTMF: Input \"%s\" must be even number of characters.\n", text);
|
||||
}
|
||||
errors++;
|
||||
return (errors);
|
||||
}
|
||||
|
||||
t = text;
|
||||
b = buttons;
|
||||
if (np < 1 || np > MAXMHPAIRS) {
|
||||
|
||||
if (toupper(t[0]) < 'A' || toupper(t[0]) > 'R' || toupper(t[1]) < 'A' || toupper(t[1]) > 'R') {
|
||||
if (! quiet) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Maidenhead Gridsquare Locator to DTMF: Input \"%s\" must be 1 to %d pairs of characters.\n", text, np);
|
||||
}
|
||||
errors++;
|
||||
return (errors);
|
||||
}
|
||||
|
||||
for (i = 0; i < np; i++) {
|
||||
|
||||
char t0 = text[i*2];
|
||||
char t1 = text[i*2+1];
|
||||
|
||||
if (toupper(t0) < mhpair[i].min_ch || toupper(t0) > mhpair[i].max_ch ||
|
||||
toupper(t1) < mhpair[i].min_ch || toupper(t1) > mhpair[i].max_ch) {
|
||||
if (! quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("The first pair of characters in Maidenhead locator \"%s\" must be in range of A thru R.\n", text);
|
||||
dw_printf("The %s pair of characters in Maidenhead locator \"%s\" must be in range of %c thru %c.\n",
|
||||
mhpair[i].position, text, mhpair[i].min_ch, mhpair[i].max_ch);
|
||||
}
|
||||
strlcpy (buttons, "", buttonsize);
|
||||
errors++;
|
||||
return(errors);
|
||||
}
|
||||
|
||||
errors += tt_letter_to_two_digits (*t, quiet, b);
|
||||
t++;
|
||||
b += 2;
|
||||
if (mhpair[i].min_ch == 'A') { /* Should be letters */
|
||||
|
||||
errors += tt_letter_to_two_digits (*t, quiet, b);
|
||||
t++;
|
||||
b += 2;
|
||||
char b3[3];
|
||||
|
||||
if (strlen(text) > 2) {
|
||||
errors += tt_letter_to_two_digits (t0, quiet, b3);
|
||||
strlcat (buttons, b3, buttonsize);
|
||||
|
||||
if ( ! isdigit(t[0]) || ! isdigit(t[1])) {
|
||||
if (! quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("The second pair of characters in Maidenhead locator \"%s\" must digits 0 thru 9.\n", text);
|
||||
}
|
||||
errors++;
|
||||
return(errors);
|
||||
errors += tt_letter_to_two_digits (t1, quiet, b3);
|
||||
strlcat (buttons, b3, buttonsize);
|
||||
}
|
||||
else { /* Should be digits */
|
||||
|
||||
*b++ = *t++;
|
||||
*b++ = *t++;
|
||||
*b = '\0';
|
||||
char b3[3];
|
||||
|
||||
if (strlen(text) > 4) {
|
||||
|
||||
if (toupper(t[0]) < 'A' || toupper(t[0]) > 'X' || toupper(t[1]) < 'A' || toupper(t[1]) > 'X') {
|
||||
if (! quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("The third pair of characters in Maidenhead locator \"%s\" must be in range of A thru X.\n", text);
|
||||
}
|
||||
errors++;
|
||||
return(errors);
|
||||
}
|
||||
|
||||
errors += tt_letter_to_two_digits (*t, quiet, b);
|
||||
t++;
|
||||
b += 2;
|
||||
|
||||
errors += tt_letter_to_two_digits (*t, quiet, b);
|
||||
t++;
|
||||
b += 2;
|
||||
|
||||
if (strlen(text) > 6) {
|
||||
|
||||
if ( ! isdigit(t[0]) || ! isdigit(t[1])) {
|
||||
if (! quiet) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf("The fourth pair of characters in Maidenhead locator \"%s\" must digits 0 thru 9.\n", text);
|
||||
}
|
||||
errors++;
|
||||
return(errors);
|
||||
}
|
||||
|
||||
*b++ = *t++;
|
||||
*b++ = *t++;
|
||||
*b = '\0';
|
||||
}
|
||||
b3[0] = t0;
|
||||
b3[1] = t1;
|
||||
b3[2] = '\0';
|
||||
strlcat (buttons, b3, buttonsize);
|
||||
}
|
||||
}
|
||||
|
||||
if (errors != 0) strlcpy (buttons, "", buttonsize);
|
||||
|
||||
return (errors);
|
||||
|
||||
} /* tt_text_to_mhead */
|
||||
|
@ -1232,9 +1239,9 @@ int tt_text_to_mhead (char *text, int quiet, char *buttons)
|
|||
*
|
||||
*----------------------------------------------------------------*/
|
||||
|
||||
int tt_satsq_to_text (char *buttons, int quiet, char *text)
|
||||
int tt_satsq_to_text (const char *buttons, int quiet, char *text)
|
||||
{
|
||||
char *b;
|
||||
const char *b;
|
||||
int row, col;
|
||||
int errors = 0;
|
||||
|
||||
|
@ -1395,13 +1402,13 @@ int main (int argc, char *argv[])
|
|||
dw_printf ("\"%s\"\n", buttons);
|
||||
}
|
||||
|
||||
n = tt_text_to_mhead (text, 1, buttons);
|
||||
n = tt_text_to_mhead (text, 1, buttons, sizeof(buttons));
|
||||
if (n == 0) {
|
||||
dw_printf ("Push buttons for Maidenhead Grid Square Locator:\n");
|
||||
dw_printf ("\"%s\"\n", buttons);
|
||||
}
|
||||
|
||||
n = tt_text_to_satsq (text, 1, buttons);
|
||||
n = tt_text_to_satsq (text, 1, buttons, sizeof(buttons));
|
||||
if (n == 0) {
|
||||
dw_printf ("Push buttons for satellite gridsquare:\n");
|
||||
dw_printf ("\"%s\"\n", buttons);
|
||||
|
@ -1442,7 +1449,7 @@ int main (int argc, char *argv[])
|
|||
strcpy (buttons, argv[1]);
|
||||
|
||||
for (n = 2; n < argc; n++) {
|
||||
strcat (buttons, argv[n]);
|
||||
strlcat (buttons, argv[n], sizeof(buttons));
|
||||
}
|
||||
|
||||
switch (tt_guess_type(buttons)) {
|
||||
|
@ -1471,7 +1478,7 @@ int main (int argc, char *argv[])
|
|||
dw_printf ("\"%s\"\n", text);
|
||||
}
|
||||
|
||||
n = tt_mhead_to_text (buttons, 1, text);
|
||||
n = tt_mhead_to_text (buttons, 1, text, sizeof(text));
|
||||
if (n == 0) {
|
||||
dw_printf ("Decoded Maidenhead Locator from DTMF digits:\n");
|
||||
dw_printf ("\"%s\"\n", text);
|
||||
|
@ -1490,6 +1497,108 @@ int main (int argc, char *argv[])
|
|||
#endif /* decoding */
|
||||
|
||||
|
||||
#if TTT_TEST
|
||||
|
||||
/* end tt-text.c */
|
||||
/* gcc -g -DTTT_TEST tt_text.c textcolor.o misc.a && ./a.exe */
|
||||
|
||||
|
||||
/* Quick unit test. */
|
||||
|
||||
static int error_count;
|
||||
|
||||
static void test_text2tt (char *text, char *expect_mp, char *expect_2k, char *expect_c10, char *expect_loc, char *expect_sat)
|
||||
{
|
||||
char buttons[100];
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("\nConvert from text \"%s\" to tone sequence.\n", text);
|
||||
|
||||
tt_text_to_multipress (text, 0, buttons);
|
||||
if (strcmp(buttons, expect_mp) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected multi-press \"%s\" but got \"%s\"\n", expect_mp, buttons); }
|
||||
|
||||
tt_text_to_two_key (text, 0, buttons);
|
||||
if (strcmp(buttons, expect_2k) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected two-key \"%s\" but got \"%s\"\n", expect_2k, buttons); }
|
||||
|
||||
tt_text_to_call10 (text, 0, buttons);
|
||||
if (strcmp(buttons, expect_c10) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected call 6+4 \"%s\" but got \"%s\"\n", expect_c10, buttons); }
|
||||
|
||||
tt_text_to_mhead (text, 0, buttons, sizeof(buttons));
|
||||
if (strcmp(buttons, expect_loc) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected Maidenhead \"%s\" but got \"%s\"\n", expect_loc, buttons); }
|
||||
|
||||
tt_text_to_satsq (text, 0, buttons, sizeof(buttons));
|
||||
if (strcmp(buttons, expect_sat) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected Sat Sq \"%s\" but got \"%s\"\n", expect_sat, buttons); }
|
||||
}
|
||||
|
||||
static void test_tt2text (char *buttons, char *expect_mp, char *expect_2k, char *expect_c10, char *expect_loc, char *expect_sat)
|
||||
{
|
||||
char text[100];
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("\nConvert tone sequence \"%s\" to text.\n", buttons);
|
||||
|
||||
tt_multipress_to_text (buttons, 0, text);
|
||||
if (strcmp(text, expect_mp) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected multi-press \"%s\" but got \"%s\"\n", expect_mp, text); }
|
||||
|
||||
tt_two_key_to_text (buttons, 0, text);
|
||||
if (strcmp(text, expect_2k) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected two-key \"%s\" but got \"%s\"\n", expect_2k, text); }
|
||||
|
||||
tt_call10_to_text (buttons, 0, text);
|
||||
if (strcmp(text, expect_c10) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected call 6+4 \"%s\" but got \"%s\"\n", expect_c10, text); }
|
||||
|
||||
tt_mhead_to_text (buttons, 0, text, sizeof(text));
|
||||
if (strcmp(text, expect_loc) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected Maidenhead \"%s\" but got \"%s\"\n", expect_loc, text); }
|
||||
|
||||
tt_satsq_to_text (buttons, 0, text);
|
||||
if (strcmp(text, expect_sat) != 0) { error_count++; text_color_set(DW_COLOR_ERROR); dw_printf ("Expected Sat Sq \"%s\" but got \"%s\"\n", expect_sat, text); }
|
||||
}
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
text_color_set (DW_COLOR_INFO);
|
||||
dw_printf ("Test conversions between normal text and DTMF representation.\n");
|
||||
dw_printf ("Some error messages are normal. Just look for number of errors at end.\n");
|
||||
|
||||
error_count = 0;
|
||||
|
||||
/* original text multipress two-key call10 mhead satsq */
|
||||
|
||||
test_text2tt ("abcdefg 0123", "2A22A2223A33A33340A00122223333", "2A2B2C3A3B3C4A0A0123", "", "", "");
|
||||
|
||||
test_text2tt ("WB4APR", "922444427A777", "9A2B42A7A7C", "9242771558", "", "");
|
||||
|
||||
test_text2tt ("EM29QE78", "3362222999997733777778888", "3B6A297B3B78", "", "326129723278", "");
|
||||
|
||||
test_text2tt ("FM19", "3336199999", "3C6A19", "3619003333", "336119", "1819");
|
||||
|
||||
|
||||
/* tone_seq multipress two-key call10 mhead satsq */
|
||||
|
||||
test_tt2text ("2A22A2223A33A33340A00122223333", "ABCDEFG 0123", "A2A222D3D3334 00122223333", "", "", "");
|
||||
|
||||
test_tt2text ("9242771558", "WAGAQ1KT", "9242771558", "WB4APR", "", "");
|
||||
|
||||
test_tt2text ("326129723278", "DAM1AWPADAPT", "326129723278", "", "EM29QE78", "");
|
||||
|
||||
test_tt2text ("1819", "1T1W", "1819", "", "", "FM19");
|
||||
|
||||
|
||||
if (error_count > 0) {
|
||||
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("\nERROR: %d tests failed.\n", error_count);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
text_color_set (DW_COLOR_REC);
|
||||
dw_printf ("\nSUCCESS! All tests passed.\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
|
||||
|
||||
} /* end main */
|
||||
|
||||
#endif
|
||||
|
||||
/* end tt_text.c */
|
||||
|
||||
|
|
20
tt_text.h
20
tt_text.h
|
@ -4,28 +4,28 @@
|
|||
|
||||
/* Encode normal human readable to DTMF representation. */
|
||||
|
||||
int tt_text_to_multipress (char *text, int quiet, char *buttons);
|
||||
int tt_text_to_multipress (const char *text, int quiet, char *buttons);
|
||||
|
||||
int tt_text_to_two_key (char *text, int quiet, char *buttons);
|
||||
int tt_text_to_two_key (const char *text, int quiet, char *buttons);
|
||||
|
||||
int tt_text_to_call10 (char *text, int quiet, char *buttons) ;
|
||||
int tt_text_to_call10 (const char *text, int quiet, char *buttons);
|
||||
|
||||
int tt_text_to_mhead (char *text, int quiet, char *buttons) ;
|
||||
int tt_text_to_mhead (const char *text, int quiet, char *buttons, size_t buttonsiz);
|
||||
|
||||
int tt_text_to_satsq (char *text, int quiet, char *buttons) ;
|
||||
int tt_text_to_satsq (const char *text, int quiet, char *buttons, size_t buttonsiz);
|
||||
|
||||
|
||||
/* Decode DTMF to normal human readable form. */
|
||||
|
||||
int tt_multipress_to_text (char *buttons, int quiet, char *text);
|
||||
int tt_multipress_to_text (const char *buttons, int quiet, char *text);
|
||||
|
||||
int tt_two_key_to_text (char *buttons, int quiet, char *text);
|
||||
int tt_two_key_to_text (const char *buttons, int quiet, char *text);
|
||||
|
||||
int tt_call10_to_text (char *buttons, int quiet, char *text);
|
||||
int tt_call10_to_text (const char *buttons, int quiet, char *text);
|
||||
|
||||
int tt_mhead_to_text (char *buttons, int quiet, char *text);
|
||||
int tt_mhead_to_text (const char *buttons, int quiet, char *text, size_t textsiz);
|
||||
|
||||
int tt_satsq_to_text (char *buttons, int quiet, char *text);
|
||||
int tt_satsq_to_text (const char *buttons, int quiet, char *text);
|
||||
|
||||
|
||||
/* end tt_text.h */
|
|
@ -427,8 +427,10 @@ int tt_user_heard (char *callsign, int ssid, char overlay, char symbol, char *lo
|
|||
int i;
|
||||
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
//dw_printf ("tt_user_heard (%s, %d, %c, %c, %s, ...)\n", callsign, ssid, overlay, symbol, loc_text);
|
||||
// TODO: remove debug
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("tt_user_heard (%s, %d, %c, %c, %s, ...)\n", callsign, ssid, overlay, symbol, loc_text);
|
||||
|
||||
/*
|
||||
* At this time all messages are expected to contain a callsign.
|
||||
|
@ -766,7 +768,7 @@ static void xmit_object_report (int i, int first_time)
|
|||
|
||||
encode_object (object_name, 0, tt_user[i].last_heard, olat, olong,
|
||||
tt_user[i].overlay, tt_user[i].symbol,
|
||||
0,0,0,NULL, 0,0, /* PHGD, C/S */
|
||||
0,0,0,NULL, G_UNKNOWN, G_UNKNOWN, /* PHGD, Course/Speed */
|
||||
atof(tt_user[i].freq), 0, 0, info_comment, object_info, sizeof(object_info));
|
||||
|
||||
strlcat (stemp, object_info, sizeof(stemp));
|
||||
|
|
10
ttcalc.c
10
ttcalc.c
|
@ -237,7 +237,7 @@ int main (int argc, char *argv[])
|
|||
* Convert to AX.25 frame.
|
||||
* Notice that the special destination will cause it to be spoken.
|
||||
*/
|
||||
sprintf (reply_text, "N0CALL>SPEECH:%d", n);
|
||||
snprintf (reply_text, sizeof(reply_text), "N0CALL>SPEECH:%d", n);
|
||||
reply_pp = ax25_from_text(reply_text, 1);
|
||||
|
||||
/*
|
||||
|
@ -508,7 +508,7 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
case AF_INET:
|
||||
sa4 = (struct sockaddr_in *)pAddr;
|
||||
#if __WIN32__
|
||||
sprintf (pStringBuf, "%d.%d.%d.%d", sa4->sin_addr.S_un.S_un_b.s_b1,
|
||||
snprintf (pStringBuf, StringBufSize, "%d.%d.%d.%d", sa4->sin_addr.S_un.S_un_b.s_b1,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b2,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b3,
|
||||
sa4->sin_addr.S_un.S_un_b.s_b4);
|
||||
|
@ -519,7 +519,7 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
case AF_INET6:
|
||||
sa6 = (struct sockaddr_in6 *)pAddr;
|
||||
#if __WIN32__
|
||||
sprintf (pStringBuf, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
snprintf (pStringBuf, StringBufSize, "%x:%x:%x:%x:%x:%x:%x:%x",
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[0]),
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[1]),
|
||||
ntohs(((unsigned short *)(&(sa6->sin6_addr)))[2]),
|
||||
|
@ -533,9 +533,9 @@ static char * ia_to_text (int Family, void * pAddr, char * pStringBuf, size_t S
|
|||
#endif
|
||||
break;
|
||||
default:
|
||||
sprintf (pStringBuf, "Invalid address family!");
|
||||
snprintf (pStringBuf, StringBufSize, "Invalid address family!");
|
||||
}
|
||||
assert (strlen(pStringBuf) < StringBufSize);
|
||||
|
||||
return pStringBuf;
|
||||
|
||||
} /* end ia_to_text */
|
||||
|
|
89
walk96.c
89
walk96.c
|
@ -32,47 +32,43 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if __WIN32__
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#define __USE_XOPEN2KXSI 1
|
||||
#define __USE_XOPEN 1
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/errno.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "config.h"
|
||||
#include "ax25_pad.h"
|
||||
#include "textcolor.h"
|
||||
#include "latlong.h"
|
||||
#include "nmea.h"
|
||||
#include "dwgps.h"
|
||||
#include "encode_aprs.h"
|
||||
#include "serial_port.h"
|
||||
#include "kiss_frame.h"
|
||||
|
||||
|
||||
#define MYCALL "WB2OSZ" /************ Change this if you use it!!! ***************/
|
||||
|
||||
#define HOWLONG 20 /* Run for 20 seconds then quit. */
|
||||
|
||||
|
||||
|
||||
static MYFDTYPE tnc;
|
||||
|
||||
static void walk96 (int fix, double lat, double lon, float knots, float course, float alt);
|
||||
|
||||
main (int argc, char *argv[])
|
||||
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
struct misc_config_s config;
|
||||
char cmd[100];
|
||||
int debug_gps = 0;
|
||||
int n;
|
||||
|
||||
|
||||
// Look for Silicon Labs CP210x
|
||||
// TD-D72A USB - Look for Silicon Labs CP210x.
|
||||
// Just happens to be same on desktop & laptop.
|
||||
|
||||
tnc = serial_port_open ("COM5", 9600);
|
||||
|
@ -82,35 +78,60 @@ main (int argc, char *argv[])
|
|||
exit (EXIT_FAILURE); // defined in stdlib.h
|
||||
}
|
||||
|
||||
strcpy (cmd, "\r\rhbaud 9600\rkiss on\rrestart\r");
|
||||
|
||||
strlcpy (cmd, "\r\rhbaud 9600\rkiss on\rrestart\r", sizeof(cmd));
|
||||
serial_port_write (tnc, cmd, strlen(cmd));
|
||||
SLEEP_MS(500);
|
||||
|
||||
|
||||
// USB GPS happens to be COM22
|
||||
|
||||
memset (&config, 0, sizeof(config));
|
||||
strcpy (config.nmea_port, "COM1");
|
||||
nmea_init (&config);
|
||||
strlcpy (config.gpsnmea_port, "COM22", sizeof(config.nmea_port));
|
||||
|
||||
dwgps_init (&config, debug_gps);
|
||||
|
||||
SLEEP_SEC(1); /* Wait for sample before reading. */
|
||||
|
||||
for (n=0; n<HOWLONG; n++) {
|
||||
|
||||
dwgps_info_t info;
|
||||
dwfix_t fix;
|
||||
|
||||
fix = dwgps_read (&info);
|
||||
|
||||
if (fix > DWFIX_2D) {
|
||||
walk96 (fix, info.dlat, info.dlon, info.speed_knots, info.track, info.altitude);
|
||||
}
|
||||
else if (fix < 0) {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("Can't communicate with GPS receiver.\n");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
else {
|
||||
text_color_set (DW_COLOR_ERROR);
|
||||
dw_printf ("GPS fix not available.\n");
|
||||
}
|
||||
SLEEP_SEC(1);
|
||||
}
|
||||
|
||||
SLEEP_SEC(20);
|
||||
|
||||
// Exit out of KISS mode.
|
||||
|
||||
serial_port_write (tnc, "\xc0\xff\c0", 3);
|
||||
serial_port_write (tnc, "\xc0\xff\xc0", 3);
|
||||
|
||||
SLEEP_MS(100);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Should be called once per second. */
|
||||
|
||||
void walk96 (int fix, double lat, double lon, float knots, float course, float alt)
|
||||
static void walk96 (int fix, double lat, double lon, float knots, float course, float alt)
|
||||
{
|
||||
static int sequence = 0;
|
||||
char comment[50];
|
||||
|
||||
sequence++;
|
||||
sprintf (comment, "Sequence number %04d", sequence);
|
||||
snprintf (comment, sizeof(comment), "Sequence number %04d", sequence);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -125,16 +146,20 @@ void walk96 (int fix, double lat, double lon, float knots, float course, float a
|
|||
|
||||
char position_report[AX25_MAX_PACKET_LEN];
|
||||
|
||||
|
||||
// TODO (high, bug): Why do we see !4237.13N/07120.84W=PHG0000... when all values set to unknown.
|
||||
|
||||
|
||||
info_len = encode_position (messaging, compressed,
|
||||
lat, lon, (int)(DW_METERS_TO_FEET(alt)),
|
||||
'/', '?', // TODO: look up code for person.
|
||||
G_UNKNOWN, G_UNKNOWN, G_UNKNOWN, "", // PHG
|
||||
(int)course, (int)knots,
|
||||
'/', '=',
|
||||
G_UNKNOWN, G_UNKNOWN, G_UNKNOWN, "", // PHGd
|
||||
(int)roundf(course), (int)roundf(knots),
|
||||
445.925, 0, 0,
|
||||
comment,
|
||||
info, sizeof(info));
|
||||
|
||||
sprintf (position_report, "%s>WALK96:%s", MYCALL, info);
|
||||
snprintf (position_report, sizeof(position_report), "%s>WALK96:%s", MYCALL, info);
|
||||
|
||||
text_color_set (DW_COLOR_XMIT);
|
||||
dw_printf ("%s\n", position_report);
|
||||
|
|
17
xmit.c
17
xmit.c
|
@ -59,13 +59,6 @@
|
|||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
//#include <sys/time.h>
|
||||
//#include <time.h>
|
||||
|
||||
//#if __WIN32__
|
||||
//#include <windows.h>
|
||||
//#endif
|
||||
|
||||
#include "direwolf.h"
|
||||
#include "ax25_pad.h"
|
||||
#include "textcolor.h"
|
||||
|
@ -449,7 +442,7 @@ static void * xmit_thread (void *arg)
|
|||
ssid = ax25_get_ssid(pp, AX25_DESTINATION);
|
||||
}
|
||||
else {
|
||||
strcpy (dest, "");
|
||||
strlcpy (dest, "", sizeof(dest));
|
||||
}
|
||||
|
||||
if (strcmp(dest, "SPEECH") == 0) {
|
||||
|
@ -852,16 +845,16 @@ int xmit_speak_it (char *script, int c, char *orig_msg)
|
|||
|
||||
/* Remove any quotes because it will mess up command line argument parsing. */
|
||||
|
||||
strcpy (msg, orig_msg);
|
||||
strlcpy (msg, orig_msg, sizeof(msg));
|
||||
|
||||
for (p=msg; *p!='\0'; p++) {
|
||||
if (*p == '"') *p = ' ';
|
||||
}
|
||||
|
||||
#if __WIN32__
|
||||
sprintf (cmd, "%s %d \"%s\" >nul", script, c, msg);
|
||||
snprintf (cmd, sizeof(cmd), "%s %d \"%s\" >nul", script, c, msg);
|
||||
#else
|
||||
sprintf (cmd, "%s %d \"%s\"", script, c, msg);
|
||||
snprintf (cmd, sizeof(cmd), "%s %d \"%s\"", script, c, msg);
|
||||
#endif
|
||||
|
||||
//text_color_set(DW_COLOR_DEBUG);
|
||||
|
@ -878,7 +871,7 @@ int xmit_speak_it (char *script, int c, char *orig_msg)
|
|||
dw_printf ("Failed to run text-to-speech script, %s\n", script);
|
||||
|
||||
ignore = getcwd (cwd, sizeof(cwd));
|
||||
strcpy (path, getenv("PATH"));
|
||||
strlcpy (path, getenv("PATH"), sizeof(path));
|
||||
|
||||
dw_printf ("CWD = %s\n", cwd);
|
||||
dw_printf ("PATH = %s\n", path);
|
||||
|
|
Loading…
Reference in New Issue