mirror of https://github.com/wb2osz/direwolf.git
Version 1.1
modified: .gitattributes modified: APRStt-Implementation-Notes.pdf modified: CHANGES.txt modified: Makefile.linux modified: Makefile.win new file: Raspberry-Pi-APRS-Tracker.pdf modified: Raspberry-Pi-APRS.pdf modified: User-Guide.pdf modified: aclients.c modified: aprs_tt.c modified: aprs_tt.h modified: atest.c modified: audio.c modified: audio.h modified: audio_win.c modified: ax25_pad.c modified: ax25_pad.h modified: beacon.c modified: beacon.h modified: config.c modified: config.h modified: decode_aprs.c modified: decode_aprs.h modified: demod_afsk.c modified: digipeater.c modified: digipeater.h modified: direwolf.c modified: direwolf.conf modified: direwolf.h modified: dsp.c modified: dwgps.c modified: encode_aprs.c modified: encode_aprs.h modified: fsk_demod_state.h new file: grm_sym.h modified: hdlc_rec.c modified: hdlc_rec2.c modified: hdlc_rec2.h modified: kiss.c modified: kiss_frame.c modified: kiss_frame.h modified: kissnet.c modified: latlong.c modified: latlong.h new file: log.c new file: log.h new file: log2gpx.c new file: mgn_icon.h modified: misc/README-dire-wolf.txt modified: multi_modem.c new file: nmea.c new file: nmea.h modified: ptt.c modified: rdq.c modified: regex/README-dire-wolf.txt new file: rpack.h modified: rrbb.c modified: rrbb.h modified: server.c modified: symbols-new.txt modified: symbols.c modified: symbolsX.txt new file: telemetry.c new file: telemetry.h modified: textcolor.c modified: tocalls.txt modified: utm/README.txt modified: version.h modified: xmit.c modified: xmit.h
This commit is contained in:
parent
8978f2de6c
commit
b5d1d1c3dd
|
@ -15,3 +15,18 @@
|
||||||
*.PDF diff=astextplain
|
*.PDF diff=astextplain
|
||||||
*.rtf diff=astextplain
|
*.rtf diff=astextplain
|
||||||
*.RTF diff=astextplain
|
*.RTF diff=astextplain
|
||||||
|
|
||||||
|
# My rules to remove any doubt
|
||||||
|
|
||||||
|
*.c text
|
||||||
|
*.cpp text
|
||||||
|
*.h text
|
||||||
|
*.pl text
|
||||||
|
Makefile* text
|
||||||
|
*.txt text
|
||||||
|
*.desktop text
|
||||||
|
*.conf text
|
||||||
|
*.rc text
|
||||||
|
|
||||||
|
*.ico binary
|
||||||
|
*.png binary
|
||||||
|
|
Binary file not shown.
85
CHANGES.txt
85
CHANGES.txt
|
@ -3,6 +3,78 @@ Revision history
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
Version 1.1 -- December 2014
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* Changes since beta test version.
|
||||||
|
|
||||||
|
It is still highly recommended, but no longer mandatory, that
|
||||||
|
beaconing be enabled for digipeating to work.
|
||||||
|
|
||||||
|
|
||||||
|
* Known problems.
|
||||||
|
|
||||||
|
Sometimes kissattach fails to connect with "direwolf -p".
|
||||||
|
The User Guide and Raspberry Pi APRS document have a couple work-arounds.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-----------
|
||||||
|
Version 1.1 -- Beta Test 1 -- November 2014
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* New Features:
|
||||||
|
|
||||||
|
Logging of received packets and utility to convert log file
|
||||||
|
into GPX format.
|
||||||
|
|
||||||
|
AGW network port formerly allowed only one connection at a
|
||||||
|
time. It can now accept 3 client applications at the same time.
|
||||||
|
(Same has not yet been done for network KISS port.)
|
||||||
|
|
||||||
|
Frequency / offset / tone standard formats are now recognized.
|
||||||
|
Non-standard attempts, in the comment, are often detected and
|
||||||
|
a message suggests the correct format.
|
||||||
|
|
||||||
|
Telemetry is now recognized. Messages are printed for
|
||||||
|
usage that does not adhere to the published standard.
|
||||||
|
|
||||||
|
Tracker function transmits location from GPS position.
|
||||||
|
New configuration file options: TBEACON and SMARTBEACONING.
|
||||||
|
(For Linux only. Warning - has not been well tested.)
|
||||||
|
|
||||||
|
Experimental packet regeneration feature for HF use.
|
||||||
|
Will be documented later if proves to be useful...
|
||||||
|
|
||||||
|
Several enhancements for trying to fix incorrect CRC.
|
||||||
|
- Additional types of attempts to fix a bad CRC.
|
||||||
|
- Optimized code to reduce execution time.
|
||||||
|
- Improved detection of duplicate packets from different fixup attempts.
|
||||||
|
- Set limit on number of packets in fix up later queue.
|
||||||
|
|
||||||
|
Beacon positions can be specified in either latitude / longitude
|
||||||
|
or UTM coordinates.
|
||||||
|
|
||||||
|
|
||||||
|
* Bugs fixed:
|
||||||
|
|
||||||
|
For Windows version, maximum serial port was COM9.
|
||||||
|
It is now possible to use COM10 and higher.
|
||||||
|
|
||||||
|
Fixed issue with KISS protocol decoder state that showed up
|
||||||
|
only with "binary" data in packets (e.g. RMS Express).
|
||||||
|
|
||||||
|
An extra 00 byte was being appended to packets from AGW
|
||||||
|
network protocol 'K' messages.
|
||||||
|
|
||||||
|
Invalid data from an AGW client application could cause an
|
||||||
|
application crash.
|
||||||
|
|
||||||
|
OSS (audio interface for non-Linux versions of Unix) should
|
||||||
|
be better now.
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
Version 1.0a May 2014
|
Version 1.0a May 2014
|
||||||
-----------
|
-----------
|
||||||
|
@ -36,6 +108,13 @@ Improved support for UTF-8 character set.
|
||||||
|
|
||||||
Improved troubleshooting display for APRStt macros.
|
Improved troubleshooting display for APRStt macros.
|
||||||
|
|
||||||
|
In earlier versions, the DTMF decoder was always active because it
|
||||||
|
took a negligible amount of CPU time. Unfortunately this sometimes
|
||||||
|
resulted in too many false positives from some other types of digital
|
||||||
|
transmissions heard on HF. Starting in version 1.0, the DTMF decoder
|
||||||
|
is enabled only when the APRStt gateway is configured.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
|
@ -107,7 +186,7 @@ APRStt-Implementation-Notes.pdf
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
Version 0.6
|
Version 0.6 February 2013
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,7 +231,7 @@ run this in another window:
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
Version 0.5
|
Version 0.5 March 2012
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
||||||
|
@ -160,7 +239,7 @@ More error checking and messages for invalid APRS data.
|
||||||
|
|
||||||
|
|
||||||
-----------
|
-----------
|
||||||
Version 0.4
|
Version 0.4 September 2011
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
First general availability.
|
First general availability.
|
||||||
|
|
134
Makefile.linux
134
Makefile.linux
|
@ -2,7 +2,7 @@
|
||||||
# Makefile for Linux version of Dire Wolf.
|
# Makefile for Linux version of Dire Wolf.
|
||||||
#
|
#
|
||||||
|
|
||||||
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients
|
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
|
|
||||||
|
@ -81,18 +81,30 @@ CC = gcc
|
||||||
arch := $(shell echo | gcc -E -dM - | grep __i386__)
|
arch := $(shell echo | gcc -E -dM - | grep __i386__)
|
||||||
|
|
||||||
ifneq ($(arch),)
|
ifneq ($(arch),)
|
||||||
CFLAGS := -DUSE_ALSA -O3 -march=pentium3 -pthread
|
# You might see improvement with -march fine tuned to your hardware.
|
||||||
|
# Probably should keep pentium3 if you will be redistributing binaries
|
||||||
|
# to other people.
|
||||||
|
CFLAGS := -O3 -march=pentium3 -pthread -Iutm
|
||||||
else
|
else
|
||||||
CFLAGS := -DUSE_ALSA -O3 -pthread
|
CFLAGS := -O3 -pthread -Iutm
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Uncomment following lines to enable GPS interface.
|
|
||||||
# DO NOT USE THIS. Still needs more work.
|
# If you want to use OSS (for FreeBSD, OpenBSD) instead of
|
||||||
|
# ALSA (for Linux), comment out the two lines below.
|
||||||
|
|
||||||
|
CFLAGS += -DUSE_ALSA
|
||||||
|
LDLIBS += -lasound
|
||||||
|
|
||||||
|
|
||||||
|
# Uncomment following lines to enable GPS interface & tracker function.
|
||||||
|
|
||||||
#CFLAGS += -DENABLE_GPS
|
#CFLAGS += -DENABLE_GPS
|
||||||
#LDLIBS += -lgps
|
#LDLIBS += -lgps
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Name of current directory.
|
# Name of current directory.
|
||||||
# Used to generate zip file name for distribution.
|
# Used to generate zip file name for distribution.
|
||||||
|
|
||||||
|
@ -107,9 +119,9 @@ direwolf : direwolf.o config.o demod.o dsp.o demod_afsk.o demod_9600.o hdlc_rec
|
||||||
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
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 digipeater.o dedupe.o tq.o xmit.o \
|
gen_tone.o audio.o digipeater.o dedupe.o tq.o xmit.o \
|
||||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o encode_aprs.o latlong.o textcolor.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 \
|
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o log.o telemetry.o \
|
||||||
utm.a
|
utm.a
|
||||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread -lrt -lasound $(LDLIBS) -lm
|
$(CC) $(CFLAGS) -o $@ $^ -lpthread -lrt $(LDLIBS) -lm
|
||||||
|
|
||||||
|
|
||||||
# Optimization for slow processors.
|
# Optimization for slow processors.
|
||||||
|
@ -132,40 +144,51 @@ LatLong-UTMconversion.o : utm/LatLong-UTMconversion.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $^
|
$(CC) $(CFLAGS) -c -o $@ $^
|
||||||
|
|
||||||
|
|
||||||
# Optional install step.
|
# Optional installation into /usr/local/...
|
||||||
|
# Needs to be run as root or with sudo.
|
||||||
|
|
||||||
# TODO: Review file locations.
|
# TODO: Review file locations.
|
||||||
# TODO: Handle Linux variations correctly.
|
|
||||||
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
|
||||||
# For now, just put reference to it at the end so only last step fails.
|
|
||||||
|
|
||||||
install : direwolf decode_aprs tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
install : direwolf decode_aprs tocalls.txt symbols-new.txt symbolsX.txt dw-icon.png direwolf.desktop
|
||||||
sudo install direwolf /usr/local/bin
|
install direwolf /usr/local/bin
|
||||||
sudo install decode_aprs /usr/local/bin
|
install decode_aprs /usr/local/bin
|
||||||
sudo install text2tt /usr/local/bin
|
install text2tt /usr/local/bin
|
||||||
sudo install tt2text /usr/local/bin
|
install tt2text /usr/local/bin
|
||||||
sudo install ll2utm /usr/local/bin
|
install ll2utm /usr/local/bin
|
||||||
sudo install utm2ll /usr/local/bin
|
install utm2ll /usr/local/bin
|
||||||
sudo install aclients /usr/local/bin
|
install aclients /usr/local/bin
|
||||||
sudo install -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
install log2gpx /usr/local/bin
|
||||||
sudo install -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
install -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||||
sudo install -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
install -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||||
sudo install -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
install -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||||
sudo install -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
install -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||||
cp direwolf.conf ~
|
install -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||||
|
install -D --mode=644 CHANGES.txt /usr/local/share/doc/direwolf/CHANGES.txt
|
||||||
|
install -D --mode=644 LICENSE-dire-wolf.txt /usr/local/share/doc/direwolf/LICENSE-dire-wolf.txt
|
||||||
|
install -D --mode=644 LICENSE-other.txt /usr/local/share/doc/direwolf/LICENSE-other.txt
|
||||||
|
install -D --mode=644 User-Guide.pdf /usr/local/share/doc/direwolf/User-Guide.pdf
|
||||||
|
install -D --mode=644 Raspberry-Pi-APRS.pdf /usr/local/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
||||||
|
install -D --mode=644 Raspberry-Pi-APRS-Tracker.pdf /usr/local/share/doc/direwolf/Raspberry-Pi-APRS-Tracker.pdf
|
||||||
|
install -D --mode=644 APRStt-Implementation-Notes.pdf /usr/local/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
||||||
|
install -D --mode=644 Quick-Start-Guide-Windows.pdf /usr/local/share/doc/direwolf/Quick-Start-Guide-Windows.pdf
|
||||||
|
|
||||||
|
|
||||||
|
# The Raspberry Pi has ~/Desktop but Ubuntu does not.
|
||||||
|
|
||||||
|
# TODO: Handle Linux variations correctly.
|
||||||
|
|
||||||
|
|
||||||
|
install-rpi : dw-start.sh
|
||||||
cp dw-start.sh ~
|
cp dw-start.sh ~
|
||||||
sudo install -D --mode=644 CHANGES.txt /usr/local/share/doc/direwolf/CHANGES.txt
|
|
||||||
sudo install -D --mode=644 LICENSE-dire-wolf.txt /usr/local/share/doc/direwolf/LICENSE-dire-wolf.txt
|
|
||||||
sudo install -D --mode=644 LICENSE-other.txt /usr/local/share/doc/direwolf/LICENSE-other.txt
|
|
||||||
sudo install -D --mode=644 User-Guide.pdf /usr/local/share/doc/direwolf/User-Guide.pdf
|
|
||||||
sudo install -D --mode=644 Raspberry-Pi-APRS.pdf /usr/local/share/doc/direwolf/Raspberry-Pi-APRS.pdf
|
|
||||||
sudo install -D --mode=644 APRStt-Implementation-Notes.pdf /usr/local/share/doc/direwolf/APRStt-Implementation-Notes.pdf
|
|
||||||
sudo install -D --mode=644 Quick-Start-Guide-Windows.pdf /usr/local/share/doc/direwolf/Quick-Start-Guide-Windows.pdf
|
|
||||||
ln -f -s /usr/share/applications/direwolf.desktop ~/Desktop/direwolf.desktop
|
ln -f -s /usr/share/applications/direwolf.desktop ~/Desktop/direwolf.desktop
|
||||||
|
|
||||||
|
install-conf : direwolf.conf
|
||||||
|
cp direwolf.conf ~
|
||||||
|
|
||||||
|
|
||||||
# Separate application to decode raw data.
|
# Separate application to decode raw data.
|
||||||
|
|
||||||
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c
|
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c latlong.c log.c telemetry.o
|
||||||
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^ -lm
|
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^ -lm
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,23 +205,29 @@ tt2text : tt_text.c
|
||||||
# Convert between Latitude/Longitude and UTM coordinates.
|
# Convert between Latitude/Longitude and UTM coordinates.
|
||||||
|
|
||||||
ll2utm : ll2utm.c utm.a
|
ll2utm : ll2utm.c utm.a
|
||||||
$(CC) $(CFLAGS) -I utm -o $@ $^ -lm
|
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||||
|
|
||||||
utm2ll : utm2ll.c utm.a
|
utm2ll : utm2ll.c utm.a
|
||||||
$(CC) $(CFLAGS) -I utm -o $@ $^ -lm
|
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||||
|
|
||||||
|
|
||||||
|
# Convert from log file to GPX.
|
||||||
|
|
||||||
|
log2gpx : log2gpx.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||||
|
|
||||||
|
|
||||||
# Test application to generate sound.
|
# Test application to generate sound.
|
||||||
|
|
||||||
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c textcolor.c
|
gen_packets : gen_packets.c ax25_pad.c hdlc_send.c fcs_calc.c gen_tone.c textcolor.c
|
||||||
$(CC) $(CFLAGS) -o $@ $^ -lasound -lm
|
$(CC) $(CFLAGS) -o $@ $^ $(LDLIBS) -lm
|
||||||
|
|
||||||
demod.o : tune.h
|
demod.o : tune.h
|
||||||
demod_afsk.o : tune.h
|
demod_afsk.o : tune.h
|
||||||
demod_9600.o : tune.h
|
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 symbols.c tune.h textcolor.c
|
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
|
||||||
$(CC) $(CFLAGS) -o atest $^ -lm
|
$(CC) $(CFLAGS) -o atest $^ -lm
|
||||||
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
./atest 02_Track_2.wav | grep "packets decoded in" > atest.out
|
||||||
|
|
||||||
|
@ -206,8 +235,9 @@ testagc : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o
|
||||||
# Unit test for AFSK demodulator
|
# 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 symbols.c textcolor.c
|
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c latlong.c symbols.c textcolor.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||||
time ./atest ../direwolf-0.2/02_Track_2.wav
|
time ./atest ../direwolf-0.2/02_Track_2.wav
|
||||||
|
|
||||||
# Unit test for inner digipeater algorithm
|
# Unit test for inner digipeater algorithm
|
||||||
|
@ -233,6 +263,14 @@ udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec
|
||||||
./udptest
|
./udptest
|
||||||
|
|
||||||
|
|
||||||
|
# Unit test for telemetry decoding.
|
||||||
|
|
||||||
|
|
||||||
|
etest : telemetry.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||||
|
./etest
|
||||||
|
|
||||||
|
|
||||||
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||||
|
|
||||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c
|
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c
|
||||||
|
@ -241,7 +279,7 @@ aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c
|
||||||
|
|
||||||
SRCS = direwolf.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c multi_modem.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c \
|
SRCS = direwolf.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c multi_modem.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c \
|
||||||
server.c kiss.c kissnet.c kiss_frame.c hdlc_send.c fcs_calc.c gen_tone.c audio.c \
|
server.c kiss.c kissnet.c kiss_frame.c hdlc_send.c fcs_calc.c gen_tone.c audio.c \
|
||||||
digipeater.c dedupe.c tq.c xmit.c beacon.c encode_aprs.c latlong.c encode_aprs.c latlong.c
|
digipeater.c dedupe.c tq.c xmit.c beacon.c encode_aprs.c latlong.c encode_aprs.c latlong.c telemetry.c log.c
|
||||||
|
|
||||||
|
|
||||||
depend : $(SRCS)
|
depend : $(SRCS)
|
||||||
|
@ -256,12 +294,12 @@ clean :
|
||||||
# Package it up for distribution.
|
# Package it up for distribution.
|
||||||
|
|
||||||
dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-Pi-APRS.pdf \
|
dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-Pi-APRS.pdf \
|
||||||
direwolf.desktop dw-start.sh
|
Raspberry-Pi-APRS-Tracker.pdf direwolf.desktop dw-start.sh
|
||||||
rm -f fsk_fast_filter.h
|
rm -f fsk_fast_filter.h
|
||||||
echo " " > tune.h
|
echo " " > tune.h
|
||||||
rm -f ../$z-src.zip
|
rm -f ../$z-src.zip
|
||||||
(cd .. ; zip $z-src.zip $z/CHANGES.txt $z/LICENSE* \
|
(cd .. ; zip $z-src.zip $z/CHANGES.txt $z/LICENSE* \
|
||||||
$z/User-Guide.pdf $z/Quick-Start-Guide-Windows.pdf $z/Raspberry-Pi-APRS.pdf \
|
$z/User-Guide.pdf $z/Quick-Start-Guide-Windows.pdf $z/Raspberry-Pi-APRS.pdf Raspberry-Pi-APRS-Tracker.pdf \
|
||||||
$z/Makefile* $z/*.c $z/*.h $z/regex/* $z/misc/* $z/utm/* \
|
$z/Makefile* $z/*.c $z/*.h $z/regex/* $z/misc/* $z/utm/* \
|
||||||
$z/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
$z/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||||
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
||||||
|
@ -277,11 +315,25 @@ dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-P
|
||||||
#Raspberry-Pi-APRS.pdf : Raspberry-Pi-APRS.docx
|
#Raspberry-Pi-APRS.pdf : Raspberry-Pi-APRS.docx
|
||||||
# echo "***** Raspberry-Pi-APRS.pdf is out of date *****"
|
# echo "***** Raspberry-Pi-APRS.pdf is out of date *****"
|
||||||
|
|
||||||
|
#Raspberry-Pi-APRS-Tracker.pdf : Raspberry-Pi-APRS-Tracker.docx
|
||||||
|
# echo "***** Raspberry-Pi-APRS-Tracker.pdf is out of date *****"
|
||||||
|
|
||||||
|
|
||||||
backup :
|
backup :
|
||||||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||||
cp -r . /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.
|
||||||
|
#
|
||||||
|
|
||||||
|
tocalls-symbols :
|
||||||
|
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||||
|
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||||
|
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# The following is updated by "make depend"
|
# The following is updated by "make depend"
|
||||||
#
|
#
|
||||||
|
|
64
Makefile.win
64
Makefile.win
|
@ -16,7 +16,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients
|
all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients log2gpx
|
||||||
|
|
||||||
|
|
||||||
# People say we need -mthreads option for threads to work properly.
|
# People say we need -mthreads option for threads to work properly.
|
||||||
|
@ -25,8 +25,8 @@ all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients
|
||||||
#TODO: put -Ofast back in.
|
#TODO: put -Ofast back in.
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
#CFLAGS = -g -Wall -Ofast -march=pentium3 -msse -Iregex -mthreads -DUSE_REGEX_STATIC
|
#CFLAGS = -g -Wall -Ofast -march=pentium3 -msse -Iregex -Iutm -mthreads -DUSE_REGEX_STATIC
|
||||||
CFLAGS = -g -Wall -march=pentium3 -msse -Iregex -mthreads -DUSE_REGEX_STATIC
|
CFLAGS = -g -Wall -march=pentium3 -msse -Iregex -Iutm -mthreads -DUSE_REGEX_STATIC
|
||||||
AR = ar
|
AR = ar
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ direwolf : direwolf.o config.o demod.o dsp.o demod_afsk.o demod_9600.o hdlc_rec.
|
||||||
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
decode_aprs.o symbols.o server.o kiss.o kissnet.o kiss_frame.o hdlc_send.o fcs_calc.o \
|
||||||
gen_tone.o audio_win.o digipeater.o dedupe.o tq.o xmit.o \
|
gen_tone.o audio_win.o digipeater.o dedupe.o tq.o xmit.o \
|
||||||
ptt.o beacon.o dwgps.o encode_aprs.o latlong.o textcolor.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 \
|
dtmf.o aprs_tt.o tt_user.o tt_text.o igate.o nmea.o log.o telemetry.o \
|
||||||
dw-icon.o regex.a misc.a utm.a
|
dw-icon.o regex.a misc.a utm.a
|
||||||
$(CC) $(CFLAGS) -g -o $@ $^ -lwinmm -lws2_32
|
$(CC) $(CFLAGS) -g -o $@ $^ -lwinmm -lws2_32
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ strcasestr.o : misc/strcasestr.c
|
||||||
|
|
||||||
# Separate application to decode raw data.
|
# Separate application to decode raw data.
|
||||||
|
|
||||||
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c regex.a misc.a
|
decode_aprs : decode_aprs.c symbols.c ax25_pad.c textcolor.c fcs_calc.c latlong.c log.o telemetry.o regex.a misc.a utm.a
|
||||||
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^
|
$(CC) $(CFLAGS) -o decode_aprs -DTEST $^
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,10 +153,16 @@ tt2text : tt_text.c
|
||||||
# Convert between Latitude/Longitude and UTM coordinates.
|
# Convert between Latitude/Longitude and UTM coordinates.
|
||||||
|
|
||||||
ll2utm : ll2utm.c utm.a
|
ll2utm : ll2utm.c utm.a
|
||||||
$(CC) $(CFLAGS) -I utm -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
utm2ll : utm2ll.c utm.a
|
utm2ll : utm2ll.c utm.a
|
||||||
$(CC) $(CFLAGS) -I utm -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
|
||||||
|
# Convert from log file to GPX.
|
||||||
|
|
||||||
|
log2gpx : log2gpx.c misc/strsep.c misc/strtok_r.c
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
|
||||||
# Test application to generate sound.
|
# Test application to generate sound.
|
||||||
|
@ -172,7 +178,7 @@ demod_afsk.o : tune.h
|
||||||
|
|
||||||
|
|
||||||
testagc : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
testagc : 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 symbols.c textcolor.c regex.a misc.a \
|
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c telemetry.c regex.a misc.a \
|
||||||
fsk_demod_agc.h
|
fsk_demod_agc.h
|
||||||
rm -f atest.exe
|
rm -f atest.exe
|
||||||
$(CC) $(CFLAGS) -DNOFIX -o atest $^
|
$(CC) $(CFLAGS) -DNOFIX -o atest $^
|
||||||
|
@ -183,7 +189,7 @@ noisy3.wav : gen_packets
|
||||||
./gen_packets -B 300 -n 100 -o noisy3.wav
|
./gen_packets -B 300 -n 100 -o noisy3.wav
|
||||||
|
|
||||||
testagc3 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
testagc3 : 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 symbols.c textcolor.c regex.a misc.a \
|
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c telemetry.c regex.a misc.a \
|
||||||
tune.h
|
tune.h
|
||||||
rm -f atest.exe
|
rm -f atest.exe
|
||||||
$(CC) $(CFLAGS) -o atest $^
|
$(CC) $(CFLAGS) -o atest $^
|
||||||
|
@ -194,7 +200,7 @@ noisy96.wav : gen_packets
|
||||||
./gen_packets -B 9600 -n 100 -o noisy96.wav
|
./gen_packets -B 9600 -n 100 -o noisy96.wav
|
||||||
|
|
||||||
testagc9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
testagc9 : 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 symbols.c textcolor.c regex.a misc.a \
|
rrbb.c fcs_calc.c ax25_pad.c decode_aprs.c symbols.c textcolor.c telemetry.c regex.a misc.a \
|
||||||
tune.h
|
tune.h
|
||||||
rm -f atest.exe
|
rm -f atest.exe
|
||||||
$(CC) $(CFLAGS) -o atest $^
|
$(CC) $(CFLAGS) -o atest $^
|
||||||
|
@ -206,14 +212,14 @@ testagc9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.
|
||||||
|
|
||||||
|
|
||||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
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 symbols.c textcolor.c misc.a regex.a \
|
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
|
fsk_fast_filter.h
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
echo " " > tune.h
|
echo " " > tune.h
|
||||||
./atest ..\\direwolf-0.2\\02_Track_2.wav
|
./atest ..\\direwolf-0.2\\02_Track_2.wav
|
||||||
|
|
||||||
atest9 : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.c multi_modem.c \
|
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 symbols.c textcolor.c misc.a regex.a \
|
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
|
fsk_fast_filter.h
|
||||||
$(CC) $(CFLAGS) -o $@ $^
|
$(CC) $(CFLAGS) -o $@ $^
|
||||||
./atest9 -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
./atest9 -B 9600 ../walkabout9600.wav | grep "packets decoded in" >atest.out
|
||||||
|
@ -247,6 +253,14 @@ udptest : udp_test.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec
|
||||||
./udptest
|
./udptest
|
||||||
|
|
||||||
|
|
||||||
|
# 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.
|
# Multiple AGWPE network or serial port clients to test TNCs side by side.
|
||||||
|
|
||||||
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
aclients : aclients.c ax25_pad.c fcs_calc.c textcolor.c misc.a regex.a
|
||||||
|
@ -258,7 +272,7 @@ SRCS = direwolf.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c \
|
||||||
fcs_calc.c ax25_pad.c decode_aprs.c symbols.c \
|
fcs_calc.c ax25_pad.c decode_aprs.c symbols.c \
|
||||||
server.c kiss.c kissnet.c kiss_frame.c hdlc_send.c fcs_calc.c gen_tone.c audio_win.c \
|
server.c kiss.c kissnet.c kiss_frame.c hdlc_send.c fcs_calc.c gen_tone.c audio_win.c \
|
||||||
digipeater.c dedupe.c tq.c xmit.c beacon.c \
|
digipeater.c dedupe.c tq.c xmit.c beacon.c \
|
||||||
encode_aprs.c latlong.c \
|
encode_aprs.c latlong.c telemetry.c \
|
||||||
dtmf.c aprs_tt.c tt_text.c igate.c
|
dtmf.c aprs_tt.c tt_text.c igate.c
|
||||||
|
|
||||||
|
|
||||||
|
@ -275,15 +289,15 @@ clean :
|
||||||
|
|
||||||
|
|
||||||
dist-win : direwolf.exe decode_aprs.exe CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf \
|
dist-win : direwolf.exe decode_aprs.exe CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf \
|
||||||
Raspberry-Pi-APRS.pdf APRStt-Implementation-Notes.pdf
|
Raspberry-Pi-APRS.pdf Raspberry-Pi-APRS-Tracker.pdf APRStt-Implementation-Notes.pdf
|
||||||
rm -f ../$z-win.zip
|
rm -f ../$z-win.zip
|
||||||
zip ../$z-win.zip CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf \
|
zip ../$z-win.zip CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf \
|
||||||
Raspberry-Pi-APRS.pdf APRStt-Implementation-Notes.pdf LICENSE* *.conf \
|
Raspberry-Pi-APRS.pdf Raspberry-Pi-APRS-Tracker.pdf APRStt-Implementation-Notes.pdf LICENSE* *.conf \
|
||||||
direwolf.exe decode_aprs.exe tocalls.txt symbols-new.txt symbolsX.txt \
|
direwolf.exe decode_aprs.exe tocalls.txt symbols-new.txt symbolsX.txt \
|
||||||
text2tt.exe tt2text.exe ll2utm.exe utm2ll.exe aclients.exe
|
text2tt.exe tt2text.exe ll2utm.exe utm2ll.exe aclients.exe log2gpx.exe
|
||||||
|
|
||||||
dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-Pi-APRS.pdf \
|
dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-Pi-APRS.pdf \
|
||||||
APRStt-Implementation-Notes.pdf \
|
Raspberry-Pi-APRS-Tracker.pdf APRStt-Implementation-Notes.pdf \
|
||||||
direwolf.desktop dw-start.sh \
|
direwolf.desktop dw-start.sh \
|
||||||
tocalls.txt symbols-new.txt symbolsX.txt
|
tocalls.txt symbols-new.txt symbolsX.txt
|
||||||
rm -f fsk_fast_filter.h
|
rm -f fsk_fast_filter.h
|
||||||
|
@ -292,7 +306,7 @@ dist-src : CHANGES.txt User-Guide.pdf Quick-Start-Guide-Windows.pdf Raspberry-Pi
|
||||||
(cd .. ; zip $z-src.zip \
|
(cd .. ; zip $z-src.zip \
|
||||||
$z/CHANGES.txt $z/LICENSE* \
|
$z/CHANGES.txt $z/LICENSE* \
|
||||||
$z/User-Guide.pdf $z/Quick-Start-Guide-Windows.pdf \
|
$z/User-Guide.pdf $z/Quick-Start-Guide-Windows.pdf \
|
||||||
$z/Raspberry-Pi-APRS.pdf $z/APRStt-Implementation-Notes.pdf \
|
$z/Raspberry-Pi-APRS.pdf $z/Raspberry-Pi-APRS-Tracker.pdf $z/APRStt-Implementation-Notes.pdf \
|
||||||
$z/Makefile* $z/*.c $z/*.h $z/regex/* $z/misc/* $z/utm/* \
|
$z/Makefile* $z/*.c $z/*.h $z/regex/* $z/misc/* $z/utm/* \
|
||||||
$z/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
$z/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||||
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
$z/dw-icon.png $z/dw-icon.rc $z/dw-icon.ico \
|
||||||
|
@ -309,6 +323,10 @@ Quick-Start-Guide-Windows.pdf : Quick-Start-Guide-Windows.docx
|
||||||
Raspberry-Pi-APRS.pdf : Raspberry-Pi-APRS.docx
|
Raspberry-Pi-APRS.pdf : Raspberry-Pi-APRS.docx
|
||||||
echo "***** Raspberry-Pi-APRS.pdf is out of date *****"
|
echo "***** Raspberry-Pi-APRS.pdf is out of date *****"
|
||||||
|
|
||||||
|
Raspberry-Pi-APRS-Tracker.pdf : Raspberry-Pi-APRS-Tracker.docx
|
||||||
|
echo "***** Raspberry-Pi-APRS-Tracker.pdf is out of date *****"
|
||||||
|
|
||||||
|
|
||||||
APRStt-Implementation-Notes.pdf : APRStt-Implementation-Notes.docx
|
APRStt-Implementation-Notes.pdf : APRStt-Implementation-Notes.docx
|
||||||
echo "***** APRStt-Implementation-Notes.pdf is out of date *****"
|
echo "***** APRStt-Implementation-Notes.pdf is out of date *****"
|
||||||
|
|
||||||
|
@ -317,6 +335,16 @@ backup :
|
||||||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||||
cp -r . /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.
|
||||||
|
#
|
||||||
|
|
||||||
|
tocalls-symbols :
|
||||||
|
wget http://www.aprs.org/aprs11/tocalls.txt -O tocalls.txt
|
||||||
|
wget http://www.aprs.org/symbols/symbols-new.txt -O symbols-new.txt
|
||||||
|
wget http://www.aprs.org/symbols/symbolsX.txt -O symbolsX.txt
|
||||||
|
|
||||||
#
|
#
|
||||||
# The following is updated by "make depend"
|
# The following is updated by "make depend"
|
||||||
#
|
#
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
User-Guide.pdf
BIN
User-Guide.pdf
Binary file not shown.
|
@ -519,7 +519,7 @@ static void * client_thread_net (void *arg)
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd), 0);
|
send (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd), 0);
|
||||||
#else
|
#else
|
||||||
(void)write (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
err = write (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -649,6 +649,8 @@ static void * client_thread_serial (void *arg)
|
||||||
DCB dcb;
|
DCB dcb;
|
||||||
int ok;
|
int ok;
|
||||||
|
|
||||||
|
// Bug: Won't work for ports above COM9.
|
||||||
|
// http://support.microsoft.com/kb/115831
|
||||||
|
|
||||||
fd = CreateFile(port[my_index], GENERIC_READ | GENERIC_WRITE,
|
fd = CreateFile(port[my_index], GENERIC_READ | GENERIC_WRITE,
|
||||||
0, NULL, OPEN_EXISTING, 0, NULL);
|
0, NULL, OPEN_EXISTING, 0, NULL);
|
||||||
|
@ -671,6 +673,7 @@ static void * client_thread_serial (void *arg)
|
||||||
|
|
||||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx */
|
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx */
|
||||||
|
|
||||||
|
dcb.DCBlength = sizeof(DCB);
|
||||||
dcb.BaudRate = 9600;
|
dcb.BaudRate = 9600;
|
||||||
dcb.fBinary = 1;
|
dcb.fBinary = 1;
|
||||||
dcb.fParity = 0;
|
dcb.fParity = 0;
|
||||||
|
|
17
aprs_tt.c
17
aprs_tt.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013,2014 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -32,6 +32,9 @@
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define APRS_TT_C 1
|
||||||
|
|
||||||
|
|
||||||
// TODO: clean up terminolgy.
|
// TODO: clean up terminolgy.
|
||||||
// "Message" has a specific meaning in APRS and this is not it.
|
// "Message" has a specific meaning in APRS and this is not it.
|
||||||
// Touch Tone sequence might be appropriate.
|
// Touch Tone sequence might be appropriate.
|
||||||
|
@ -872,6 +875,7 @@ static int parse_symbol (char *e)
|
||||||
*
|
*
|
||||||
* Outputs: m_latitude
|
* Outputs: m_latitude
|
||||||
* m_longitude
|
* m_longitude
|
||||||
|
* m_dao
|
||||||
*
|
*
|
||||||
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
* Returns: 0 for success or one of the TT_ERROR_... codes.
|
||||||
*
|
*
|
||||||
|
@ -915,6 +919,9 @@ static int parse_location (char *e)
|
||||||
m_dao[3] = e[1]; /* Type of location. e.g. !TB6! */
|
m_dao[3] = e[1]; /* Type of location. e.g. !TB6! */
|
||||||
/* Will be changed by point types. */
|
/* Will be changed by point types. */
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
@ -1320,7 +1327,13 @@ static void raw_tt_data_to_app (int chan, char *msg)
|
||||||
* thru the multi modem duplicate processing.
|
* thru the multi modem duplicate processing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
app_process_rec_packet (chan, -1, pp, -2, RETRY_NONE, "tt");
|
if (pp != NULL) {
|
||||||
|
app_process_rec_packet (chan, -1, pp, -2, RETRY_NONE, "tt");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Could not convert \"%s\" into APRS packet.\n", raw_tt_msg);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#ifndef APRS_TT_H
|
#ifndef APRS_TT_H
|
||||||
#define APRS_TT_H 1
|
#define APRS_TT_H 1
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For holding location format specifications from config file.
|
* For holding location format specifications from config file.
|
||||||
* Same thing is also useful for macro definitions.
|
* Same thing is also useful for macro definitions.
|
||||||
|
@ -52,7 +53,7 @@ struct ttloc_s {
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configuratin options for APRStt.
|
* Configuration options for APRStt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TT_MAX_XMITS 10
|
#define TT_MAX_XMITS 10
|
||||||
|
@ -77,6 +78,8 @@ struct tt_config_s {
|
||||||
int corral_ambiguity;
|
int corral_ambiguity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void aprs_tt_init (struct tt_config_s *p_config);
|
void aprs_tt_init (struct tt_config_s *p_config);
|
||||||
|
|
||||||
|
@ -95,6 +98,10 @@ void aprs_tt_button (int chan, char button);
|
||||||
#define TT_ERROR_NO_CALL 9 /* No call or object name included. */
|
#define TT_ERROR_NO_CALL 9 /* No call or object name included. */
|
||||||
|
|
||||||
|
|
||||||
|
#define APRSTT_LOC_DESC_LEN 32 /* Need at least 26 */
|
||||||
|
|
||||||
|
void aprs_tt_dao_to_desc (char *dao, char *str);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* end aprs_tt.h */
|
/* end aprs_tt.h */
|
64
atest.c
64
atest.c
|
@ -145,14 +145,64 @@ int main (int argc, char *argv[])
|
||||||
modem.samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
|
modem.samples_per_sec = DEFAULT_SAMPLES_PER_SEC;
|
||||||
modem.bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
|
modem.bits_per_sample = DEFAULT_BITS_PER_SAMPLE;
|
||||||
|
|
||||||
|
// Results v0.9:
|
||||||
|
//
|
||||||
|
// fix_bits = 0 971 packets, 69 sec
|
||||||
|
// fix_bits = SINGLE 990 64
|
||||||
|
// fix_bits = DOUBLE 992 65
|
||||||
|
// fix_bits = TRIPLE 992 67
|
||||||
|
// fix_bits = TWO_SEP 1004 476
|
||||||
|
|
||||||
|
// Essentially no difference in time for those with order N time.
|
||||||
|
// Time increases greatly for the one with order N^2 time.
|
||||||
|
|
||||||
|
|
||||||
|
// Results: version 1.1, decoder C, modem.fix_bits = RETRY_MAX - 1
|
||||||
|
//
|
||||||
|
// 971 NONE
|
||||||
|
// +19 SINGLE
|
||||||
|
// +2 DOUBLE
|
||||||
|
// +12 TWO_SEP
|
||||||
|
// +3 REMOVE_MANY
|
||||||
|
// ----
|
||||||
|
// 1007 Total in 1008 sec. More than twice as long as earlier version.
|
||||||
|
|
||||||
|
// Results: version 1.1, decoders ABC, modem.fix_bits = RETRY_MAX - 1
|
||||||
|
//
|
||||||
|
// 976 NONE
|
||||||
|
// +21 SINGLE
|
||||||
|
// +1 DOUBLE
|
||||||
|
// +22 TWO_SEP
|
||||||
|
// +1 MANY
|
||||||
|
// +3 REMOVE_MANY
|
||||||
|
// ----
|
||||||
|
// 1024 Total in 2042 sec.
|
||||||
|
// About 34 minutes of CPU time for a roughly 40 minute CD.
|
||||||
|
// Many computers wouldn't be able to keep up.
|
||||||
|
|
||||||
|
// The SINGLE and TWO_SEP techniques are the most effective.
|
||||||
|
// Should we reorder the enum values so that TWO_SEP
|
||||||
|
// comes after SINGLE? That way "FIX_BITS 2" would
|
||||||
|
// use the two most productive techniques and not waste
|
||||||
|
// time on the others. People with plenty of CPU power
|
||||||
|
// to spare can still specify larger numbers for the other
|
||||||
|
// techniques with less return on investment.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: tabulate results from atest2.c.txt
|
||||||
|
|
||||||
|
|
||||||
/* TODO: should have a command line option for this. */
|
/* TODO: should have a command line option for this. */
|
||||||
/* Results v0.9: 971/69, 990/64, 992/65, 992/67, 1004/476 */
|
|
||||||
|
|
||||||
modem.fix_bits = RETRY_NONE;
|
modem.fix_bits = RETRY_NONE;
|
||||||
modem.fix_bits = RETRY_SINGLE;
|
//modem.fix_bits = RETRY_SWAP_SINGLE;
|
||||||
modem.fix_bits = RETRY_DOUBLE;
|
//modem.fix_bits = RETRY_SWAP_DOUBLE;
|
||||||
//modem.fix_bits = RETRY_TRIPLE;
|
//modem.fix_bits = RETRY_SWAP_TRIPLE;
|
||||||
//modem.fix_bits = RETRY_TWO_SEP;
|
//modem.fix_bits = RETRY_INSERT_DOUBLE;
|
||||||
|
modem.fix_bits = RETRY_SWAP_TWO_SEP;
|
||||||
|
//modem.fix_bits = RETRY_REMOVE_MANY;
|
||||||
|
//modem.fix_bits = RETRY_MAX - 1;
|
||||||
|
|
||||||
for (channel=0; channel<MAX_CHANS; channel++) {
|
for (channel=0; channel<MAX_CHANS; channel++) {
|
||||||
|
|
||||||
|
@ -162,6 +212,7 @@ int main (int argc, char *argv[])
|
||||||
modem.space_freq[channel] = DEFAULT_SPACE_FREQ;
|
modem.space_freq[channel] = DEFAULT_SPACE_FREQ;
|
||||||
modem.baud[channel] = DEFAULT_BAUD;
|
modem.baud[channel] = DEFAULT_BAUD;
|
||||||
strcpy (modem.profiles[channel], "C");
|
strcpy (modem.profiles[channel], "C");
|
||||||
|
//strcpy (modem.profiles[channel], "ABC");
|
||||||
// temp
|
// temp
|
||||||
// strcpy (modem.profiles[channel], "F");
|
// strcpy (modem.profiles[channel], "F");
|
||||||
modem.num_subchan[channel] = strlen(modem.profiles[channel]);
|
modem.num_subchan[channel] = strlen(modem.profiles[channel]);
|
||||||
|
@ -334,7 +385,6 @@ int main (int argc, char *argv[])
|
||||||
/* process_rec_frame, below, is called. */
|
/* process_rec_frame, below, is called. */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
printf ("\n\n");
|
printf ("\n\n");
|
||||||
printf ("%d packets decoded in %d seconds.\n", packets_decoded, (int)(time(NULL) - start_time));
|
printf ("%d packets decoded in %d seconds.\n", packets_decoded, (int)(time(NULL) - start_time));
|
||||||
|
@ -415,7 +465,7 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
printf ("\n");
|
printf ("\n");
|
||||||
|
printf("DECODED[%d] ", packets_decoded );
|
||||||
if (h != AX25_SOURCE) {
|
if (h != AX25_SOURCE) {
|
||||||
printf ("Digipeater ");
|
printf ("Digipeater ");
|
||||||
}
|
}
|
||||||
|
|
82
audio.c
82
audio.c
|
@ -50,15 +50,13 @@
|
||||||
*
|
*
|
||||||
* http://www.alsa-project.org/main/index.php/Asoundrc
|
* http://www.alsa-project.org/main/index.php/Asoundrc
|
||||||
*
|
*
|
||||||
* Credits: Fabrice FAURE contributed code for the SDR UDP interface.
|
* Credits: Release 1.0: Fabrice FAURE contributed code for the SDR UDP interface.
|
||||||
*
|
*
|
||||||
* Discussion here: http://gqrx.dk/doc/streaming-audio-over-udp
|
* Discussion here: http://gqrx.dk/doc/streaming-audio-over-udp
|
||||||
*
|
*
|
||||||
*
|
* Release 1.1: Gabor Berczi provided fixes for the OSS code
|
||||||
* Future: Will probably rip out the OSS code.
|
* which had fallen into decay.
|
||||||
* ALSA was added to Linux kernel 10 years ago.
|
*
|
||||||
* Cygwin doesn't have it but I see no reason to support Cygwin
|
|
||||||
* now that we have a native Windows version.
|
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -81,8 +79,16 @@
|
||||||
#if USE_ALSA
|
#if USE_ALSA
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#else
|
#else
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#include <soundcard.h>
|
||||||
|
#else
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "direwolf.h"
|
#include "direwolf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
@ -101,6 +107,7 @@ static int set_alsa_params (snd_pcm_t *handle, struct audio_s *pa, char *name, c
|
||||||
//static void alsa_select_device (char *pick_dev, int direction, char *result);
|
//static void alsa_select_device (char *pick_dev, int direction, char *result);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
static int set_oss_params (int fd, struct audio_s *pa);
|
||||||
static int oss_audio_device_fd = -1; /* Single device, both directions. */
|
static int oss_audio_device_fd = -1; /* Single device, both directions. */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -180,11 +187,11 @@ int audio_open (struct audio_s *pa)
|
||||||
int err;
|
int err;
|
||||||
int chan;
|
int chan;
|
||||||
|
|
||||||
#if USE_ALSA
|
|
||||||
|
|
||||||
char audio_in_name[30];
|
char audio_in_name[30];
|
||||||
char audio_out_name[30];
|
char audio_out_name[30];
|
||||||
|
|
||||||
|
#if USE_ALSA
|
||||||
|
|
||||||
assert (audio_in_handle == NULL);
|
assert (audio_in_handle == NULL);
|
||||||
assert (audio_out_handle == NULL);
|
assert (audio_out_handle == NULL);
|
||||||
|
|
||||||
|
@ -234,19 +241,18 @@ int audio_open (struct audio_s *pa)
|
||||||
outbuf_ptr = NULL;
|
outbuf_ptr = NULL;
|
||||||
outbuf_len = 0;
|
outbuf_len = 0;
|
||||||
|
|
||||||
#if USE_ALSA
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine the type of audio input.
|
* Determine the type of audio input.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
audio_in_type = AUDIO_IN_TYPE_SOUNDCARD;
|
audio_in_type = AUDIO_IN_TYPE_SOUNDCARD;
|
||||||
|
|
||||||
if (strcasecmp(pa->adevice_in, "stdin") == 0 || strcmp(pa->adevice_in, "-") == 0) {
|
if (strcasecmp(pa->adevice_in, "stdin") == 0 || strcmp(pa->adevice_in, "-") == 0) {
|
||||||
audio_in_type = AUDIO_IN_TYPE_STDIN;
|
audio_in_type = AUDIO_IN_TYPE_STDIN;
|
||||||
/* Change - to stdin for readability. */
|
/* Change - to stdin for readability. */
|
||||||
strcpy (pa->adevice_in, "stdin");
|
strcpy (pa->adevice_in, "stdin");
|
||||||
}
|
}
|
||||||
else if (strncasecmp(pa->adevice_in, "udp:", 4) == 0) {
|
if (strncasecmp(pa->adevice_in, "udp:", 4) == 0) {
|
||||||
audio_in_type = AUDIO_IN_TYPE_SDR_UDP;
|
audio_in_type = AUDIO_IN_TYPE_SDR_UDP;
|
||||||
/* Supply default port if none specified. */
|
/* Supply default port if none specified. */
|
||||||
if (strcasecmp(pa->adevice_in,"udp") == 0 ||
|
if (strcasecmp(pa->adevice_in,"udp") == 0 ||
|
||||||
|
@ -285,7 +291,7 @@ int audio_open (struct audio_s *pa)
|
||||||
* Soundcard - ALSA.
|
* Soundcard - ALSA.
|
||||||
*/
|
*/
|
||||||
case AUDIO_IN_TYPE_SOUNDCARD:
|
case AUDIO_IN_TYPE_SOUNDCARD:
|
||||||
|
#if USE_ALSA
|
||||||
err = snd_pcm_open (&audio_in_handle, audio_in_name, SND_PCM_STREAM_CAPTURE, 0);
|
err = snd_pcm_open (&audio_in_handle, audio_in_name, SND_PCM_STREAM_CAPTURE, 0);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -296,6 +302,23 @@ int audio_open (struct audio_s *pa)
|
||||||
|
|
||||||
inbuf_size_in_bytes = set_alsa_params (audio_in_handle, pa, audio_in_name, "input");
|
inbuf_size_in_bytes = set_alsa_params (audio_in_handle, pa, audio_in_name, "input");
|
||||||
break;
|
break;
|
||||||
|
#else // OSS
|
||||||
|
oss_audio_device_fd = open (pa->adevice_in, O_RDWR);
|
||||||
|
|
||||||
|
if (oss_audio_device_fd < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("%s:\n", pa->adevice_in);
|
||||||
|
// sprintf (message, "Could not open audio device %s", pa->adevice_in);
|
||||||
|
// perror (message);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
outbuf_size_in_bytes = inbuf_size_in_bytes = set_oss_params (oss_audio_device_fd, pa);
|
||||||
|
|
||||||
|
if (inbuf_size_in_bytes <= 0 || outbuf_size_in_bytes <= 0) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UDP.
|
* UDP.
|
||||||
|
@ -353,6 +376,8 @@ int audio_open (struct audio_s *pa)
|
||||||
/*
|
/*
|
||||||
* Output device. Only "soundcard" is supported at this time.
|
* Output device. Only "soundcard" is supported at this time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if USE_ALSA
|
||||||
err = snd_pcm_open (&audio_out_handle, audio_out_name, SND_PCM_STREAM_PLAYBACK, 0);
|
err = snd_pcm_open (&audio_out_handle, audio_out_name, SND_PCM_STREAM_PLAYBACK, 0);
|
||||||
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
@ -368,34 +393,7 @@ int audio_open (struct audio_s *pa)
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#else /* end of ALSA case */
|
|
||||||
|
|
||||||
|
|
||||||
#error OSS support will probably be removed. Complain if you still care about OSS.
|
|
||||||
|
|
||||||
oss_audio_device_fd = open (pa->adevice_in, O_RDWR);
|
|
||||||
|
|
||||||
if (oss_audio_device_fd < 0) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("%s:\n", pa->adevice_in);
|
|
||||||
sprintf (message, "Could not open audio device %s", pa->adevice_in);
|
|
||||||
perror (message);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
outbuf_size_in_bytes = inbuf_size_in_bytes = set_oss_params (oss_audio_device_fd, pa);
|
|
||||||
|
|
||||||
if (inbuf_size_in_bytes <= 0 || outbuf_size_in_bytes <= 0) {
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* end of OSS case */
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally allocate buffer for each direction.
|
* Finally allocate buffer for each direction.
|
||||||
|
@ -811,7 +809,7 @@ int audio_get (void)
|
||||||
this_time = time(NULL);
|
this_time = time(NULL);
|
||||||
if (this_time >= last_time + duration) {
|
if (this_time >= last_time + duration) {
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\nPast %d seconds, %d audio samples, %d errors.\n\n",
|
dw_printf ("\nPast %d seconds, %d audio samples processed, %d errors.\n\n",
|
||||||
duration, sample_count, error_count);
|
duration, sample_count, error_count);
|
||||||
last_time = this_time;
|
last_time = this_time;
|
||||||
sample_count = 0;
|
sample_count = 0;
|
||||||
|
|
8
audio.h
8
audio.h
|
@ -22,7 +22,8 @@
|
||||||
enum ptt_method_e {
|
enum ptt_method_e {
|
||||||
PTT_METHOD_NONE, /* VOX or no transmit. */
|
PTT_METHOD_NONE, /* VOX or no transmit. */
|
||||||
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
|
PTT_METHOD_SERIAL, /* Serial port RTS or DTR. */
|
||||||
PTT_METHOD_GPIO }; /* General purpos I/O. */
|
PTT_METHOD_GPIO, /* General purpose I/O, Linux only. */
|
||||||
|
PTT_METHOD_LPT }; /* Parallel printer port, Linux only. */
|
||||||
|
|
||||||
typedef enum ptt_method_e ptt_method_t;
|
typedef enum ptt_method_e ptt_method_t;
|
||||||
|
|
||||||
|
@ -93,6 +94,9 @@ struct audio_s {
|
||||||
/* PTT_RTS, PTT_DTR. */
|
/* PTT_RTS, PTT_DTR. */
|
||||||
|
|
||||||
int ptt_gpio[MAX_CHANS]; /* GPIO number. */
|
int ptt_gpio[MAX_CHANS]; /* GPIO number. */
|
||||||
|
|
||||||
|
int ptt_lpt_bit[MAX_CHANS]; /* Bit number for parallel printer port. */
|
||||||
|
/* Bit 0 = pin 2, ..., bit 7 = pin 9. */
|
||||||
|
|
||||||
int ptt_invert[MAX_CHANS]; /* Invert the output. */
|
int ptt_invert[MAX_CHANS]; /* Invert the output. */
|
||||||
|
|
||||||
|
@ -153,7 +157,7 @@ struct audio_s {
|
||||||
|
|
||||||
#define DEFAULT_BITS_PER_SAMPLE 16
|
#define DEFAULT_BITS_PER_SAMPLE 16
|
||||||
|
|
||||||
#define DEFAULT_FIX_BITS RETRY_SINGLE
|
#define DEFAULT_FIX_BITS RETRY_SWAP_SINGLE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Standard for AFSK on VHF FM.
|
* Standard for AFSK on VHF FM.
|
||||||
|
|
|
@ -744,7 +744,7 @@ int audio_get (void)
|
||||||
this_time = time(NULL);
|
this_time = time(NULL);
|
||||||
if (this_time >= last_time + duration) {
|
if (this_time >= last_time + duration) {
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\nPast %d seconds, %d audio samples, %d errors.\n\n",
|
dw_printf ("\nPast %d seconds, %d audio samples processed, %d errors.\n\n",
|
||||||
duration, sample_count, error_count);
|
duration, sample_count, error_count);
|
||||||
last_time = this_time;
|
last_time = this_time;
|
||||||
sample_count = 0;
|
sample_count = 0;
|
||||||
|
|
670
ax25_pad.c
670
ax25_pad.c
File diff suppressed because it is too large
Load Diff
49
ax25_pad.h
49
ax25_pad.h
|
@ -49,7 +49,8 @@
|
||||||
* #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN)
|
* #define AX25_MAX_PACKET_LEN ( AX25_MAX_ADDRS * 7 + 2 + AX25_MAX_INFO_LEN)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* the more general case. */
|
/* The more general case. */
|
||||||
|
/* An AX.25 frame can have a control byte and no protocol. */
|
||||||
|
|
||||||
#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 )
|
#define AX25_MIN_PACKET_LEN ( 2 * 7 + 1 )
|
||||||
|
|
||||||
|
@ -77,20 +78,17 @@ struct packet_s {
|
||||||
|
|
||||||
struct packet_s *nextp; /* Pointer to next in queue. */
|
struct packet_s *nextp; /* Pointer to next in queue. */
|
||||||
|
|
||||||
int num_addr; /* Number of elements used in two below. */
|
int num_addr; /* Number of addresses in frame. */
|
||||||
/* Range of 0 .. AX25_MAX_ADDRS. */
|
/* Range of AX25_MIN_ADDRS .. AX25_MAX_ADDRS for AX.25. */
|
||||||
|
/* It will be 0 if it doesn't look like AX.25. */
|
||||||
|
/* -1 is used temporarily at allocation to mean */
|
||||||
|
/* not determined yet. */
|
||||||
|
|
||||||
char addrs[AX25_MAX_ADDRS][AX25_MAX_ADDR_LEN];
|
|
||||||
/* Contains the address without the ssid. */
|
|
||||||
/* Why is it larger than 7? */
|
|
||||||
/* Messages from an IGate server can have longer */
|
|
||||||
/* addresses after qAC. Up to 9 observed so far. */
|
|
||||||
|
|
||||||
/* usual human readable form. e.g. WB20SZ-15 */
|
|
||||||
|
|
||||||
unsigned char ssid_etc[AX25_MAX_ADDRS]; /* SSID octet from each address. */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* The 7th octet of each address contains:
|
||||||
|
*
|
||||||
* Bits: H R R SSID 0
|
* Bits: H R R SSID 0
|
||||||
*
|
*
|
||||||
* H for digipeaters set to 0 intially.
|
* H for digipeaters set to 0 intially.
|
||||||
|
@ -118,13 +116,12 @@ struct packet_s {
|
||||||
#define SSID_LAST_MASK 0x01
|
#define SSID_LAST_MASK 0x01
|
||||||
|
|
||||||
|
|
||||||
int the_rest_len; /* Frame length minus the address part. */
|
int frame_len; /* Frame length without CRC. */
|
||||||
|
|
||||||
unsigned char the_rest[2 + 3 + AX25_MAX_INFO_LEN + 1];
|
|
||||||
/* The rest after removing the addresses. */
|
unsigned char frame_data[AX25_MAX_PACKET_LEN+1];
|
||||||
/* Includes control, protocol ID, Information, */
|
/* Raw frame contents, without the CRC. */
|
||||||
/* and throw in one more for a character */
|
|
||||||
/* string nul terminator. */
|
|
||||||
|
|
||||||
int magic2; /* Will get stomped on if above overflows. */
|
int magic2; /* Will get stomped on if above overflows. */
|
||||||
};
|
};
|
||||||
|
@ -158,7 +155,8 @@ typedef struct packet_s *packet_t;
|
||||||
|
|
||||||
static inline int ax25_get_control_offset (packet_t this_p)
|
static inline int ax25_get_control_offset (packet_t this_p)
|
||||||
{
|
{
|
||||||
return (0);
|
//return (0);
|
||||||
|
return (this_p->num_addr*7);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ax25_get_num_control (packet_t this_p)
|
static inline int ax25_get_num_control (packet_t this_p)
|
||||||
|
@ -174,7 +172,7 @@ static inline int ax25_get_num_control (packet_t this_p)
|
||||||
|
|
||||||
static inline int ax25_get_pid_offset (packet_t this_p)
|
static inline int ax25_get_pid_offset (packet_t this_p)
|
||||||
{
|
{
|
||||||
return (ax25_get_num_control(this_p));
|
return (ax25_get_control_offset (this_p) + ax25_get_num_control(this_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ax25_get_num_pid (packet_t this_p)
|
static int ax25_get_num_pid (packet_t this_p)
|
||||||
|
@ -182,12 +180,12 @@ static int ax25_get_num_pid (packet_t this_p)
|
||||||
int c;
|
int c;
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
c = this_p->the_rest[ax25_get_control_offset(this_p)];
|
c = this_p->frame_data[ax25_get_control_offset(this_p)];
|
||||||
|
|
||||||
if ( (c & 0x01) == 0 || /* I xxxx xxx0 */
|
if ( (c & 0x01) == 0 || /* I xxxx xxx0 */
|
||||||
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
|
c == 0x03 || c == 0x13) { /* UI 000x 0011 */
|
||||||
|
|
||||||
pid = this_p->the_rest[ax25_get_pid_offset(this_p)];
|
pid = this_p->frame_data[ax25_get_pid_offset(this_p)];
|
||||||
if (pid == 0xff) {
|
if (pid == 0xff) {
|
||||||
return (2); /* pid 1111 1111 means another follows. */
|
return (2); /* pid 1111 1111 means another follows. */
|
||||||
}
|
}
|
||||||
|
@ -210,17 +208,20 @@ static int ax25_get_num_pid (packet_t this_p)
|
||||||
|
|
||||||
static inline int ax25_get_info_offset (packet_t this_p)
|
static inline int ax25_get_info_offset (packet_t this_p)
|
||||||
{
|
{
|
||||||
return (ax25_get_num_control(this_p) + ax25_get_num_pid(this_p));
|
return (ax25_get_control_offset (this_p) + ax25_get_num_control(this_p) + ax25_get_num_pid(this_p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ax25_get_num_info (packet_t this_p)
|
static int ax25_get_num_info (packet_t this_p)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
/* assuming AX.25 frame. */
|
||||||
|
|
||||||
len = this_p->the_rest_len - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
|
len = this_p->frame_len - this_p->num_addr * 7 - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
len = 0; /* print error? */
|
len = 0; /* print error? */
|
||||||
}
|
}
|
||||||
|
|
||||||
return (len);
|
return (len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +279,8 @@ extern void ax25_format_addrs (packet_t pp, char *);
|
||||||
|
|
||||||
extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
|
extern int ax25_pack (packet_t pp, unsigned char result[AX25_MAX_PACKET_LEN]);
|
||||||
|
|
||||||
|
extern void ax25_hex_dump (packet_t this_p);
|
||||||
|
|
||||||
extern int ax25_is_aprs (packet_t pp);
|
extern int ax25_is_aprs (packet_t pp);
|
||||||
|
|
||||||
extern int ax25_get_control (packet_t this_p);
|
extern int ax25_get_control (packet_t this_p);
|
||||||
|
|
173
beacon.c
173
beacon.c
|
@ -57,6 +57,7 @@
|
||||||
#include "beacon.h"
|
#include "beacon.h"
|
||||||
#include "latlong.h"
|
#include "latlong.h"
|
||||||
#include "dwgps.h"
|
#include "dwgps.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,6 +84,16 @@ static unsigned __stdcall beacon_thread (void *arg);
|
||||||
static void * beacon_thread (void *arg);
|
static void * beacon_thread (void *arg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int g_tracker_debug_level = 0; // 1 for data from gps.
|
||||||
|
// 2 + Smart Beaconing logic.
|
||||||
|
// 3 + Send transmissions to log file.
|
||||||
|
|
||||||
|
|
||||||
|
void beacon_tracker_set_debug (int level)
|
||||||
|
{
|
||||||
|
g_tracker_debug_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
|
@ -141,7 +152,7 @@ void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi)
|
||||||
* table entry should be ignored later on.
|
* table entry should be ignored later on.
|
||||||
*/
|
*/
|
||||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||||
int chan = g_misc_config_p->beacon[j].chan;
|
int chan = g_misc_config_p->beacon[j].sendto_chan;
|
||||||
|
|
||||||
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
|
if (chan < 0) chan = 0; /* For IGate, use channel 0 call. */
|
||||||
|
|
||||||
|
@ -177,7 +188,7 @@ void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi)
|
||||||
|
|
||||||
case BEACON_TRACKER:
|
case BEACON_TRACKER:
|
||||||
|
|
||||||
#if defined(GPS_ENABLED) || defined(DEBUG_SIM)
|
#if defined(ENABLE_GPS) || defined(DEBUG_SIM)
|
||||||
g_using_gps++;
|
g_using_gps++;
|
||||||
#else
|
#else
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -322,8 +333,6 @@ void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define KNOTS_TO_MPH 1.150779
|
|
||||||
|
|
||||||
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
#define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||||
|
|
||||||
|
|
||||||
|
@ -360,7 +369,8 @@ static void * beacon_thread (void *arg)
|
||||||
float my_course = 0; /* degrees */
|
float my_course = 0; /* degrees */
|
||||||
float my_speed_knots = 0;
|
float my_speed_knots = 0;
|
||||||
float my_speed_mph = 0;
|
float my_speed_mph = 0;
|
||||||
float my_alt = 0; /* meters */
|
float my_alt_m = G_UNKNOWN; /* meters */
|
||||||
|
int my_alt_ft = G_UNKNOWN;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SmartBeaconing state.
|
* SmartBeaconing state.
|
||||||
|
@ -439,15 +449,40 @@ static void * beacon_thread (void *arg)
|
||||||
fprintf (stderr, "Can't read /tmp/cs.\n");
|
fprintf (stderr, "Can't read /tmp/cs.\n");
|
||||||
}
|
}
|
||||||
fix = 3;
|
fix = 3;
|
||||||
my_speed_mph = KNOTS_TO_MPH * my_speed_knots;
|
my_speed_mph = DW_KNOTS_TO_MPH(my_speed_knots);
|
||||||
my_lat = 42.99;
|
my_lat = 42.99;
|
||||||
my_lon = 71.99;
|
my_lon = 71.99;
|
||||||
my_alt = 100;
|
my_alt_m = 100;
|
||||||
#else
|
#else
|
||||||
if (g_using_gps) {
|
if (g_using_gps) {
|
||||||
|
|
||||||
fix = dwgps_read (&my_lat, &my_lon, &my_speed_knots, &my_course, &my_alt);
|
fix = dwgps_read (&my_lat, &my_lon, &my_speed_knots, &my_course, &my_alt_m);
|
||||||
my_speed_mph = KNOTS_TO_MPH * my_speed_knots;
|
my_speed_mph = DW_KNOTS_TO_MPH(my_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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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. */
|
/* Don't complain here for no fix. */
|
||||||
/* Possibly at the point where about to transmit. */
|
/* Possibly at the point where about to transmit. */
|
||||||
|
@ -460,14 +495,26 @@ static void * beacon_thread (void *arg)
|
||||||
if (g_misc_config_p->sb_configured && g_using_gps && fix >= 2) {
|
if (g_misc_config_p->sb_configured && g_using_gps && fix >= 2) {
|
||||||
|
|
||||||
if (my_speed_mph > g_misc_config_p->sb_fast_speed) {
|
if (my_speed_mph > g_misc_config_p->sb_fast_speed) {
|
||||||
sb_every = g_misc_config_p->sb_fast_rate;
|
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) {
|
else if (my_speed_mph < g_misc_config_p->sb_slow_speed) {
|
||||||
sb_every = g_misc_config_p->sb_slow_rate;
|
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 {
|
else {
|
||||||
/* Can't divide by 0 assuming sb_slow_speed > 0. */
|
/* 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;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG_SIM
|
#if DEBUG_SIM
|
||||||
|
@ -493,6 +540,13 @@ static void * beacon_thread (void *arg)
|
||||||
if (heading_change(my_course, sb_prev_course) > turn_threshold &&
|
if (heading_change(my_course, sb_prev_course) > turn_threshold &&
|
||||||
now >= sb_prev_time + g_misc_config_p->sb_turn_time) {
|
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. */
|
/* Send it now. */
|
||||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||||
|
@ -517,6 +571,7 @@ static void * beacon_thread (void *arg)
|
||||||
char beacon_text[AX25_MAX_PACKET_LEN];
|
char beacon_text[AX25_MAX_PACKET_LEN];
|
||||||
packet_t pp = NULL;
|
packet_t pp = NULL;
|
||||||
char mycall[AX25_MAX_ADDR_LEN];
|
char mycall[AX25_MAX_ADDR_LEN];
|
||||||
|
int alt_ft;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain source call for the beacon.
|
* Obtain source call for the beacon.
|
||||||
|
@ -524,16 +579,16 @@ static void * beacon_thread (void *arg)
|
||||||
* When sending to IGate server, use call from first radio channel.
|
* When sending to IGate server, use call from first radio channel.
|
||||||
*
|
*
|
||||||
* Check added in version 1.0a. Previously used index of -1.
|
* Check added in version 1.0a. Previously used index of -1.
|
||||||
|
*
|
||||||
|
* Version 1.1 - channel should now be 0 for IGate.
|
||||||
|
* Type of destination is encoded separately.
|
||||||
*/
|
*/
|
||||||
strcpy (mycall, "NOCALL");
|
strcpy (mycall, "NOCALL");
|
||||||
|
|
||||||
if (g_misc_config_p->beacon[j].chan == -1) {
|
assert (g_misc_config_p->beacon[j].sendto_chan >= 0);
|
||||||
strcpy (mycall, g_digi_config_p->mycall[0]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
strcpy (mycall, g_digi_config_p->mycall[g_misc_config_p->beacon[j].chan]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
strcpy (mycall, g_digi_config_p->mycall[g_misc_config_p->beacon[j].sendto_chan]);
|
||||||
|
|
||||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
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);
|
dw_printf ("MYCALL not set for beacon in config file line %d.\n", g_misc_config_p->beacon[j].lineno);
|
||||||
|
@ -542,13 +597,22 @@ static void * beacon_thread (void *arg)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare the monitor format header.
|
* Prepare the monitor format header.
|
||||||
|
*
|
||||||
|
* src > dest [ , via ]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
strcpy (beacon_text, mycall);
|
strcpy (beacon_text, mycall);
|
||||||
strcat (beacon_text, ">");
|
strcat (beacon_text, ">");
|
||||||
sprintf (stemp, "%s%1d%1d", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION);
|
|
||||||
strcat (beacon_text, stemp);
|
if (g_misc_config_p->beacon[j].dest != NULL) {
|
||||||
if (g_misc_config_p->beacon[j].via) {
|
strcat (beacon_text, g_misc_config_p->beacon[j].dest);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf (stemp, "%s%1d%1d", APP_TOCALL, MAJOR_VERSION, MINOR_VERSION);
|
||||||
|
strcat (beacon_text, stemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_misc_config_p->beacon[j].via != NULL) {
|
||||||
strcat (beacon_text, ",");
|
strcat (beacon_text, ",");
|
||||||
strcat (beacon_text, g_misc_config_p->beacon[j].via);
|
strcat (beacon_text, g_misc_config_p->beacon[j].via);
|
||||||
}
|
}
|
||||||
|
@ -561,7 +625,10 @@ static void * beacon_thread (void *arg)
|
||||||
|
|
||||||
case BEACON_POSITION:
|
case BEACON_POSITION:
|
||||||
|
|
||||||
encode_position (g_misc_config_p->beacon[j].compress, g_misc_config_p->beacon[j].lat, g_misc_config_p->beacon[j].lon,
|
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,
|
||||||
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
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,
|
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 */
|
0, 0, /* course, speed */
|
||||||
|
@ -594,8 +661,9 @@ static void * beacon_thread (void *arg)
|
||||||
if (coarse == 0) {
|
if (coarse == 0) {
|
||||||
coarse = 360;
|
coarse = 360;
|
||||||
}
|
}
|
||||||
encode_position (g_misc_config_p->beacon[j].compress,
|
encode_position (g_misc_config_p->beacon[j].messaging,
|
||||||
my_lat, my_lon,
|
g_misc_config_p->beacon[j].compress,
|
||||||
|
my_lat, my_lon, my_alt_ft,
|
||||||
g_misc_config_p->beacon[j].symtab, g_misc_config_p->beacon[j].symbol,
|
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,
|
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(my_speed_knots),
|
||||||
|
@ -617,6 +685,34 @@ static void * beacon_thread (void *arg)
|
||||||
else {
|
else {
|
||||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
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 */
|
||||||
|
/* the signals. */
|
||||||
|
|
||||||
|
if (g_tracker_debug_level >= 3) {
|
||||||
|
|
||||||
|
decode_aprs_t A;
|
||||||
|
|
||||||
|
memset (&A, 0, sizeof(A));
|
||||||
|
A.g_freq = G_UNKNOWN;
|
||||||
|
A.g_offset = G_UNKNOWN;
|
||||||
|
A.g_tone = G_UNKNOWN;
|
||||||
|
A.g_dcs = G_UNKNOWN;
|
||||||
|
|
||||||
|
strcpy (A.g_src, mycall);
|
||||||
|
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_course = coarse;
|
||||||
|
A.g_altitude = my_alt_ft;
|
||||||
|
|
||||||
|
/* Fake channel of 999 to distinguish from real data. */
|
||||||
|
log_write (999, &A, NULL, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g_misc_config_p->beacon[j].next = now + 2;
|
g_misc_config_p->beacon[j].next = now + 2;
|
||||||
|
@ -650,18 +746,33 @@ static void * beacon_thread (void *arg)
|
||||||
|
|
||||||
if (pp != NULL) {
|
if (pp != NULL) {
|
||||||
|
|
||||||
/* Send to IGate server or radio. */
|
/* Send to desired destination. */
|
||||||
|
|
||||||
|
switch (g_misc_config_p->beacon[j].sendto_type) {
|
||||||
|
|
||||||
|
case SENDTO_IGATE:
|
||||||
|
|
||||||
|
|
||||||
if (g_misc_config_p->beacon[j].chan == -1) {
|
|
||||||
#if 1
|
#if 1
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[ig] %s\n", beacon_text);
|
dw_printf ("[ig] %s\n", beacon_text);
|
||||||
#endif
|
#endif
|
||||||
igate_send_rec_packet (0, pp);
|
igate_send_rec_packet (0, pp);
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
}
|
break;
|
||||||
else {
|
|
||||||
tq_append (g_misc_config_p->beacon[j].chan, TQ_PRIO_1_LO, pp);
|
case SENDTO_XMIT:
|
||||||
|
default:
|
||||||
|
|
||||||
|
tq_append (g_misc_config_p->beacon[j].sendto_chan, TQ_PRIO_1_LO, pp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SENDTO_RECV:
|
||||||
|
|
||||||
|
// TODO: Put into receive queue rather than calling directly.
|
||||||
|
|
||||||
|
app_process_rec_packet (g_misc_config_p->beacon[j].sendto_chan, 0, pp, -1, 0, "");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
2
beacon.h
2
beacon.h
|
@ -2,3 +2,5 @@
|
||||||
/* beacon.h */
|
/* beacon.h */
|
||||||
|
|
||||||
void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi);
|
void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi);
|
||||||
|
|
||||||
|
void beacon_tracker_set_debug (int level);
|
||||||
|
|
317
config.c
317
config.c
|
@ -54,6 +54,7 @@
|
||||||
#include "igate.h"
|
#include "igate.h"
|
||||||
#include "latlong.h"
|
#include "latlong.h"
|
||||||
#include "symbols.h"
|
#include "symbols.h"
|
||||||
|
#include "LatLong-UTMconversion.h"
|
||||||
|
|
||||||
|
|
||||||
//#include "tq.h"
|
//#include "tq.h"
|
||||||
|
@ -415,6 +416,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
strcpy (p_modem->ptt_device[channel], "");
|
strcpy (p_modem->ptt_device[channel], "");
|
||||||
p_modem->ptt_line[channel] = PTT_LINE_RTS;
|
p_modem->ptt_line[channel] = PTT_LINE_RTS;
|
||||||
p_modem->ptt_gpio[channel] = 0;
|
p_modem->ptt_gpio[channel] = 0;
|
||||||
|
p_modem->ptt_lpt_bit[channel] = 0;
|
||||||
p_modem->ptt_invert[channel] = 0;
|
p_modem->ptt_invert[channel] = 0;
|
||||||
|
|
||||||
p_modem->slottime[channel] = DEFAULT_SLOTTIME;
|
p_modem->slottime[channel] = DEFAULT_SLOTTIME;
|
||||||
|
@ -477,6 +479,8 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
|
|
||||||
//strcpy (p_misc_config->nullmodem, DEFAULT_NULLMODEM);
|
//strcpy (p_misc_config->nullmodem, DEFAULT_NULLMODEM);
|
||||||
strcpy (p_misc_config->nullmodem, "");
|
strcpy (p_misc_config->nullmodem, "");
|
||||||
|
strcpy (p_misc_config->nmea_port, "");
|
||||||
|
strcpy (p_misc_config->logdir, "");
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -642,16 +646,28 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char *p;
|
|
||||||
|
|
||||||
strncpy (p_digi_config->mycall[channel], t, sizeof(p_digi_config->mycall[channel])-1);
|
// Definitely set for current channel.
|
||||||
|
// Set for other channels which have not been set yet.
|
||||||
|
|
||||||
for (p = p_digi_config->mycall[channel]; *p != '\0'; p++) {
|
int c;
|
||||||
if (islower(*p)) {
|
|
||||||
*p = toupper(*p); /* silently force upper case. */
|
for (c = 0; c < MAX_CHANS; c++) {
|
||||||
|
|
||||||
|
if (c == channel || strlen(p_digi_config->mycall[c]) == 0 || strcasecmp(p_digi_config->mycall[c], "NOCALL") == 0) {
|
||||||
|
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
strncpy (p_digi_config->mycall[c], t, sizeof(p_digi_config->mycall[c])-1);
|
||||||
|
|
||||||
|
for (p = p_digi_config->mycall[c]; *p != '\0'; p++) {
|
||||||
|
if (islower(*p)) {
|
||||||
|
*p = toupper(*p); /* silently force upper case. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: additional checks if valid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: additional checks if valid
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -898,6 +914,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
*
|
*
|
||||||
* PTT serial-port [-]rts-or-dtr
|
* PTT serial-port [-]rts-or-dtr
|
||||||
* PTT GPIO [-]gpio-num
|
* PTT GPIO [-]gpio-num
|
||||||
|
* PTT LPT [-]bit-num
|
||||||
*/
|
*/
|
||||||
|
|
||||||
else if (strcasecmp(t, "PTT") == 0) {
|
else if (strcasecmp(t, "PTT") == 0) {
|
||||||
|
@ -910,7 +927,60 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcasecmp(t, "GPIO") != 0) {
|
if (strcasecmp(t, "GPIO") == 0) {
|
||||||
|
|
||||||
|
/* GPIO case, Linux only. */
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file line %d: PTT with GPIO is only available on Linux.\n", line);
|
||||||
|
#else
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file line %d: Missing GPIO number.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*t == '-') {
|
||||||
|
p_modem->ptt_gpio[channel] = atoi(t+1);
|
||||||
|
p_modem->ptt_invert[channel] = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p_modem->ptt_gpio[channel] = atoi(t);
|
||||||
|
p_modem->ptt_invert[channel] = 0;
|
||||||
|
}
|
||||||
|
p_modem->ptt_method[channel] = PTT_METHOD_GPIO;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (strcasecmp(t, "LPT") == 0) {
|
||||||
|
|
||||||
|
/* Parallel printer case, x86 Linux only. */
|
||||||
|
|
||||||
|
#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
|
||||||
|
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file line %d: Missing LPT bit number.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*t == '-') {
|
||||||
|
p_modem->ptt_lpt_bit[channel] = atoi(t+1);
|
||||||
|
p_modem->ptt_invert[channel] = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p_modem->ptt_lpt_bit[channel] = atoi(t);
|
||||||
|
p_modem->ptt_invert[channel] = 0;
|
||||||
|
}
|
||||||
|
p_modem->ptt_method[channel] = PTT_METHOD_LPT;
|
||||||
|
#else
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file line %d: PTT with LPT is only available on x86 Linux.\n", line);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
/* serial port case. */
|
/* serial port case. */
|
||||||
|
|
||||||
|
@ -949,34 +1019,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
|
|
||||||
p_modem->ptt_method[channel] = PTT_METHOD_SERIAL;
|
p_modem->ptt_method[channel] = PTT_METHOD_SERIAL;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
|
||||||
/* GPIO case, Linux only. */
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
#if 0
|
|
||||||
//#if __WIN32__
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Config file line %d: PTT with GPIO is only available on Linux.\n", line);
|
|
||||||
#else
|
|
||||||
t = strtok (NULL, " ,\t\n\r");
|
|
||||||
if (t == NULL) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("Config file line %d: Missing GPIO number.\n", line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*t == '-') {
|
|
||||||
p_modem->ptt_gpio[channel] = atoi(t+1);
|
|
||||||
p_modem->ptt_invert[channel] = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
p_modem->ptt_gpio[channel] = atoi(t);
|
|
||||||
p_modem->ptt_invert[channel] = 0;
|
|
||||||
}
|
|
||||||
p_modem->ptt_method[channel] = PTT_METHOD_GPIO;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1193,6 +1236,48 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* REGEN - Signal regeneration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (strcasecmp(t, "regen") == 0) {
|
||||||
|
int from_chan, to_chan;
|
||||||
|
//int e;
|
||||||
|
//char message[100];
|
||||||
|
|
||||||
|
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: Missing FROM-channel on line %d.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
from_chan = atoi(t);
|
||||||
|
if (from_chan < 0 || from_chan > p_digi_config->num_chans-1) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: FROM-channel must be in range of 0 to %d on line %d.\n",
|
||||||
|
p_digi_config->num_chans-1, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: Missing TO-channel on line %d.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
to_chan = atoi(t);
|
||||||
|
if (to_chan < 0 || to_chan > p_digi_config->num_chans-1) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: TO-channel must be in range of 0 to %d on line %d.\n",
|
||||||
|
p_digi_config->num_chans-1, line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
p_digi_config->regen[from_chan][to_chan] = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ==================== APRStt gateway ====================
|
* ==================== APRStt gateway ====================
|
||||||
|
@ -2016,6 +2101,36 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NMEA - Device name for communication with NMEA device.
|
||||||
|
*/
|
||||||
|
else if (strcasecmp(t, "nmea") == 0) {
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: Missing device name for NMEA port on line %d.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy (p_misc_config->nmea_port, t, sizeof(p_misc_config->nmea_port)-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LOGDIR - Directory name for storing log files. Use "." for current working directory.
|
||||||
|
*/
|
||||||
|
else if (strcasecmp(t, "logdir") == 0) {
|
||||||
|
t = strtok (NULL, " ,\t\n\r");
|
||||||
|
if (t == NULL) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file: Missing directory name for LOGDIR on line %d.\n", line);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy (p_misc_config->logdir, t, sizeof(p_misc_config->logdir)-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIX_BITS - Attempt to fix frames with bad FCS.
|
* FIX_BITS - Attempt to fix frames with bad FCS.
|
||||||
*/
|
*/
|
||||||
|
@ -2029,7 +2144,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
n = atoi(t);
|
n = atoi(t);
|
||||||
if (n >= RETRY_NONE && n <= RETRY_TWO_SEP) {
|
if (n >= RETRY_NONE && n <= RETRY_REMOVE_TWO_SEP) {
|
||||||
p_modem->fix_bits = (retry_t)n;
|
p_modem->fix_bits = (retry_t)n;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -2050,7 +2165,8 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Config file, line %d: Old style 'BEACON' has been replaced with new commands.\n", line);
|
dw_printf ("Config file, line %d: Old style 'BEACON' has been replaced with new commands.\n", line);
|
||||||
|
dw_printf ("Use PBEACON, OBEACON, or CBEACON instead.\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2067,7 +2183,21 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
strcasecmp(t, "OBEACON") == 0 ||
|
strcasecmp(t, "OBEACON") == 0 ||
|
||||||
strcasecmp(t, "TBEACON") == 0 ||
|
strcasecmp(t, "TBEACON") == 0 ||
|
||||||
strcasecmp(t, "CBEACON") == 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) {
|
if (p_misc_config->num_beacons < MAX_BEACONS) {
|
||||||
|
|
||||||
memset (&(p_misc_config->beacon[p_misc_config->num_beacons]), 0, sizeof(struct beacon_s));
|
memset (&(p_misc_config->beacon[p_misc_config->num_beacons]), 0, sizeof(struct beacon_s));
|
||||||
|
@ -2201,12 +2331,14 @@ void config_init (char *fname, struct audio_s *p_modem,
|
||||||
|
|
||||||
b = 0;
|
b = 0;
|
||||||
for (k=0; k<p_misc_config->num_beacons; k++) {
|
for (k=0; k<p_misc_config->num_beacons; k++) {
|
||||||
if (p_misc_config->beacon[p_misc_config->num_beacons].chan == j) b++;
|
if (p_misc_config->beacon[p_misc_config->num_beacons].sendto_chan == j) b++;
|
||||||
}
|
}
|
||||||
if (b == 0) {
|
if (b == 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Config file: Beaconing should be configured for channel %d when digipeating is enabled.\n", i);
|
dw_printf ("Config file: Beaconing should be configured for channel %d when digipeating is enabled.\n", i);
|
||||||
p_digi_config->enabled[i][j] = 0;
|
// It's a recommendation, not a requirement.
|
||||||
|
// Was there some good reason to turn it off in earlier version?
|
||||||
|
//p_digi_config->enabled[i][j] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2245,16 +2377,22 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line)
|
||||||
int q;
|
int q;
|
||||||
char temp_symbol[100];
|
char temp_symbol[100];
|
||||||
int ok;
|
int ok;
|
||||||
|
char zone[8];
|
||||||
strcpy (temp_symbol, "");
|
double easting = G_UNKNOWN;
|
||||||
|
double northing = G_UNKNOWN;
|
||||||
|
|
||||||
b->chan = 0;
|
strcpy (temp_symbol, "");
|
||||||
|
strcpy (zone, "");
|
||||||
|
|
||||||
|
b->sendto_type = SENDTO_XMIT;
|
||||||
|
b->sendto_chan = 0;
|
||||||
b->delay = 60;
|
b->delay = 60;
|
||||||
b->every = 600;
|
b->every = 600;
|
||||||
//b->delay = 6; // TODO: temp. remove
|
//b->delay = 6; // temp test.
|
||||||
//b->every = 3600;
|
//b->every = 3600;
|
||||||
b->lat = G_UNKNOWN;
|
b->lat = G_UNKNOWN;
|
||||||
b->lon = G_UNKNOWN;
|
b->lon = G_UNKNOWN;
|
||||||
|
b->alt_m = G_UNKNOWN;
|
||||||
b->symtab = '/';
|
b->symtab = '/';
|
||||||
b->symbol = '-'; /* house */
|
b->symbol = '-'; /* house */
|
||||||
|
|
||||||
|
@ -2353,10 +2491,31 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line)
|
||||||
}
|
}
|
||||||
else if (strcasecmp(keyword, "SENDTO") == 0) {
|
else if (strcasecmp(keyword, "SENDTO") == 0) {
|
||||||
if (value[0] == 'i' || value[0] == 'I') {
|
if (value[0] == 'i' || value[0] == 'I') {
|
||||||
b->chan = -1;
|
b->sendto_type = SENDTO_IGATE;
|
||||||
|
b->sendto_chan = 0;
|
||||||
|
}
|
||||||
|
else if (value[0] == 'r' || value[0] == 'R') {
|
||||||
|
b->sendto_type = SENDTO_RECV;
|
||||||
|
b->sendto_chan = atoi(value+1);
|
||||||
|
}
|
||||||
|
else if (value[0] == 't' || value[0] == 'T' || value[0] == 'x' || value[0] == 'X') {
|
||||||
|
b->sendto_type = SENDTO_XMIT;
|
||||||
|
b->sendto_chan = atoi(value+1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
b->chan = atoi(value);
|
b->sendto_type = SENDTO_XMIT;
|
||||||
|
b->sendto_chan = atoi(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcasecmp(keyword, "DEST") == 0) {
|
||||||
|
b->dest = strdup(value);
|
||||||
|
for (p = b->dest; *p != '\0'; p++) {
|
||||||
|
if (islower(*p)) {
|
||||||
|
*p = toupper(*p); /* silently force upper case. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (strlen(b->dest) > 9) {
|
||||||
|
b->dest[9] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcasecmp(keyword, "VIA") == 0) {
|
else if (strcasecmp(keyword, "VIA") == 0) {
|
||||||
|
@ -2379,6 +2538,18 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line)
|
||||||
else if (strcasecmp(keyword, "LONG") == 0 || strcasecmp(keyword, "LON") == 0) {
|
else if (strcasecmp(keyword, "LONG") == 0 || strcasecmp(keyword, "LON") == 0) {
|
||||||
b->lon = parse_ll (value, LON, line);
|
b->lon = parse_ll (value, LON, line);
|
||||||
}
|
}
|
||||||
|
else if (strcasecmp(keyword, "ALT") == 0 || strcasecmp(keyword, "ALTITUDE") == 0) {
|
||||||
|
b->alt_m = atof(value);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(keyword, "ZONE") == 0) {
|
||||||
|
strncpy(zone, value, sizeof(zone));
|
||||||
|
}
|
||||||
|
else if (strcasecmp(keyword, "EAST") == 0 || strcasecmp(keyword, "EASTING") == 0) {
|
||||||
|
easting = atof(value);
|
||||||
|
}
|
||||||
|
else if (strcasecmp(keyword, "NORTH") == 0 || strcasecmp(keyword, "NORTHING") == 0) {
|
||||||
|
northing = atof(value);
|
||||||
|
}
|
||||||
else if (strcasecmp(keyword, "SYMBOL") == 0) {
|
else if (strcasecmp(keyword, "SYMBOL") == 0) {
|
||||||
/* Defer processing in case overlay appears later. */
|
/* Defer processing in case overlay appears later. */
|
||||||
strcpy (temp_symbol, value);
|
strcpy (temp_symbol, value);
|
||||||
|
@ -2419,6 +2590,9 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line)
|
||||||
else if (strcasecmp(keyword, "COMPRESS") == 0 || strcasecmp(keyword, "COMPRESSED") == 0) {
|
else if (strcasecmp(keyword, "COMPRESS") == 0 || strcasecmp(keyword, "COMPRESSED") == 0) {
|
||||||
b->compress = atoi(value);
|
b->compress = atoi(value);
|
||||||
}
|
}
|
||||||
|
else if (strcasecmp(keyword, "MESSAGING") == 0) {
|
||||||
|
b->messaging = atoi(value);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Config file, line %d: Invalid option keyword, %s.\n", line, keyword);
|
dw_printf ("Config file, line %d: Invalid option keyword, %s.\n", line, keyword);
|
||||||
|
@ -2426,6 +2600,59 @@ static int beacon_options(char *cmd, struct beacon_s *b, int line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert UTM coordintes to lat / long.
|
||||||
|
*/
|
||||||
|
if (strlen(zone) > 0 || easting != G_UNKNOWN || northing != G_UNKNOWN) {
|
||||||
|
|
||||||
|
if (strlen(zone) > 0 && easting != G_UNKNOWN && northing != G_UNKNOWN) {
|
||||||
|
|
||||||
|
int znum;
|
||||||
|
char *zlet;
|
||||||
|
|
||||||
|
znum = strtoul(zone, &zlet, 10);
|
||||||
|
|
||||||
|
if (znum >= 1 && znum <= 60) {
|
||||||
|
|
||||||
|
//printf ("zlet = %c 0x%02x\n", *zlet, *zlet);
|
||||||
|
|
||||||
|
if (*zlet == '\0' || strchr ("CDEFGHJKLMNPQRSTUVWX", *zlet) != NULL) {
|
||||||
|
|
||||||
|
if (easting >= 0 && easting <= 999999) {
|
||||||
|
|
||||||
|
if (northing >= 0 && northing <= 9999999) {
|
||||||
|
|
||||||
|
UTMtoLL (WSG84, northing, easting, zone, &b->lat, &b->lon);
|
||||||
|
|
||||||
|
// printf ("config UTM debug: latitude = %.6f, longitude = %.6f\n", b->lat, b->lon);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file, line %d: Northing value is out of range.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file, line %d: Easting value is out of range.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file, line %d: Latitudinal band must be one of CDEFGHJKLMNPQRSTUVWX.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file, line %d: UTM zone is out of range.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Config file, line %d: When any of ZONE, EASTING, NORTHING specifed, they must all be specified.\n", line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process symbol now that we have any later overlay.
|
* Process symbol now that we have any later overlay.
|
||||||
*/
|
*/
|
||||||
|
|
28
config.h
28
config.h
|
@ -25,6 +25,9 @@
|
||||||
|
|
||||||
enum beacon_type_e { BEACON_IGNORE, BEACON_POSITION, BEACON_OBJECT, BEACON_TRACKER, BEACON_CUSTOM };
|
enum beacon_type_e { BEACON_IGNORE, BEACON_POSITION, BEACON_OBJECT, BEACON_TRACKER, BEACON_CUSTOM };
|
||||||
|
|
||||||
|
enum sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
|
||||||
|
|
||||||
|
|
||||||
#define MAX_BEACONS 30
|
#define MAX_BEACONS 30
|
||||||
|
|
||||||
struct misc_config_s {
|
struct misc_config_s {
|
||||||
|
@ -40,6 +43,11 @@ struct misc_config_s {
|
||||||
char nullmodem[40]; /* Serial port name for our end of the */
|
char nullmodem[40]; /* Serial port name for our end of the */
|
||||||
/* virtual null modem for native Windows apps. */
|
/* 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 logdir[80]; /* Directory for saving activity logs. */
|
||||||
|
|
||||||
int sb_configured; /* TRUE if SmartBeaconing is configured. */
|
int sb_configured; /* TRUE if SmartBeaconing is configured. */
|
||||||
int sb_fast_speed; /* MPH */
|
int sb_fast_speed; /* MPH */
|
||||||
int sb_fast_rate; /* seconds */
|
int sb_fast_rate; /* seconds */
|
||||||
|
@ -58,7 +66,18 @@ struct misc_config_s {
|
||||||
|
|
||||||
int lineno; /* Line number from config file for later error messages. */
|
int lineno; /* Line number from config file for later error messages. */
|
||||||
|
|
||||||
int chan; /* Send to Channel for transmission. -1 for IGate. */
|
enum sendto_type_e sendto_type;
|
||||||
|
|
||||||
|
/* SENDTO_XMIT - Usually beacons go to a radio transmitter. */
|
||||||
|
/* chan, below is the channel number. */
|
||||||
|
/* SENDTO_IGATE - Send to IGate, probably to announce my position */
|
||||||
|
/* rather than relying on someone else to hear */
|
||||||
|
/* me on the radio and report me. */
|
||||||
|
/* SENDTO_RECV - Pretend this was heard on the specified */
|
||||||
|
/* radio channel. Mostly for testing. It is a */
|
||||||
|
/* convenient way to send packets to attached apps. */
|
||||||
|
|
||||||
|
int sendto_chan; /* Transmit or simulated receive channel for above. Should be 0 for IGate. */
|
||||||
|
|
||||||
int delay; /* Seconds to delay before first transmission. */
|
int delay; /* Seconds to delay before first transmission. */
|
||||||
|
|
||||||
|
@ -68,6 +87,9 @@ struct misc_config_s {
|
||||||
|
|
||||||
time_t next; /* Unix time to transmit next one. */
|
time_t next; /* Unix time to transmit next one. */
|
||||||
|
|
||||||
|
char *dest; /* NULL or explicit AX.25 destination to use */
|
||||||
|
/* instead of the software version such as APDW11. */
|
||||||
|
|
||||||
int compress; /* Use more compact form? */
|
int compress; /* Use more compact form? */
|
||||||
|
|
||||||
char objname[10]; /* Object name. Any printable characters. */
|
char objname[10]; /* Object name. Any printable characters. */
|
||||||
|
@ -77,8 +99,12 @@ struct misc_config_s {
|
||||||
char *custom_info; /* Info part for handcrafted custom beacon. */
|
char *custom_info; /* Info part for handcrafted custom beacon. */
|
||||||
/* Ignore the rest below if this is set. */
|
/* Ignore the rest below if this is set. */
|
||||||
|
|
||||||
|
int messaging; /* Set messaging attribute for position report. */
|
||||||
|
/* i.e. Data Type Indicator of '=' rather than '!' */
|
||||||
|
|
||||||
double lat; /* Latitude and longitude. */
|
double lat; /* Latitude and longitude. */
|
||||||
double lon;
|
double lon;
|
||||||
|
float alt_m; /* Altitude in meters. */
|
||||||
|
|
||||||
char symtab; /* Symbol table: / or \ or overlay character. */
|
char symtab; /* Symbol table: / or \ or overlay character. */
|
||||||
char symbol; /* Symbol code. */
|
char symbol; /* Symbol code. */
|
||||||
|
|
1827
decode_aprs.c
1827
decode_aprs.c
File diff suppressed because it is too large
Load Diff
103
decode_aprs.h
103
decode_aprs.h
|
@ -1,5 +1,106 @@
|
||||||
|
|
||||||
/* decode_aprs.h */
|
/* decode_aprs.h */
|
||||||
|
|
||||||
extern void decode_aprs (packet_t pp);
|
|
||||||
|
|
||||||
|
#ifndef DECODE_APRS_H
|
||||||
|
|
||||||
|
#define DECODE_APRS_H 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef G_UNKNOWN
|
||||||
|
#include "latlong.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef AX25_MAX_ADDR_LEN
|
||||||
|
#include "ax25_pad.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef APRSTT_LOC_DESC_LEN
|
||||||
|
#include "aprs_tt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct decode_aprs_s {
|
||||||
|
|
||||||
|
char g_src[AX25_MAX_ADDR_LEN];
|
||||||
|
|
||||||
|
char g_msg_type[60]; /* Message type. Telemetry descriptions get pretty long. */
|
||||||
|
|
||||||
|
char g_symbol_table; /* The Symbol Table Identifier character selects one */
|
||||||
|
/* of the two Symbol Tables, or it may be used as */
|
||||||
|
/* single-character (alpha or numeric) overlay, as follows: */
|
||||||
|
|
||||||
|
/* / Primary Symbol Table (mostly stations) */
|
||||||
|
|
||||||
|
/* \ Alternate Symbol Table (mostly Objects) */
|
||||||
|
|
||||||
|
/* 0-9 Numeric overlay. Symbol from Alternate Symbol */
|
||||||
|
/* Table (uncompressed lat/long data format) */
|
||||||
|
|
||||||
|
/* a-j Numeric overlay. Symbol from Alternate */
|
||||||
|
/* Symbol Table (compressed lat/long data */
|
||||||
|
/* format only). i.e. a-j maps to 0-9 */
|
||||||
|
|
||||||
|
/* A-Z Alpha overlay. Symbol from Alternate Symbol Table */
|
||||||
|
|
||||||
|
|
||||||
|
char g_symbol_code; /* Where the Symbol Table Identifier is 0-9 or A-Z (or a-j */
|
||||||
|
/* with compressed position data only), the symbol comes from */
|
||||||
|
/* the Alternate Symbol Table, and is overlaid with the */
|
||||||
|
/* identifier (as a single digit or a capital letter). */
|
||||||
|
|
||||||
|
char g_aprstt_loc[APRSTT_LOC_DESC_LEN]; /* APRStt location from !DAO! */
|
||||||
|
|
||||||
|
double g_lat, g_lon; /* Location, degrees. Negative for South or West. */
|
||||||
|
/* Set to G_UNKNOWN if missing or error. */
|
||||||
|
|
||||||
|
char g_maidenhead[9]; /* 4 or 6 (or 8?) character maidenhead locator. */
|
||||||
|
|
||||||
|
char g_name[20]; /* Object or item name. */
|
||||||
|
|
||||||
|
float g_speed; /* Speed in MPH. */
|
||||||
|
|
||||||
|
float g_course; /* 0 = North, 90 = East, etc. */
|
||||||
|
|
||||||
|
int g_power; /* Transmitter power in watts. */
|
||||||
|
|
||||||
|
int g_height; /* Antenna height above average terrain, feet. */
|
||||||
|
|
||||||
|
int g_gain; /* Antenna gain in dB. */
|
||||||
|
|
||||||
|
char g_directivity[10]; /* Direction of max signal strength */
|
||||||
|
|
||||||
|
float g_range; /* Precomputed radio range in miles. */
|
||||||
|
|
||||||
|
float g_altitude; /* Feet above median sea level. */
|
||||||
|
|
||||||
|
char g_mfr[80]; /* Manufacturer or application. */
|
||||||
|
|
||||||
|
char g_mic_e_status[30]; /* MIC-E message. */
|
||||||
|
|
||||||
|
double g_freq; /* Frequency, MHz */
|
||||||
|
|
||||||
|
float g_tone; /* CTCSS tone, Hz, one fractional digit */
|
||||||
|
|
||||||
|
int g_dcs; /* Digital coded squelch, print as 3 octal digits. */
|
||||||
|
|
||||||
|
int g_offset; /* Transmit offset, KHz */
|
||||||
|
|
||||||
|
char g_weather[500]; /* Weather. Can get quite long. Rethink max size. */
|
||||||
|
|
||||||
|
char g_telemetry[256]; /* Telemetry data. Rethink max size. */
|
||||||
|
|
||||||
|
char g_comment[256]; /* Comment. */
|
||||||
|
|
||||||
|
} decode_aprs_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern void decode_aprs (decode_aprs_t *A, packet_t pp);
|
||||||
|
|
||||||
|
extern void decode_aprs_print (decode_aprs_t *A);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -92,12 +92,7 @@ static inline float z (float x, float y)
|
||||||
__attribute__((hot))
|
__attribute__((hot))
|
||||||
static inline void push_sample (float val, float *buff, int size)
|
static inline void push_sample (float val, float *buff, int size)
|
||||||
{
|
{
|
||||||
int j;
|
memmove(buff+1,buff,(size-1)*sizeof(float));
|
||||||
|
|
||||||
// TODO: memmove any faster?
|
|
||||||
for (j = size - 1; j >= 1; j--) {
|
|
||||||
buff[j] = buff[j-1];
|
|
||||||
}
|
|
||||||
buff[0] = val;
|
buff[0] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
42
digipeater.c
42
digipeater.c
|
@ -459,6 +459,44 @@ static packet_t digipeat_match (packet_t pp, char *mycall_rec, char *mycall_xmit
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: digi_regen
|
||||||
|
*
|
||||||
|
* Purpose: Send regenerated copy of what we received.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Radio channel where it was received.
|
||||||
|
*
|
||||||
|
* pp - Packet object.
|
||||||
|
*
|
||||||
|
* Returns: None.
|
||||||
|
*
|
||||||
|
* Description: TODO...
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void digi_regen (int from_chan, packet_t pp)
|
||||||
|
{
|
||||||
|
int to_chan;
|
||||||
|
packet_t result;
|
||||||
|
|
||||||
|
// dw_printf ("digi_regen()\n");
|
||||||
|
|
||||||
|
assert (from_chan >= 0 && from_chan < my_config.num_chans);
|
||||||
|
|
||||||
|
for (to_chan=0; to_chan<my_config.num_chans; to_chan++) {
|
||||||
|
if (my_config.regen[from_chan][to_chan]) {
|
||||||
|
result = ax25_dup (pp);
|
||||||
|
if (result != NULL) {
|
||||||
|
// TODO: if AX.25 and has been digipeated, put in HI queue?
|
||||||
|
tq_append (to_chan, TQ_PRIO_1_LO, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end dig_regen */
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: main
|
* Name: main
|
||||||
|
@ -509,7 +547,7 @@ static void test (char *in, char *out)
|
||||||
|
|
||||||
if (strcmp(in, rec) != 0) {
|
if (strcmp(in, rec) != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Text/internal/text error %s -> %s\n", in, rec);
|
dw_printf ("Text/internal/text error-1 %s -> %s\n", in, rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -527,7 +565,7 @@ static void test (char *in, char *out)
|
||||||
|
|
||||||
if (strcmp(in, rec) != 0) {
|
if (strcmp(in, rec) != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("internal/frame/internal/text error %s -> %s\n", in, rec);
|
dw_printf ("internal/frame/internal/text error-2 %s -> %s\n", in, rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -41,6 +41,8 @@ struct digi_config_s {
|
||||||
|
|
||||||
enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS];
|
enum preempt_e { PREEMPT_OFF, PREEMPT_DROP, PREEMPT_MARK, PREEMPT_TRACE } preempt[MAX_CHANS][MAX_CHANS];
|
||||||
|
|
||||||
|
int regen[MAX_CHANS][MAX_CHANS]; // Regenerate packet.
|
||||||
|
// Sort of like digipeating but passed along unchanged.
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,6 +58,9 @@ extern void digipeater_init (struct digi_config_s *p_digi_config);
|
||||||
|
|
||||||
extern void digipeater (int from_chan, packet_t pp);
|
extern void digipeater (int from_chan, packet_t pp);
|
||||||
|
|
||||||
|
void digi_regen (int from_chan, packet_t pp);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* end digipeater.h */
|
/* end digipeater.h */
|
||||||
|
|
148
direwolf.c
148
direwolf.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011, 2012, 2013 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2012, 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -42,6 +42,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
#else
|
#else
|
||||||
|
@ -49,7 +50,11 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#include <soundcard.h>
|
||||||
|
#else
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
|
#endif
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
@ -72,6 +77,7 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "kiss.h"
|
#include "kiss.h"
|
||||||
#include "kissnet.h"
|
#include "kissnet.h"
|
||||||
|
#include "nmea.h"
|
||||||
#include "gen_tone.h"
|
#include "gen_tone.h"
|
||||||
#include "digipeater.h"
|
#include "digipeater.h"
|
||||||
#include "tq.h"
|
#include "tq.h"
|
||||||
|
@ -86,8 +92,12 @@
|
||||||
#include "igate.h"
|
#include "igate.h"
|
||||||
#include "symbols.h"
|
#include "symbols.h"
|
||||||
#include "dwgps.h"
|
#include "dwgps.h"
|
||||||
|
#include "nmea.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
|
||||||
|
//static int idx_decoded = 0;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
static BOOL cleanup_win (int);
|
static BOOL cleanup_win (int);
|
||||||
#else
|
#else
|
||||||
|
@ -130,8 +140,10 @@ static void __cpuid(int cpuinfo[4], int infotype){
|
||||||
|
|
||||||
static struct audio_s modem;
|
static struct audio_s modem;
|
||||||
|
|
||||||
static int d_u_opt = 0; /* "-d u" command line option. */
|
static int d_u_opt = 0; /* "-d u" command line option to print UTF-8 also in hexadecimal. */
|
||||||
|
static int d_p_opt = 0; /* "-d p" option for dumping packets over radio. */
|
||||||
|
|
||||||
|
static struct misc_config_s misc_config;
|
||||||
|
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
|
@ -145,11 +157,18 @@ int main (int argc, char *argv[])
|
||||||
struct digi_config_s digi_config;
|
struct digi_config_s digi_config;
|
||||||
struct tt_config_s tt_config;
|
struct tt_config_s tt_config;
|
||||||
struct igate_config_s igate_config;
|
struct igate_config_s igate_config;
|
||||||
struct misc_config_s misc_config;
|
|
||||||
int r_opt = 0, n_opt = 0, b_opt = 0, B_opt = 0, D_opt = 0; /* Command line options. */
|
int r_opt = 0, n_opt = 0, b_opt = 0, B_opt = 0, D_opt = 0; /* Command line options. */
|
||||||
|
char l_opt[80];
|
||||||
char input_file[80];
|
char input_file[80];
|
||||||
|
|
||||||
int t_opt = 1; /* Text color option. */
|
int t_opt = 1; /* Text color option. */
|
||||||
|
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. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
strcpy(l_opt, "");
|
||||||
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
@ -195,12 +214,9 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
text_color_init(t_opt);
|
text_color_init(t_opt);
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test 2\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test 1\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||||
//dw_printf ("Dire Wolf version %d.%d (%s) Development version\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
//dw_printf ("Dire Wolf DEVELOPMENT version %d.%d %s (%s)\n", MAJOR_VERSION, MINOR_VERSION, "M", __DATE__);
|
||||||
|
dw_printf ("Dire Wolf version %d.%d, December 2014\n", MAJOR_VERSION, MINOR_VERSION);
|
||||||
// Note "a" for fix with beacon sent to IGate Server.
|
|
||||||
|
|
||||||
dw_printf ("Dire Wolf version %d.%da\n", MAJOR_VERSION, MINOR_VERSION);
|
|
||||||
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
@ -272,6 +288,7 @@ int main (int argc, char *argv[])
|
||||||
int this_option_optind = optind ? optind : 1;
|
int this_option_optind = optind ? optind : 1;
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c;
|
int c;
|
||||||
|
char *p;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"future1", 1, 0, 0},
|
{"future1", 1, 0, 0},
|
||||||
{"future2", 0, 0, 0},
|
{"future2", 0, 0, 0},
|
||||||
|
@ -281,7 +298,7 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
/* ':' following option character means arg is required. */
|
/* ':' following option character means arg is required. */
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "B:D:c:pxr:b:n:d:t:U",
|
c = getopt_long(argc, argv, "B:D:c:pxr:b:n:d:t:Ul:",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -380,12 +397,26 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
case 'd': /* Set debug option. */
|
case 'd': /* Set debug option. */
|
||||||
|
|
||||||
switch (optarg[0]) {
|
/* New in 1.1. Can combine multiple such as "-d pkk" */
|
||||||
|
|
||||||
|
for (p=optarg; *p!='\0'; p++) {
|
||||||
|
switch (*p) {
|
||||||
|
|
||||||
case 'a': server_set_debug(1); break;
|
case 'a': server_set_debug(1); break;
|
||||||
case 'k': kiss_serial_set_debug (1); break;
|
|
||||||
case 'n': kiss_net_set_debug (1); break;
|
case 'k': d_k_opt++; kiss_serial_set_debug (d_k_opt); break;
|
||||||
|
case 'n': d_n_opt++; kiss_net_set_debug (d_n_opt); break;
|
||||||
|
|
||||||
case 'u': d_u_opt = 1; break;
|
case 'u': d_u_opt = 1; break;
|
||||||
|
|
||||||
|
// separate out gps & waypoints.
|
||||||
|
|
||||||
|
case 't': d_t_opt++; beacon_tracker_set_debug (d_t_opt); break;
|
||||||
|
|
||||||
|
case 'w': nmea_set_debug (1); break; // not documented yet.
|
||||||
|
case 'p': d_p_opt = 1; break; // TODO: packet dump for xmit side.
|
||||||
default: break;
|
default: break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -403,6 +434,10 @@ int main (int argc, char *argv[])
|
||||||
exit (0);
|
exit (0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'l': /* -l for log file directory name */
|
||||||
|
|
||||||
|
strncpy (l_opt, optarg, sizeof(l_opt)-1);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
@ -471,6 +506,10 @@ int main (int argc, char *argv[])
|
||||||
modem.decimate[0] = D_opt;
|
modem.decimate[0] = D_opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strlen(l_opt) > 0) {
|
||||||
|
strncpy (misc_config.logdir, l_opt, sizeof(misc_config.logdir)-1);
|
||||||
|
}
|
||||||
|
|
||||||
misc_config.enable_kiss_pt = enable_pseudo_terminal;
|
misc_config.enable_kiss_pt = enable_pseudo_terminal;
|
||||||
|
|
||||||
if (strlen(input_file) > 0) {
|
if (strlen(input_file) > 0) {
|
||||||
|
@ -521,7 +560,7 @@ int main (int argc, char *argv[])
|
||||||
* Initialize the transmit queue.
|
* Initialize the transmit queue.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
xmit_init (&modem);
|
xmit_init (&modem, d_p_opt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If -x option specified, transmit alternating tones for transmitter
|
* If -x option specified, transmit alternating tones for transmitter
|
||||||
|
@ -565,6 +604,11 @@ int main (int argc, char *argv[])
|
||||||
*/
|
*/
|
||||||
kiss_init (&misc_config);
|
kiss_init (&misc_config);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open port for communication with GPS.
|
||||||
|
*/
|
||||||
|
nmea_init (&misc_config);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create thread for trying to salvage frames with bad FCS.
|
* Create thread for trying to salvage frames with bad FCS.
|
||||||
*/
|
*/
|
||||||
|
@ -576,6 +620,8 @@ int main (int argc, char *argv[])
|
||||||
beacon_init (&misc_config, &digi_config);
|
beacon_init (&misc_config, &digi_config);
|
||||||
|
|
||||||
|
|
||||||
|
log_init(misc_config.logdir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get sound samples and decode them.
|
* Get sound samples and decode them.
|
||||||
* Use hot attribute for all functions called for every audio sample.
|
* Use hot attribute for all functions called for every audio sample.
|
||||||
|
@ -662,7 +708,8 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
|
|
||||||
assert (chan >= 0 && chan < MAX_CHANS);
|
assert (chan >= 0 && chan < MAX_CHANS);
|
||||||
assert (subchan >= -1 && subchan < MAX_SUBCHANS);
|
assert (subchan >= -1 && subchan < MAX_SUBCHANS);
|
||||||
|
assert (pp != NULL); // 1.1J+
|
||||||
|
|
||||||
|
|
||||||
ax25_format_addrs (pp, stemp);
|
ax25_format_addrs (pp, stemp);
|
||||||
|
|
||||||
|
@ -687,6 +734,8 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
|
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
//idx_decoded++;
|
||||||
|
//dw_printf ("DECODED[%d] " , idx_decoded);
|
||||||
|
|
||||||
if (h != -1 && h != AX25_SOURCE) {
|
if (h != -1 && h != AX25_SOURCE) {
|
||||||
dw_printf ("Digipeater ");
|
dw_printf ("Digipeater ");
|
||||||
|
@ -720,6 +769,8 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Display non-APRS packets in a different color.
|
// Display non-APRS packets in a different color.
|
||||||
|
|
||||||
// Display subchannel only when multiple modems configured for channel.
|
// Display subchannel only when multiple modems configured for channel.
|
||||||
|
@ -746,10 +797,17 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
}
|
}
|
||||||
|
|
||||||
dw_printf ("%s", stemp); /* stations followed by : */
|
dw_printf ("%s", stemp); /* stations followed by : */
|
||||||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
|
||||||
|
// for APRS we generally want to display non-ASCII to see UTF-8.
|
||||||
|
// for other, probably want to restrict to ASCII only because we are
|
||||||
|
// more likely to have compressed data than UTF-8 text.
|
||||||
|
|
||||||
|
// TODO: Might want to use d_u_opt for transmitted frames too.
|
||||||
|
|
||||||
|
ax25_safe_print ((char *)pinfo, info_len, ( ! ax25_is_aprs(pp)) && ( ! d_u_opt) );
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
// Display in pure ASCII if non-ASCII characters and "-d u" option specified.
|
// Also display in pure ASCII if non-ASCII characters and "-d u" option specified.
|
||||||
|
|
||||||
if (d_u_opt) {
|
if (d_u_opt) {
|
||||||
|
|
||||||
|
@ -767,12 +825,44 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Optional hex dump of packet. */
|
||||||
|
|
||||||
|
if (d_p_opt) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
ax25_hex_dump (pp);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Decode the contents of APRS frames and display in human-readable form. */
|
/* Decode the contents of APRS frames and display in human-readable form. */
|
||||||
|
|
||||||
if (ax25_is_aprs(pp)) {
|
if (ax25_is_aprs(pp)) {
|
||||||
decode_aprs (pp);
|
|
||||||
|
decode_aprs_t A;
|
||||||
|
|
||||||
|
decode_aprs (&A, pp);
|
||||||
|
|
||||||
|
//Print it all out in human readable format.
|
||||||
|
|
||||||
|
decode_aprs_print (&A);
|
||||||
|
|
||||||
|
// Send to log file.
|
||||||
|
|
||||||
|
log_write (chan, &A, pp, alevel, retries);
|
||||||
|
|
||||||
|
// Convert to NMEA waypoint sentence.
|
||||||
|
|
||||||
|
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),
|
||||||
|
A.g_comment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send to another application if connected. */
|
/* Send to another application if connected. */
|
||||||
|
|
||||||
int flen;
|
int flen;
|
||||||
|
@ -791,6 +881,11 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
igate_send_rec_packet (chan, pp);
|
igate_send_rec_packet (chan, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send out a regenerated copy. Applies to all types, not just APRS. */
|
||||||
|
|
||||||
|
digi_regen (chan, pp);
|
||||||
|
|
||||||
|
|
||||||
/* Note that packet can be modified in place so this is the last thing we should do with it. */
|
/* Note that packet can be modified in place so this is the last thing we should do with it. */
|
||||||
/* Again, use only those with correct CRC. */
|
/* Again, use only those with correct CRC. */
|
||||||
/* We don't want to spread corrupted data! */
|
/* We don't want to spread corrupted data! */
|
||||||
|
@ -800,6 +895,7 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
||||||
digipeater (chan, pp);
|
digipeater (chan, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
|
|
||||||
} /* end app_process_rec_packet */
|
} /* end app_process_rec_packet */
|
||||||
|
@ -814,6 +910,7 @@ static BOOL cleanup_win (int ctrltype)
|
||||||
if (ctrltype == CTRL_C_EVENT || ctrltype == CTRL_CLOSE_EVENT) {
|
if (ctrltype == CTRL_C_EVENT || ctrltype == CTRL_CLOSE_EVENT) {
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("\nQRT\n");
|
dw_printf ("\nQRT\n");
|
||||||
|
log_term ();
|
||||||
ptt_term ();
|
ptt_term ();
|
||||||
dwgps_term ();
|
dwgps_term ();
|
||||||
SLEEP_SEC(1);
|
SLEEP_SEC(1);
|
||||||
|
@ -829,8 +926,10 @@ static void cleanup_linux (int x)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("\nQRT\n");
|
dw_printf ("\nQRT\n");
|
||||||
|
log_term ();
|
||||||
ptt_term ();
|
ptt_term ();
|
||||||
dwgps_term ();
|
dwgps_term ();
|
||||||
|
SLEEP_SEC(1);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,6 +947,7 @@ static void usage (char **argv)
|
||||||
dw_printf ("Usage: direwolf [options]\n");
|
dw_printf ("Usage: direwolf [options]\n");
|
||||||
dw_printf ("Options:\n");
|
dw_printf ("Options:\n");
|
||||||
dw_printf (" -c fname Configuration file name.\n");
|
dw_printf (" -c fname Configuration file name.\n");
|
||||||
|
dw_printf (" -l logdir Directory name for log files. Use . for current.\n");
|
||||||
|
|
||||||
dw_printf (" -r n Audio sample rate, per sec.\n");
|
dw_printf (" -r n Audio sample rate, per sec.\n");
|
||||||
dw_printf (" -n n Number of audio channels, 1 or 2.\n");
|
dw_printf (" -n n Number of audio channels, 1 or 2.\n");
|
||||||
|
@ -857,11 +957,13 @@ static void usage (char **argv)
|
||||||
dw_printf (" If > 2400, K9NG/G3RUH style encoding is used.\n");
|
dw_printf (" If > 2400, K9NG/G3RUH style encoding is used.\n");
|
||||||
dw_printf (" Otherwise, AFSK tones are set to 1200 & 2200.\n");
|
dw_printf (" Otherwise, AFSK tones are set to 1200 & 2200.\n");
|
||||||
|
|
||||||
dw_printf (" -d Debug communication with client application, one of\n");
|
dw_printf (" -d Debug options:\n");
|
||||||
dw_printf (" a a = AGWPE network protocol.\n");
|
dw_printf (" a a = AGWPE network protocol client.\n");
|
||||||
dw_printf (" k k = KISS serial port.\n");
|
dw_printf (" k k = KISS serial port client.\n");
|
||||||
dw_printf (" n n = KISS network.\n");
|
dw_printf (" n n = KISS network client.\n");
|
||||||
dw_printf (" u u = Display non-ASCII text in hexadecimal.\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 (" -t n Text colors. 1=normal, 0=disabled.\n");
|
dw_printf (" -t n Text colors. 1=normal, 0=disabled.\n");
|
||||||
|
|
||||||
|
|
132
direwolf.conf
132
direwolf.conf
|
@ -24,7 +24,7 @@
|
||||||
# (3) DIGIPEATER - configure digipeating rules.
|
# (3) DIGIPEATER - configure digipeating rules.
|
||||||
#
|
#
|
||||||
# Look for lines starting with DIGIPEATER.
|
# Look for lines starting with DIGIPEATER.
|
||||||
# Most people will probably use the first example.
|
# Most people will probably use the given example.
|
||||||
# Just remove the "#" from the start of the line
|
# Just remove the "#" from the start of the line
|
||||||
# to enable it.
|
# to enable it.
|
||||||
#
|
#
|
||||||
|
@ -115,6 +115,7 @@
|
||||||
# ADEVICE - plughw:1,0
|
# ADEVICE - plughw:1,0
|
||||||
# ADEVICE UDP:7355 default
|
# ADEVICE UDP:7355 default
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# This is the sound card audio sample rate.
|
# This is the sound card audio sample rate.
|
||||||
# The default is 44100. Other standard values are 22050 or 11025.
|
# The default is 44100. Other standard values are 22050 or 11025.
|
||||||
|
@ -165,11 +166,13 @@ CHANNEL 0
|
||||||
|
|
||||||
MYCALL NOCALL
|
MYCALL NOCALL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# VHF FM operation normally uses 1200 baud data with AFSK tones of 1200 and 2200 Hz.
|
# VHF FM operation normally uses 1200 baud data with AFSK tones of 1200 and 2200 Hz.
|
||||||
#
|
#
|
||||||
|
|
||||||
MODEM 1200 1200 2200
|
MODEM 1200 1200 2200
|
||||||
|
|
||||||
#
|
#
|
||||||
# 200 Hz shift is normally used for 300 baud HF SSB operation.
|
# 200 Hz shift is normally used for 300 baud HF SSB operation.
|
||||||
|
@ -254,7 +257,7 @@ CHANNEL 1
|
||||||
|
|
||||||
MYCALL NOCALL
|
MYCALL NOCALL
|
||||||
|
|
||||||
MODEM 1200 1200 2200
|
MODEM 1200 1200 2200
|
||||||
|
|
||||||
#
|
#
|
||||||
# For this example, we use the same serial port for both
|
# For this example, we use the same serial port for both
|
||||||
|
@ -277,7 +280,7 @@ TXTAIL 10
|
||||||
#
|
#
|
||||||
# Dire Wolf acts as a virtual TNC and can communicate with
|
# Dire Wolf acts as a virtual TNC and can communicate with
|
||||||
# two different protocols:
|
# two different protocols:
|
||||||
# - the “AGW TCPIP Socket Interface” - default port 8000
|
# - the "AGW TCPIP Socket Interface" - default port 8000
|
||||||
# - KISS TNC via serial port
|
# - KISS TNC via serial port
|
||||||
# - KISS protocol over TCP socket - default port 8001
|
# - KISS protocol over TCP socket - default port 8001
|
||||||
#
|
#
|
||||||
|
@ -321,15 +324,12 @@ KISSPORT 8001
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Version 0.6 adds a new feature where it is sometimes possible
|
# It is sometimes possible to recover frames with a bad FCS.
|
||||||
# to recover frames with a bad FCS. Several levels of effort
|
|
||||||
# are possible.
|
|
||||||
#
|
#
|
||||||
# 0 [NONE] - Don't try to repair.
|
# 0 [NONE] - Don't try to repair.
|
||||||
# 1 [SINGLE] - Attempt to fix single bit error. (default)
|
# 1 [SINGLE] - Attempt to fix single bit error. (default)
|
||||||
# 2 [DOUBLE] - Also attempt to fix two adjacent bits.
|
# 2 [DOUBLE] - Also attempt to fix two adjacent bits.
|
||||||
# 3 [TRIPLE] - Also attempt to fix three adjacent bits.
|
# ... see User Guide for more values and in-depth discussion.
|
||||||
# 4 [TWO_SEP] - Also attempt to fix two non-adjacent (separated) bits.
|
|
||||||
#
|
#
|
||||||
|
|
||||||
FIX_BITS 1
|
FIX_BITS 1
|
||||||
|
@ -358,10 +358,16 @@ FIX_BITS 1
|
||||||
# The others are kept local.
|
# The others are kept local.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
#PBEACON delay=00:10 every=0:30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1,WIDE2-1
|
||||||
|
|
||||||
#PBEACON delay=00:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1,WIDE2-1
|
#PBEACON delay=00:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA" via=WIDE1-1,WIDE2-1
|
||||||
#PBEACON delay=10:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
#PBEACON delay=10:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||||
#PBEACON delay=20:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
#PBEACON delay=20:15 every=30 overlay=S symbol="digi" lat=42^37.14N long=071^20.83W power=50 height=20 gain=4 comment="Chelmsford MA"
|
||||||
|
|
||||||
|
# With UTM coordinates instead of latitude and longitude.
|
||||||
|
|
||||||
|
#PBEACON delay=00:15 every=10 overlay=S symbol="digi" zone=19T easting=306130 northing=4726010
|
||||||
|
|
||||||
#
|
#
|
||||||
# Modify this for your particular situation before removing
|
# Modify this for your particular situation before removing
|
||||||
# the # comment character from the beginning of the lines above.
|
# the # comment character from the beginning of the lines above.
|
||||||
|
@ -374,98 +380,16 @@ FIX_BITS 1
|
||||||
# #
|
# #
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
||||||
#
|
|
||||||
# Digipeating is activated with commands of the form:
|
|
||||||
#
|
|
||||||
# DIGIPEAT from-chan to-chan aliases wide [ preemptive ]
|
|
||||||
#
|
|
||||||
# where,
|
|
||||||
#
|
|
||||||
# from-chan is the channel where the packet is received.
|
|
||||||
#
|
|
||||||
# to-chan is the channel where the packet is to be re-transmitted.
|
|
||||||
#
|
|
||||||
# aliases is a pattern for digipeating ONCE. Anything matching
|
|
||||||
# this pattern is effectively treated like WIDE1-1.
|
|
||||||
# 'MYCALL' for the receiving channel is an implied
|
|
||||||
# member of this list.
|
|
||||||
#
|
|
||||||
# wide is the pattern for normal WIDEn-N digipeating
|
|
||||||
# where the ssid is decremented.
|
|
||||||
#
|
|
||||||
# preemptive is the "preemptive" digipeating option. See
|
|
||||||
# User Guide for more details.
|
|
||||||
#
|
|
||||||
# Pattern matching uses "extended regular expressions." Rather than listing
|
|
||||||
# all the different possibilities (such as "WIDE3-3,WIDE4-4,WIDE5-5,WIDE6-6,WIDE7-7"),
|
|
||||||
# a pattern can be specified such as "^WIDE[34567]-[1-7]$". This means:
|
|
||||||
#
|
|
||||||
# ^ beginning of call. Without this, leading characters
|
|
||||||
# don't need to match and ZWIDE3-3 would end up matching.
|
|
||||||
#
|
|
||||||
# WIDE is an exact literal match of upper case letters W I D E.
|
|
||||||
#
|
|
||||||
# [34567] means ANY ONE of the characters listed.
|
|
||||||
#
|
|
||||||
# - is an exact literal match of the "-" character (when not
|
|
||||||
# found inside of []).
|
|
||||||
#
|
|
||||||
# [1-7] is an alternative form where we have a range of characters
|
|
||||||
# rather than listing them all individually.
|
|
||||||
#
|
|
||||||
# $ means end of call. Without this, trailing characters don't
|
|
||||||
# need to match. As an example, we would end up matching
|
|
||||||
# WIDE3-15 besides WIDE3-1.
|
|
||||||
#
|
|
||||||
# Google "Extended Regular Expressions" for more information.
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# If the first unused digipeater field, in the received packet,
|
|
||||||
# matches the first pattern, it is treated the same way you
|
|
||||||
# would expect WIDE1-1 to behave.
|
|
||||||
#
|
|
||||||
# The digipeater name is replaced by MYCALL of the destination channel.
|
|
||||||
#
|
|
||||||
# Example: W1ABC>APRS,WIDE7-7
|
|
||||||
# Becomes: W1ABC>APRS,WB2OSZ-5*
|
|
||||||
#
|
|
||||||
# In this example, we trap large values of N as recommended in
|
|
||||||
# http://www.aprs.org/fix14439.html
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
|
||||||
# If not caught by the first pattern, see if it matches the second pattern.
|
|
||||||
#
|
|
||||||
# Matches will be processed with the usual WIDEn-N rules.
|
|
||||||
#
|
|
||||||
# If N >= 2, the N value is decremented and MYCALL (of the destination
|
|
||||||
# channel) is inserted if enough room.
|
|
||||||
#
|
|
||||||
# Example: W1ABC>APRS,WIDE2-2
|
|
||||||
# Becomes: W1ABC>APRS,WB2OSZ-5*,WIDE2-1
|
|
||||||
#
|
|
||||||
# If N = 1, we don't want to keep WIDEn-0 in the digipeater list so
|
|
||||||
# the station is replaced by MYCALL.
|
|
||||||
#
|
|
||||||
# Example: W1ABC>APRS,W9XYZ*,WIDE2-1
|
|
||||||
# Becomes: W1ABC>APRS,W9XYZ,WB2OSZ-5*
|
|
||||||
#
|
|
||||||
|
|
||||||
#-------------------------------------------------------
|
|
||||||
# ---------- Example 1: Typical digipeater ----------
|
|
||||||
#-------------------------------------------------------
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# For most common situations, use something like this by removing
|
# For most common situations, use something like this by removing
|
||||||
# the "#" from the beginning of the line.
|
# the "#" from the beginning of the line below.
|
||||||
# To disable digipeating, put # at the beginning of the line.
|
#
|
||||||
#
|
|
||||||
|
|
||||||
# DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$ TRACE
|
|
||||||
|
|
||||||
|
|
||||||
|
#DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$ TRACE
|
||||||
|
|
||||||
|
# See User Guide for more explanation of what this means and how
|
||||||
|
# it can be customized for your particular needs.
|
||||||
|
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# #
|
# #
|
||||||
|
@ -512,7 +436,7 @@ FIX_BITS 1
|
||||||
|
|
||||||
#IGFILTER m/50
|
#IGFILTER m/50
|
||||||
|
|
||||||
# Finally, we don’t want to flood the radio channel.
|
# Finally, we don't want to flood the radio channel.
|
||||||
# The IGate function will limit the number of packets transmitted
|
# The IGate function will limit the number of packets transmitted
|
||||||
# during 1 minute and 5 minute intervals. If a limit would
|
# during 1 minute and 5 minute intervals. If a limit would
|
||||||
# be exceeded, the packet is dropped and message is displayed in red.
|
# be exceeded, the packet is dropped and message is displayed in red.
|
||||||
|
@ -530,7 +454,7 @@ IGTXLIMIT 6 10
|
||||||
# Dire Wolf can receive DTMF (commonly known as Touch Tone)
|
# Dire Wolf can receive DTMF (commonly known as Touch Tone)
|
||||||
# messages and convert them to packet objects.
|
# messages and convert them to packet objects.
|
||||||
#
|
#
|
||||||
# See "APRStt-Implementation-Notes" document for details.
|
# See separate "APRStt-Implementation-Notes" document for details.
|
||||||
#
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -571,8 +495,8 @@ TTUTM B6xxxyyy 19T 10 300000 4720000
|
||||||
TTCORRAL 37^55.50N 81^7.00W 0^0.02N
|
TTCORRAL 37^55.50N 81^7.00W 0^0.02N
|
||||||
|
|
||||||
# Compact messages - Fixed locations xx and object yyy where
|
# Compact messages - Fixed locations xx and object yyy where
|
||||||
# Object numbers 100 – 199 = bicycle
|
# Object numbers 100 - 199 = bicycle
|
||||||
# Object numbers 200 – 299 = fire truck
|
# Object numbers 200 - 299 = fire truck
|
||||||
# Others = dog
|
# Others = dog
|
||||||
|
|
||||||
TTMACRO xx1yy B9xx*AB166*AA2B4C5B3B0A1yy
|
TTMACRO xx1yy B9xx*AB166*AA2B4C5B3B0A1yy
|
||||||
|
|
22
direwolf.h
22
direwolf.h
|
@ -29,11 +29,29 @@
|
||||||
#define SLEEP_MS(n) usleep((n)*1000)
|
#define SLEEP_MS(n) usleep((n)*1000)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
#define PTW32_STATIC_LIB
|
#define PTW32_STATIC_LIB
|
||||||
#include "pthreads/pthread.h"
|
#include "pthreads/pthread.h"
|
||||||
#else
|
#else
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Not sure where to put these. */
|
||||||
|
|
||||||
|
/* Prefix with DW_ because /usr/include/gps.h uses a couple of these names. */
|
||||||
|
|
||||||
|
|
||||||
|
#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)
|
||||||
|
#define DW_KM_TO_MILES(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.621371192)
|
||||||
|
|
||||||
|
#define DW_KNOTS_TO_MPH(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 1.15077945)
|
||||||
|
#define DW_KNOTS_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.51444444444)
|
||||||
|
#define DW_MPH_TO_KNOTS(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.868976)
|
||||||
|
#define DW_MPH_TO_METERS_PER_SEC(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.44704)
|
||||||
|
|
||||||
|
#define DW_MBAR_TO_INHG(x) ((x) == G_UNKNOWN ? G_UNKNOWN : (x) * 0.0295333727)
|
||||||
|
|
||||||
|
#endif /* ifndef DIREWOLF_H */
|
22
dsp.c
22
dsp.c
|
@ -128,7 +128,7 @@ float window (bp_window_t type, int size, int j)
|
||||||
void gen_lowpass (float fc, float *lp_filter, int filter_size, bp_window_t wtype)
|
void gen_lowpass (float fc, float *lp_filter, int filter_size, bp_window_t wtype)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
float lp_sum;
|
float G;
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG1
|
#if DEBUG1
|
||||||
|
@ -165,12 +165,12 @@ void gen_lowpass (float fc, float *lp_filter, int filter_size, bp_window_t wtype
|
||||||
/*
|
/*
|
||||||
* Normalize lowpass for unity gain.
|
* Normalize lowpass for unity gain.
|
||||||
*/
|
*/
|
||||||
lp_sum = 0;
|
G = 0;
|
||||||
for (j=0; j<filter_size; j++) {
|
for (j=0; j<filter_size; j++) {
|
||||||
lp_sum += lp_filter[j];
|
G += lp_filter[j];
|
||||||
}
|
}
|
||||||
for (j=0; j<filter_size; j++) {
|
for (j=0; j<filter_size; j++) {
|
||||||
lp_filter[j] = lp_filter[j] / lp_sum;
|
lp_filter[j] = lp_filter[j] / G;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,7 +198,8 @@ void gen_lowpass (float fc, float *lp_filter, int filter_size, bp_window_t wtype
|
||||||
void gen_bandpass (float f1, float f2, float *bp_filter, int filter_size, bp_window_t wtype)
|
void gen_bandpass (float f1, float f2, float *bp_filter, int filter_size, bp_window_t wtype)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
float bp_sum;
|
float w;
|
||||||
|
float G;
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG1
|
#if DEBUG1
|
||||||
|
@ -235,13 +236,18 @@ void gen_bandpass (float f1, float f2, float *bp_filter, int filter_size, bp_win
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Normalize bandpass for unity gain.
|
* Normalize bandpass for unity gain.
|
||||||
|
* TODO: This is not right.
|
||||||
|
* Can't use same technique as for lowpass.
|
||||||
|
* Instead compute gain in middle of passband.
|
||||||
|
* See http://dsp.stackexchange.com/questions/4693/fir-filter-gain
|
||||||
*/
|
*/
|
||||||
bp_sum = 0;
|
w = 2 * M_PI * (f1 + f2) / 2;
|
||||||
|
G = 0;
|
||||||
for (j=0; j<filter_size; j++) {
|
for (j=0; j<filter_size; j++) {
|
||||||
bp_sum += bp_filter[j];
|
G += bp_filter[j]; // TBD
|
||||||
}
|
}
|
||||||
for (j=0; j<filter_size; j++) {
|
for (j=0; j<filter_size; j++) {
|
||||||
bp_filter[j] = bp_filter[j] / bp_sum;
|
bp_filter[j] = bp_filter[j] / G;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
746
dwgps.c
746
dwgps.c
|
@ -1,327 +1,419 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 2 of the License, or
|
// the Free Software Foundation, either version 2 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------------
|
/*------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Module: dwgps.c
|
* Module: dwgps.c
|
||||||
*
|
*
|
||||||
* Purpose: Interface to location data, i.e. GPS receiver.
|
* Purpose: Interface to location data, i.e. GPS receiver.
|
||||||
*
|
*
|
||||||
* Description: Tracker beacons need to know the current location.
|
* Description: Tracker beacons need to know the current location.
|
||||||
* At this time, I can't think of any other reason why
|
* At this time, I can't think of any other reason why
|
||||||
* we would need this information.
|
* we would need this information.
|
||||||
*
|
*
|
||||||
* For Linux, we use gpsd and libgps.
|
* For Linux, we use gpsd and libgps.
|
||||||
* This has the extra benefit that the system clock can
|
* This has the extra benefit that the system clock can
|
||||||
* be set from the GPS signal.
|
* be set from the GPS signal.
|
||||||
*
|
*
|
||||||
* Not yet implemented for Windows. Not sure how yet.
|
* Not yet implemented for Windows. Not sure how yet.
|
||||||
* The Windows location API is new in Windows 7.
|
* The Windows location API is new in Windows 7.
|
||||||
* At the end of 2013, about 1/3 of Windows users are
|
* At the end of 2013, about 1/3 of Windows users are
|
||||||
* still using XP so that still needs to be supported.
|
* still using XP so that still needs to be supported.
|
||||||
*
|
*
|
||||||
* Reference:
|
* Reference:
|
||||||
*
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
#if TEST
|
#if TEST
|
||||||
#define ENABLE_GPS 1
|
#define ENABLE_GPS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#if ENABLE_GPS
|
#if ENABLE_GPS
|
||||||
#include <gps.h>
|
#include <gps.h>
|
||||||
|
|
||||||
#if GPSD_API_MAJOR_VERSION != 5
|
#if GPSD_API_MAJOR_VERSION != 5
|
||||||
#error libgps API version might be incompatible.
|
#error libgps API version might be incompatible.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "direwolf.h"
|
#include "direwolf.h"
|
||||||
#include "textcolor.h"
|
#include "textcolor.h"
|
||||||
#include "dwgps.h"
|
#include "dwgps.h"
|
||||||
|
|
||||||
|
|
||||||
/* Was init successful? */
|
/* Was init successful? */
|
||||||
|
|
||||||
static enum { INIT_NOT_YET, INIT_SUCCESS, INIT_FAILED } init_status = INIT_NOT_YET;
|
static enum { INIT_NOT_YET, INIT_SUCCESS, INIT_FAILED } init_status = INIT_NOT_YET;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#else
|
#else
|
||||||
#if ENABLE_GPS
|
#if ENABLE_GPS
|
||||||
|
|
||||||
static struct gps_data_t gpsdata;
|
static struct gps_data_t gpsdata;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: dwgps_init
|
* Name: dwgps_init
|
||||||
*
|
*
|
||||||
* Purpose: Intialize the GPS interface.
|
* Purpose: Intialize the GPS interface.
|
||||||
*
|
*
|
||||||
* Inputs: none.
|
* Inputs: none.
|
||||||
*
|
*
|
||||||
* Returns: 0 = success
|
* Returns: 0 = success
|
||||||
* -1 = failure
|
* -1 = failure
|
||||||
*
|
*
|
||||||
* Description: For Linux, this maps into gps_open.
|
* Description: For Linux, this maps into gps_open.
|
||||||
* Not yet implemented for Windows.
|
* Not yet implemented for Windows.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
int dwgps_init (void)
|
int dwgps_init (void)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
/*
|
||||||
dw_printf ("GPS interface not yet available in Windows version.\n");
|
* Windows version. Not implemented yet.
|
||||||
init_status = INIT_FAILED;
|
*/
|
||||||
return (-1);
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
#elif ENABLE_GPS
|
dw_printf ("GPS interface not yet available in Windows version.\n");
|
||||||
|
init_status = INIT_FAILED;
|
||||||
int err;
|
return (-1);
|
||||||
|
|
||||||
err = gps_open (GPSD_SHARED_MEMORY, NULL, &gpsdata);
|
#elif ENABLE_GPS
|
||||||
if (err != 0) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
int err;
|
||||||
dw_printf ("Unable to connect to GPS receiver.\n");
|
|
||||||
if (err == NL_NOHOST) {
|
#if USE_GPS_SHM
|
||||||
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");
|
/*
|
||||||
}
|
* Linux - Shared memory interface to gpsd.
|
||||||
else {
|
*
|
||||||
dw_printf ("%s\n", gps_errstr(errno));
|
* I wanted to use this method because it is simpler and more efficient.
|
||||||
}
|
*
|
||||||
init_status = INIT_FAILED;
|
* The current version of gpsd, supplied with Raspian, is 3.6 from back in
|
||||||
return (-1);
|
* May 2012, is missing support for the shared memory interface.
|
||||||
}
|
* https://github.com/raspberrypi/linux/issues/523
|
||||||
init_status = INIT_SUCCESS;
|
*
|
||||||
return (0);
|
* I tried to download a newer source and build with shared memory support
|
||||||
#else
|
* but ran into a couple other issues.
|
||||||
|
*
|
||||||
text_color_set(DW_COLOR_ERROR);
|
* sudo apt-get install libncurses5-dev
|
||||||
dw_printf ("GPS interface not enabled in this version.\n");
|
* sudo apt-get install scons
|
||||||
dw_printf ("See documentation on how to rebuild with ENABLE_GPS.\n");
|
* cd ~
|
||||||
init_status = INIT_FAILED;
|
* wget http://download-mirror.savannah.gnu.org/releases/gpsd/gpsd-3.11.tar.gz
|
||||||
return (-1);
|
* tar xfz gpsd-3.11.tar.gz
|
||||||
|
* cd gpsd-3.11
|
||||||
#endif
|
* scons prefix=/usr libdir=lib/arm-linux-gnueabihf shm_export=True python=False
|
||||||
|
* sudo scons udev-install
|
||||||
} /* end dwgps_init */
|
*
|
||||||
|
* For now, we will use the socket interface.
|
||||||
|
* Maybe get back to this again someday.
|
||||||
|
*/
|
||||||
/*-------------------------------------------------------------------
|
|
||||||
*
|
err = gps_open (GPSD_SHARED_MEMORY, NULL, &gpsdata);
|
||||||
* Name: dwgps_read
|
if (err != 0) {
|
||||||
*
|
text_color_set(DW_COLOR_ERROR);
|
||||||
* Purpose: Obtain current location from GPS receiver.
|
dw_printf ("Unable to connect to GPSD shared memory interface, status=%d.\n", err);
|
||||||
*
|
if (err == NL_NOHOST) {
|
||||||
* Outputs: *plat - Latitude.
|
// I don't think this is right but we are not using it anyhow.
|
||||||
* *plon - Longitude.
|
dw_printf ("Shared memory interface is not enabled in libgps.\n");
|
||||||
* *pspeed - Speed, knots.
|
dw_printf ("Download the gpsd source and build with 'shm_export=True' option.\n");
|
||||||
* *pcourse - Course over ground, degrees.
|
}
|
||||||
* *palt - Altitude, meters.
|
else {
|
||||||
*
|
dw_printf ("%s\n", gps_errstr(errno));
|
||||||
* Returns: -1 = error
|
}
|
||||||
* 0 = data not available (no fix)
|
init_status = INIT_FAILED;
|
||||||
* 2 = 2D fix, lat/lon, speed, and course are set.
|
return (-1);
|
||||||
* 3 - 3D fix, altitude is also set.
|
}
|
||||||
*
|
init_status = INIT_SUCCESS;
|
||||||
*--------------------------------------------------------------------*/
|
return (0);
|
||||||
|
|
||||||
int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float *palt)
|
#else
|
||||||
{
|
|
||||||
#if __WIN32__
|
/*
|
||||||
|
* Linux - Socket interface to gpsd.
|
||||||
text_color_set(DW_COLOR_ERROR);
|
*/
|
||||||
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
|
||||||
return (-1);
|
err = gps_open ("localhost", DEFAULT_GPSD_PORT, &gpsdata);
|
||||||
|
if (err != 0) {
|
||||||
#elif ENABLE_GPS
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Unable to connect to GPSD stream, status%d.\n", err);
|
||||||
int err;
|
dw_printf ("%s\n", gps_errstr(errno));
|
||||||
|
init_status = INIT_FAILED;
|
||||||
if (init_status != INIT_SUCCESS) {
|
return (-1);
|
||||||
text_color_set(DW_COLOR_ERROR);
|
}
|
||||||
dw_printf ("Internal error, dwgps_read without successful init.\n");
|
|
||||||
return (-1);
|
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||||
}
|
|
||||||
|
init_status = INIT_SUCCESS;
|
||||||
err = gps_read (&gpsdata);
|
return (0);
|
||||||
|
|
||||||
#if DEBUG
|
#endif
|
||||||
dw_printf ("gps_read returns %d bytes\n", err);
|
|
||||||
#endif
|
#else /* end ENABLE_GPS */
|
||||||
if (err > 0) {
|
|
||||||
if (gpsdata.status >= STATUS_FIX && gpsdata.fix.mode >= MODE_2D) {
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("GPS interface not enabled in this version.\n");
|
||||||
*plat = gpsdata.fix.latitude;
|
dw_printf ("See documentation on how to rebuild with ENABLE_GPS.\n");
|
||||||
*plon = gpsdata.fix.longitude;
|
init_status = INIT_FAILED;
|
||||||
*pcourse = gpsdata.fix.track;
|
return (-1);
|
||||||
*pspeed = MPS_TO_KNOTS * gpsdata.fix.speed; /* libgps uses meters/sec */
|
|
||||||
|
#endif
|
||||||
if (gpsdata.fix.mode >= MODE_3D) {
|
|
||||||
*palt = gpsdata.fix.altitude;
|
} /* end dwgps_init */
|
||||||
return (3);
|
|
||||||
}
|
|
||||||
return (2);
|
|
||||||
}
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
/* No fix. Probably temporary condition. */
|
* Name: dwgps_read
|
||||||
return (0);
|
*
|
||||||
}
|
* Purpose: Obtain current location from GPS receiver.
|
||||||
else if (err == 0) {
|
*
|
||||||
/* No data available */
|
* Outputs: *plat - Latitude.
|
||||||
return (0);
|
* *plon - Longitude.
|
||||||
}
|
* *pspeed - Speed, knots.
|
||||||
else {
|
* *pcourse - Course over ground, degrees.
|
||||||
/* More serious error. */
|
* *palt - Altitude, meters.
|
||||||
return (-1);
|
*
|
||||||
}
|
* Returns: -1 = error
|
||||||
#else
|
* 0 = location currently not available (no fix)
|
||||||
|
* 2 = 2D fix, lat/lon, speed, and course are set.
|
||||||
text_color_set(DW_COLOR_ERROR);
|
* 3 - 3D fix, altitude is also set.
|
||||||
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
*
|
||||||
return (-1);
|
*--------------------------------------------------------------------*/
|
||||||
#endif
|
|
||||||
|
int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float *palt)
|
||||||
} /* end dwgps_read */
|
{
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
text_color_set(DW_COLOR_ERROR);
|
||||||
*
|
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
||||||
* Name: dwgps_term
|
return (-1);
|
||||||
*
|
|
||||||
* Purpose: Shut down GPS interface before exiting from application.
|
#elif ENABLE_GPS
|
||||||
*
|
|
||||||
* Inputs: none.
|
int err;
|
||||||
*
|
|
||||||
* Returns: none.
|
if (init_status != INIT_SUCCESS) {
|
||||||
*
|
text_color_set(DW_COLOR_ERROR);
|
||||||
*--------------------------------------------------------------------*/
|
dw_printf ("Internal error, dwgps_read without successful init.\n");
|
||||||
|
return (-1);
|
||||||
void dwgps_term (void) {
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if USE_GPS_SHM
|
||||||
|
|
||||||
#elif ENABLE_GPS
|
/*
|
||||||
|
* Shared memory version.
|
||||||
if (init_status == INIT_SUCCESS) {
|
*/
|
||||||
gps_close (&gpsdata);
|
|
||||||
}
|
err = gps_read (&gpsdata);
|
||||||
#else
|
|
||||||
|
#if DEBUG
|
||||||
#endif
|
dw_printf ("gps_read returns %d bytes\n", err);
|
||||||
|
#endif
|
||||||
} /* end dwgps_term */
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Socket version.
|
||||||
/*-------------------------------------------------------------------
|
*/
|
||||||
*
|
|
||||||
* Name: main
|
// Wait for up to 1000 milliseconds.
|
||||||
*
|
// This should only happen in the beaconing thread so
|
||||||
* Purpose: Simple unit test for other functions in this file.
|
// I'm not worried about other functions hanging.
|
||||||
*
|
|
||||||
* Description: Compile with -DTEST option.
|
if (gps_waiting(&gpsdata, 1000)) {
|
||||||
*
|
|
||||||
* gcc -DTEST dwgps.c textcolor.c -lgps
|
err = gps_read (&gpsdata);
|
||||||
*
|
}
|
||||||
*--------------------------------------------------------------------*/
|
else {
|
||||||
|
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||||
#if TEST
|
sleep (1);
|
||||||
|
}
|
||||||
int main (int argc, char *argv[])
|
|
||||||
{
|
#endif
|
||||||
|
|
||||||
#if __WIN32__
|
if (err > 0) {
|
||||||
|
/* Data is available. */
|
||||||
printf ("Not in win32 version yet.\n");
|
|
||||||
|
if (gpsdata.status >= STATUS_FIX && gpsdata.fix.mode >= MODE_2D) {
|
||||||
#elif ENABLE_GPS
|
|
||||||
int err;
|
*plat = gpsdata.fix.latitude;
|
||||||
int fix;
|
*plon = gpsdata.fix.longitude;
|
||||||
double lat;
|
*pcourse = gpsdata.fix.track;
|
||||||
double lon;
|
*pspeed = MPS_TO_KNOTS * gpsdata.fix.speed; /* libgps uses meters/sec */
|
||||||
float speed;
|
|
||||||
float course;
|
if (gpsdata.fix.mode >= MODE_3D) {
|
||||||
float alt;
|
*palt = gpsdata.fix.altitude;
|
||||||
|
return (3);
|
||||||
err = dwgps_init ();
|
}
|
||||||
|
return (2);
|
||||||
if (err != 0) exit(1);
|
}
|
||||||
|
|
||||||
while (1) {
|
/* No fix. Probably temporary condition. */
|
||||||
fix = dwgps_read (&lat, &lon, &speed, &course, &alt)
;
|
return (0);
|
||||||
switch (fix) {
|
}
|
||||||
case 3:
|
else if (err == 0) {
|
||||||
case 2:
|
|
||||||
dw_printf ("%.6f %.6f", lat, lon);
|
/* No data available at the present time. */
|
||||||
dw_printf (" %.1f knots %.0f degrees", speed, course);
|
return (0);
|
||||||
if (fix==3) dw_printf (" altitude = %.1f meters", alt);
|
}
|
||||||
dw_printf ("\n");
|
else {
|
||||||
break;
|
|
||||||
case 0:
|
/* More serious error. */
|
||||||
dw_printf ("location currently not available.\n");
|
return (-1);
|
||||||
break;
|
}
|
||||||
default:
|
#else
|
||||||
dw_printf ("ERROR getting GPS information.\n");
|
|
||||||
}
|
text_color_set(DW_COLOR_ERROR);
|
||||||
sleep (3);
|
dw_printf ("Internal error, dwgps_read, shouldn't be here.\n");
|
||||||
}
|
return (-1);
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
} /* end dwgps_read */
|
||||||
|
|
||||||
printf ("Test: Shouldn't be here.\n");
|
|
||||||
#endif
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
} /* end main */
|
* Name: dwgps_term
|
||||||
|
*
|
||||||
|
* Purpose: Shut down GPS interface before exiting from application.
|
||||||
#endif
|
*
|
||||||
|
* Inputs: none.
|
||||||
|
*
|
||||||
|
* Returns: none.
|
||||||
/* end dwgps.c */
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} /* end dwgps_term */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: main
|
||||||
|
*
|
||||||
|
* Purpose: Simple unit test for other functions in this file.
|
||||||
|
*
|
||||||
|
* Description: Compile with -DTEST option.
|
||||||
|
*
|
||||||
|
* gcc -DTEST dwgps.c textcolor.c -lgps
|
||||||
|
* ./a.out
|
||||||
|
*
|
||||||
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
|
||||||
|
printf ("Not in win32 version yet.\n");
|
||||||
|
|
||||||
|
#elif ENABLE_GPS
|
||||||
|
int err;
|
||||||
|
int fix;
|
||||||
|
double lat;
|
||||||
|
double lon;
|
||||||
|
float speed;
|
||||||
|
float course;
|
||||||
|
float alt;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* end dwgps.c */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -443,9 +443,12 @@ static int frequency_spec (float freq, float tone, float offset, char *presult)
|
||||||
*
|
*
|
||||||
* Purpose: Construct info part for position report format.
|
* Purpose: Construct info part for position report format.
|
||||||
*
|
*
|
||||||
* Inputs: compressed - Send in compressed form?
|
* Inputs: messaging - This determines whether the data type indicator
|
||||||
|
* is set to '!' (false) or '=' (true).
|
||||||
|
* compressed - Send in compressed form?
|
||||||
* lat - Latitude.
|
* lat - Latitude.
|
||||||
* lon - Longitude.
|
* lon - Longitude.
|
||||||
|
* alt_ft - Altitude in feet.
|
||||||
* symtab - Symbol table id or overlay.
|
* symtab - Symbol table id or overlay.
|
||||||
* symbol - Symbol id.
|
* symbol - Symbol id.
|
||||||
*
|
*
|
||||||
|
@ -494,7 +497,7 @@ typedef struct aprs_compressed_pos_s {
|
||||||
} aprs_compressed_pos_t;
|
} aprs_compressed_pos_t;
|
||||||
|
|
||||||
|
|
||||||
int encode_position (int compressed, double lat, double lon,
|
int encode_position (int messaging, int compressed, double lat, double lon, int alt_ft,
|
||||||
char symtab, char symbol,
|
char symtab, char symbol,
|
||||||
int power, int height, int gain, char *dir,
|
int power, int height, int gain, char *dir,
|
||||||
int course, int speed,
|
int course, int speed,
|
||||||
|
@ -507,7 +510,7 @@ int encode_position (int compressed, double lat, double lon,
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
aprs_compressed_pos_t *p = (aprs_compressed_pos_t *)presult;
|
aprs_compressed_pos_t *p = (aprs_compressed_pos_t *)presult;
|
||||||
|
|
||||||
p->dti = '!';
|
p->dti = messaging ? '=' : '!';
|
||||||
set_comp_position (symtab, symbol, lat, lon,
|
set_comp_position (symtab, symbol, lat, lon,
|
||||||
power, height, gain,
|
power, height, gain,
|
||||||
course, speed,
|
course, speed,
|
||||||
|
@ -517,7 +520,7 @@ int encode_position (int compressed, double lat, double lon,
|
||||||
else {
|
else {
|
||||||
aprs_ll_pos_t *p = (aprs_ll_pos_t *)presult;
|
aprs_ll_pos_t *p = (aprs_ll_pos_t *)presult;
|
||||||
|
|
||||||
p->dti = '!';
|
p->dti = messaging ? '=' : '!';
|
||||||
set_norm_position (symtab, symbol, lat, lon, &(p->pos));
|
set_norm_position (symtab, symbol, lat, lon, &(p->pos));
|
||||||
result_len = 1 + sizeof (p->pos);
|
result_len = 1 + sizeof (p->pos);
|
||||||
|
|
||||||
|
@ -540,6 +543,19 @@ int encode_position (int compressed, double lat, double lon,
|
||||||
|
|
||||||
presult[result_len] = '\0';
|
presult[result_len] = '\0';
|
||||||
|
|
||||||
|
/* Altitude. Can be anywhere in comment. */
|
||||||
|
|
||||||
|
if (alt_ft != G_UNKNOWN) {
|
||||||
|
char salt[12];
|
||||||
|
/* Not clear if altitude can be negative. */
|
||||||
|
/* Be sure it will be converted to 6 digits. */
|
||||||
|
if (alt_ft < 0) alt_ft = 0;
|
||||||
|
if (alt_ft > 999999) alt_ft = 999999;
|
||||||
|
sprintf (salt, "/A=%06d", alt_ft);
|
||||||
|
strcat (presult, salt);
|
||||||
|
result_len += strlen(salt);
|
||||||
|
}
|
||||||
|
|
||||||
/* Finally, comment text. */
|
/* Finally, comment text. */
|
||||||
|
|
||||||
if (comment != NULL) {
|
if (comment != NULL) {
|
||||||
|
@ -696,17 +712,13 @@ int encode_object (char *name, int compressed, time_t thyme, double lat, double
|
||||||
*
|
*
|
||||||
* Description: Just a smattering, not an organized test.
|
* Description: Just a smattering, not an organized test.
|
||||||
*
|
*
|
||||||
* $ rm a.exe ; gcc -DEN_MAIN encode_aprs.c latlong.c ; ./a.exe
|
* $ rm a.exe ; gcc -DEN_MAIN encode_aprs.c latlong.c textcolor.c ; ./a.exe
|
||||||
*
|
*
|
||||||
*----------------------------------------------------------------*/
|
*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
#if EN_MAIN
|
#if EN_MAIN
|
||||||
|
|
||||||
void text_color_set ( enum dw_color_e c )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -716,75 +728,86 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
/*********** Position ***********/
|
/*********** Position ***********/
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
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);
|
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!4234.61ND07126.47W&") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
/* with PHG. */
|
/* with PHG. */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
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);
|
50, 100, 6, "N", 0, 0, 0, 0, 0, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&PHG7368") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!4234.61ND07126.47W&PHG7368") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
/* with freq. */
|
/* with freq. */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
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);
|
0, 0, 0, NULL, 0, 0, 146.955, 74.4, -0.6, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&146.955MHz T074 -060 ") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!4234.61ND07126.47W&146.955MHz T074 -060 ") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
/* with course/speed, freq, and comment! */
|
/* with course/speed, freq, and comment! */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
encode_position (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);
|
0, 0, 0, NULL, 180, 55, 146.955, 74.4, -0.6, "River flooding", result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz T074 -060 River flooding") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz T074 -060 River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
/* Course speed, no tone, + offset */
|
/* Course speed, no tone, + offset */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
encode_position (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);
|
0, 0, 0, NULL, 180, 55, 146.955, 0, 0.6, "River flooding", result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 River flooding") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz Toff +060 River flooding") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
|
|
||||||
|
/* Course speed, no tone, + offset + altitude */
|
||||||
|
|
||||||
|
encode_position (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);
|
||||||
|
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__);
|
||||||
|
|
||||||
|
|
||||||
/*********** Compressed position. ***********/
|
/*********** Compressed position. ***********/
|
||||||
|
|
||||||
encode_position (1, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
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);
|
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!D8yKC<Hn[& ") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!D8yKC<Hn[& !") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
|
|
||||||
/* with PHG. In this case it is converted to precomputed radio range. */
|
/* with PHG. In this case it is converted to precomputed radio range. TODO: check on this. Is 27.4 correct? */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
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);
|
50, 100, 6, "N", 0, 0, 0, 0, 0, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&PHG7368 TBD ???") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, "!D8yKC<Hn[&{CG") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
/* with course/speed, freq, and comment! */
|
/* with course/speed, freq, and comment! TODO: check on this 55 knots should be 63 MPH. we get 62. */
|
||||||
|
|
||||||
encode_position (0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
encode_position (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);
|
0, 0, 0, NULL, 180, 55, 146.955, 74.4, -0.6, "River flooding", result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, "!4234.61ND07126.47W&180/055146.955MHz T074 -060 River flooding") != 0) dw_printf ("ERROR!\n");
|
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
|
||||||
|
|
||||||
|
// TODO: test alt; cs+alt
|
||||||
|
|
||||||
/*********** Object. ***********/
|
/*********** Object. ***********/
|
||||||
|
|
||||||
|
|
||||||
encode_object ("WB1GOF-C", 0, 0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
encode_object ("WB1GOF-C", 0, 0, 42+34.61/60, -(71+26.47/60), 'D', '&',
|
||||||
0, 0, 0, NULL, result);
|
0, 0, 0, NULL, 0, 0, 0, 0, 0, NULL, result);
|
||||||
dw_printf ("%s\n", result);
|
dw_printf ("%s\n", result);
|
||||||
if (strcmp(result, ";WB1GOF-C *111111z4234.61ND07126.47W& TBD???") != 0) dw_printf ("ERROR!\n");
|
if (strcmp(result, ";WB1GOF-C *111111z4234.61ND07126.47W&") != 0) dw_printf ("ERROR! line %d\n", __LINE__);
|
||||||
|
|
||||||
|
// TODO: need more tests.
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
int encode_position (int compressed, double lat, double lon,
|
int encode_position (int messaging, int compressed, double lat, double lon, int alt_ft,
|
||||||
char symtab, char symbol,
|
char symtab, char symbol,
|
||||||
int power, int height, int gain, char *dir,
|
int power, int height, int gain, char *dir,
|
||||||
int course, int speed,
|
int course, int speed,
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
#ifndef FSK_DEMOD_STATE_H
|
#ifndef FSK_DEMOD_STATE_H
|
||||||
|
|
||||||
|
#include "rpack.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Demodulator state.
|
* Demodulator state.
|
||||||
* Different copy is required for each channel & subchannel being processed concurrently.
|
* Different copy is required for each channel & subchannel being processed concurrently.
|
||||||
|
@ -166,6 +169,47 @@ struct demodulator_state_s
|
||||||
float lev_prev_peak;
|
float lev_prev_peak;
|
||||||
float lev_prev_ave;
|
float lev_prev_ave;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special for Rino decoder only.
|
||||||
|
* One for each possible signal polarity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
struct gr_state_s {
|
||||||
|
|
||||||
|
signed int data_clock_pll; // PLL for data clock recovery.
|
||||||
|
// It is incremented by pll_step_per_sample
|
||||||
|
// for each audio sample.
|
||||||
|
|
||||||
|
signed int prev_d_c_pll; // Previous value of above, before
|
||||||
|
// incrementing, to detect overflows.
|
||||||
|
|
||||||
|
float gr_minus_peak; // For automatic gain control.
|
||||||
|
float gr_plus_peak;
|
||||||
|
|
||||||
|
int gr_sync; // Is sync pulse present?
|
||||||
|
int gr_prev_sync; // Previous state to detect leading edge.
|
||||||
|
|
||||||
|
int gr_first_sample; // Index of starting sample index for debugging.
|
||||||
|
|
||||||
|
int gr_dcd; // Data carrier detect. i.e. are we
|
||||||
|
// currently decoding a message.
|
||||||
|
|
||||||
|
float gr_early_sum; // For averaging bit values in two regions.
|
||||||
|
int gr_early_count;
|
||||||
|
float gr_late_sum;
|
||||||
|
int gr_late_count;
|
||||||
|
float gr_sync_sum;
|
||||||
|
int gr_sync_count;
|
||||||
|
|
||||||
|
int gr_bit_count; // Bit index into message.
|
||||||
|
|
||||||
|
struct rpack_s rpack; // Collection of bits.
|
||||||
|
|
||||||
|
} gr_state[2];
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FSK_DEMOD_STATE_H 1
|
#define FSK_DEMOD_STATE_H 1
|
||||||
|
|
|
@ -0,0 +1,501 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* grm_sym.h
|
||||||
|
*
|
||||||
|
* Symbol codes for use in $PGRMWPL sentence.
|
||||||
|
*
|
||||||
|
* Copied from
|
||||||
|
* Garmin Device Interface Specification
|
||||||
|
* May 19, 2006
|
||||||
|
* Drawing Number: 001-00063-00 Rev. C
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
typedef unsigned short symbol_type_t;
|
||||||
|
|
||||||
|
enum symbol_type_e
|
||||||
|
{
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
Marine symbols
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
sym_anchor = 0, /* white anchor symbol */
|
||||||
|
sym_bell = 1, /* white bell symbol */
|
||||||
|
sym_diamond_grn = 2, /* green diamond symbol */
|
||||||
|
sym_diamond_red = 3, /* red diamond symbol */
|
||||||
|
sym_dive1 = 4, /* diver down flag 1 */
|
||||||
|
sym_dive2 = 5, /* diver down flag 2 */
|
||||||
|
sym_dollar = 6, /* white dollar symbol */
|
||||||
|
sym_fish = 7, /* white fish symbol */
|
||||||
|
sym_fuel = 8, /* white fuel symbol */
|
||||||
|
sym_horn = 9, /* white horn symbol */
|
||||||
|
sym_house = 10, /* white house symbol */
|
||||||
|
sym_knife = 11, /* white knife & fork symbol */
|
||||||
|
sym_light = 12, /* white light symbol */
|
||||||
|
sym_mug = 13, /* white mug symbol */
|
||||||
|
sym_skull = 14, /* white skull and crossbones symbol*/
|
||||||
|
sym_square_grn = 15, /* green square symbol */
|
||||||
|
sym_square_red = 16, /* red square symbol */
|
||||||
|
sym_wbuoy = 17, /* white buoy waypoint symbol */
|
||||||
|
sym_wpt_dot = 18, /* waypoint dot */
|
||||||
|
sym_wreck = 19, /* white wreck symbol */
|
||||||
|
sym_null = 20, /* null symbol (transparent) */
|
||||||
|
sym_mob = 21, /* man overboard symbol */
|
||||||
|
sym_buoy_ambr = 22, /* amber map buoy symbol */
|
||||||
|
sym_buoy_blck = 23, /* black map buoy symbol */
|
||||||
|
sym_buoy_blue = 24, /* blue map buoy symbol */
|
||||||
|
sym_buoy_grn = 25, /* green map buoy symbol */
|
||||||
|
sym_buoy_grn_red = 26, /* green/red map buoy symbol */
|
||||||
|
sym_buoy_grn_wht = 27, /* green/white map buoy symbol */
|
||||||
|
sym_buoy_orng = 28, /* orange map buoy symbol */
|
||||||
|
sym_buoy_red = 29, /* red map buoy symbol */
|
||||||
|
sym_buoy_red_grn = 30, /* red/green map buoy symbol */
|
||||||
|
sym_buoy_red_wht = 31, /* red/white map buoy symbol */
|
||||||
|
sym_buoy_violet = 32, /* violet map buoy symbol */
|
||||||
|
sym_buoy_wht = 33, /* white map buoy symbol */
|
||||||
|
sym_buoy_wht_grn = 34, /* white/green map buoy symbol */
|
||||||
|
sym_buoy_wht_red = 35, /* white/red map buoy symbol */
|
||||||
|
sym_dot = 36, /* white dot symbol */
|
||||||
|
sym_rbcn = 37, /* radio beacon symbol */
|
||||||
|
sym_boat_ramp = 150, /* boat ramp symbol */
|
||||||
|
sym_camp = 151, /* campground symbol */
|
||||||
|
sym_restrooms = 152, /* restrooms symbol */
|
||||||
|
sym_showers = 153, /* shower symbol */
|
||||||
|
sym_drinking_wtr = 154, /* drinking water symbol */
|
||||||
|
sym_phone = 155, /* telephone symbol */
|
||||||
|
sym_1st_aid = 156, /* first aid symbol */
|
||||||
|
sym_info = 157, /* information symbol */
|
||||||
|
sym_parking = 158, /* parking symbol */
|
||||||
|
sym_park = 159, /* park symbol */
|
||||||
|
sym_picnic = 160, /* picnic symbol */
|
||||||
|
sym_scenic = 161, /* scenic area symbol */
|
||||||
|
sym_skiing = 162, /* skiing symbol */
|
||||||
|
sym_swimming = 163, /* swimming symbol */
|
||||||
|
sym_dam = 164, /* dam symbol */
|
||||||
|
sym_controlled = 165, /* controlled area symbol */
|
||||||
|
sym_danger = 166, /* danger symbol */
|
||||||
|
sym_restricted = 167, /* restricted area symbol */
|
||||||
|
sym_null_2 = 168, /* null symbol */
|
||||||
|
sym_ball = 169, /* ball symbol */
|
||||||
|
sym_car = 170, /* car symbol */
|
||||||
|
sym_deer = 171, /* deer symbol */
|
||||||
|
sym_shpng_cart = 172, /* shopping cart symbol */
|
||||||
|
sym_lodging = 173, /* lodging symbol */
|
||||||
|
sym_mine = 174, /* mine symbol */
|
||||||
|
sym_trail_head = 175, /* trail head symbol */
|
||||||
|
sym_truck_stop = 176, /* truck stop symbol */
|
||||||
|
sym_user_exit = 177, /* user exit symbol */
|
||||||
|
sym_flag = 178, /* flag symbol */
|
||||||
|
sym_circle_x = 179, /* circle with x in the center */
|
||||||
|
sym_open_24hr = 180, /* open 24 hours symbol */
|
||||||
|
sym_fhs_facility = 181, /* U Fishing Hot Spots™ Facility */
|
||||||
|
sym_bot_cond = 182, /* Bottom Conditions */
|
||||||
|
sym_tide_pred_stn = 183, /* Tide/Current Prediction Station */
|
||||||
|
sym_anchor_prohib = 184, /* U anchor prohibited symbol */
|
||||||
|
sym_beacon = 185, /* U beacon symbol */
|
||||||
|
sym_coast_guard = 186, /* U coast guard symbol */
|
||||||
|
sym_reef = 187, /* U reef symbol */
|
||||||
|
sym_weedbed = 188, /* U weedbed symbol */
|
||||||
|
sym_dropoff = 189, /* U dropoff symbol */
|
||||||
|
sym_dock = 190, /* U dock symbol */
|
||||||
|
sym_marina = 191, /* U marina symbol */
|
||||||
|
sym_bait_tackle = 192, /* U bait and tackle symbol */
|
||||||
|
sym_stump = 193, /* U stump symbol */
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
User customizable symbols
|
||||||
|
The values from sym_begin_custom to sym_end_custom inclusive are
|
||||||
|
reserved for the identification of user customizable symbols.
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
sym_begin_custom = 7680, /* first user customizable symbol */
|
||||||
|
sym_end_custom = 8191, /* last user customizable symbol */
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
Land symbols
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
sym_is_hwy = 8192, /* interstate hwy symbol */
|
||||||
|
sym_us_hwy = 8193, /* us hwy symbol */
|
||||||
|
sym_st_hwy = 8194, /* state hwy symbol */
|
||||||
|
sym_mi_mrkr = 8195, /* mile marker symbol */
|
||||||
|
sym_trcbck = 8196, /* TracBack (feet) symbol */
|
||||||
|
sym_golf = 8197, /* golf symbol */
|
||||||
|
sym_sml_cty = 8198, /* small city symbol */
|
||||||
|
sym_med_cty = 8199, /* medium city symbol */
|
||||||
|
sym_lrg_cty = 8200, /* large city symbol */
|
||||||
|
sym_freeway = 8201, /* intl freeway hwy symbol */
|
||||||
|
sym_ntl_hwy = 8202, /* intl national hwy symbol */
|
||||||
|
sym_cap_cty = 8203, /* capitol city symbol (star) */
|
||||||
|
sym_amuse_pk = 8204, /* amusement park symbol */
|
||||||
|
sym_bowling = 8205, /* bowling symbol */
|
||||||
|
sym_car_rental = 8206, /* car rental symbol */
|
||||||
|
sym_car_repair = 8207, /* car repair symbol */
|
||||||
|
sym_fastfood = 8208, /* fast food symbol */
|
||||||
|
sym_fitness = 8209, /* fitness symbol */
|
||||||
|
sym_movie = 8210, /* movie symbol */
|
||||||
|
sym_museum = 8211, /* museum symbol */
|
||||||
|
sym_pharmacy = 8212, /* pharmacy symbol */
|
||||||
|
sym_pizza = 8213, /* pizza symbol */
|
||||||
|
sym_post_ofc = 8214, /* post office symbol */
|
||||||
|
sym_rv_park = 8215, /* RV park symbol */
|
||||||
|
sym_school = 8216, /* school symbol */
|
||||||
|
sym_stadium = 8217, /* stadium symbol */
|
||||||
|
sym_store = 8218, /* dept. store symbol */
|
||||||
|
sym_zoo = 8219, /* zoo symbol */
|
||||||
|
sym_gas_plus = 8220, /* convenience store symbol */
|
||||||
|
sym_faces = 8221, /* live theater symbol */
|
||||||
|
sym_ramp_int = 8222, /* ramp intersection symbol */
|
||||||
|
sym_st_int = 8223, /* street intersection symbol */
|
||||||
|
sym_weigh_sttn = 8226, /* inspection/weigh station symbol */
|
||||||
|
sym_toll_booth = 8227, /* toll booth symbol */
|
||||||
|
sym_elev_pt = 8228, /* elevation point symbol */
|
||||||
|
sym_ex_no_srvc = 8229, /* exit without services symbol */
|
||||||
|
sym_geo_place_mm = 8230, /* Geographic place name, man-made */
|
||||||
|
sym_geo_place_wtr = 8231, /* Geographic place name, water */
|
||||||
|
sym_geo_place_lnd = 8232, /* Geographic place name, land */
|
||||||
|
sym_bridge = 8233, /* bridge symbol */
|
||||||
|
sym_building = 8234, /* building symbol */
|
||||||
|
sym_cemetery = 8235, /* cemetery symbol */
|
||||||
|
sym_church = 8236, /* church symbol */
|
||||||
|
sym_civil = 8237, /* civil location symbol */
|
||||||
|
sym_crossing = 8238, /* crossing symbol */
|
||||||
|
sym_hist_town = 8239, /* historical town symbol */
|
||||||
|
sym_levee = 8240, /* levee symbol */
|
||||||
|
sym_military = 8241, /* military location symbol */
|
||||||
|
sym_oil_field = 8242, /* oil field symbol */
|
||||||
|
sym_tunnel = 8243, /* tunnel symbol */
|
||||||
|
sym_beach = 8244, /* beach symbol */
|
||||||
|
sym_forest = 8245, /* forest symbol */
|
||||||
|
sym_summit = 8246, /* summit symbol */
|
||||||
|
sym_lrg_ramp_int = 8247, /* large ramp intersection symbol */
|
||||||
|
sym_lrg_ex_no_srvc = 8248, /* large exit without services smbl */
|
||||||
|
sym_badge = 8249, /* police/official badge symbol */
|
||||||
|
sym_cards = 8250, /* gambling/casino symbol */
|
||||||
|
sym_snowski = 8251, /* snow skiing symbol */
|
||||||
|
sym_iceskate = 8252, /* ice skating symbol */
|
||||||
|
sym_wrecker = 8253, /* tow truck (wrecker) symbol */
|
||||||
|
sym_border = 8254, /* border crossing (port of entry) */
|
||||||
|
sym_geocache = 8255, /* geocache location */
|
||||||
|
sym_geocache_fnd = 8256, /* found geocache */
|
||||||
|
sym_cntct_smiley = 8257, /* Rino contact symbol, "smiley" */
|
||||||
|
sym_cntct_ball_cap = 8258, /* Rino contact symbol, "ball cap" */
|
||||||
|
sym_cntct_big_ears = 8259, /* Rino contact symbol, "big ear" */
|
||||||
|
sym_cntct_spike = 8260, /* Rino contact symbol, "spike" */
|
||||||
|
sym_cntct_goatee = 8261, /* Rino contact symbol, "goatee" */
|
||||||
|
sym_cntct_afro = 8262, /* Rino contact symbol, "afro" */
|
||||||
|
sym_cntct_dreads = 8263, /* Rino contact symbol, "dreads" */
|
||||||
|
sym_cntct_female1 = 8264, /* Rino contact symbol, "female 1" */
|
||||||
|
sym_cntct_female2 = 8265, /* Rino contact symbol, "female 2" */
|
||||||
|
sym_cntct_female3 = 8266, /* Rino contact symbol, "female 3" */
|
||||||
|
sym_cntct_ranger = 8267, /* Rino contact symbol, "ranger" */
|
||||||
|
sym_cntct_kung_fu = 8268, /* Rino contact symbol, "kung fu" */
|
||||||
|
sym_cntct_sumo = 8269, /* Rino contact symbol, "sumo" */
|
||||||
|
sym_cntct_pirate = 8270, /* Rino contact symbol, "pirate" */
|
||||||
|
sym_cntct_biker = 8271, /* Rino contact symbol, "biker" */
|
||||||
|
sym_cntct_alien = 8272, /* Rino contact symbol, "alien" */
|
||||||
|
sym_cntct_bug = 8273, /* Rino contact symbol, "bug" */
|
||||||
|
sym_cntct_cat = 8274, /* Rino contact symbol, "cat" */
|
||||||
|
sym_cntct_dog = 8275, /* Rino contact symbol, "dog" */
|
||||||
|
sym_cntct_pig = 8276, /* Rino contact symbol, "pig" */
|
||||||
|
sym_hydrant = 8282, /* water hydrant symbol */
|
||||||
|
sym_flag_blue = 8284, /* blue flag symbol */
|
||||||
|
sym_flag_green = 8285, /* green flag symbol */
|
||||||
|
sym_flag_red = 8286, /* red flag symbol */
|
||||||
|
sym_pin_blue = 8287, /* blue pin symbol */
|
||||||
|
sym_pin_green = 8288, /* green pin symbol */
|
||||||
|
sym_pin_red = 8289, /* red pin symbol */
|
||||||
|
sym_block_blue = 8290, /* blue block symbol */
|
||||||
|
sym_block_green = 8291, /* green block symbol */
|
||||||
|
sym_block_red = 8292, /* red block symbol */
|
||||||
|
sym_bike_trail = 8293, /* bike trail symbol */
|
||||||
|
sym_circle_red = 8294, /* red circle symbol */
|
||||||
|
sym_circle_green = 8295, /* green circle symbol */
|
||||||
|
sym_circle_blue = 8296, /* blue circle symbol */
|
||||||
|
sym_diamond_blue = 8299, /* blue diamond symbol */
|
||||||
|
sym_oval_red = 8300, /* red oval symbol */
|
||||||
|
sym_oval_green = 8301, /* green oval symbol */
|
||||||
|
sym_oval_blue = 8302, /* blue oval symbol */
|
||||||
|
sym_rect_red = 8303, /* red rectangle symbol */
|
||||||
|
sym_rect_green = 8304, /* green rectangle symbol */
|
||||||
|
sym_rect_blue = 8305, /* blue rectangle symbol */
|
||||||
|
sym_square_blue = 8308, /* blue square symbol */
|
||||||
|
sym_letter_a_red = 8309, /* red letter 'A' symbol */
|
||||||
|
sym_letter_b_red = 8310, /* red letter 'B' symbol */
|
||||||
|
sym_letter_c_red = 8311, /* red letter 'C' symbol */
|
||||||
|
sym_letter_d_red = 8312, /* red letter 'D' symbol */
|
||||||
|
sym_letter_a_green = 8313, /* green letter 'A' symbol */
|
||||||
|
sym_letter_c_green = 8314, /* green letter 'C' symbol */
|
||||||
|
sym_letter_b_green = 8315, /* green letter 'B' symbol */
|
||||||
|
sym_letter_d_green = 8316, /* green letter 'D' symbol */
|
||||||
|
sym_letter_a_blue = 8317, /* blue letter 'A' symbol */
|
||||||
|
sym_letter_b_blue = 8318, /* blue letter 'B' symbol */
|
||||||
|
sym_letter_c_blue = 8319, /* blue letter 'C' symbol */
|
||||||
|
sym_letter_d_blue = 8320, /* blue letter 'D' symbol */
|
||||||
|
sym_number_0_red = 8321, /* red number '0' symbol */
|
||||||
|
sym_number_1_red = 8322, /* red number '1' symbol */
|
||||||
|
sym_number_2_red = 8323, /* red number '2' symbol */
|
||||||
|
sym_number_3_red = 8324, /* red number '3' symbol */
|
||||||
|
sym_number_4_red = 8325, /* red number '4' symbol */
|
||||||
|
sym_number_5_red = 8326, /* red number '5' symbol */
|
||||||
|
sym_number_6_red = 8327, /* red number '6' symbol */
|
||||||
|
sym_number_7_red = 8328, /* red number '7' symbol */
|
||||||
|
sym_number_8_red = 8329, /* red number '8' symbol */
|
||||||
|
sym_number_9_red = 8330, /* red number '9' symbol */
|
||||||
|
sym_number_0_green = 8331, /* green number '0' symbol */
|
||||||
|
sym_number_1_green = 8332, /* green number '1' symbol */
|
||||||
|
sym_number_2_green = 8333, /* green number '2' symbol */
|
||||||
|
sym_number_3_green = 8334, /* green number '3' symbol */
|
||||||
|
sym_number_4_green = 8335, /* green number '4' symbol */
|
||||||
|
sym_number_5_green = 8336, /* green number '5' symbol */
|
||||||
|
sym_number_6_green = 8337, /* green number '6' symbol */
|
||||||
|
sym_number_7_green = 8338, /* green number '7' symbol */
|
||||||
|
sym_number_8_green = 8339, /* green number '8' symbol */
|
||||||
|
sym_number_9_green = 8340, /* green number '9' symbol */
|
||||||
|
sym_number_0_blue = 8341, /* blue number '0' symbol */
|
||||||
|
sym_number_1_blue = 8342, /* blue number '1' symbol */
|
||||||
|
sym_number_2_blue = 8343, /* blue number '2' symbol */
|
||||||
|
sym_number_3_blue = 8344, /* blue number '3' symbol */
|
||||||
|
sym_number_4_blue = 8345, /* blue number '4' symbol */
|
||||||
|
sym_number_5_blue = 8346, /* blue number '5' symbol */
|
||||||
|
sym_number_6_blue = 8347, /* blue number '6' symbol */
|
||||||
|
sym_number_7_blue = 8348, /* blue number '7' symbol */
|
||||||
|
sym_number_8_blue = 8349, /* blue number '8' symbol */
|
||||||
|
sym_number_9_blue = 8350, /* blue number '9' symbol */
|
||||||
|
sym_triangle_blue = 8351, /* blue triangle symbol */
|
||||||
|
sym_triangle_green = 8352, /* green triangle symbol */
|
||||||
|
sym_triangle_red = 8353, /* red triangle symbol */
|
||||||
|
sym_food_asian = 8359, /* asian food symbol */
|
||||||
|
sym_food_deli = 8360, /* deli symbol */
|
||||||
|
sym_food_italian = 8361, /* italian food symbol */
|
||||||
|
sym_food_seafood = 8362, /* seafood symbol */
|
||||||
|
sym_food_steak = 8363, /* steak symbol */
|
||||||
|
/*---------------------------------------------------------------
|
||||||
|
Aviation symbols
|
||||||
|
---------------------------------------------------------------*/
|
||||||
|
sym_airport = 16384, /* airport symbol */
|
||||||
|
sym_int = 16385, /* intersection symbol */
|
||||||
|
sym_ndb = 16386, /* non-directional beacon symbol */
|
||||||
|
sym_vor = 16387, /* VHF omni-range symbol */
|
||||||
|
sym_heliport = 16388, /* heliport symbol */
|
||||||
|
sym_private = 16389, /* private field symbol */
|
||||||
|
sym_soft_fld = 16390, /* soft field symbol */
|
||||||
|
sym_tall_tower = 16391, /* tall tower symbol */
|
||||||
|
sym_short_tower = 16392, /* short tower symbol */
|
||||||
|
sym_glider = 16393, /* glider symbol */
|
||||||
|
sym_ultralight = 16394, /* ultralight symbol */
|
||||||
|
sym_parachute = 16395, /* parachute symbol */
|
||||||
|
sym_vortac = 16396, /* VOR/TACAN symbol */
|
||||||
|
sym_vordme = 16397, /* VOR-DME symbol */
|
||||||
|
sym_faf = 16398, /* first approach fix */
|
||||||
|
sym_lom = 16399, /* localizer outer marker */
|
||||||
|
sym_map = 16400, /* missed approach point */
|
||||||
|
sym_tacan = 16401, /* TACAN symbol */
|
||||||
|
sym_seaplane = 16402, /* Seaplane Base */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping from APRS symbols to Garmin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: NEEDS MORE WORK!!!
|
||||||
|
|
||||||
|
|
||||||
|
#define SYMTAB_SIZE 95
|
||||||
|
|
||||||
|
#define sym_default sym_diamond_grn
|
||||||
|
|
||||||
|
|
||||||
|
static const symbol_type_t grm_primary_symtab[SYMTAB_SIZE] = {
|
||||||
|
|
||||||
|
sym_default, // 00 --no-symbol--
|
||||||
|
sym_cntct_ranger, // ! 01 Police, Sheriff
|
||||||
|
sym_default, // " 02 reserved (was rain)
|
||||||
|
sym_rbcn, // # 03 DIGI (white center)
|
||||||
|
sym_phone, // $ 04 PHONE
|
||||||
|
sym_rbcn, // % 05 DX CLUSTER
|
||||||
|
sym_rbcn, // & 06 HF GATEway
|
||||||
|
sym_glider, // ' 07 Small AIRCRAFT
|
||||||
|
sym_rbcn, // ( 08 Mobile Satellite Station
|
||||||
|
sym_default, // ) 09 Wheelchair (handicapped)
|
||||||
|
sym_car, // * 10 SnowMobile
|
||||||
|
sym_1st_aid, // + 11 Red Cross
|
||||||
|
sym_cntct_ball_cap, // , 12 Boy Scouts
|
||||||
|
sym_house, // - 13 House QTH (VHF)
|
||||||
|
sym_default, // . 14 X
|
||||||
|
sym_default, // / 15 Red Dot
|
||||||
|
sym_default, // 0 16 # circle (obsolete)
|
||||||
|
sym_default, // 1 17 TBD
|
||||||
|
sym_default, // 2 18 TBD
|
||||||
|
sym_default, // 3 19 TBD
|
||||||
|
sym_default, // 4 20 TBD
|
||||||
|
sym_default, // 5 21 TBD
|
||||||
|
sym_default, // 6 22 TBD
|
||||||
|
sym_default, // 7 23 TBD
|
||||||
|
sym_default, // 8 24 TBD
|
||||||
|
sym_default, // 9 25 TBD
|
||||||
|
sym_default, // : 26 FIRE
|
||||||
|
sym_camp, // ; 27 Campground (Portable ops)
|
||||||
|
sym_cntct_biker, // < 28 Motorcycle
|
||||||
|
sym_default, // = 29 RAILROAD ENGINE
|
||||||
|
sym_car, // > 30 CAR
|
||||||
|
sym_default, // ? 31 SERVER for Files
|
||||||
|
sym_default, // @ 32 HC FUTURE predict (dot)
|
||||||
|
sym_1st_aid, // A 33 Aid Station
|
||||||
|
sym_rbcn, // B 34 BBS or PBBS
|
||||||
|
sym_boat_ramp, // C 35 Canoe
|
||||||
|
sym_default, // D 36
|
||||||
|
sym_default, // E 37 EYEBALL (Eye catcher!)
|
||||||
|
sym_default, // F 38 Farm Vehicle (tractor)
|
||||||
|
sym_default, // G 39 Grid Square (6 digit)
|
||||||
|
sym_lodging, // H 40 HOTEL (blue bed symbol)
|
||||||
|
sym_rbcn, // I 41 TcpIp on air network stn
|
||||||
|
sym_default, // J 42
|
||||||
|
sym_school, // K 43 School
|
||||||
|
sym_default, // L 44 PC user
|
||||||
|
sym_default, // M 45 MacAPRS
|
||||||
|
sym_default, // N 46 NTS Station
|
||||||
|
sym_parachute, // O 47 BALLOON
|
||||||
|
sym_cntct_ranger, // P 48 Police
|
||||||
|
sym_default, // Q 49 TBD
|
||||||
|
sym_rv_park, // R 50 REC. VEHICLE
|
||||||
|
sym_glider, // S 51 SHUTTLE
|
||||||
|
sym_default, // T 52 SSTV
|
||||||
|
sym_car, // U 53 BUS
|
||||||
|
sym_cntct_biker, // V 54 ATV
|
||||||
|
sym_default, // W 55 National WX Service Site
|
||||||
|
sym_default, // X 56 HELO
|
||||||
|
sym_default, // Y 57 YACHT (sail)
|
||||||
|
sym_default, // Z 58 WinAPRS
|
||||||
|
sym_cntct_smiley, // [ 59 Human/Person (HT)
|
||||||
|
sym_triangle_green, // \ 60 TRIANGLE(DF station)
|
||||||
|
sym_default, // ] 61 MAIL/PostOffice(was PBBS)
|
||||||
|
sym_glider, // ^ 62 LARGE AIRCRAFT
|
||||||
|
sym_default, // _ 63 WEATHER Station (blue)
|
||||||
|
sym_rbcn, // ` 64 Dish Antenna
|
||||||
|
sym_1st_aid, // a 65 AMBULANCE
|
||||||
|
sym_cntct_biker, // b 66 BIKE
|
||||||
|
sym_default, // c 67 Incident Command Post
|
||||||
|
sym_hydrant, // d 68 Fire dept
|
||||||
|
sym_deer, // e 69 HORSE (equestrian)
|
||||||
|
sym_hydrant, // f 70 FIRE TRUCK
|
||||||
|
sym_glider, // g 71 Glider
|
||||||
|
sym_1st_aid, // h 72 HOSPITAL
|
||||||
|
sym_default, // i 73 IOTA (islands on the air)
|
||||||
|
sym_car, // j 74 JEEP
|
||||||
|
sym_car, // k 75 TRUCK
|
||||||
|
sym_default, // l 76 Laptop
|
||||||
|
sym_rbcn, // m 77 Mic-E Repeater
|
||||||
|
sym_default, // n 78 Node (black bulls-eye)
|
||||||
|
sym_default, // o 79 EOC
|
||||||
|
sym_cntct_dog, // p 80 ROVER (puppy, or dog)
|
||||||
|
sym_default, // q 81 GRID SQ shown above 128 m
|
||||||
|
sym_rbcn, // r 82 Repeater
|
||||||
|
sym_default, // s 83 SHIP (pwr boat)
|
||||||
|
sym_truck_stop, // t 84 TRUCK STOP
|
||||||
|
sym_truck_stop, // u 85 TRUCK (18 wheeler)
|
||||||
|
sym_car, // v 86 VAN
|
||||||
|
sym_drinking_wtr, // w 87 WATER station
|
||||||
|
sym_default, // x 88 xAPRS (Unix)
|
||||||
|
sym_tall_tower, // y 89 YAGI @ QTH
|
||||||
|
sym_default, // z 90 TBD
|
||||||
|
sym_default, // { 91
|
||||||
|
sym_default, // | 92 TNC Stream Switch
|
||||||
|
sym_default, // } 93
|
||||||
|
sym_default }; // ~ 94 TNC Stream Switch
|
||||||
|
|
||||||
|
static const symbol_type_t grm_alternate_symtab[SYMTAB_SIZE] = {
|
||||||
|
|
||||||
|
sym_default, // 00 --no-symbol--
|
||||||
|
sym_default, // ! 01 EMERGENCY (!)
|
||||||
|
sym_default, // " 02 reserved
|
||||||
|
sym_default, // # 03 OVERLAY DIGI (green star)
|
||||||
|
sym_default, // $ 04 Bank or ATM (green box)
|
||||||
|
sym_default, // % 05 Power Plant with overlay
|
||||||
|
sym_rbcn, // & 06 I=Igte IGate R=RX T=1hopTX 2=2hopTX
|
||||||
|
sym_default, // ' 07 Crash (& now Incident sites)
|
||||||
|
sym_default, // ( 08 CLOUDY (other clouds w ovrly)
|
||||||
|
sym_hydrant, // ) 09 Firenet MEO, MODIS Earth Obs.
|
||||||
|
sym_default, // * 10 SNOW (& future ovrly codes)
|
||||||
|
sym_default, // + 11 Church
|
||||||
|
sym_cntct_female1, // , 12 Girl Scouts
|
||||||
|
sym_house, // - 13 House (H=HF) (O = Op Present)
|
||||||
|
sym_default, // . 14 Ambiguous (Big Question mark)
|
||||||
|
sym_default, // / 15 Waypoint Destination
|
||||||
|
sym_default, // 0 16 CIRCLE (E/I/W=IRLP/Echolink/WIRES)
|
||||||
|
sym_default, // 1 17
|
||||||
|
sym_default, // 2 18
|
||||||
|
sym_default, // 3 19
|
||||||
|
sym_default, // 4 20
|
||||||
|
sym_default, // 5 21
|
||||||
|
sym_default, // 6 22
|
||||||
|
sym_default, // 7 23
|
||||||
|
sym_default, // 8 24 802.11 or other network node
|
||||||
|
sym_default, // 9 25 Gas Station (blue pump)
|
||||||
|
sym_default, // : 26 Hail (& future ovrly codes)
|
||||||
|
sym_park, // ; 27 Park/Picnic area
|
||||||
|
sym_default, // < 28 ADVISORY (one WX flag)
|
||||||
|
sym_rbcn, // = 29 APRStt Touchtone (DTMF users)
|
||||||
|
sym_car, // > 30 OVERLAYED CAR
|
||||||
|
sym_default, // ? 31 INFO Kiosk (Blue box with ?)
|
||||||
|
sym_default, // @ 32 HURICANE/Trop-Storm
|
||||||
|
sym_default, // A 33 overlayBOX DTMF & RFID & XO
|
||||||
|
sym_default, // B 34 Blwng Snow (& future codes)
|
||||||
|
sym_coast_guard, // C 35 Coast Guard
|
||||||
|
sym_default, // D 36 Drizzle (proposed APRStt)
|
||||||
|
sym_default, // E 37 Smoke (& other vis codes)
|
||||||
|
sym_default, // F 38 Freezng rain (&future codes)
|
||||||
|
sym_default, // G 39 Snow Shwr (& future ovrlys)
|
||||||
|
sym_default, // H 40 Haze (& Overlay Hazards)
|
||||||
|
sym_default, // I 41 Rain Shower
|
||||||
|
sym_default, // J 42 Lightening (& future ovrlys)
|
||||||
|
sym_rbcn, // K 43 Kenwood HT (W)
|
||||||
|
sym_light, // L 44 Lighthouse
|
||||||
|
sym_default, // M 45 MARS (A=Army,N=Navy,F=AF)
|
||||||
|
sym_default, // N 46 Navigation Buoy
|
||||||
|
sym_default, // O 47 Rocket
|
||||||
|
sym_default, // P 48 Parking
|
||||||
|
sym_default, // Q 49 QUAKE
|
||||||
|
sym_default, // R 50 Restaurant
|
||||||
|
sym_rbcn, // S 51 Satellite/Pacsat
|
||||||
|
sym_default, // T 52 Thunderstorm
|
||||||
|
sym_default, // U 53 SUNNY
|
||||||
|
sym_default, // V 54 VORTAC Nav Aid
|
||||||
|
sym_default, // W 55 # NWS site (NWS options)
|
||||||
|
sym_pharmacy, // X 56 Pharmacy Rx (Apothicary)
|
||||||
|
sym_rbcn, // Y 57 Radios and devices
|
||||||
|
sym_default, // Z 58
|
||||||
|
sym_default, // [ 59 W.Cloud (& humans w Ovrly)
|
||||||
|
sym_default, // \ 60 New overlayable GPS symbol
|
||||||
|
sym_default, // ] 61
|
||||||
|
sym_glider, // ^ 62 # Aircraft (shows heading)
|
||||||
|
sym_default, // _ 63 # WX site (green digi)
|
||||||
|
sym_default, // ` 64 Rain (all types w ovrly)
|
||||||
|
sym_default, // a 65 ARRL, ARES, WinLINK
|
||||||
|
sym_default, // b 66 Blwng Dst/Snd (& others)
|
||||||
|
sym_default, // c 67 CD triangle RACES/SATERN/etc
|
||||||
|
sym_default, // d 68 DX spot by callsign
|
||||||
|
sym_default, // e 69 Sleet (& future ovrly codes)
|
||||||
|
sym_default, // f 70 Funnel Cloud
|
||||||
|
sym_default, // g 71 Gale Flags
|
||||||
|
sym_default, // h 72 Store. or HAMFST Hh=HAM store
|
||||||
|
sym_default, // i 73 BOX or points of Interest
|
||||||
|
sym_default, // j 74 WorkZone (Steam Shovel)
|
||||||
|
sym_car, // k 75 Special Vehicle SUV,ATV,4x4
|
||||||
|
sym_default, // l 76 Areas (box,circles,etc)
|
||||||
|
sym_default, // m 77 Value Sign (3 digit display)
|
||||||
|
sym_default, // n 78 OVERLAY TRIANGLE
|
||||||
|
sym_default, // o 79 small circle
|
||||||
|
sym_default, // p 80 Prtly Cldy (& future ovrlys)
|
||||||
|
sym_default, // q 81
|
||||||
|
sym_restrooms, // r 82 Restrooms
|
||||||
|
sym_default, // s 83 OVERLAY SHIP/boat (top view)
|
||||||
|
sym_default, // t 84 Tornado
|
||||||
|
sym_car, // u 85 OVERLAYED TRUCK
|
||||||
|
sym_car, // v 86 OVERLAYED Van
|
||||||
|
sym_default, // w 87 Flooding
|
||||||
|
sym_wreck, // x 88 Wreck or Obstruction ->X<-
|
||||||
|
sym_default, // y 89 Skywarn
|
||||||
|
sym_default, // z 90 OVERLAYED Shelter
|
||||||
|
sym_default, // { 91 Fog (& future ovrly codes)
|
||||||
|
sym_default, // | 92 TNC Stream Switch
|
||||||
|
sym_default, // } 93
|
||||||
|
sym_default }; // ~ 94 TNC Stream Switch
|
||||||
|
|
|
@ -367,6 +367,7 @@ void hdlc_rec_bit (int chan, int subchan, int raw, int is_scrambled, int descram
|
||||||
int alevel = demod_get_audio_level (chan, subchan);
|
int alevel = demod_get_audio_level (chan, subchan);
|
||||||
|
|
||||||
rrbb_set_audio_level (H->rrbb, alevel);
|
rrbb_set_audio_level (H->rrbb, alevel);
|
||||||
|
rrbb_set_fix_bits (H->rrbb, H->fix_bits);
|
||||||
hdlc_rec2_block (H->rrbb, H->fix_bits);
|
hdlc_rec2_block (H->rrbb, H->fix_bits);
|
||||||
/* Now owned by someone else who will free it. */
|
/* Now owned by someone else who will free it. */
|
||||||
H->rrbb = rrbb_new (chan, subchan, is_scrambled, descram_state); /* Allocate a new one. */
|
H->rrbb = rrbb_new (chan, subchan, is_scrambled, descram_state); /* Allocate a new one. */
|
||||||
|
|
590
hdlc_rec2.c
590
hdlc_rec2.c
|
@ -1,7 +1,6 @@
|
||||||
//
|
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011, 2012, 2013 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2012, 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,12 +25,32 @@
|
||||||
* else has done the work of pulling it out from between
|
* else has done the work of pulling it out from between
|
||||||
* the special "flag" sequences.
|
* the special "flag" sequences.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* New in version 1.1:
|
||||||
|
*
|
||||||
|
* Several enhancements provided by Fabrice FAURE:
|
||||||
|
*
|
||||||
|
* - Additional types of attempts to fix a bad CRC.
|
||||||
|
* - Optimized code to reduce execution time.
|
||||||
|
* - Improved detection of duplicate packets from different fixup attempts.
|
||||||
|
* - Set limit on number of packets in fix up later queue.
|
||||||
|
*
|
||||||
|
* One of the new recovery attempt cases recovers three additional
|
||||||
|
* packets that were lost before. The one thing I disagree with is
|
||||||
|
* use of the word "swap" because that sounds like two things
|
||||||
|
* are being exchanged for each other. I would prefer "flip"
|
||||||
|
* or "invert" to describe changing a bit to the opposite state.
|
||||||
|
* I took "swap" out of the user-visible messages but left the
|
||||||
|
* rest of the source code as provided.
|
||||||
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
//Optimize processing by accessing directly to decoded bits
|
||||||
|
#define RRBB_C 1
|
||||||
#include "direwolf.h"
|
#include "direwolf.h"
|
||||||
#include "hdlc_rec2.h"
|
#include "hdlc_rec2.h"
|
||||||
#include "fcs_calc.h"
|
#include "fcs_calc.h"
|
||||||
|
@ -40,6 +59,9 @@
|
||||||
#include "rrbb.h"
|
#include "rrbb.h"
|
||||||
#include "rdq.h"
|
#include "rdq.h"
|
||||||
#include "multi_modem.h"
|
#include "multi_modem.h"
|
||||||
|
//#define DEBUG 1
|
||||||
|
//#define DEBUGx 1
|
||||||
|
//#define DEBUG_LATER 1
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -82,13 +104,13 @@ struct hdlc_state_s {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_RETRY_SWAP_BITS 24 /* Maximum number of contiguous bits to swap */
|
||||||
|
#define MAX_RETRY_REMOVE_SEPARATED_BITS 24 /* Maximum number of contiguous bits to remove */
|
||||||
|
|
||||||
|
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_conf_t retry_conf);
|
||||||
|
|
||||||
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t bits_flipped, int flip_a, int flip_b, int flip_c);
|
|
||||||
static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits);
|
static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits);
|
||||||
static int sanity_check (unsigned char *buf, int blen, retry_t bits_flipped);
|
static int sanity_check (unsigned char *buf, int blen, retry_t bits_flipped);
|
||||||
#if DEBUG
|
#if DEBUG_LATER
|
||||||
static double dtime_now (void);
|
static double dtime_now (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -161,8 +183,19 @@ void hdlc_rec2_block (rrbb_t block, retry_t fix_bits)
|
||||||
rrbb_set_slice_val (block, 0);
|
rrbb_set_slice_val (block, 0);
|
||||||
|
|
||||||
#else /* not SLICENDICE */
|
#else /* not SLICENDICE */
|
||||||
|
/* Create an empty retry configuration */
|
||||||
|
retry_conf_t retry_cfg;
|
||||||
|
|
||||||
ok = try_decode (block, chan, subchan, alevel, RETRY_NONE, -1, -1, -1);
|
/* By default we don't try to alter any bits */
|
||||||
|
retry_cfg.type = RETRY_TYPE_NONE;
|
||||||
|
retry_cfg.mode = RETRY_MODE_CONTIGUOUS;
|
||||||
|
retry_cfg.retry = RETRY_NONE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 0;
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = 0;
|
||||||
|
/* Prepare the decoded bits in an array for faster processing
|
||||||
|
*(at cost of memory but 1 or 2 kbytes is nothing compared to processing time ) */
|
||||||
|
rrbb_compute_bits(block);
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -183,7 +216,7 @@ void hdlc_rec2_block (rrbb_t block, retry_t fix_bits)
|
||||||
* Put in queue for retrying later at lower priority.
|
* Put in queue for retrying later at lower priority.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (fix_bits < RETRY_TWO_SEP) {
|
if (fix_bits < RETRY_SWAP_TWO_SEP) {
|
||||||
rrbb_delete (block);
|
rrbb_delete (block);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -196,20 +229,29 @@ void hdlc_rec2_block (rrbb_t block, retry_t fix_bits)
|
||||||
static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits)
|
static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel, retry_t fix_bits)
|
||||||
{
|
{
|
||||||
int ok;
|
int ok;
|
||||||
int len, i;
|
int len, i,j;
|
||||||
|
|
||||||
|
|
||||||
len = rrbb_get_len(block);
|
len = rrbb_get_len(block);
|
||||||
|
/* Prepare the retry configuration */
|
||||||
|
retry_conf_t retry_cfg;
|
||||||
|
/* Will modify only contiguous bits*/
|
||||||
|
retry_cfg.mode = RETRY_MODE_CONTIGUOUS;
|
||||||
/*
|
/*
|
||||||
* Try fixing one bit.
|
* Try fixing one bit.
|
||||||
*/
|
*/
|
||||||
if (fix_bits < RETRY_SINGLE) {
|
if (fix_bits < RETRY_SWAP_SINGLE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Try to swap one bit */
|
||||||
|
retry_cfg.type = RETRY_TYPE_SWAP;
|
||||||
|
retry_cfg.retry = RETRY_SWAP_SINGLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 1;
|
||||||
|
|
||||||
for (i=0; i<len; i++) {
|
for (i=0; i<len; i++) {
|
||||||
ok = try_decode (block, chan, subchan, alevel, RETRY_SINGLE, i, -1, -1);
|
/* Set the index of the bit to swap */
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -222,12 +264,17 @@ static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel
|
||||||
/*
|
/*
|
||||||
* Try fixing two adjacent bits.
|
* Try fixing two adjacent bits.
|
||||||
*/
|
*/
|
||||||
if (fix_bits < RETRY_DOUBLE) {
|
if (fix_bits < RETRY_SWAP_DOUBLE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Try to swap two contiguous bits */
|
||||||
|
retry_cfg.retry = RETRY_SWAP_DOUBLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 2;
|
||||||
|
|
||||||
|
|
||||||
for (i=0; i<len-1; i++) {
|
for (i=0; i<len-1; i++) {
|
||||||
ok = try_decode (block, chan, subchan, alevel, RETRY_DOUBLE, i, i+1, -1);
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -240,13 +287,16 @@ static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel
|
||||||
/*
|
/*
|
||||||
* Try fixing adjacent three bits.
|
* Try fixing adjacent three bits.
|
||||||
*/
|
*/
|
||||||
if (fix_bits < RETRY_TRIPLE) {
|
if (fix_bits < RETRY_SWAP_TRIPLE) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Try to swap three contiguous bits */
|
||||||
|
retry_cfg.retry = RETRY_SWAP_TRIPLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 3;
|
||||||
|
|
||||||
len = rrbb_get_len(block);
|
|
||||||
for (i=0; i<len-2; i++) {
|
for (i=0; i<len-2; i++) {
|
||||||
ok = try_decode (block, chan, subchan, alevel, RETRY_TRIPLE, i, i+1, i+2);
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -256,71 +306,362 @@ static int try_to_fix_quick_now (rrbb_t block, int chan, int subchan, int alevel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fix_bits < RETRY_REMOVE_SINGLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try removing one bit.
|
||||||
|
*/
|
||||||
|
retry_cfg.type = RETRY_TYPE_REMOVE;
|
||||||
|
retry_cfg.retry = RETRY_REMOVE_SINGLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 1;
|
||||||
|
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by removing SINGLE bit %d of %d ***\n", i, len);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fix_bits < RETRY_REMOVE_DOUBLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try removing two contiguous bits.
|
||||||
|
*/
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Try removing DOUBLE bits *** for %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
retry_cfg.retry = RETRY_REMOVE_DOUBLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 2;
|
||||||
|
|
||||||
|
for (i=0; i<len-1; i++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by removing DOUBLE bits %d of %d ***\n", i, len);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fix_bits < RETRY_REMOVE_TRIPLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try removing three contiguous bits.
|
||||||
|
*/
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Try removing TRIPLE bits *** for %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
retry_cfg.retry = RETRY_REMOVE_TRIPLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 3;
|
||||||
|
|
||||||
|
for (i=0; i<len-2; i++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by removing TRIPLE bits %d of %d ***\n", i, len);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fix_bits < RETRY_INSERT_SINGLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try inserting one bit (two values possibles for this inserted bit).
|
||||||
|
*/
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Try inserting SINGLE bit *** for %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
retry_cfg.type = RETRY_TYPE_INSERT;
|
||||||
|
retry_cfg.retry = RETRY_INSERT_SINGLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 1;
|
||||||
|
|
||||||
|
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
retry_cfg.insert_value=0;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (!ok) {
|
||||||
|
retry_cfg.insert_value=1;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by inserting SINGLE bit %d of %d ***\n", i, len);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fix_bits < RETRY_INSERT_DOUBLE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try inserting two contiguous bits (4 possible values for two bits).
|
||||||
|
*/
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Try inserting DOUBLE bits *** for %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
retry_cfg.retry = RETRY_INSERT_DOUBLE;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = 2;
|
||||||
|
|
||||||
|
|
||||||
|
for (i=0; i<len-1; i++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
for (j=0;j<4;j++) {
|
||||||
|
retry_cfg.insert_value=j;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by inserting DOUBLE bits %d of %d ***\n", i, len);
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hdlc_rec2_try_to_fix_later (rrbb_t block, int chan, int subchan, int alevel)
|
void hdlc_rec2_try_to_fix_later (rrbb_t block, int chan, int subchan, int alevel)
|
||||||
{
|
{
|
||||||
int ok;
|
int ok;
|
||||||
int len, i;
|
int len, i, j;
|
||||||
#if DEBUG
|
retry_t fix_bits;
|
||||||
|
#if DEBUG_LATER
|
||||||
double tstart, tend;
|
double tstart, tend;
|
||||||
#endif
|
#endif
|
||||||
|
retry_conf_t retry_cfg;
|
||||||
len = rrbb_get_len(block);
|
len = rrbb_get_len(block);
|
||||||
|
fix_bits = rrbb_get_fix_bits (block);
|
||||||
|
|
||||||
|
if (fix_bits < RETRY_SWAP_TWO_SEP) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
retry_cfg.mode = RETRY_MODE_SEPARATED;
|
||||||
/*
|
/*
|
||||||
* Two non-adjacent ("separated") single bits.
|
* Two non-adjacent ("separated") single bits.
|
||||||
* It chews up a lot of CPU time. Test takes 4 times longer to run.
|
* It chews up a lot of CPU time. Test takes 4 times longer to run.
|
||||||
*
|
*
|
||||||
* Ran up to 4.82 seconds for 1040 bits before giving up.
|
* Ran up to xx seconds (TODO check again with optimized code) seconds for 1040 bits before giving up .
|
||||||
* Processing time is order N squared so time goes up rapidly with larger frames.
|
* Processing time is order N squared so time goes up rapidly with larger frames.
|
||||||
*/
|
*/
|
||||||
|
retry_cfg.type = RETRY_TYPE_SWAP;
|
||||||
|
retry_cfg.retry = RETRY_SWAP_TWO_SEP;
|
||||||
|
retry_cfg.u_bits.sep.bit_idx_c = -1;
|
||||||
|
|
||||||
#if DEBUG
|
#ifdef DEBUG_LATER
|
||||||
tstart = dtime_now();
|
tstart = dtime_now();
|
||||||
|
dw_printf ("*** Try flipping TWO SEPARATED BITS %d bits\n", len);
|
||||||
#endif
|
#endif
|
||||||
len = rrbb_get_len(block);
|
len = rrbb_get_len(block);
|
||||||
for (i=0; i<len-2; i++) {
|
for (i=0; i<len-2; i++) {
|
||||||
|
retry_cfg.u_bits.sep.bit_idx_a = i;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
ok = 0;
|
ok = 0;
|
||||||
for (j=i+2; j<len; j++) {
|
for (j=i+2; j<len; j++) {
|
||||||
ok = try_decode (block, chan, subchan, alevel, RETRY_TWO_SEP, i, j, -1);
|
retry_cfg.u_bits.sep.bit_idx_b = j;
|
||||||
if (ok)
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ok) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
tend = dtime_now();
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("*** Success by flipping TWO SEPARATED bits %d and %d of %d *** %.3f sec.\n", i, j, len, tend-tstart);
|
dw_printf ("*** Success by flipping TWO SEPARATED bits %d and %d of %d \n", i, j, len);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if DEBUGx
|
#if DEBUG_LATER
|
||||||
tend = dtime_now();
|
tend = dtime_now();
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("*** No luck flipping TWO SEPARATED bits of %d *** %.3f sec.\n", len, tend-tstart);
|
dw_printf ("*** No luck flipping TWO SEPARATED bits of %d *** %.3f sec.\n", len, tend-tstart);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (fix_bits < RETRY_SWAP_MANY) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
/* Try to swap many contiguous bits */
|
||||||
|
retry_cfg.mode = RETRY_MODE_CONTIGUOUS;
|
||||||
|
retry_cfg.type = RETRY_TYPE_SWAP;
|
||||||
|
retry_cfg.retry = RETRY_SWAP_MANY;
|
||||||
|
|
||||||
|
#ifdef DEBUG_LATER
|
||||||
|
tstart = dtime_now();
|
||||||
|
dw_printf ("*** Try swapping many BITS %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
len = rrbb_get_len(block);
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
for (j=1; j<len-i && j < MAX_RETRY_SWAP_BITS;j++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = j;
|
||||||
|
// dw_printf ("*** Trying swapping %d bits starting at %d of %d ***\n", j,i, len);
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by swapping %d bits starting at %d of %d ***\n", j,i, len);
|
||||||
|
#endif
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DEBUG_LATER
|
||||||
|
tend = dtime_now();
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** No luck swapping many bits for len %d in %.3f sec.\n",len, tend-tstart);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fix_bits < RETRY_REMOVE_MANY) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Try to remove many contiguous bits */
|
||||||
|
retry_cfg.type = RETRY_TYPE_REMOVE;
|
||||||
|
retry_cfg.retry = RETRY_REMOVE_MANY;
|
||||||
|
#ifdef DEBUG_LATER
|
||||||
|
tstart = dtime_now();
|
||||||
|
dw_printf ("*** Trying removing many bits for len\n", len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
len = rrbb_get_len(block);
|
||||||
|
for (i=0; i<2; i++) {
|
||||||
|
for (j=1; j<len-i && j<len/2;j++) {
|
||||||
|
retry_cfg.u_bits.contig.bit_idx = i;
|
||||||
|
retry_cfg.u_bits.contig.nr_bits = j;
|
||||||
|
#ifdef DEBUG
|
||||||
|
dw_printf ("*** Trying removing %d bits starting at %d of %d ***\n", j,i, len);
|
||||||
|
#endif
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by removing %d bits starting at %d of %d ***\n", j,i, len);
|
||||||
|
#endif
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DEBUG_LATER
|
||||||
|
tend = dtime_now();
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** No luck removing many bits for len %d *** in %.3f sec.\n", len, tend-tstart);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fix_bits < RETRY_REMOVE_TWO_SEP) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to remove Two non-adjacent ("separated") single bits.
|
||||||
|
*/
|
||||||
|
retry_cfg.mode = RETRY_MODE_SEPARATED;
|
||||||
|
retry_cfg.type = RETRY_TYPE_REMOVE;
|
||||||
|
retry_cfg.retry = RETRY_REMOVE_TWO_SEP;
|
||||||
|
retry_cfg.u_bits.sep.bit_idx_c = -1;
|
||||||
|
|
||||||
|
#if DEBUG_LATER
|
||||||
|
tstart = dtime_now();
|
||||||
|
dw_printf ("*** Try removing TWO SEPARATED BITS %d bits\n", len);
|
||||||
|
#endif
|
||||||
|
len = rrbb_get_len(block);
|
||||||
|
for (i=0; i<len-2; i++) {
|
||||||
|
retry_cfg.u_bits.sep.bit_idx_a = i;
|
||||||
|
int j;
|
||||||
|
ok = 0;
|
||||||
|
for (j=i+2; j<len && j - i < MAX_RETRY_REMOVE_SEPARATED_BITS; j++) {
|
||||||
|
retry_cfg.u_bits.sep.bit_idx_b = j;
|
||||||
|
ok = try_decode (block, chan, subchan, alevel, retry_cfg);
|
||||||
|
if (ok) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
#if DEBUG_LATER
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** Success by removing TWO SEPARATED bits %d and %d of %d \n", i, j, len);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DEBUG_LATER
|
||||||
|
tend = dtime_now();
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("*** No luck removing TWO SEPARATED bits of %d *** %.3f sec.\n", len, tend-tstart);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* Check if the specified index of bit has been modified with the current type of configuration
|
||||||
|
* Provide a specific implementation for contiguous mode to optimize number of tests done in the loop */
|
||||||
|
inline static char is_contig_bit_modified(int bit_idx, retry_conf_t retry_conf) {
|
||||||
|
int cont_bit_idx = retry_conf.u_bits.contig.bit_idx;
|
||||||
|
int cont_nr_bits = retry_conf.u_bits.contig.nr_bits;
|
||||||
|
|
||||||
|
if (bit_idx >= cont_bit_idx && (bit_idx < cont_bit_idx + cont_nr_bits ))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Check if the specified index of bit has been modified with the current type of configuration in separated bit index mode
|
||||||
|
* Provide a specific implementation for separated mode to optimize number of tests done in the loop */
|
||||||
|
inline static char is_sep_bit_modified(int bit_idx, retry_conf_t retry_conf) {
|
||||||
|
if (bit_idx == retry_conf.u_bits.sep.bit_idx_a ||
|
||||||
|
bit_idx == retry_conf.u_bits.sep.bit_idx_b ||
|
||||||
|
bit_idx == retry_conf.u_bits.sep.bit_idx_c)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the bit value from a precalculated array to optimize access time in the loop */
|
||||||
|
inline static unsigned int get_bit (const rrbb_t b,const unsigned int ind)
|
||||||
|
{
|
||||||
|
return b->computed_data[ind];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_conf_t retry_conf)
|
||||||
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t bits_flipped, int flip_a, int flip_b, int flip_c)
|
|
||||||
{
|
{
|
||||||
struct hdlc_state_s H;
|
struct hdlc_state_s H;
|
||||||
int blen; /* Block length in bits. */
|
int blen; /* Block length in bits. */
|
||||||
int i;
|
int i;
|
||||||
int raw; /* From demodulator. */
|
unsigned int raw; /* From demodulator. */
|
||||||
int dbit; /* Data bit after undoing NRZI. */
|
int crc_failed = 1;
|
||||||
|
int retry_conf_mode = retry_conf.mode;
|
||||||
|
int retry_conf_type = retry_conf.type;
|
||||||
|
int retry_conf_retry = retry_conf.retry;
|
||||||
|
|
||||||
|
|
||||||
H.prev_raw = rrbb_get_bit (block, 0); /* Actually last bit of the */
|
H.prev_raw = get_bit (block, 0); /* Actually last bit of the */
|
||||||
/* opening flag so we can derive the */
|
/* opening flag so we can derive the */
|
||||||
/* first data bit. */
|
/* first data bit. */
|
||||||
|
|
||||||
|
@ -328,8 +669,8 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
/* This is the last bit of the "flag" pattern. */
|
/* This is the last bit of the "flag" pattern. */
|
||||||
/* If it was corrupted we wouldn't have detected */
|
/* If it was corrupted we wouldn't have detected */
|
||||||
/* the start of frame. */
|
/* the start of frame. */
|
||||||
|
if (retry_conf.mode == RETRY_MODE_CONTIGUOUS && is_contig_bit_modified(0, retry_conf) ||
|
||||||
if (0 == flip_a || 0 == flip_b || 0 == flip_c){
|
retry_conf.mode == RETRY_MODE_SEPARATED && is_sep_bit_modified(0, retry_conf)) {
|
||||||
H.prev_raw = ! H.prev_raw;
|
H.prev_raw = ! H.prev_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,90 +679,127 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
H.olen = 0;
|
H.olen = 0;
|
||||||
H.frame_len = 0;
|
H.frame_len = 0;
|
||||||
|
|
||||||
blen = rrbb_get_len (block);
|
blen = rrbb_get_len(block);
|
||||||
|
/* Prepare space for the inserted bits in contiguous mode (separated mode for insert is not supported yet) */
|
||||||
|
if (retry_conf.type == RETRY_TYPE_INSERT && retry_conf.mode == RETRY_MODE_CONTIGUOUS)
|
||||||
|
blen+=retry_conf.u_bits.contig.nr_bits;
|
||||||
|
|
||||||
#if DEBUGx
|
#if DEBUGx
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("try_decode: blen=%d\n", blen);
|
if (retry_conf.type == RETRY_TYPE_NONE)
|
||||||
|
dw_printf ("try_decode: blen=%d\n", blen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i=1; i<blen; i++) {
|
for (i=1; i<blen; i++) {
|
||||||
|
/* Get the value for the current bit */
|
||||||
raw = rrbb_get_bit (block, i);
|
raw = get_bit (block, i);
|
||||||
|
/* If swap two sep mode , swap the bit if needed */
|
||||||
if (i == flip_a || i == flip_b || i == flip_c){
|
if (retry_conf_retry == RETRY_SWAP_TWO_SEP) {
|
||||||
raw = ! raw;
|
if (is_sep_bit_modified(i, retry_conf))
|
||||||
|
raw = ! raw;
|
||||||
|
/* Else if remove two sep bits mode , remove the bit if needed */
|
||||||
|
} else if (retry_conf_retry == RETRY_REMOVE_TWO_SEP) {
|
||||||
|
if (is_sep_bit_modified(i, retry_conf))
|
||||||
|
//Remove (ignore) this bit from the buffer!
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
/* Else handle all the others contiguous modes */
|
||||||
|
else if (retry_conf_mode == RETRY_MODE_CONTIGUOUS) {
|
||||||
|
/* If contiguous remove, ignore this bit from the buffer */
|
||||||
|
if (retry_conf_type == RETRY_TYPE_REMOVE) {
|
||||||
|
if ( is_contig_bit_modified(i, retry_conf))
|
||||||
|
//Remove (ignore) this bit from the buffer!
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If insert bits mode */
|
||||||
|
else if (retry_conf_type == RETRY_TYPE_INSERT) {
|
||||||
|
int nr_bits = retry_conf.u_bits.contig.nr_bits;
|
||||||
|
int bit_idx = retry_conf.u_bits.contig.bit_idx;
|
||||||
|
/* If bit is after the index to insert, use the existing bit value (but shifted from the array) */
|
||||||
|
if (i >= bit_idx + nr_bits)
|
||||||
|
raw = get_bit (block, i-nr_bits);
|
||||||
|
/* Else if this is a bit to insert, calculate the value of the bit from insert_value */
|
||||||
|
else if (is_contig_bit_modified(i, retry_conf)) {
|
||||||
|
raw = (retry_conf.insert_value >> (i-bit_idx)) & 1;
|
||||||
|
/* dw_printf ("raw is %d for i %d bit_idx %d insert_value %d\n",
|
||||||
|
raw, i, bit_idx, retry_conf.insert_value);*/
|
||||||
|
/* Else use the original bit value from the buffer */
|
||||||
|
} else {
|
||||||
|
/* Already set before */
|
||||||
|
}
|
||||||
|
/* If in swap mode */
|
||||||
|
} else if (retry_conf_type == RETRY_TYPE_SWAP) {
|
||||||
|
/* If this is the bit to swap */
|
||||||
|
if (is_contig_bit_modified(i, retry_conf))
|
||||||
|
raw = ! raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Octets are sent LSB first.
|
||||||
|
* Shift the most recent 8 bits thru the pattern detector.
|
||||||
|
*/
|
||||||
|
H.pat_det >>= 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Using NRZI encoding,
|
* Using NRZI encoding,
|
||||||
* A '0' bit is represented by an inversion since previous bit.
|
* A '0' bit is represented by an inversion since previous bit.
|
||||||
* A '1' bit is represented by no change.
|
* A '1' bit is represented by no change.
|
||||||
|
* Note: this code can be factorized with the raw != H.prev_raw code at the cost of processing time
|
||||||
*/
|
*/
|
||||||
|
if (raw == H.prev_raw) {
|
||||||
dbit = (raw == H.prev_raw);
|
H.pat_det |= 0x80;
|
||||||
H.prev_raw = raw;
|
/* Valid data will never have 7 one bits in a row: exit. */
|
||||||
|
if (H.pat_det == 0xfe) {
|
||||||
/*
|
|
||||||
* Octets are sent LSB first.
|
|
||||||
* Shift the most recent 8 bits thru the pattern detector.
|
|
||||||
*/
|
|
||||||
H.pat_det >>= 1;
|
|
||||||
if (dbit) {
|
|
||||||
H.pat_det |= 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (H.pat_det == 0x7e) {
|
|
||||||
/* The special pattern 01111110 indicates beginning and ending of a frame. */
|
|
||||||
#if DEBUGx
|
#if DEBUGx
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("try_decode: found flag, i=%d\n", i);
|
dw_printf ("try_decode: found abort, i=%d\n", i);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else if (H.pat_det == 0xfe) {
|
H.oacc >>= 1;
|
||||||
/* Valid data will never have 7 one bits in a row. */
|
H.oacc |= 0x80;
|
||||||
|
} else {
|
||||||
|
H.prev_raw = raw;
|
||||||
|
/* The special pattern 01111110 indicates beginning and ending of a frame: exit. */
|
||||||
|
if (H.pat_det == 0x7e) {
|
||||||
#if DEBUGx
|
#if DEBUGx
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("try_decode: found abort, i=%d\n", i);
|
dw_printf ("try_decode: found flag, i=%d\n", i);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
else if ( (H.pat_det & 0xfc) == 0x7c ) {
|
|
||||||
/*
|
/*
|
||||||
* If we have five '1' bits in a row, followed by a '0' bit,
|
* If we have five '1' bits in a row, followed by a '0' bit,
|
||||||
*
|
*
|
||||||
* 0111110xx
|
* 011111xx
|
||||||
*
|
*
|
||||||
* the current '0' bit should be discarded because it was added for
|
* the current '0' bit should be discarded because it was added for
|
||||||
* "bit stuffing."
|
* "bit stuffing."
|
||||||
*/
|
*/
|
||||||
;
|
|
||||||
} else {
|
} else if ( (H.pat_det >> 2) == 0x1f ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
H.oacc >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In all other cases, accumulate bits into octets, and complete octets
|
* Now accumulate bits into octets, and complete octets
|
||||||
* into the frame buffer.
|
* into the frame buffer.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
H.oacc >>= 1;
|
|
||||||
if (dbit) {
|
|
||||||
H.oacc |= 0x80;
|
|
||||||
}
|
|
||||||
H.olen++;
|
H.olen++;
|
||||||
|
|
||||||
if (H.olen == 8) {
|
if (H.olen & 8) {
|
||||||
H.olen = 0;
|
H.olen = 0;
|
||||||
|
|
||||||
if (H.frame_len < MAX_FRAME_LEN) {
|
if (H.frame_len < MAX_FRAME_LEN) {
|
||||||
H.frame_buf[H.frame_len] = H.oacc;
|
H.frame_buf[H.frame_len] = H.oacc;
|
||||||
H.frame_len++;
|
H.frame_len++;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} /* end of loop on all bits in block */
|
||||||
|
|
||||||
} /* end of loop on all bits in block */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do we have a minimum number of complete bytes?
|
* Do we have a minimum number of complete bytes?
|
||||||
*/
|
*/
|
||||||
|
@ -436,6 +814,7 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
unsigned short actual_fcs, expected_fcs;
|
unsigned short actual_fcs, expected_fcs;
|
||||||
|
|
||||||
#if DEBUGx
|
#if DEBUGx
|
||||||
|
if (retry_conf.type == RETRY_TYPE_NONE) {
|
||||||
int j;
|
int j;
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("NEW WAY: frame len = %d\n", H.frame_len);
|
dw_printf ("NEW WAY: frame len = %d\n", H.frame_len);
|
||||||
|
@ -443,6 +822,8 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
dw_printf (" %02x", H.frame_buf[j]);
|
dw_printf (" %02x", H.frame_buf[j]);
|
||||||
}
|
}
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Check FCS, low byte first, and process... */
|
/* Check FCS, low byte first, and process... */
|
||||||
|
|
||||||
|
@ -457,7 +838,7 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
|
|
||||||
expected_fcs = fcs_calc (H.frame_buf, H.frame_len - 2);
|
expected_fcs = fcs_calc (H.frame_buf, H.frame_len - 2);
|
||||||
|
|
||||||
if (actual_fcs == expected_fcs && sanity_check (H.frame_buf, H.frame_len - 2, bits_flipped)) {
|
if (actual_fcs == expected_fcs && sanity_check (H.frame_buf, H.frame_len - 2, retry_conf.retry)) {
|
||||||
|
|
||||||
|
|
||||||
// TODO: Shouldn't be necessary to pass chan, subchan, alevel into
|
// TODO: Shouldn't be necessary to pass chan, subchan, alevel into
|
||||||
|
@ -468,10 +849,47 @@ static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_t
|
||||||
assert (rrbb_get_subchan(block) == subchan);
|
assert (rrbb_get_subchan(block) == subchan);
|
||||||
assert (rrbb_get_audio_level(block) == alevel);
|
assert (rrbb_get_audio_level(block) == alevel);
|
||||||
|
|
||||||
multi_modem_process_rec_frame (chan, subchan, H.frame_buf, H.frame_len - 2, alevel, bits_flipped); /* len-2 to remove FCS. */
|
multi_modem_process_rec_frame (chan, subchan, H.frame_buf, H.frame_len - 2, alevel, retry_conf.retry); /* len-2 to remove FCS. */
|
||||||
return 1; /* success */
|
return 1; /* success */
|
||||||
}
|
} else {
|
||||||
|
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
crc_failed = 0;
|
||||||
|
goto failure;
|
||||||
}
|
}
|
||||||
|
failure:
|
||||||
|
#if DEBUGx
|
||||||
|
if (retry_conf.type == RETRY_TYPE_NONE ) {
|
||||||
|
int j;
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
if (crc_failed)
|
||||||
|
dw_printf ("CRC failed\n");
|
||||||
|
if (H.olen != 0)
|
||||||
|
dw_printf ("Bad olen: %d \n", H.olen);
|
||||||
|
else if (H.frame_len < MIN_FRAME_LEN) {
|
||||||
|
dw_printf ("Frame too small\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dw_printf ("FAILURE with frame: frame len = %d\n", H.frame_len);
|
||||||
|
dw_printf ("\n");
|
||||||
|
for (j=0; j<H.frame_len; j++) {
|
||||||
|
dw_printf (" %02x", H.frame_buf[j]);
|
||||||
|
}
|
||||||
|
dw_printf ("\nDEC\n");
|
||||||
|
for (j=0; j<H.frame_len; j++) {
|
||||||
|
dw_printf ("%c", H.frame_buf[j]>>1);
|
||||||
|
}
|
||||||
|
dw_printf ("\nORIG\n");
|
||||||
|
for (j=0; j<H.frame_len; j++) {
|
||||||
|
dw_printf ("%c", H.frame_buf[j]);
|
||||||
|
}
|
||||||
|
dw_printf ("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
end:
|
||||||
return 0; /* failure. */
|
return 0; /* failure. */
|
||||||
|
|
||||||
} /* end try_decode */
|
} /* end try_decode */
|
||||||
|
@ -634,7 +1052,6 @@ static int sanity_check (unsigned char *buf, int blen, retry_t bits_flipped)
|
||||||
/* only use this to calculate elapsed time. */
|
/* only use this to calculate elapsed time. */
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
|
|
||||||
static double dtime_now (void)
|
static double dtime_now (void)
|
||||||
{
|
{
|
||||||
|
@ -658,4 +1075,3 @@ static double dtime_now (void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
64
hdlc_rec2.h
64
hdlc_rec2.h
|
@ -3,15 +3,59 @@
|
||||||
#define HDLC_REC2_H 1
|
#define HDLC_REC2_H 1
|
||||||
|
|
||||||
|
|
||||||
#include "rrbb.h"
|
|
||||||
#include "ax25_pad.h" /* for packet_t */
|
#include "ax25_pad.h" /* for packet_t */
|
||||||
|
#include "rrbb.h"
|
||||||
|
|
||||||
typedef enum retry_e {
|
typedef enum retry_e {
|
||||||
RETRY_NONE=0,
|
RETRY_NONE=0,
|
||||||
RETRY_SINGLE=1,
|
RETRY_SWAP_SINGLE=1,
|
||||||
RETRY_DOUBLE=2,
|
RETRY_SWAP_DOUBLE=2,
|
||||||
RETRY_TRIPLE=3,
|
RETRY_SWAP_TRIPLE=3,
|
||||||
RETRY_TWO_SEP=4 } retry_t;
|
RETRY_REMOVE_SINGLE=4,
|
||||||
|
RETRY_REMOVE_DOUBLE=5,
|
||||||
|
RETRY_REMOVE_TRIPLE=6,
|
||||||
|
RETRY_INSERT_SINGLE=7,
|
||||||
|
RETRY_INSERT_DOUBLE=8,
|
||||||
|
RETRY_SWAP_TWO_SEP=9,
|
||||||
|
RETRY_SWAP_MANY=10,
|
||||||
|
RETRY_REMOVE_MANY=11,
|
||||||
|
RETRY_REMOVE_TWO_SEP=12,
|
||||||
|
RETRY_MAX = 13} retry_t;
|
||||||
|
|
||||||
|
typedef enum retry_mode_e {
|
||||||
|
RETRY_MODE_CONTIGUOUS=0,
|
||||||
|
RETRY_MODE_SEPARATED=1,
|
||||||
|
} retry_mode_t;
|
||||||
|
|
||||||
|
typedef enum retry_type_e {
|
||||||
|
RETRY_TYPE_NONE=0,
|
||||||
|
RETRY_TYPE_SWAP=1,
|
||||||
|
RETRY_TYPE_REMOVE=2,
|
||||||
|
RETRY_TYPE_INSERT=3} retry_type_t;
|
||||||
|
|
||||||
|
typedef struct retry_conf_s {
|
||||||
|
retry_t retry;
|
||||||
|
retry_mode_t mode;
|
||||||
|
retry_type_t type;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
int bit_idx_a; /* */
|
||||||
|
int bit_idx_b; /* */
|
||||||
|
int bit_idx_c; /* */
|
||||||
|
} sep; /* RETRY_MODE_SEPARATED */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int bit_idx;
|
||||||
|
int nr_bits;
|
||||||
|
} contig; /* RETRY_MODE_CONTIGUOUS */
|
||||||
|
|
||||||
|
} u_bits;
|
||||||
|
int insert_value;
|
||||||
|
|
||||||
|
} retry_conf_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(DIREWOLF_C) || defined(ATEST_C) || defined(UDPTEST_C)
|
#if defined(DIREWOLF_C) || defined(ATEST_C) || defined(UDPTEST_C)
|
||||||
|
|
||||||
|
@ -20,7 +64,15 @@ static const char * retry_text[] = {
|
||||||
"SINGLE",
|
"SINGLE",
|
||||||
"DOUBLE",
|
"DOUBLE",
|
||||||
"TRIPLE",
|
"TRIPLE",
|
||||||
"TWO_SEP" };
|
"REMOVE_SINGLE",
|
||||||
|
"REMOVE_DOUBLE",
|
||||||
|
"REMOVE_TRIPLE",
|
||||||
|
"INSERT_SINGLE",
|
||||||
|
"INSERT_DOUBLE",
|
||||||
|
"TWO_SEP",
|
||||||
|
"MANY",
|
||||||
|
"REMOVE_MANY",
|
||||||
|
"REMOVE_SEP"};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void hdlc_rec2_block (rrbb_t block, retry_t fix_bits);
|
void hdlc_rec2_block (rrbb_t block, retry_t fix_bits);
|
||||||
|
|
207
kiss.c
207
kiss.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011,2013 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -129,8 +129,12 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
#include <errno.h>
|
||||||
|
#else
|
||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -164,14 +168,16 @@ static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */
|
||||||
|
|
||||||
static MYFDTYPE pt_master_fd = MYFDERROR; /* File descriptor for my end. */
|
static MYFDTYPE pt_master_fd = MYFDERROR; /* File descriptor for my end. */
|
||||||
|
|
||||||
static MYFDTYPE pt_slave_fd = MYFDERROR; /* File descriptor for pseudo terminal */
|
static char pt_slave_name[32]; /* Pseudo terminal slave name */
|
||||||
/* for use by application. */
|
/* like /dev/pts/999 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Symlink to pseudo terminal name which changes.
|
* Symlink to pseudo terminal name which changes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEV_KISS_TNC "/tmp/kisstnc"
|
#define TMP_KISSTNC_SYMLINK "/tmp/kisstnc"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -186,9 +192,14 @@ static MYFDTYPE nullmodem_fd = MYFDERROR;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: define in one place, use everywhere.
|
||||||
|
#if __WIN32__
|
||||||
|
#define THREAD_F unsigned __stdcall
|
||||||
|
#else
|
||||||
|
#define THREAD_F void *
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static THREAD_F kiss_listen_thread (void *arg);
|
||||||
static void * kiss_listen_thread (void *arg);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -262,7 +273,7 @@ void kiss_init (struct misc_config_s *mc)
|
||||||
pt_master_fd = kiss_open_pt ();
|
pt_master_fd = kiss_open_pt ();
|
||||||
|
|
||||||
if (pt_master_fd != MYFDERROR) {
|
if (pt_master_fd != MYFDERROR) {
|
||||||
e = pthread_create (&kiss_pterm_listen_tid, (pthread_attr_t*)NULL, kiss_listen_thread, (void*)(long)pt_master_fd);
|
e = pthread_create (&kiss_pterm_listen_tid, (pthread_attr_t*)NULL, kiss_listen_thread, NULL);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror("Could not create kiss listening thread for Linux pseudo terminal");
|
perror("Could not create kiss listening thread for Linux pseudo terminal");
|
||||||
|
@ -300,14 +311,14 @@ void kiss_init (struct misc_config_s *mc)
|
||||||
|
|
||||||
if (nullmodem_fd != MYFDERROR) {
|
if (nullmodem_fd != MYFDERROR) {
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
kiss_nullmodem_listen_th = _beginthreadex (NULL, 0, kiss_listen_thread, (void*)(long)nullmodem_fd, 0, NULL);
|
kiss_nullmodem_listen_th = (HANDLE)_beginthreadex (NULL, 0, kiss_listen_thread, NULL, 0, NULL);
|
||||||
if (kiss_nullmodem_listen_th == NULL) {
|
if (kiss_nullmodem_listen_th == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create kiss nullmodem thread\n");
|
dw_printf ("Could not create kiss nullmodem thread\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
e = pthread_create (&kiss_nullmodem_listen_tid, NULL, kiss_listen_thread, (void*)(long)nullmodem_fd);
|
e = pthread_create (&kiss_nullmodem_listen_tid, NULL, kiss_listen_thread, NULL);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror("Could not create kiss listening thread for Windows virtual COM port.");
|
perror("Could not create kiss listening thread for Windows virtual COM port.");
|
||||||
|
@ -341,7 +352,7 @@ void kiss_init (struct misc_config_s *mc)
|
||||||
static MYFDTYPE kiss_open_pt (void)
|
static MYFDTYPE kiss_open_pt (void)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
char *slave_device;
|
char *pts;
|
||||||
struct termios ts;
|
struct termios ts;
|
||||||
int e;
|
int e;
|
||||||
//int flags;
|
//int flags;
|
||||||
|
@ -357,12 +368,13 @@ static MYFDTYPE kiss_open_pt (void)
|
||||||
if (fd == MYFDERROR
|
if (fd == MYFDERROR
|
||||||
|| grantpt (fd) == MYFDERROR
|
|| grantpt (fd) == MYFDERROR
|
||||||
|| unlockpt (fd) == MYFDERROR
|
|| unlockpt (fd) == MYFDERROR
|
||||||
|| (slave_device = ptsname (fd)) == NULL) {
|
|| (pts = ptsname (fd)) == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("ERROR - Could not create pseudo terminal for KISS TNC.\n");
|
dw_printf ("ERROR - Could not create pseudo terminal for KISS TNC.\n");
|
||||||
return (MYFDERROR);
|
return (MYFDERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strcpy (pt_slave_name, pts);
|
||||||
|
|
||||||
e = tcgetattr (fd, &ts);
|
e = tcgetattr (fd, &ts);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
|
@ -416,9 +428,29 @@ static MYFDTYPE kiss_open_pt (void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("Virtual KISS TNC is available on %s\n", slave_device);
|
dw_printf("Virtual KISS TNC is available on %s\n", pt_slave_name);
|
||||||
dw_printf("WARNING - Dire Wolf will hang eventually if nothing is reading from it.\n");
|
dw_printf("WARNING - Dire Wolf will hang eventually if nothing is reading from it.\n");
|
||||||
|
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
// Sample code shows this. Why would we open it here?
|
||||||
|
// On Ubuntu, the slave side disappears after a few
|
||||||
|
// seconds if no one opens it. Same on Raspian which
|
||||||
|
// is also based on Debian.
|
||||||
|
// Need to revisit this.
|
||||||
|
|
||||||
|
MYFDTYPE pt_slave_fd;
|
||||||
|
|
||||||
|
pt_slave_fd = open(pt_slave_name, O_RDWR|O_NOCTTY);
|
||||||
|
|
||||||
|
if (pt_slave_fd < 0) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Can't open %s\n", pt_slave_name);
|
||||||
|
perror ("");
|
||||||
|
return MYFDERROR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The device name is not the same every time.
|
* The device name is not the same every time.
|
||||||
* This is inconvenient for the application because it might
|
* This is inconvenient for the application because it might
|
||||||
|
@ -427,31 +459,21 @@ static MYFDTYPE kiss_open_pt (void)
|
||||||
* does not need to change when the pseudo terminal name changes.
|
* does not need to change when the pseudo terminal name changes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//TODO: remove symlink on exit.
|
unlink (TMP_KISSTNC_SYMLINK);
|
||||||
unlink (DEV_KISS_TNC);
|
|
||||||
|
|
||||||
if (symlink (slave_device, DEV_KISS_TNC) == 0) {
|
|
||||||
dw_printf ("Created symlink %s -> %s\n", DEV_KISS_TNC, slave_device);
|
// TODO: Is this removed when application exits?
|
||||||
|
|
||||||
|
if (symlink (pt_slave_name, TMP_KISSTNC_SYMLINK) == 0) {
|
||||||
|
dw_printf ("Created symlink %s -> %s\n", TMP_KISSTNC_SYMLINK, pt_slave_name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Failed to create symlink %s\n", DEV_KISS_TNC);
|
dw_printf ("Failed to create symlink %s\n", TMP_KISSTNC_SYMLINK);
|
||||||
perror ("");
|
perror ("");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
|
||||||
// Sample code shows this. Why would we open it here?
|
|
||||||
// On Ubuntu, the slave side disappears after a few
|
|
||||||
// seconds if no one opens it.
|
|
||||||
|
|
||||||
pt_slave_fd = open(slave_device, O_RDWR|O_NOCTTY);
|
|
||||||
|
|
||||||
if (pt_slave_fd < 0)
|
|
||||||
return MYFDERROR;
|
|
||||||
#endif
|
|
||||||
return (fd);
|
return (fd);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -470,8 +492,8 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
||||||
|
|
||||||
MYFDTYPE fd;
|
MYFDTYPE fd;
|
||||||
DCB dcb;
|
DCB dcb;
|
||||||
int ok;
|
int ok;
|
||||||
|
char bettername[50];
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
@ -487,8 +509,20 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
||||||
|
|
||||||
// Read http://support.microsoft.com/kb/156932
|
// Read http://support.microsoft.com/kb/156932
|
||||||
|
|
||||||
|
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
|
||||||
|
// http://support.microsoft.com/kb/115831
|
||||||
|
|
||||||
fd = CreateFile(devicename, GENERIC_READ | GENERIC_WRITE,
|
strcpy (bettername, devicename);
|
||||||
|
if (strncasecmp(devicename, "COM", 3) == 0) {
|
||||||
|
int n;
|
||||||
|
n = atoi(devicename+3);
|
||||||
|
if (n >= 10) {
|
||||||
|
strcpy (bettername, "\\\\.\\");
|
||||||
|
strcat (bettername, devicename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = CreateFile(bettername, GENERIC_READ | GENERIC_WRITE,
|
||||||
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||||
|
|
||||||
if (fd == MYFDERROR) {
|
if (fd == MYFDERROR) {
|
||||||
|
@ -510,7 +544,8 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
||||||
|
|
||||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx */
|
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx */
|
||||||
|
|
||||||
// dcb.BaudRate ? shouldn't matter
|
dcb.DCBlength = sizeof(DCB);
|
||||||
|
dcb.BaudRate = CBR_9600; // shouldn't matter
|
||||||
dcb.fBinary = 1;
|
dcb.fBinary = 1;
|
||||||
dcb.fParity = 0;
|
dcb.fParity = 0;
|
||||||
dcb.fOutxCtsFlow = 0;
|
dcb.fOutxCtsFlow = 0;
|
||||||
|
@ -609,7 +644,7 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
||||||
|
|
||||||
void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
||||||
{
|
{
|
||||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
||||||
int kiss_len;
|
int kiss_len;
|
||||||
int j;
|
int j;
|
||||||
int err;
|
int err;
|
||||||
|
@ -637,31 +672,28 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
kiss_len = 0;
|
|
||||||
kiss_buff[kiss_len++] = FEND;
|
|
||||||
kiss_buff[kiss_len++] = chan << 4;
|
|
||||||
|
|
||||||
for (j=0; j<flen; j++) {
|
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
|
||||||
|
|
||||||
|
assert (flen < sizeof(stemp));
|
||||||
|
|
||||||
if (fbuf[j] == FEND) {
|
stemp[0] = (chan << 4) + 0;
|
||||||
kiss_buff[kiss_len++] = FESC;
|
memcpy (stemp+1, fbuf, flen);
|
||||||
kiss_buff[kiss_len++] = TFEND;
|
|
||||||
}
|
if (kiss_debug >= 2) {
|
||||||
else if (fbuf[j] == FESC) {
|
/* AX.25 frame with the CRC removed. */
|
||||||
kiss_buff[kiss_len++] = FESC;
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
kiss_buff[kiss_len++] = TFESC;
|
dw_printf ("\n");
|
||||||
}
|
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
||||||
else {
|
hex_dump ((char*)fbuf, flen);
|
||||||
kiss_buff[kiss_len++] = fbuf[j];
|
|
||||||
}
|
|
||||||
assert (kiss_len < sizeof (kiss_buff));
|
|
||||||
}
|
}
|
||||||
kiss_buff[kiss_len++] = FEND;
|
|
||||||
|
|
||||||
/* This has the escapes but not the surrounding FENDs. */
|
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
||||||
|
|
||||||
|
/* This has KISS framing and escapes for sending to client app. */
|
||||||
|
|
||||||
if (kiss_debug) {
|
if (kiss_debug) {
|
||||||
kiss_debug_print (TO_CLIENT, NULL, kiss_buff+1, kiss_len-2);
|
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -732,7 +764,7 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
||||||
//nullmodem_fd = MYFDERROR;
|
//nullmodem_fd = MYFDERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (nwritten != flen)
|
else if (nwritten != kiss_len)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError sending KISS message to client application thru null modem. Only %d of %d written.\n\n", (int)nwritten, kiss_len);
|
dw_printf ("\nError sending KISS message to client application thru null modem. Only %d of %d written.\n\n", (int)nwritten, kiss_len);
|
||||||
|
@ -770,22 +802,16 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
||||||
*
|
*
|
||||||
* Purpose: Wait for messages from an application.
|
* Purpose: Wait for messages from an application.
|
||||||
*
|
*
|
||||||
* Inputs: arg - File descriptor for reading.
|
* Global In: nullmodem_fd or pt_master_fd
|
||||||
*
|
|
||||||
* Outputs: pt_slave_fd - File descriptor for communicating with client app.
|
|
||||||
*
|
*
|
||||||
* Description: Process messages from the client application.
|
* Description: Process messages from the client application.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
//TODO: should pass fd by reference so it can be zapped.
|
|
||||||
//BUG: If we close it here, that fact doesn't get back
|
|
||||||
// to the main receiving thread.
|
|
||||||
|
|
||||||
/* Return one byte (value 0 - 255) or terminate thread on error. */
|
/* Return one byte (value 0 - 255) or terminate thread on error. */
|
||||||
|
|
||||||
|
|
||||||
static int kiss_get (MYFDTYPE fd)
|
static int kiss_get (/* MYFDTYPE fd*/ void )
|
||||||
{
|
{
|
||||||
unsigned char ch;
|
unsigned char ch;
|
||||||
|
|
||||||
|
@ -808,7 +834,7 @@ static int kiss_get (MYFDTYPE fd)
|
||||||
|
|
||||||
while (n == 0) {
|
while (n == 0) {
|
||||||
|
|
||||||
if ( ! ReadFile (fd, &ch, 1, &n, &ov_rd))
|
if ( ! ReadFile (nullmodem_fd, &ch, 1, &n, &ov_rd))
|
||||||
{
|
{
|
||||||
int err1 = GetLastError();
|
int err1 = GetLastError();
|
||||||
|
|
||||||
|
@ -818,7 +844,7 @@ static int kiss_get (MYFDTYPE fd)
|
||||||
|
|
||||||
if (WaitForSingleObject (ov_rd.hEvent, INFINITE) == WAIT_OBJECT_0)
|
if (WaitForSingleObject (ov_rd.hEvent, INFINITE) == WAIT_OBJECT_0)
|
||||||
{
|
{
|
||||||
if ( ! GetOverlappedResult (fd, &ov_rd, &n, 1))
|
if ( ! GetOverlappedResult (nullmodem_fd, &ov_rd, &n, 1))
|
||||||
{
|
{
|
||||||
int err3 = GetLastError();
|
int err3 = GetLastError();
|
||||||
|
|
||||||
|
@ -835,8 +861,8 @@ static int kiss_get (MYFDTYPE fd)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nKISS ReadFile error %d. Closing connection.\n\n", err1);
|
dw_printf ("\nKISS ReadFile error %d. Closing connection.\n\n", err1);
|
||||||
//CloseHandle (fd);
|
CloseHandle (nullmodem_fd);
|
||||||
//fd = MYFDERROR;
|
nullmodem_fd = MYFDERROR;
|
||||||
//pthread_exit (NULL);
|
//pthread_exit (NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -857,18 +883,32 @@ static int kiss_get (MYFDTYPE fd)
|
||||||
|
|
||||||
#else /* Linux/Cygwin version */
|
#else /* Linux/Cygwin version */
|
||||||
|
|
||||||
int n;
|
int n = 0;
|
||||||
|
|
||||||
n = read(fd, &ch, (size_t)1);
|
while ( n == 0 ) {
|
||||||
|
|
||||||
if (n != 1) {
|
n = read(pt_master_fd, &ch, (size_t)1);
|
||||||
//text_color_set(DW_COLOR_ERROR);
|
|
||||||
//dw_printf ("\nError receiving kiss message from client application. Closing connection %d.\n\n", fd);
|
|
||||||
|
|
||||||
close (fd);
|
if (n != 1) {
|
||||||
|
|
||||||
fd = MYFDERROR;
|
text_color_set(DW_COLOR_ERROR);
|
||||||
pthread_exit (NULL);
|
dw_printf ("\nError receiving kiss message from client application. Closing %s.\n\n", pt_slave_name);
|
||||||
|
perror ("");
|
||||||
|
|
||||||
|
/* Message added between 1.1 beta test and final version 1.1 */
|
||||||
|
|
||||||
|
/* TODO: Determine root cause and find proper solution. */
|
||||||
|
|
||||||
|
dw_printf ("This is a known problem that sometimes shows up when using with kissattach.\n");
|
||||||
|
dw_printf ("There are a couple work-arounds described in the Dire Wolf User Guide\n");
|
||||||
|
dw_printf ("and the Raspberry Pi APRS documents.\n");
|
||||||
|
|
||||||
|
close (pt_master_fd);
|
||||||
|
|
||||||
|
pt_master_fd = MYFDERROR;
|
||||||
|
unlink (TMP_KISSTNC_SYMLINK);
|
||||||
|
pthread_exit (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -897,10 +937,8 @@ static int kiss_get (MYFDTYPE fd)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void * kiss_listen_thread (void *arg)
|
static THREAD_F kiss_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
MYFDTYPE fd = (MYFDTYPE)(long)arg;
|
|
||||||
|
|
||||||
unsigned char ch;
|
unsigned char ch;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -910,14 +948,15 @@ static void * kiss_listen_thread (void *arg)
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = kiss_get(fd);
|
ch = kiss_get();
|
||||||
|
kiss_rec_byte (&kf, ch, kiss_debug, kiss_send_rec_packet);
|
||||||
|
}
|
||||||
|
|
||||||
if (kiss_frame (&kf, ch, kiss_debug, kiss_send_rec_packet)) {
|
#if __WIN32__
|
||||||
kiss_process_msg (&kf, kiss_debug);
|
return(0);
|
||||||
}
|
#else
|
||||||
} /* while (1) */
|
return; /* Unreachable but avoids compiler warning. */
|
||||||
|
#endif
|
||||||
return (NULL); /* Unreachable but avoids compiler warning. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end kiss.c */
|
/* end kiss.c */
|
||||||
|
|
400
kiss_frame.c
400
kiss_frame.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 John Langner, WB2OSZ
|
// Copyright (C) 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -84,13 +84,181 @@
|
||||||
#include "tq.h"
|
#include "tq.h"
|
||||||
#include "xmit.h"
|
#include "xmit.h"
|
||||||
|
|
||||||
|
/* In server.c. Should probably move to some misc. function file. */
|
||||||
|
void hex_dump (unsigned char *p, int len);
|
||||||
|
|
||||||
|
|
||||||
|
static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug);
|
||||||
|
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
|
||||||
|
#define dw_printf printf
|
||||||
|
|
||||||
|
void text_color_set (dw_color_t c)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: kiss_frame
|
* Name: kiss_encapsulate
|
||||||
*
|
*
|
||||||
* Purpose: Extract a KISS frame from byte stream.
|
* Purpose: Ecapsulate a frame into KISS format.
|
||||||
|
*
|
||||||
|
* Inputs: in - Address of input block.
|
||||||
|
* First byte is the "type indicator" with type and
|
||||||
|
* channel but we don't care about that here.
|
||||||
|
* Note that this is "binary" data and can contain
|
||||||
|
* nul (0x00) values. Don't treat it like a text string!
|
||||||
|
*
|
||||||
|
* ilen - Number of bytes in input block.
|
||||||
|
*
|
||||||
|
* Outputs: out - Address where to place the KISS encoded representation.
|
||||||
|
* The sequence is:
|
||||||
|
* FEND - Magic frame separator.
|
||||||
|
* data - with certain byte values replaced so
|
||||||
|
* FEND will never occur here.
|
||||||
|
* FEND - Magic frame separator.
|
||||||
|
*
|
||||||
|
* Returns: Number of bytes in the output.
|
||||||
|
* Absolute max length will be twice input plus 2.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
int kiss_encapsulate (unsigned char *in, int ilen, unsigned char *out)
|
||||||
|
{
|
||||||
|
int olen;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
olen = 0;
|
||||||
|
out[olen++] = FEND;
|
||||||
|
for (j=0; j<ilen; j++) {
|
||||||
|
|
||||||
|
if (in[j] == FEND) {
|
||||||
|
out[olen++] = FESC;
|
||||||
|
out[olen++] = TFEND;
|
||||||
|
}
|
||||||
|
else if (in[j] == FESC) {
|
||||||
|
out[olen++] = FESC;
|
||||||
|
out[olen++] = TFESC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out[olen++] = in[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out[olen++] = FEND;
|
||||||
|
|
||||||
|
return (olen);
|
||||||
|
|
||||||
|
} /* end kiss_encapsulate */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: kiss_unwrap
|
||||||
|
*
|
||||||
|
* Purpose: Extract original data from a KISS frame.
|
||||||
|
*
|
||||||
|
* Inputs: in - Address of the received the KISS encoded representation.
|
||||||
|
* The sequence is:
|
||||||
|
* FEND - Magic frame separator, optional.
|
||||||
|
* data - with certain byte values replaced so
|
||||||
|
* FEND will never occur here.
|
||||||
|
* FEND - Magic frame separator.
|
||||||
|
* ilen - Number of bytes in input block.
|
||||||
|
*
|
||||||
|
* Inputs: out - Where to put the resulting frame without
|
||||||
|
* the escapes or FEND.
|
||||||
|
* First byte is the "type indicator" with type and
|
||||||
|
* channel but we don't care about that here.
|
||||||
|
* Note that this is "binary" data and can contain
|
||||||
|
* nul (0x00) values. Don't treat it like a text string!
|
||||||
|
*
|
||||||
|
* Returns: Number of bytes in the output.
|
||||||
|
*
|
||||||
|
*-----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static int kiss_unwrap (unsigned char *in, int ilen, unsigned char *out)
|
||||||
|
{
|
||||||
|
int olen;
|
||||||
|
int j;
|
||||||
|
int escaped_mode;
|
||||||
|
|
||||||
|
olen = 0;
|
||||||
|
escaped_mode = 0;
|
||||||
|
|
||||||
|
if (ilen < 2) {
|
||||||
|
/* Need at least the "type indicator" byte and FEND. */
|
||||||
|
/* Probably more. */
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("KISS message less than minimum length.\n");
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in[ilen-1] == FEND) {
|
||||||
|
ilen--; /* Don't try to process below. */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("KISS frame should end with FEND.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in[0] == FEND) {
|
||||||
|
j = 1; /* skip over optional leading FEND. */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( ; j<ilen; j++) {
|
||||||
|
|
||||||
|
if (in[j] == FEND) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("KISS frame should not have FEND in the middle.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escaped_mode) {
|
||||||
|
|
||||||
|
if (in[j] == TFESC) {
|
||||||
|
out[olen++] = FESC;
|
||||||
|
}
|
||||||
|
else if (in[j] == TFEND) {
|
||||||
|
out[olen++] = FEND;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("KISS protocol error. Found 0x%02x after FESC.\n", in[j]);
|
||||||
|
}
|
||||||
|
escaped_mode = 0;
|
||||||
|
}
|
||||||
|
else if (in[j] == FESC) {
|
||||||
|
escaped_mode = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out[olen++] = in[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (olen);
|
||||||
|
|
||||||
|
} /* end kiss_unwrap */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TEST
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: kiss_rec_byte
|
||||||
|
*
|
||||||
|
* Purpose: Process one byte from a KISS client app.
|
||||||
*
|
*
|
||||||
* Inputs: kf - Current state of building a frame.
|
* Inputs: kf - Current state of building a frame.
|
||||||
* ch - A byte from the input stream.
|
* ch - A byte from the input stream.
|
||||||
|
@ -100,10 +268,8 @@
|
||||||
* Outputs: kf - Current state is updated.
|
* Outputs: kf - Current state is updated.
|
||||||
*
|
*
|
||||||
* Returns: TRUE when a complete frame is ready for processing.
|
* Returns: TRUE when a complete frame is ready for processing.
|
||||||
|
// TODO: void later
|
||||||
*
|
*
|
||||||
* Bug: For send, the debug output shows exactly what is
|
|
||||||
* being sent including the surrounding FEND and any
|
|
||||||
* escapes. For receive, we don't show those.
|
|
||||||
*
|
*
|
||||||
*-----------------------------------------------------------------*/
|
*-----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -131,12 +297,18 @@
|
||||||
* Let's try to keep it happy by sending back a command prompt.
|
* Let's try to keep it happy by sending back a command prompt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int))
|
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
switch (kf->state) {
|
switch (kf->state) {
|
||||||
|
|
||||||
case KS_SEARCHING: /* Searching for starting FEND. */
|
case KS_SEARCHING: /* Searching for starting FEND. */
|
||||||
|
default:
|
||||||
|
|
||||||
if (ch == FEND) {
|
if (ch == FEND) {
|
||||||
|
|
||||||
|
@ -150,8 +322,9 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
||||||
}
|
}
|
||||||
|
|
||||||
kf->kiss_len = 0;
|
kf->kiss_len = 0;
|
||||||
|
kf->kiss_msg[kf->kiss_len++] = ch;
|
||||||
kf->state = KS_COLLECTING;
|
kf->state = KS_COLLECTING;
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Noise to be rejected. */
|
/* Noise to be rejected. */
|
||||||
|
@ -165,7 +338,7 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
||||||
kf->noise[kf->noise_len] = '\0';
|
kf->noise[kf->noise_len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to appease it by sending something back. */
|
/* Try to appease client app by sending something back. */
|
||||||
if (strcasecmp("restart\r", (char*)(kf->noise)) == 0 ||
|
if (strcasecmp("restart\r", (char*)(kf->noise)) == 0 ||
|
||||||
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
|
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
|
||||||
(*sendfun) (0, (unsigned char *)"\xc0\xc0", -1);
|
(*sendfun) (0, (unsigned char *)"\xc0\xc0", -1);
|
||||||
|
@ -175,24 +348,51 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
||||||
}
|
}
|
||||||
kf->noise_len = 0;
|
kf->noise_len = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
case KS_COLLECTING: /* Frame collection in progress. */
|
case KS_COLLECTING: /* Frame collection in progress. */
|
||||||
|
|
||||||
|
|
||||||
if (ch == FEND) {
|
if (ch == FEND) {
|
||||||
|
|
||||||
|
unsigned char unwrapped[AX25_MAX_PACKET_LEN];
|
||||||
|
int ulen;
|
||||||
|
|
||||||
/* End of frame. */
|
/* End of frame. */
|
||||||
|
|
||||||
if (kf->kiss_len == 0) {
|
if (kf->kiss_len == 0) {
|
||||||
|
/* Empty frame. Starting a new one. */
|
||||||
|
kf->kiss_msg[kf->kiss_len++] = ch;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (kf->kiss_len == 1 && kf->kiss_msg[0] == FEND) {
|
||||||
/* Empty frame. Just go on collecting. */
|
/* Empty frame. Just go on collecting. */
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kf->kiss_msg[kf->kiss_len++] = ch;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
|
/* As received over the wire from client app. */
|
||||||
kiss_debug_print (FROM_CLIENT, NULL, kf->kiss_msg, kf->kiss_len);
|
kiss_debug_print (FROM_CLIENT, NULL, kf->kiss_msg, kf->kiss_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulen = kiss_unwrap (kf->kiss_msg, kf->kiss_len, unwrapped);
|
||||||
|
|
||||||
|
if (debug >= 2) {
|
||||||
|
/* Append CRC to this and it goes out over the radio. */
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("\n");
|
||||||
|
dw_printf ("Packet content after removing KISS framing and any escapes:\n");
|
||||||
|
/* Don't include the "type" indicator. */
|
||||||
|
/* It contains the radio channel and type should always be 0 here. */
|
||||||
|
hex_dump (unwrapped+1, ulen-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
kiss_process_msg (unwrapped, ulen, debug);
|
||||||
|
|
||||||
kf->state = KS_SEARCHING;
|
kf->state = KS_SEARCHING;
|
||||||
return 1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kf->kiss_len < MAX_KISS_LEN) {
|
if (kf->kiss_len < MAX_KISS_LEN) {
|
||||||
|
@ -202,58 +402,40 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("KISS message exceeded maximum length.\n");
|
dw_printf ("KISS message exceeded maximum length.\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return;
|
||||||
|
break;
|
||||||
case KS_ESCAPE: /* Expecting TFESC or TFEND. */
|
|
||||||
|
|
||||||
if (kf->kiss_len >= MAX_KISS_LEN) {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("KISS message exceeded maximum length.\n");
|
|
||||||
kf->state = KS_COLLECTING;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == TFESC) {
|
|
||||||
kf->kiss_msg[kf->kiss_len++] = FESC;
|
|
||||||
}
|
|
||||||
else if (ch == TFEND) {
|
|
||||||
kf->kiss_msg[kf->kiss_len++] = FEND;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
|
||||||
dw_printf ("KISS protocol error. TFESC or TFEND expected.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
kf->state = KS_COLLECTING;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0; /* unreachable but suppress compiler warning. */
|
return; /* unreachable but suppress compiler warning. */
|
||||||
|
|
||||||
} /* end kiss_frame */
|
} /* end kiss_rec_byte */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: kiss_process_msg
|
* Name: kiss_process_msg
|
||||||
*
|
*
|
||||||
* Purpose: Process a message from the KISS client.
|
* Purpose: Process a message from the KISS client.
|
||||||
*
|
*
|
||||||
* Inputs: kf - Current state of building a frame.
|
* Inputs: kiss_msg - Kiss frame with FEND and escapes removed.
|
||||||
* Should be complete.
|
* The first byte contains channel and command.
|
||||||
|
*
|
||||||
|
* kiss_len - Number of bytes including the command.
|
||||||
*
|
*
|
||||||
* debug - Debug option is selected.
|
* debug - Debug option is selected.
|
||||||
*
|
*
|
||||||
*-----------------------------------------------------------------*/
|
*-----------------------------------------------------------------*/
|
||||||
|
|
||||||
void kiss_process_msg (kiss_frame_t *kf, int debug)
|
static void kiss_process_msg (unsigned char *kiss_msg, int kiss_len, int debug)
|
||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
int cmd;
|
int cmd;
|
||||||
packet_t pp;
|
packet_t pp;
|
||||||
|
|
||||||
port = (kf->kiss_msg[0] >> 4) & 0xf;
|
port = (kiss_msg[0] >> 4) & 0xf;
|
||||||
cmd = kf->kiss_msg[0] & 0xf;
|
cmd = kiss_msg[0] & 0xf;
|
||||||
|
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
|
@ -262,12 +444,12 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
||||||
/* Special hack - Discard apparently bad data from Linux AX25. */
|
/* Special hack - Discard apparently bad data from Linux AX25. */
|
||||||
|
|
||||||
if ((port == 2 || port == 8) &&
|
if ((port == 2 || port == 8) &&
|
||||||
kf->kiss_msg[1] == 'Q' << 1 &&
|
kiss_msg[1] == 'Q' << 1 &&
|
||||||
kf->kiss_msg[2] == 'S' << 1 &&
|
kiss_msg[2] == 'S' << 1 &&
|
||||||
kf->kiss_msg[3] == 'T' << 1 &&
|
kiss_msg[3] == 'T' << 1 &&
|
||||||
kf->kiss_msg[4] == ' ' << 1 &&
|
kiss_msg[4] == ' ' << 1 &&
|
||||||
kf->kiss_msg[15] == 3 &&
|
kiss_msg[15] == 3 &&
|
||||||
kf->kiss_msg[16] == 0xcd) {
|
kiss_msg[16] == 0xcd) {
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -275,62 +457,71 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should really check if single or dual channel mode.
|
||||||
|
// Do more thoroughly in 1.2.
|
||||||
|
|
||||||
|
if (port != 0 && port != 1) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Invalid channel %d from KISS client app.\n", port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pp = ax25_from_frame (kf->kiss_msg+1, kf->kiss_len-1, -1);
|
pp = ax25_from_frame (kiss_msg+1, kiss_len-1, -1);
|
||||||
if (pp == NULL) {
|
if (pp == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("ERROR - Invalid KISS data frame from client app.\n");
|
dw_printf ("ERROR - Invalid KISS data frame from client app.\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
/* How can we determine if it is an original or repeated message? */
|
/* How can we determine if it is an original or repeated message? */
|
||||||
/* If there is at least one digipeater in the frame, AND */
|
/* If there is at least one digipeater in the frame, AND */
|
||||||
/* that digipeater has been used, it should go out quickly thru */
|
/* that digipeater has been used, it should go out quickly thru */
|
||||||
/* the high priority queue. */
|
/* the high priority queue. */
|
||||||
/* Otherwise, it is an original for the low priority queue. */
|
/* Otherwise, it is an original for the low priority queue. */
|
||||||
|
|
||||||
if (ax25_get_num_repeaters(pp) >= 1 &&
|
if (ax25_get_num_repeaters(pp) >= 1 &&
|
||||||
ax25_get_h(pp,AX25_REPEATER_1)) {
|
ax25_get_h(pp,AX25_REPEATER_1)) {
|
||||||
tq_append (port, TQ_PRIO_0_HI, pp);
|
tq_append (port, TQ_PRIO_0_HI, pp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tq_append (port, TQ_PRIO_1_LO, pp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
break;
|
||||||
tq_append (port, TQ_PRIO_1_LO, pp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1: /* TXDELAY */
|
case 1: /* TXDELAY */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set TXDELAY = %d, port %d\n", kf->kiss_msg[1], port);
|
dw_printf ("KISS protocol set TXDELAY = %d, port %d\n", kiss_msg[1], port);
|
||||||
xmit_set_txdelay (port, kf->kiss_msg[1]);
|
xmit_set_txdelay (port, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: /* Persistence */
|
case 2: /* Persistence */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set Persistence = %d, port %d\n", kf->kiss_msg[1], port);
|
dw_printf ("KISS protocol set Persistence = %d, port %d\n", kiss_msg[1], port);
|
||||||
xmit_set_persist (port, kf->kiss_msg[1]);
|
xmit_set_persist (port, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: /* SlotTime */
|
case 3: /* SlotTime */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set SlotTime = %d, port %d\n", kf->kiss_msg[1], port);
|
dw_printf ("KISS protocol set SlotTime = %d, port %d\n", kiss_msg[1], port);
|
||||||
xmit_set_slottime (port, kf->kiss_msg[1]);
|
xmit_set_slottime (port, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: /* TXtail */
|
case 4: /* TXtail */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set TXtail = %d, port %d\n", kf->kiss_msg[1], port);
|
dw_printf ("KISS protocol set TXtail = %d, port %d\n", kiss_msg[1], port);
|
||||||
xmit_set_txtail (port, kf->kiss_msg[1]);
|
xmit_set_txtail (port, kiss_msg[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: /* FullDuplex */
|
case 5: /* FullDuplex */
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("KISS protocol set FullDuplex = %d, port %d\n", kf->kiss_msg[1], port);
|
dw_printf ("KISS protocol set FullDuplex = %d, port %d\n", kiss_msg[1], port);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: /* TNC specific */
|
case 6: /* TNC specific */
|
||||||
|
@ -348,7 +539,7 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
||||||
default:
|
default:
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("KISS Invalid command %d\n", cmd);
|
dw_printf ("KISS Invalid command %d\n", cmd);
|
||||||
kiss_debug_print (FROM_CLIENT, NULL, kf->kiss_msg, kf->kiss_len);
|
kiss_debug_print (FROM_CLIENT, NULL, kiss_msg, kiss_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,12 +560,6 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
/* In server.c. Should probably move to some misc. function file. */
|
|
||||||
|
|
||||||
void hex_dump (unsigned char *p, int len);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int msg_len)
|
void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int msg_len)
|
||||||
{
|
{
|
||||||
const char *direction [2] = { "from", "to" };
|
const char *direction [2] = { "from", "to" };
|
||||||
|
@ -390,18 +575,69 @@ void kiss_debug_print (fromto_t fromto, char *special, unsigned char *pmsg, int
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
if (special == NULL) {
|
if (special == NULL) {
|
||||||
|
unsigned char *p; /* to skip over FEND if present. */
|
||||||
|
|
||||||
|
p = pmsg;
|
||||||
|
if (*p == FEND) p++;
|
||||||
|
|
||||||
dw_printf ("%s %s %s KISS client application, port %d, total length = %d\n",
|
dw_printf ("%s %s %s KISS client application, port %d, total length = %d\n",
|
||||||
prefix[(int)fromto], function[pmsg[0] & 0xf], direction[(int)fromto],
|
prefix[(int)fromto], function[p[0] & 0xf], direction[(int)fromto],
|
||||||
(pmsg[0] >> 4) & 0xf, msg_len);
|
(p[0] >> 4) & 0xf, msg_len);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dw_printf ("%s %s %s KISS client application, total length = %d\n",
|
dw_printf ("%s %s %s KISS client application, total length = %d\n",
|
||||||
prefix[(int)fromto], special, direction[(int)fromto],
|
prefix[(int)fromto], special, direction[(int)fromto],
|
||||||
msg_len);
|
msg_len);
|
||||||
}
|
}
|
||||||
hex_dump ((char*)pmsg, msg_len);
|
hex_dump (pmsg, msg_len);
|
||||||
|
|
||||||
} /* end kiss_debug_print */
|
} /* end kiss_debug_print */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Quick unit test for encapsulate & unwrap */
|
||||||
|
|
||||||
|
// $ gcc -DTEST kiss_frame.c ; ./a
|
||||||
|
// Quick KISS test passed OK.
|
||||||
|
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
|
||||||
|
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
unsigned char din[512];
|
||||||
|
unsigned char kissed[520];
|
||||||
|
unsigned char dout[520];
|
||||||
|
int klen;
|
||||||
|
int dlen;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k = 0; k < 512; k++) {
|
||||||
|
if (k < 256) {
|
||||||
|
din[k] = k;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
din[k] = 511 - k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
klen = kiss_encapsulate (din, 512, kissed);
|
||||||
|
assert (klen == 512 + 6);
|
||||||
|
|
||||||
|
dlen = kiss_unwrap (kissed, klen, dout);
|
||||||
|
assert (dlen == 512);
|
||||||
|
assert (memcmp(din, dout, 512) == 0);
|
||||||
|
|
||||||
|
dlen = kiss_unwrap (kissed+1, klen-1, dout);
|
||||||
|
assert (dlen == 512);
|
||||||
|
assert (memcmp(din, dout, 512) == 0);
|
||||||
|
|
||||||
|
printf ("Quick KISS test passed OK.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* end kiss_frame.c */
|
/* end kiss_frame.c */
|
||||||
|
|
14
kiss_frame.h
14
kiss_frame.h
|
@ -12,13 +12,14 @@
|
||||||
#define TFESC 0xDD
|
#define TFESC 0xDD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum kiss_state_e {
|
enum kiss_state_e {
|
||||||
KS_SEARCHING, /* Looking for FEND to start KISS frame. */
|
KS_SEARCHING, /* Looking for FEND to start KISS frame. */
|
||||||
KS_COLLECTING, /* In process of collecting KISS frame. */
|
KS_COLLECTING}; /* In process of collecting KISS frame. */
|
||||||
KS_ESCAPE }; /* FESC found in frame. */
|
|
||||||
|
|
||||||
#define MAX_KISS_LEN 2048 /* Spec calls for at least 1024. */
|
#define MAX_KISS_LEN 2048 /* Spec calls for at least 1024. */
|
||||||
|
/* Might want to make it longer to accomodate */
|
||||||
|
/* maximum packet length. */
|
||||||
|
|
||||||
#define MAX_NOISE_LEN 100
|
#define MAX_NOISE_LEN 100
|
||||||
|
|
||||||
|
@ -27,6 +28,8 @@ typedef struct kiss_frame_s {
|
||||||
enum kiss_state_e state;
|
enum kiss_state_e state;
|
||||||
|
|
||||||
unsigned char kiss_msg[MAX_KISS_LEN];
|
unsigned char kiss_msg[MAX_KISS_LEN];
|
||||||
|
/* Leading FEND is optional. */
|
||||||
|
/* Contains escapes and ending FEND. */
|
||||||
int kiss_len;
|
int kiss_len;
|
||||||
|
|
||||||
unsigned char noise[MAX_NOISE_LEN];
|
unsigned char noise[MAX_NOISE_LEN];
|
||||||
|
@ -36,9 +39,10 @@ typedef struct kiss_frame_s {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(int,unsigned char*,int));
|
int kiss_encapsulate (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));
|
||||||
|
|
||||||
void kiss_process_msg (kiss_frame_t *kf, int debug);
|
|
||||||
|
|
||||||
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
||||||
|
|
||||||
|
|
45
kissnet.c
45
kissnet.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011-2013 John Langner, WB2OSZ
|
// Copyright (C) 2011-2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -125,6 +125,7 @@
|
||||||
|
|
||||||
|
|
||||||
static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */
|
static kiss_frame_t kf; /* Accumulated KISS frame and state of decoder. */
|
||||||
|
// TODO: multiple instances if multiple KISS network clients!
|
||||||
|
|
||||||
|
|
||||||
static int client_sock; /* File descriptor for socket for */
|
static int client_sock; /* File descriptor for socket for */
|
||||||
|
@ -471,31 +472,28 @@ void kissnet_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
kiss_len = 0;
|
|
||||||
kiss_buff[kiss_len++] = FEND;
|
|
||||||
kiss_buff[kiss_len++] = chan << 4;
|
|
||||||
|
|
||||||
for (j=0; j<flen; j++) {
|
unsigned char stemp[AX25_MAX_PACKET_LEN + 1];
|
||||||
|
|
||||||
|
assert (flen < sizeof(stemp));
|
||||||
|
|
||||||
if (fbuf[j] == FEND) {
|
stemp[0] = (chan << 4) + 0;
|
||||||
kiss_buff[kiss_len++] = FESC;
|
memcpy (stemp+1, fbuf, flen);
|
||||||
kiss_buff[kiss_len++] = TFEND;
|
|
||||||
}
|
if (kiss_debug >= 2) {
|
||||||
else if (fbuf[j] == FESC) {
|
/* AX.25 frame with the CRC removed. */
|
||||||
kiss_buff[kiss_len++] = FESC;
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
kiss_buff[kiss_len++] = TFESC;
|
dw_printf ("\n");
|
||||||
}
|
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
||||||
else {
|
hex_dump ((char*)fbuf, flen);
|
||||||
kiss_buff[kiss_len++] = fbuf[j];
|
|
||||||
}
|
|
||||||
assert (kiss_len < sizeof (kiss_buff));
|
|
||||||
}
|
}
|
||||||
kiss_buff[kiss_len++] = FEND;
|
|
||||||
|
|
||||||
/* Bug: This has the escapes but not the surrounding FENDs. */
|
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
||||||
|
|
||||||
|
/* This has the escapes and the surrounding FENDs. */
|
||||||
|
|
||||||
if (kiss_debug) {
|
if (kiss_debug) {
|
||||||
kiss_debug_print (TO_CLIENT, NULL, kiss_buff+1, kiss_len-2);
|
kiss_debug_print (TO_CLIENT, NULL, kiss_buff, kiss_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,11 +656,8 @@ static void * kissnet_listen_thread (void *arg)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = kiss_get();
|
ch = kiss_get();
|
||||||
|
kiss_rec_byte (&kf, ch, kiss_debug, kissnet_send_rec_packet);
|
||||||
if (kiss_frame (&kf, ch, kiss_debug, kissnet_send_rec_packet)) {
|
}
|
||||||
kiss_process_msg (&kf, kiss_debug);
|
|
||||||
}
|
|
||||||
} /* while (1) */
|
|
||||||
|
|
||||||
return (NULL); /* to suppress compiler warning. */
|
return (NULL); /* to suppress compiler warning. */
|
||||||
|
|
||||||
|
|
242
latlong.c
242
latlong.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2013 John Langner, WB2OSZ
|
// Copyright (C) 2013,2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -279,3 +279,243 @@ void longitude_to_comp_str (double dlong, char *clon)
|
||||||
clon[2] = x2 + 33;
|
clon[2] = x2 + 33;
|
||||||
clon[3] = x3 + 33;
|
clon[3] = x3 + 33;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: latitude_to_nmea
|
||||||
|
*
|
||||||
|
* Purpose: Convert numeric latitude to strings for NMEA sentence.
|
||||||
|
*
|
||||||
|
* Inputs: dlat - Floating point degrees.
|
||||||
|
*
|
||||||
|
* Outputs: slat - String in format ddmm.mmmm
|
||||||
|
* hemi - Hemisphere or empty string.
|
||||||
|
*
|
||||||
|
* Returns: None
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void latitude_to_nmea (double dlat, char *slat, char *hemi)
|
||||||
|
{
|
||||||
|
int ideg; /* whole number of degrees. */
|
||||||
|
double dmin; /* Minutes after removing degrees. */
|
||||||
|
char smin[10]; /* Minutes in format mm.mmmm */
|
||||||
|
|
||||||
|
if (dlat == G_UNKNOWN) {
|
||||||
|
strcpy (slat, "");
|
||||||
|
strcpy (hemi, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlat < -90.) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Latitude is less than -90. Changing to -90.n");
|
||||||
|
dlat = -90.;
|
||||||
|
}
|
||||||
|
if (dlat > 90.) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Latitude is greater than 90. Changing to 90.n");
|
||||||
|
dlat = 90.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlat < 0) {
|
||||||
|
dlat = (- dlat);
|
||||||
|
strcpy (hemi, "S");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy (hemi, "N");
|
||||||
|
}
|
||||||
|
|
||||||
|
ideg = (int)dlat;
|
||||||
|
dmin = (dlat - ideg) * 60.;
|
||||||
|
|
||||||
|
sprintf (smin, "%07.4f", dmin);
|
||||||
|
/* Due to roundoff, 59.99999 could come out as "60.0000" */
|
||||||
|
if (smin[0] == '6') {
|
||||||
|
smin[0] = '0';
|
||||||
|
ideg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf (slat, "%02d%s", ideg, smin);
|
||||||
|
|
||||||
|
} /* end latitude_to_str */
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Name: longitude_to_nmea
|
||||||
|
*
|
||||||
|
* Purpose: Convert numeric longitude to strings for NMEA sentence.
|
||||||
|
*
|
||||||
|
* Inputs: dlong - Floating point degrees.
|
||||||
|
*
|
||||||
|
* Outputs: slong - String in format dddmm.mmmm
|
||||||
|
* hemi - Hemisphere or empty string.
|
||||||
|
*
|
||||||
|
* Returns: None
|
||||||
|
*
|
||||||
|
*----------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void longitude_to_nmea (double dlong, char *slong, char *hemi)
|
||||||
|
{
|
||||||
|
int ideg; /* whole number of degrees. */
|
||||||
|
double dmin; /* Minutes after removing degrees. */
|
||||||
|
char smin[10]; /* Minutes in format mm.mmmm */
|
||||||
|
|
||||||
|
if (dlong == G_UNKNOWN) {
|
||||||
|
strcpy (slong, "");
|
||||||
|
strcpy (hemi, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlong < -180.) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("longitude is less than -180. Changing to -180.n");
|
||||||
|
dlong = -180.;
|
||||||
|
}
|
||||||
|
if (dlong > 180.) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("longitude is greater than 180. Changing to 180.n");
|
||||||
|
dlong = 180.;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dlong < 0) {
|
||||||
|
dlong = (- dlong);
|
||||||
|
strcpy (hemi, "W");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy (hemi, "E");
|
||||||
|
}
|
||||||
|
|
||||||
|
ideg = (int)dlong;
|
||||||
|
dmin = (dlong - ideg) * 60.;
|
||||||
|
|
||||||
|
sprintf (smin, "%07.4f", dmin);
|
||||||
|
/* Due to roundoff, 59.99999 could come out as "60.0000" */
|
||||||
|
if (smin[0] == '6') {
|
||||||
|
smin[0] = '0';
|
||||||
|
ideg++;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf (slong, "%03d%s", ideg, smin);
|
||||||
|
|
||||||
|
} /* end longitude_to_nmea */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Function: latitude_from_nmea
|
||||||
|
*
|
||||||
|
* Purpose: Convert NMEA latitude encoding to degrees.
|
||||||
|
*
|
||||||
|
* Inputs: pstr - Pointer to numeric string.
|
||||||
|
* phemi - Pointer to following field. Should be N or S.
|
||||||
|
*
|
||||||
|
* Returns: Double precision value in degrees. Negative for South.
|
||||||
|
*
|
||||||
|
* Description: Latitude field has
|
||||||
|
* 2 digits for degrees
|
||||||
|
* 2 digits for minutes
|
||||||
|
* period
|
||||||
|
* Variable number of fractional digits for minutes.
|
||||||
|
* I've seen 2, 3, and 4 fractional digits.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Bugs: Very little validation of data.
|
||||||
|
*
|
||||||
|
* Errors: Return constant G_UNKNOWN for any type of error.
|
||||||
|
* Could we use special "NaN" code?
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
double latitude_from_nmea (char *pstr, char *phemi)
|
||||||
|
{
|
||||||
|
|
||||||
|
double lat;
|
||||||
|
|
||||||
|
if ( ! isdigit((unsigned char)(pstr[0]))) return (G_UNKNOWN);
|
||||||
|
|
||||||
|
if (pstr[4] != '.') return (G_UNKNOWN);
|
||||||
|
|
||||||
|
|
||||||
|
lat = (pstr[0] - '0') * 10 + (pstr[1] - '0') + atof(pstr+2) / 60.0;
|
||||||
|
|
||||||
|
if (lat < 0 || lat > 90) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Error: Latitude not in range of 0 to 90.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saw this one time:
|
||||||
|
// $GPRMC,000000,V,0000.0000,0,00000.0000,0,000,000,000000,,*01
|
||||||
|
|
||||||
|
// If location is unknown, I think the hemisphere should be
|
||||||
|
// an empty string. TODO: Check on this.
|
||||||
|
// 'V' means void, so sentence should be discarded rather than
|
||||||
|
// trying to extract any data from it.
|
||||||
|
|
||||||
|
if (*phemi != 'N' && *phemi != 'S' && *phemi != '\0') {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Error: Latitude hemisphere should be N or S.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*phemi == 'S') lat = ( - lat);
|
||||||
|
|
||||||
|
return (lat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Function: longitude_from_nmea
|
||||||
|
*
|
||||||
|
* Purpose: Convert NMEA longitude encoding to degrees.
|
||||||
|
*
|
||||||
|
* Inputs: pstr - Pointer to numeric string.
|
||||||
|
* phemi - Pointer to following field. Should be E or W.
|
||||||
|
*
|
||||||
|
* Returns: Double precision value in degrees. Negative for West.
|
||||||
|
*
|
||||||
|
* Description: Longitude field has
|
||||||
|
* 3 digits for degrees
|
||||||
|
* 2 digits for minutes
|
||||||
|
* period
|
||||||
|
* Variable number of fractional digits for minutes
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Bugs: Very little validation of data.
|
||||||
|
*
|
||||||
|
* Errors: Return constant G_UNKNOWN for any type of error.
|
||||||
|
* Could we use special "NaN" code?
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
double longitude_from_nmea (char *pstr, char *phemi)
|
||||||
|
{
|
||||||
|
double lon;
|
||||||
|
|
||||||
|
if ( ! isdigit((unsigned char)(pstr[0]))) return (G_UNKNOWN);
|
||||||
|
|
||||||
|
if (pstr[5] != '.') return (G_UNKNOWN);
|
||||||
|
|
||||||
|
lon = (pstr[0] - '0') * 100 + (pstr[1] - '0') * 10 + (pstr[2] - '0') + atof(pstr+3) / 60.0;
|
||||||
|
|
||||||
|
if (lon < 0 || lon > 180) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Error: Longitude not in range of 0 to 180.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*phemi != 'E' && *phemi != 'W' && *phemi != '\0') {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf("Error: Longitude hemisphere should be E or W.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*phemi == 'W') lon = ( - lon);
|
||||||
|
|
||||||
|
return (lon);
|
||||||
|
}
|
||||||
|
|
|
@ -9,5 +9,12 @@
|
||||||
|
|
||||||
void latitude_to_str (double dlat, int ambiguity, char *slat);
|
void latitude_to_str (double dlat, int ambiguity, char *slat);
|
||||||
void longitude_to_str (double dlong, int ambiguity, char *slong);
|
void longitude_to_str (double dlong, int ambiguity, char *slong);
|
||||||
|
|
||||||
void latitude_to_comp_str (double dlat, char *clat);
|
void latitude_to_comp_str (double dlat, char *clat);
|
||||||
void longitude_to_comp_str (double dlon, char *clon);
|
void longitude_to_comp_str (double dlon, char *clon);
|
||||||
|
|
||||||
|
void latitude_to_nmea (double dlat, char *slat, char *hemi);
|
||||||
|
void longitude_to_nmea (double dlong, char *slong, char *hemi);
|
||||||
|
|
||||||
|
double latitude_from_nmea (char *pstr, char *phemi);
|
||||||
|
double longitude_from_nmea (char *pstr, char *phemi);
|
||||||
|
|
|
@ -0,0 +1,362 @@
|
||||||
|
//
|
||||||
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 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/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File: log.c
|
||||||
|
*
|
||||||
|
* Purpose: Save received packets to a log file.
|
||||||
|
*
|
||||||
|
* Description: Rather than saving the raw, sometimes rather cryptic and
|
||||||
|
* unreadable, format, write separated properties into
|
||||||
|
* CSV format for easy reading and later processing.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "direwolf.h"
|
||||||
|
#include "ax25_pad.h"
|
||||||
|
#include "textcolor.h"
|
||||||
|
#include "decode_aprs.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CSV format needs quotes if value contains comma or quote.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void quote_for_csv (char *out, const char *in) {
|
||||||
|
const char *p;
|
||||||
|
char *q = out;
|
||||||
|
int need_quote = 0;
|
||||||
|
|
||||||
|
for (p = in; *p != '\0'; p++) {
|
||||||
|
if (*p == ',' || *p == '"') {
|
||||||
|
need_quote = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_quote) {
|
||||||
|
*q++ = '"';
|
||||||
|
for (p = in; *p != '\0'; p++) {
|
||||||
|
if (*p == '"') {
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
*q++ = '"';
|
||||||
|
*q = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy (out, in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Function: log_init
|
||||||
|
*
|
||||||
|
* Purpose: Initialization at start of application.
|
||||||
|
*
|
||||||
|
* Inputs: path - Path of log file directory.
|
||||||
|
* Use "." for current directory.
|
||||||
|
* Empty string disables feature.
|
||||||
|
*
|
||||||
|
* Global Out: g_log_dir - Save directory here for later use.
|
||||||
|
* g_log_fp - File pointer for writing.
|
||||||
|
* g_open_fname - Name of currently open file.
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static char g_log_dir[80];
|
||||||
|
static FILE *g_log_fp;
|
||||||
|
static char g_open_fname[20];
|
||||||
|
|
||||||
|
|
||||||
|
void log_init (char *path)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
strcpy (g_log_dir, "");
|
||||||
|
g_log_fp = NULL;
|
||||||
|
strcpy (g_open_fname, "");
|
||||||
|
|
||||||
|
if (strlen(path) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(path,&st) == 0) {
|
||||||
|
// Exists, but is it a directory?
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
// Specified directory exists.
|
||||||
|
strcpy (g_log_dir, path);
|
||||||
|
}
|
||||||
|
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, ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Doesn't exist. Try to create it.
|
||||||
|
// parent directory must exist.
|
||||||
|
// We don't create multiple levels like "mkdir -p"
|
||||||
|
#if __WIN32__
|
||||||
|
if (_mkdir (path) == 0) {
|
||||||
|
#else
|
||||||
|
if (mkdir (path, 0777) == 0) {
|
||||||
|
#endif
|
||||||
|
// Success.
|
||||||
|
text_color_set(DW_COLOR_INFO);
|
||||||
|
dw_printf ("Log file location \"%s\" has been created.\n", path);
|
||||||
|
strcpy (g_log_dir, path);
|
||||||
|
}
|
||||||
|
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, ".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Function: log_write
|
||||||
|
*
|
||||||
|
* Purpose: Save information to log file.
|
||||||
|
*
|
||||||
|
* Inputs: chan - Radio channel where heard.
|
||||||
|
*
|
||||||
|
* A - Explode information from APRS packet.
|
||||||
|
*
|
||||||
|
* pp - Received packet object.
|
||||||
|
*
|
||||||
|
* alevel - audio level.
|
||||||
|
*
|
||||||
|
* retries - Amount of effort to get a good CRC.
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void log_write (int chan, decode_aprs_t *A, packet_t pp, int alevel, retry_t retries)
|
||||||
|
{
|
||||||
|
time_t now; // make 'now' a parameter so we can process historical data ???
|
||||||
|
char fname[20];
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
|
||||||
|
if (strlen(g_log_dir) == 0) return;
|
||||||
|
|
||||||
|
// Generate the file name from current date, UTC.
|
||||||
|
|
||||||
|
now = time(NULL);
|
||||||
|
gmtime_r (&now, &tm);
|
||||||
|
|
||||||
|
// Microsoft doesn't recognize %F as equivalent to %Y-%m-%d
|
||||||
|
|
||||||
|
strftime (fname, sizeof(fname), "%Y-%m-%d.log", &tm);
|
||||||
|
|
||||||
|
// Close current file if name has changed
|
||||||
|
|
||||||
|
if (g_log_fp != NULL && strcmp(fname, g_open_fname) != 0) {
|
||||||
|
log_term ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open for append if not already open.
|
||||||
|
|
||||||
|
if (g_log_fp == NULL) {
|
||||||
|
char full_path[120];
|
||||||
|
struct stat st;
|
||||||
|
int already_there;
|
||||||
|
|
||||||
|
strcpy (full_path, g_log_dir);
|
||||||
|
#if __WIN32__
|
||||||
|
strcat (full_path, "\\");
|
||||||
|
#else
|
||||||
|
strcat (full_path, "/");
|
||||||
|
#endif
|
||||||
|
strcat (full_path, fname);
|
||||||
|
|
||||||
|
// See if it already exists.
|
||||||
|
// This is used later to write a header if it did not exist already.
|
||||||
|
|
||||||
|
already_there = stat(full_path,&st) == 0;
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_INFO);
|
||||||
|
dw_printf("Opening log file \"%s\".\n", fname);
|
||||||
|
|
||||||
|
g_log_fp = fopen (full_path, "a");
|
||||||
|
|
||||||
|
if (g_log_fp != NULL) {
|
||||||
|
strcpy (g_open_fname, 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, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a header suitable for importing into a spreadsheet
|
||||||
|
// only if this will be the first line.
|
||||||
|
|
||||||
|
if ( ! already_there) {
|
||||||
|
fprintf (g_log_fp, "chan,utime,isotime,source,heard,level,error,dti,name,symbol,latitude,longitude,speed,course,altitude,frequency,offset,tone,system,status,comment\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_log_fp != NULL) {
|
||||||
|
|
||||||
|
char itime[24];
|
||||||
|
char heard[AX25_MAX_ADDR_LEN+1];
|
||||||
|
int h;
|
||||||
|
char stemp[256];
|
||||||
|
char slat[16], slon[16], sspd[12], scse[12], salt[12];
|
||||||
|
char sfreq[20], soffs[10], stone[10];
|
||||||
|
char sdti[10];
|
||||||
|
char sname[24];
|
||||||
|
char ssymbol[8];
|
||||||
|
char smfr[60];
|
||||||
|
char sstatus[40];
|
||||||
|
char stelemetry[200];
|
||||||
|
char scomment[256];
|
||||||
|
|
||||||
|
|
||||||
|
// Microsoft doesn't recognize %T as equivalent to %H:%M:%S
|
||||||
|
|
||||||
|
strftime (itime, sizeof(itime), "%Y-%m-%dT%H:%M:%SZ", &tm);
|
||||||
|
|
||||||
|
/* Who are we hearing? Original station or digipeater? */
|
||||||
|
/* Similar code in direwolf.c. Combine into one function? */
|
||||||
|
|
||||||
|
strcpy(heard, "");
|
||||||
|
if (pp != NULL) {
|
||||||
|
if (ax25_get_num_addr(pp) == 0) {
|
||||||
|
/* Not AX.25. No station to display below. */
|
||||||
|
h = -1;
|
||||||
|
strcpy (heard, "");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
h = ax25_get_heard(pp);
|
||||||
|
ax25_get_addr_with_ssid(pp, h, heard);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h >= AX25_REPEATER_2 &&
|
||||||
|
strncmp(heard, "WIDE", 4) == 0 &&
|
||||||
|
isdigit(heard[4]) &&
|
||||||
|
heard[5] == '\0') {
|
||||||
|
|
||||||
|
ax25_get_addr_with_ssid(pp, h-1, heard);
|
||||||
|
strcat (heard, "?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Might need to quote anything that could contain comma or quote.
|
||||||
|
|
||||||
|
strcpy(sdti, "");
|
||||||
|
if (pp != NULL) {
|
||||||
|
stemp[0] = ax25_get_dti(pp);
|
||||||
|
stemp[1] = '\0';
|
||||||
|
quote_for_csv (sdti, stemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
quote_for_csv (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 (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);
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
fprintf (g_log_fp, "%d,%d,%s,%s,%s,%d,%d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
|
||||||
|
chan, (int)now, itime,
|
||||||
|
A->g_src, heard, alevel, (int)retries, sdti,
|
||||||
|
sname, ssymbol,
|
||||||
|
slat, slon, sspd, scse, salt,
|
||||||
|
sfreq, soffs, stone,
|
||||||
|
smfr, sstatus, stelemetry, scomment);
|
||||||
|
fflush (g_log_fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end log_write */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Function: log_term
|
||||||
|
*
|
||||||
|
* Purpose: Close any open log file.
|
||||||
|
* Called when exiting or when date changes.
|
||||||
|
*
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
void log_term (void)
|
||||||
|
{
|
||||||
|
if (g_log_fp != NULL) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_INFO);
|
||||||
|
dw_printf("Closing log file \"%s\".\n", g_open_fname);
|
||||||
|
|
||||||
|
fclose (g_log_fp);
|
||||||
|
|
||||||
|
g_log_fp = NULL;
|
||||||
|
strcpy (g_open_fname, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end log_term */
|
||||||
|
|
||||||
|
|
||||||
|
/* end log.c */
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
/* log.h */
|
||||||
|
|
||||||
|
|
||||||
|
#include "hdlc_rec2.h" // for retry_t
|
||||||
|
|
||||||
|
#include "decode_aprs.h" // for decode_aprs_t
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void log_init (char *path);
|
||||||
|
|
||||||
|
void log_write (int chan, decode_aprs_t *A, packet_t pp, int alevel, retry_t retries);
|
||||||
|
|
||||||
|
void log_term (void);
|
|
@ -0,0 +1,535 @@
|
||||||
|
|
||||||
|
//
|
||||||
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2014 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/>.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
char *strsep(char **stringp, const char *delim);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Information we gather for each thing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct thing_s {
|
||||||
|
double lat;
|
||||||
|
double lon;
|
||||||
|
float alt; /* Meters above average sea level. */
|
||||||
|
float course;
|
||||||
|
float speed; /* Meters per second. */
|
||||||
|
char time[20+1+3];
|
||||||
|
char name[9+1+2];
|
||||||
|
char desc[32]; /* freq/offset/tone something like 146.955 MHz -600k PL 74.4 */
|
||||||
|
char comment[80]; /* Combined mic-e status and comment text */
|
||||||
|
} thing_t;
|
||||||
|
|
||||||
|
static thing_t *things; /* Dynamically sized array. */
|
||||||
|
static int max_things; /* Current size. */
|
||||||
|
static int num_things; /* Number of elements currently in use. */
|
||||||
|
|
||||||
|
#define UNKNOWN_VALUE (-999) /* Special value to indicate unknown altitude, speed, course. */
|
||||||
|
|
||||||
|
#define KNOTS_TO_METERS_PER_SEC(x) ((x)*0.51444444444)
|
||||||
|
|
||||||
|
|
||||||
|
static void read_csv(FILE *fp);
|
||||||
|
static void unquote (char *in, char *out);
|
||||||
|
static int compar(const void *a, const void *b);
|
||||||
|
static void process_things (int first, int last);
|
||||||
|
|
||||||
|
|
||||||
|
int main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int first, last;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate array for data.
|
||||||
|
* Expand it as needed if initial size is inadequate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
num_things = 0;
|
||||||
|
max_things = 1000;
|
||||||
|
things = malloc (max_things * sizeof(thing_t));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read files listed or stdin if none.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
read_csv (stdin);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n=1; n<argc; n++) {
|
||||||
|
if (strcmp(argv[n], "-") == 0) {
|
||||||
|
read_csv (stdin);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen (argv[n], "r");
|
||||||
|
if (fp != NULL) {
|
||||||
|
read_csv (fp);
|
||||||
|
fclose (fp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf (stderr, "Can't open %s for read.\n", argv[n]);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_things == 0) {
|
||||||
|
fprintf (stderr, "Nothing to process.\n");
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sort the data so everything for the same name is adjacent and
|
||||||
|
* in order of time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
qsort (things, num_things, sizeof(thing_t), compar);
|
||||||
|
|
||||||
|
//for (i=0; i<num_things; i++) {
|
||||||
|
// printf ("%d: %s %.6f %.6f %.1f %s\n",
|
||||||
|
// i,
|
||||||
|
// things[i].time,
|
||||||
|
// things[i].lat,
|
||||||
|
// things[i].lon,
|
||||||
|
// things[i].alt,
|
||||||
|
// things[i].name);
|
||||||
|
//}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPX file header.
|
||||||
|
*/
|
||||||
|
printf ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
|
||||||
|
printf ("<gpx version=\"1.1\" creator=\"Dire Wolf\">\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Group together all records for the same entity.
|
||||||
|
*/
|
||||||
|
last = first = 0;
|
||||||
|
while (first < num_things) {
|
||||||
|
|
||||||
|
while (last < num_things-1 && strcmp(things[first].name, things[last+1].name) == 0) {
|
||||||
|
last++;
|
||||||
|
}
|
||||||
|
process_things (first, last);
|
||||||
|
first = last + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPX file tail.
|
||||||
|
*/
|
||||||
|
printf ("</gpx>\n");
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read from given file, already open, into things array.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void read_csv(FILE *fp)
|
||||||
|
{
|
||||||
|
char raw[500];
|
||||||
|
char csv[500];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while (fgets(raw, sizeof(raw), fp) != NULL) {
|
||||||
|
|
||||||
|
char *next;
|
||||||
|
|
||||||
|
char *pchan;
|
||||||
|
char *putime;
|
||||||
|
char *pisotime;
|
||||||
|
char *psource;
|
||||||
|
char *pheard;
|
||||||
|
char *plevel;
|
||||||
|
char *perror;
|
||||||
|
char *pdti;
|
||||||
|
char *pname;
|
||||||
|
char *psymbol;
|
||||||
|
char *platitude;
|
||||||
|
char *plongitude;
|
||||||
|
char *pspeed;
|
||||||
|
char *pcourse;
|
||||||
|
char *paltitude;
|
||||||
|
char *pfreq;
|
||||||
|
char *poffset;
|
||||||
|
char *ptone;
|
||||||
|
char *psystem;
|
||||||
|
char *pstatus;
|
||||||
|
char *ptelemetry;
|
||||||
|
char *pcomment;
|
||||||
|
|
||||||
|
|
||||||
|
n = strlen(raw) - 1;
|
||||||
|
while (n >= 0 && (raw[n] == '\r' || raw[n] == '\n')) {
|
||||||
|
raw[n] = '\0';
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
unquote (raw, csv);
|
||||||
|
|
||||||
|
//printf ("%s\n", csv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Separate out the fields.
|
||||||
|
*/
|
||||||
|
next = csv;
|
||||||
|
pchan = strsep(&next,"\t");
|
||||||
|
putime = strsep(&next,"\t");
|
||||||
|
pisotime = strsep(&next,"\t");
|
||||||
|
psource = strsep(&next,"\t");
|
||||||
|
pheard = strsep(&next,"\t");
|
||||||
|
plevel = strsep(&next,"\t");
|
||||||
|
perror = strsep(&next,"\t");
|
||||||
|
pdti = strsep(&next,"\t");
|
||||||
|
pname = strsep(&next,"\t");
|
||||||
|
psymbol = strsep(&next,"\t");
|
||||||
|
platitude = strsep(&next,"\t");
|
||||||
|
plongitude = strsep(&next,"\t");
|
||||||
|
pspeed = strsep(&next,"\t"); /* Knots, must convert. */
|
||||||
|
pcourse = strsep(&next,"\t");
|
||||||
|
paltitude = strsep(&next,"\t"); /* Meters, already correct units. */
|
||||||
|
pfreq = strsep(&next,"\t");
|
||||||
|
poffset = strsep(&next,"\t");
|
||||||
|
ptone = strsep(&next,"\t");
|
||||||
|
psystem = strsep(&next,"\t");
|
||||||
|
pstatus = strsep(&next,"\t");
|
||||||
|
ptelemetry = strsep(&next,"\t"); /* Currently unused. Add to description? */
|
||||||
|
pcomment = strsep(&next,"\t");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip header line with names of fields.
|
||||||
|
*/
|
||||||
|
if (strcmp(pchan, "chan") == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save only if we have valid data.
|
||||||
|
* (Some packets don't contain a position.)
|
||||||
|
*/
|
||||||
|
if (pisotime != NULL && strlen(pisotime) > 0 &&
|
||||||
|
pname != NULL && strlen(pname) > 0 &&
|
||||||
|
platitude != NULL && strlen(platitude) > 0 &&
|
||||||
|
plongitude != NULL && strlen(plongitude) > 0) {
|
||||||
|
|
||||||
|
float speed = UNKNOWN_VALUE;
|
||||||
|
float course = UNKNOWN_VALUE;
|
||||||
|
float alt = UNKNOWN_VALUE;
|
||||||
|
double freq = UNKNOWN_VALUE;
|
||||||
|
int offset = UNKNOWN_VALUE;
|
||||||
|
char stemp[16], desc[32], comment[256];
|
||||||
|
|
||||||
|
if (pspeed != NULL && strlen(pspeed) > 0) {
|
||||||
|
speed = KNOTS_TO_METERS_PER_SEC(atof(pspeed));
|
||||||
|
}
|
||||||
|
if (pcourse != NULL && strlen(pcourse) > 0) {
|
||||||
|
course = atof(pcourse);
|
||||||
|
}
|
||||||
|
if (paltitude != NULL && strlen(paltitude) > 0) {
|
||||||
|
alt = atof(platitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* combine freq/offset/tone into one description string. */
|
||||||
|
|
||||||
|
if (pfreq != NULL && strlen(pfreq) > 0) {
|
||||||
|
freq = atof(pfreq);
|
||||||
|
sprintf (desc, "%.3f MHz", freq);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strcpy (desc, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poffset != NULL && strlen(poffset) > 0) {
|
||||||
|
offset = atoi(poffset);
|
||||||
|
if (offset != 0 && offset % 1000 == 0) {
|
||||||
|
sprintf (stemp, "%+dM", offset / 1000);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf (stemp, "%+dk", offset);
|
||||||
|
}
|
||||||
|
if (strlen(desc) > 0) strcat (desc, " ");
|
||||||
|
strcat (desc, stemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptone != NULL && strlen(ptone) > 0) {
|
||||||
|
if (*ptone == 'D') {
|
||||||
|
sprintf (stemp, "DCS %s", ptone+1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sprintf (stemp, "PL %s", ptone);
|
||||||
|
}
|
||||||
|
if (strlen(desc) > 0) strcat (desc, " ");
|
||||||
|
strcat (desc, stemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy (comment, "");
|
||||||
|
if (pstatus != NULL && strlen(pstatus) > 0) {
|
||||||
|
strcpy (comment, pstatus);
|
||||||
|
}
|
||||||
|
if (pcomment != NULL && strlen(pcomment) > 0) {
|
||||||
|
if (strlen(comment) > 0) strcat (comment, ", ");
|
||||||
|
strcat (comment, pcomment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_things == max_things) {
|
||||||
|
/* It's full. Grow the array by 50%. */
|
||||||
|
max_things += max_things / 2;
|
||||||
|
things = realloc (things, max_things*sizeof(thing_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
things[num_things].lat = atof(platitude);
|
||||||
|
things[num_things].lon = atof(plongitude);
|
||||||
|
things[num_things].speed = speed;
|
||||||
|
things[num_things].course = course;
|
||||||
|
things[num_things].alt = alt;
|
||||||
|
strncpy (things[num_things].time, pisotime, sizeof(things[num_things].time));
|
||||||
|
strncpy (things[num_things].name, pname, sizeof(things[num_things].name));
|
||||||
|
strncpy (things[num_things].desc, desc, sizeof(things[num_things].desc));
|
||||||
|
strncpy (things[num_things].comment, comment, sizeof(things[num_things].comment));
|
||||||
|
|
||||||
|
num_things++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare function for use with qsort.
|
||||||
|
* Order by name then date/time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int compar(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
thing_t *ta = (thing_t *)a;
|
||||||
|
thing_t *tb = (thing_t *)b;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = strcmp(ta->name, tb->name);
|
||||||
|
if (n != 0)
|
||||||
|
return (n);
|
||||||
|
return (strcmp(ta->time, tb->time));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Take quoting out of CSV data.
|
||||||
|
* Replace field separator commas with tabs while retaining
|
||||||
|
* commas that were part of the original data before quoting.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void unquote (char *in, char *out)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
char *q = out; /* Mind your p's and q's */
|
||||||
|
int quoted = 0;
|
||||||
|
|
||||||
|
for (p=in; *p!='\0'; p++) {
|
||||||
|
if (*p == '"') {
|
||||||
|
if (p == in || ( !quoted && *(p-1) == ',')) {
|
||||||
|
/* " found at beginning of field */
|
||||||
|
quoted = 1;
|
||||||
|
}
|
||||||
|
else if (*(p+1) == '\0' || (quoted && *(p+1) == ',')) {
|
||||||
|
/* " found at end of field */
|
||||||
|
quoted = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* " found somewhere in middle of field. */
|
||||||
|
/* We expect to be in quoted state and we should have a pair. */
|
||||||
|
if (quoted && *(p+1) == '"') {
|
||||||
|
/* Keep one and drop the other. */
|
||||||
|
*q++ = *p;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* This shouldn't happen. */
|
||||||
|
fprintf (stderr, "CSV data quoting is messed up.\n");
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*p == ',') {
|
||||||
|
if (quoted) {
|
||||||
|
/* Comma in original data. Keep it. */
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Comma is field separator. Replace with tab. */
|
||||||
|
*q++ = '\t';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* copy ordinary character. */
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*q = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare text values for XML.
|
||||||
|
* Replace significant characters with "predefined entities."
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void xml_text (char *in, char *out)
|
||||||
|
{
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
q = out;
|
||||||
|
for (p = in; *p != '\0'; p++) {
|
||||||
|
if (*p == '"') {
|
||||||
|
*q++ = '&';
|
||||||
|
*q++ = 'q';
|
||||||
|
*q++ = 'u';
|
||||||
|
*q++ = 'o';
|
||||||
|
*q++ = 't';
|
||||||
|
*q++ = ';';
|
||||||
|
}
|
||||||
|
else if (*p == '&') {
|
||||||
|
*q++ = '&';
|
||||||
|
*q++ = 'a';
|
||||||
|
*q++ = 'm';
|
||||||
|
*q++ = 'p';
|
||||||
|
*q++ = ';';
|
||||||
|
}
|
||||||
|
else if (*p == '\'') {
|
||||||
|
*q++ = '&';
|
||||||
|
*q++ = 'a';
|
||||||
|
*q++ = 'p';
|
||||||
|
*q++ = 'o';
|
||||||
|
*q++ = 's';
|
||||||
|
*q++ = ';';
|
||||||
|
}
|
||||||
|
else if (*p == '<') {
|
||||||
|
*q++ = '&';
|
||||||
|
*q++ = 'l';
|
||||||
|
*q++ = 't';
|
||||||
|
*q++ = ';';
|
||||||
|
}
|
||||||
|
else if (*p == '>') {
|
||||||
|
*q++ = '&';
|
||||||
|
*q++ = 'g';
|
||||||
|
*q++ = 't';
|
||||||
|
*q++ = ';';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*q++ = *p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*q = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process all things with the same name.
|
||||||
|
* They should be sorted by time.
|
||||||
|
* For stationary entities, generate just one GPX waypoint.
|
||||||
|
* For moving entities, generate a GPX track.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void process_things (int first, int last)
|
||||||
|
{
|
||||||
|
//printf ("process %d to %d\n", first, last);
|
||||||
|
int i;
|
||||||
|
int moved = 0;
|
||||||
|
char safe_name[30];
|
||||||
|
char safe_comment[120];
|
||||||
|
|
||||||
|
for (i=first+1; i<=last; i++) {
|
||||||
|
if (things[i].lat != things[first].lat) moved = 1;
|
||||||
|
if (things[i].lon != things[first].lon) moved = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moved) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate track for moving thing.
|
||||||
|
*/
|
||||||
|
xml_text (things[first].name, safe_name);
|
||||||
|
xml_text (things[first].comment, safe_comment);
|
||||||
|
|
||||||
|
printf (" <trk>\n");
|
||||||
|
printf (" <name>%s</name>\n", safe_name);
|
||||||
|
printf (" <trkseg>\n");
|
||||||
|
|
||||||
|
for (i=first; i<=last; i++) {
|
||||||
|
printf (" <trkpt lat=\"%.6f\" lon=\"%.6f\">\n", things[i].lat, things[i].lon);
|
||||||
|
if (things[i].speed != UNKNOWN_VALUE) {
|
||||||
|
printf (" <speed>%.1f</speed>\n", things[i].speed);
|
||||||
|
}
|
||||||
|
if (things[i].course != UNKNOWN_VALUE) {
|
||||||
|
printf (" <course>%.1f</course>\n", things[i].course);
|
||||||
|
}
|
||||||
|
if (things[i].alt != UNKNOWN_VALUE) {
|
||||||
|
printf (" <ele>%.1f</ele>\n", things[i].alt);
|
||||||
|
}
|
||||||
|
if (strlen(things[i].desc) > 0) {
|
||||||
|
printf (" <desc>%s</desc>\n", things[i].desc);
|
||||||
|
}
|
||||||
|
if (strlen(safe_comment) > 0) {
|
||||||
|
printf (" <cmt>%s</cmt>\n", safe_comment);
|
||||||
|
}
|
||||||
|
printf (" <time>%s</time>\n", things[i].time);
|
||||||
|
printf (" </trkpt>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (" </trkseg>\n");
|
||||||
|
printf (" </trk>\n");
|
||||||
|
|
||||||
|
/* Also generate waypoint for last location. */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Future possibility?
|
||||||
|
// <sym>Symbol Name</sym> -- not standardized.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate waypoint for stationary thing or last known position for moving thing.
|
||||||
|
*/
|
||||||
|
xml_text (things[last].name, safe_name);
|
||||||
|
xml_text (things[last].comment, safe_comment);
|
||||||
|
|
||||||
|
printf (" <wpt lat=\"%.6f\" lon=\"%.6f\">\n", things[last].lat, things[last].lon);
|
||||||
|
if (things[last].alt != UNKNOWN_VALUE) {
|
||||||
|
printf (" <ele>%.1f</ele>\n", things[last].alt);
|
||||||
|
}
|
||||||
|
if (strlen(things[i].desc) > 0) {
|
||||||
|
printf (" <desc>%s</desc>\n", things[i].desc);
|
||||||
|
}
|
||||||
|
if (strlen(safe_comment) > 0) {
|
||||||
|
printf (" <cmt>%s</cmt>\n", safe_comment);
|
||||||
|
}
|
||||||
|
printf (" <name>%s</name>\n", safe_name);
|
||||||
|
printf (" </wpt>\n");
|
||||||
|
}
|
|
@ -0,0 +1,267 @@
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MGN_icon.h
|
||||||
|
*
|
||||||
|
* Waypoint icon codes for use in the $PMGNWPL sentence.
|
||||||
|
*
|
||||||
|
* Derived from Data Transmission Protocol For Magellan Products – version 2.11
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MGN_crossed_square "a"
|
||||||
|
#define MGN_box "b"
|
||||||
|
#define MGN_house "c"
|
||||||
|
#define MGN_aerial "d"
|
||||||
|
#define MGN_airport "e"
|
||||||
|
#define MGN_amusement_park "f"
|
||||||
|
#define MGN_ATM "g"
|
||||||
|
#define MGN_auto_repair "h"
|
||||||
|
#define MGN_boating "I"
|
||||||
|
#define MGN_camping "j"
|
||||||
|
#define MGN_exit_ramp "k"
|
||||||
|
#define MGN_first_aid "l"
|
||||||
|
#define MGN_nav_aid "m"
|
||||||
|
#define MGN_buoy "n"
|
||||||
|
#define MGN_fuel "o"
|
||||||
|
#define MGN_garden "p"
|
||||||
|
#define MGN_golf "q"
|
||||||
|
#define MGN_hotel "r"
|
||||||
|
#define MGN_hunting_fishing "s"
|
||||||
|
#define MGN_large_city "t"
|
||||||
|
#define MGN_lighthouse "u"
|
||||||
|
#define MGN_major_city "v"
|
||||||
|
#define MGN_marina "w"
|
||||||
|
#define MGN_medium_city "x"
|
||||||
|
#define MGN_museum "y"
|
||||||
|
#define MGN_obstruction "z"
|
||||||
|
#define MGN_park "aa"
|
||||||
|
#define MGN_resort "ab"
|
||||||
|
#define MGN_restaurant "ac"
|
||||||
|
#define MGN_rock "ad"
|
||||||
|
#define MGN_scuba "ae"
|
||||||
|
#define MGN_RV_service "af"
|
||||||
|
#define MGN_shooting "ag"
|
||||||
|
#define MGN_sight_seeing "ah"
|
||||||
|
#define MGN_small_city "ai"
|
||||||
|
#define MGN_sounding "aj"
|
||||||
|
#define MGN_sports_arena "ak"
|
||||||
|
#define MGN_tourist_info "al"
|
||||||
|
#define MGN_truck_service "am"
|
||||||
|
#define MGN_winery "an"
|
||||||
|
#define MGN_wreck "ao"
|
||||||
|
#define MGN_zoo "ap"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mapping from APRS symbols to Magellan.
|
||||||
|
*
|
||||||
|
* This is a bit of a challenge because there
|
||||||
|
* are no icons for moving objects.
|
||||||
|
* We can use airport for flying things but
|
||||||
|
* what about wheeled transportation devices?
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: NEEDS MORE WORK!!!
|
||||||
|
|
||||||
|
|
||||||
|
#define MGN_default MGN_crossed_square
|
||||||
|
|
||||||
|
#define SYMTAB_SIZE 95
|
||||||
|
|
||||||
|
static const char mgn_primary_symtab[SYMTAB_SIZE][3] = {
|
||||||
|
|
||||||
|
MGN_default, // 00 --no-symbol--
|
||||||
|
MGN_default, // ! 01 Police, Sheriff
|
||||||
|
MGN_default, // " 02 reserved (was rain)
|
||||||
|
MGN_aerial, // # 03 DIGI (white center)
|
||||||
|
MGN_default, // $ 04 PHONE
|
||||||
|
MGN_aerial, // % 05 DX CLUSTER
|
||||||
|
MGN_aerial, // & 06 HF GATEway
|
||||||
|
MGN_airport, // ' 07 Small AIRCRAFT
|
||||||
|
MGN_aerial, // ( 08 Mobile Satellite Station
|
||||||
|
MGN_default, // ) 09 Wheelchair (handicapped)
|
||||||
|
MGN_default, // * 10 SnowMobile
|
||||||
|
MGN_default, // + 11 Red Cross
|
||||||
|
MGN_default, // , 12 Boy Scouts
|
||||||
|
MGN_house, // - 13 House QTH (VHF)
|
||||||
|
MGN_default, // . 14 X
|
||||||
|
MGN_default, // / 15 Red Dot
|
||||||
|
MGN_default, // 0 16 # circle (obsolete)
|
||||||
|
MGN_default, // 1 17 TBD
|
||||||
|
MGN_default, // 2 18 TBD
|
||||||
|
MGN_default, // 3 19 TBD
|
||||||
|
MGN_default, // 4 20 TBD
|
||||||
|
MGN_default, // 5 21 TBD
|
||||||
|
MGN_default, // 6 22 TBD
|
||||||
|
MGN_default, // 7 23 TBD
|
||||||
|
MGN_default, // 8 24 TBD
|
||||||
|
MGN_default, // 9 25 TBD
|
||||||
|
MGN_default, // : 26 FIRE
|
||||||
|
MGN_camping, // ; 27 Campground (Portable ops)
|
||||||
|
MGN_default, // < 28 Motorcycle
|
||||||
|
MGN_default, // = 29 RAILROAD ENGINE
|
||||||
|
MGN_default, // > 30 CAR
|
||||||
|
MGN_default, // ? 31 SERVER for Files
|
||||||
|
MGN_default, // @ 32 HC FUTURE predict (dot)
|
||||||
|
MGN_first_aid, // A 33 Aid Station
|
||||||
|
MGN_aerial, // B 34 BBS or PBBS
|
||||||
|
MGN_boating, // C 35 Canoe
|
||||||
|
MGN_default, // D 36
|
||||||
|
MGN_default, // E 37 EYEBALL (Eye catcher!)
|
||||||
|
MGN_default, // F 38 Farm Vehicle (tractor)
|
||||||
|
MGN_default, // G 39 Grid Square (6 digit)
|
||||||
|
MGN_default, // H 40 HOTEL (blue bed symbol)
|
||||||
|
MGN_aerial, // I 41 TcpIp on air network stn
|
||||||
|
MGN_default, // J 42
|
||||||
|
MGN_default, // K 43 School
|
||||||
|
MGN_default, // L 44 PC user
|
||||||
|
MGN_default, // M 45 MacAPRS
|
||||||
|
MGN_aerial, // N 46 NTS Station
|
||||||
|
MGN_airport, // O 47 BALLOON
|
||||||
|
MGN_default, // P 48 Police
|
||||||
|
MGN_default, // Q 49 TBD
|
||||||
|
MGN_RV_service, // R 50 REC. VEHICLE
|
||||||
|
MGN_airport, // S 51 SHUTTLE
|
||||||
|
MGN_default, // T 52 SSTV
|
||||||
|
MGN_default, // U 53 BUS
|
||||||
|
MGN_default, // V 54 ATV
|
||||||
|
MGN_default, // W 55 National WX Service Site
|
||||||
|
MGN_default, // X 56 HELO
|
||||||
|
MGN_boating, // Y 57 YACHT (sail)
|
||||||
|
MGN_default, // Z 58 WinAPRS
|
||||||
|
MGN_default, // [ 59 Human/Person (HT)
|
||||||
|
MGN_default, // \ 60 TRIANGLE(DF station)
|
||||||
|
MGN_default, // ] 61 MAIL/PostOffice(was PBBS)
|
||||||
|
MGN_airport, // ^ 62 LARGE AIRCRAFT
|
||||||
|
MGN_default, // _ 63 WEATHER Station (blue)
|
||||||
|
MGN_aerial, // ` 64 Dish Antenna
|
||||||
|
MGN_default, // a 65 AMBULANCE
|
||||||
|
MGN_default, // b 66 BIKE
|
||||||
|
MGN_default, // c 67 Incident Command Post
|
||||||
|
MGN_default, // d 68 Fire dept
|
||||||
|
MGN_zoo, // e 69 HORSE (equestrian)
|
||||||
|
MGN_default, // f 70 FIRE TRUCK
|
||||||
|
MGN_airport, // g 71 Glider
|
||||||
|
MGN_default, // h 72 HOSPITAL
|
||||||
|
MGN_default, // i 73 IOTA (islands on the air)
|
||||||
|
MGN_default, // j 74 JEEP
|
||||||
|
MGN_default, // k 75 TRUCK
|
||||||
|
MGN_default, // l 76 Laptop
|
||||||
|
MGN_aerial, // m 77 Mic-E Repeater
|
||||||
|
MGN_default, // n 78 Node (black bulls-eye)
|
||||||
|
MGN_default, // o 79 EOC
|
||||||
|
MGN_default, // p 80 ROVER (puppy, or dog)
|
||||||
|
MGN_default, // q 81 GRID SQ shown above 128 m
|
||||||
|
MGN_aerial, // r 82 Repeater
|
||||||
|
MGN_default, // s 83 SHIP (pwr boat)
|
||||||
|
MGN_default, // t 84 TRUCK STOP
|
||||||
|
MGN_default, // u 85 TRUCK (18 wheeler)
|
||||||
|
MGN_default, // v 86 VAN
|
||||||
|
MGN_default, // w 87 WATER station
|
||||||
|
MGN_aerial, // x 88 xAPRS (Unix)
|
||||||
|
MGN_aerial, // y 89 YAGI @ QTH
|
||||||
|
MGN_default, // z 90 TBD
|
||||||
|
MGN_default, // { 91
|
||||||
|
MGN_default, // | 92 TNC Stream Switch
|
||||||
|
MGN_default, // } 93
|
||||||
|
MGN_default }; // ~ 94 TNC Stream Switch
|
||||||
|
|
||||||
|
|
||||||
|
static const char mgn_alternate_symtab[SYMTAB_SIZE][3] = {
|
||||||
|
|
||||||
|
MGN_default, // 00 --no-symbol--
|
||||||
|
MGN_default, // ! 01 EMERGENCY (!)
|
||||||
|
MGN_default, // " 02 reserved
|
||||||
|
MGN_aerial, // # 03 OVERLAY DIGI (green star)
|
||||||
|
MGN_ATM, // $ 04 Bank or ATM (green box)
|
||||||
|
MGN_default, // % 05 Power Plant with overlay
|
||||||
|
MGN_aerial, // & 06 I=Igte IGate R=RX T=1hopTX 2=2hopTX
|
||||||
|
MGN_default, // ' 07 Crash (& now Incident sites)
|
||||||
|
MGN_default, // ( 08 CLOUDY (other clouds w ovrly)
|
||||||
|
MGN_aerial, // ) 09 Firenet MEO, MODIS Earth Obs.
|
||||||
|
MGN_default, // * 10 SNOW (& future ovrly codes)
|
||||||
|
MGN_default, // + 11 Church
|
||||||
|
MGN_default, // , 12 Girl Scouts
|
||||||
|
MGN_house, // - 13 House (H=HF) (O = Op Present)
|
||||||
|
MGN_default, // . 14 Ambiguous (Big Question mark)
|
||||||
|
MGN_default, // / 15 Waypoint Destination
|
||||||
|
MGN_default, // 0 16 CIRCLE (E/I/W=IRLP/Echolink/WIRES)
|
||||||
|
MGN_default, // 1 17
|
||||||
|
MGN_default, // 2 18
|
||||||
|
MGN_default, // 3 19
|
||||||
|
MGN_default, // 4 20
|
||||||
|
MGN_default, // 5 21
|
||||||
|
MGN_default, // 6 22
|
||||||
|
MGN_default, // 7 23
|
||||||
|
MGN_aerial, // 8 24 802.11 or other network node
|
||||||
|
MGN_fuel, // 9 25 Gas Station (blue pump)
|
||||||
|
MGN_default, // : 26 Hail (& future ovrly codes)
|
||||||
|
MGN_park, // ; 27 Park/Picnic area
|
||||||
|
MGN_default, // < 28 ADVISORY (one WX flag)
|
||||||
|
MGN_default, // = 29 APRStt Touchtone (DTMF users)
|
||||||
|
MGN_default, // > 30 OVERLAYED CAR
|
||||||
|
MGN_tourist_info, // ? 31 INFO Kiosk (Blue box with ?)
|
||||||
|
MGN_default, // @ 32 HURICANE/Trop-Storm
|
||||||
|
MGN_default, // A 33 overlayBOX DTMF & RFID & XO
|
||||||
|
MGN_default, // B 34 Blwng Snow (& future codes)
|
||||||
|
MGN_boating, // C 35 Coast Guard
|
||||||
|
MGN_default, // D 36 Drizzle (proposed APRStt)
|
||||||
|
MGN_default, // E 37 Smoke (& other vis codes)
|
||||||
|
MGN_default, // F 38 Freezng rain (&future codes)
|
||||||
|
MGN_default, // G 39 Snow Shwr (& future ovrlys)
|
||||||
|
MGN_default, // H 40 Haze (& Overlay Hazards)
|
||||||
|
MGN_default, // I 41 Rain Shower
|
||||||
|
MGN_default, // J 42 Lightening (& future ovrlys)
|
||||||
|
MGN_default, // K 43 Kenwood HT (W)
|
||||||
|
MGN_lighthouse, // L 44 Lighthouse
|
||||||
|
MGN_default, // M 45 MARS (A=Army,N=Navy,F=AF)
|
||||||
|
MGN_nav_aid, // N 46 Navigation Buoy
|
||||||
|
MGN_airport, // O 47 Rocket
|
||||||
|
MGN_default, // P 48 Parking
|
||||||
|
MGN_default, // Q 49 QUAKE
|
||||||
|
MGN_restaurant, // R 50 Restaurant
|
||||||
|
MGN_aerial, // S 51 Satellite/Pacsat
|
||||||
|
MGN_default, // T 52 Thunderstorm
|
||||||
|
MGN_default, // U 53 SUNNY
|
||||||
|
MGN_default, // V 54 VORTAC Nav Aid
|
||||||
|
MGN_default, // W 55 # NWS site (NWS options)
|
||||||
|
MGN_default, // X 56 Pharmacy Rx (Apothicary)
|
||||||
|
MGN_aerial, // Y 57 Radios and devices
|
||||||
|
MGN_default, // Z 58
|
||||||
|
MGN_default, // [ 59 W.Cloud (& humans w Ovrly)
|
||||||
|
MGN_default, // \ 60 New overlayable GPS symbol
|
||||||
|
MGN_default, // ] 61
|
||||||
|
MGN_airport, // ^ 62 # Aircraft (shows heading)
|
||||||
|
MGN_default, // _ 63 # WX site (green digi)
|
||||||
|
MGN_default, // ` 64 Rain (all types w ovrly)
|
||||||
|
MGN_aerial, // a 65 ARRL, ARES, WinLINK
|
||||||
|
MGN_default, // b 66 Blwng Dst/Snd (& others)
|
||||||
|
MGN_default, // c 67 CD triangle RACES/SATERN/etc
|
||||||
|
MGN_default, // d 68 DX spot by callsign
|
||||||
|
MGN_default, // e 69 Sleet (& future ovrly codes)
|
||||||
|
MGN_default, // f 70 Funnel Cloud
|
||||||
|
MGN_default, // g 71 Gale Flags
|
||||||
|
MGN_default, // h 72 Store. or HAMFST Hh=HAM store
|
||||||
|
MGN_default, // i 73 BOX or points of Interest
|
||||||
|
MGN_default, // j 74 WorkZone (Steam Shovel)
|
||||||
|
MGN_default, // k 75 Special Vehicle SUV,ATV,4x4
|
||||||
|
MGN_default, // l 76 Areas (box,circles,etc)
|
||||||
|
MGN_default, // m 77 Value Sign (3 digit display)
|
||||||
|
MGN_default, // n 78 OVERLAY TRIANGLE
|
||||||
|
MGN_default, // o 79 small circle
|
||||||
|
MGN_default, // p 80 Prtly Cldy (& future ovrlys)
|
||||||
|
MGN_default, // q 81
|
||||||
|
MGN_default, // r 82 Restrooms
|
||||||
|
MGN_default, // s 83 OVERLAY SHIP/boat (top view)
|
||||||
|
MGN_default, // t 84 Tornado
|
||||||
|
MGN_default, // u 85 OVERLAYED TRUCK
|
||||||
|
MGN_default, // v 86 OVERLAYED Van
|
||||||
|
MGN_default, // w 87 Flooding
|
||||||
|
MGN_wreck, // x 88 Wreck or Obstruction ->X<-
|
||||||
|
MGN_default, // y 89 Skywarn
|
||||||
|
MGN_default, // z 90 OVERLAYED Shelter
|
||||||
|
MGN_default, // { 91 Fog (& future ovrly codes)
|
||||||
|
MGN_default, // | 92 TNC Stream Switch
|
||||||
|
MGN_default, // } 93
|
||||||
|
MGN_default }; // ~ 94 TNC Stream Switch
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
This is NOT used for the Linux version.
|
||||||
These are part of the standard C library for Linux and Cygwin.
|
These are part of the standard C library for Linux and Cygwin.
|
||||||
For the Windows version we need to include our own copy.
|
For the Windows version we need to include our own copy.
|
||||||
|
|
||||||
|
|
136
multi_modem.c
136
multi_modem.c
|
@ -59,9 +59,19 @@
|
||||||
* multiple modems & HDLC decoders per channel. The tricky
|
* multiple modems & HDLC decoders per channel. The tricky
|
||||||
* part is picking the best one when there is more than one
|
* part is picking the best one when there is more than one
|
||||||
* success and discarding the rest.
|
* success and discarding the rest.
|
||||||
*
|
*
|
||||||
|
* New in version 1.1:
|
||||||
|
*
|
||||||
|
* Several enhancements provided by Fabrice FAURE:
|
||||||
|
*
|
||||||
|
* Additional types of attempts to fix a bad CRC.
|
||||||
|
* Optimized code to reduce execution time.
|
||||||
|
* Improved detection of duplicate packets from
|
||||||
|
* different fixup attempts.
|
||||||
|
* Set limit on number of packets in fix up later queue.
|
||||||
|
*
|
||||||
*------------------------------------------------------------------*/
|
*------------------------------------------------------------------*/
|
||||||
|
//#define DEBUG 1
|
||||||
#define DIGIPEATER_C
|
#define DIGIPEATER_C
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,8 +107,14 @@ static struct {
|
||||||
int score;
|
int score;
|
||||||
|
|
||||||
} candidate[MAX_CHANS][MAX_SUBCHANS];
|
} candidate[MAX_CHANS][MAX_SUBCHANS];
|
||||||
|
#define MAX_STORED_CRC 256
|
||||||
|
|
||||||
static unsigned int crc_of_last_to_app[MAX_CHANS];
|
typedef struct crc_s {
|
||||||
|
struct crc_s* nextp; /* Next pointer to maintain a queue. */
|
||||||
|
unsigned int crc;
|
||||||
|
} *crc_t;
|
||||||
|
|
||||||
|
static crc_t crc_queue_of_last_to_app[MAX_CHANS];
|
||||||
|
|
||||||
#define PROCESS_AFTER_BITS 2
|
#define PROCESS_AFTER_BITS 2
|
||||||
|
|
||||||
|
@ -139,13 +155,100 @@ void multi_modem_init (struct audio_s *pmodem)
|
||||||
|
|
||||||
for (chan=0; chan<modem.num_channels; chan++) {
|
for (chan=0; chan<modem.num_channels; chan++) {
|
||||||
process_age[chan] = PROCESS_AFTER_BITS * modem.samples_per_sec / modem.baud[chan];
|
process_age[chan] = PROCESS_AFTER_BITS * modem.samples_per_sec / modem.baud[chan];
|
||||||
crc_of_last_to_app[chan] = 0x12345678;
|
crc_queue_of_last_to_app[chan] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Add a crc to the end of the queue and returns the numbers of CRC stored in the queue
|
||||||
|
int crc_queue_append (unsigned int crc, unsigned int chan) {
|
||||||
|
crc_t plast;
|
||||||
|
crc_t plast1;
|
||||||
|
crc_t pnext;
|
||||||
|
crc_t new_crc;
|
||||||
|
|
||||||
|
unsigned int nb_crc = 1;
|
||||||
|
if (chan>=MAX_CHANS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new_crc = (crc_t) malloc (10*sizeof(struct crc_s));
|
||||||
|
if (!new_crc)
|
||||||
|
return -1;
|
||||||
|
new_crc->crc = crc;
|
||||||
|
new_crc->nextp = NULL;
|
||||||
|
if (crc_queue_of_last_to_app[chan] == NULL) {
|
||||||
|
crc_queue_of_last_to_app[chan] = new_crc;
|
||||||
|
nb_crc = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nb_crc = 2;
|
||||||
|
plast = crc_queue_of_last_to_app[chan];
|
||||||
|
pnext = plast->nextp;
|
||||||
|
while (pnext != NULL) {
|
||||||
|
nb_crc++;
|
||||||
|
plast = pnext;
|
||||||
|
pnext = pnext->nextp;
|
||||||
|
}
|
||||||
|
plast->nextp = new_crc;
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf("Out crc_queue_append nb_crc = %d\n", nb_crc);
|
||||||
|
#endif
|
||||||
|
return nb_crc;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove the crc from the top of the queue
|
||||||
|
unsigned int crc_queue_remove (unsigned int chan) {
|
||||||
|
|
||||||
|
unsigned int res;
|
||||||
|
crc_t plast;
|
||||||
|
crc_t pnext;
|
||||||
|
#if DEBUG
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf("In crc_queue_remove\n");
|
||||||
|
#endif
|
||||||
|
crc_t removed_crc;
|
||||||
|
if (chan>=MAX_CHANS) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
removed_crc = crc_queue_of_last_to_app[chan];
|
||||||
|
if (removed_crc == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
crc_queue_of_last_to_app[chan] = removed_crc->nextp;
|
||||||
|
res = removed_crc->crc;
|
||||||
|
free(removed_crc);
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char is_crc_in_queue(unsigned int chan, unsigned int crc) {
|
||||||
|
crc_t plast;
|
||||||
|
crc_t pnext;
|
||||||
|
|
||||||
|
if (crc_queue_of_last_to_app[chan] == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
plast = crc_queue_of_last_to_app[chan];
|
||||||
|
do {
|
||||||
|
pnext = plast->nextp;
|
||||||
|
if (plast->crc == crc) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
plast = pnext;
|
||||||
|
} while (pnext != NULL);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* Name: multi_modem_process_sample
|
* Name: multi_modem_process_sample
|
||||||
|
@ -310,22 +413,28 @@ void multi_modem_process_rec_frame (int chan, int subchan, unsigned char *fbuf,
|
||||||
* Either pass it along or drop if duplicate.
|
* Either pass it along or drop if duplicate.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (retries == RETRY_TWO_SEP) {
|
if (retries >= RETRY_SWAP_TWO_SEP) {
|
||||||
int mycrc;
|
int mycrc;
|
||||||
char spectrum[MAX_SUBCHANS+1];
|
char spectrum[MAX_SUBCHANS+1];
|
||||||
|
int dropped = 0;
|
||||||
|
|
||||||
memset (spectrum, 0, sizeof(spectrum));
|
memset (spectrum, 0, sizeof(spectrum));
|
||||||
memset (spectrum, '_', (size_t)modem.num_subchan[chan]);
|
memset (spectrum, '_', (size_t)modem.num_subchan[chan]);
|
||||||
spectrum[subchan] = '.';
|
spectrum[subchan] = '.';
|
||||||
|
|
||||||
mycrc = ax25_m_m_crc(pp);
|
mycrc = ax25_m_m_crc(pp);
|
||||||
|
/* Smetimes recovered packet is not the latest one send to the app:
|
||||||
|
* It can be a packet sent to the app before the latest one because of the processing time ...
|
||||||
|
* So we check if the crc of current packet has already been received in the queue of others crc
|
||||||
|
*/
|
||||||
|
dropped = is_crc_in_queue(chan, mycrc);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\n%s\n%d.%d: ptr=%p, retry=%d, age=, crc=%04x, score= \n",
|
dw_printf ("\n%s\n%d.%d: ptr=%p, retry=%d, age=, crc=%04x, score= , dropped =%d\n",
|
||||||
spectrum, chan, subchan, pp, (int)retries, mycrc);
|
spectrum, chan, subchan, pp, (int)retries, mycrc,dropped);
|
||||||
#endif
|
#endif
|
||||||
if (mycrc == crc_of_last_to_app[chan]) {
|
if (dropped) {
|
||||||
/* Same as last one. Drop it. */
|
/* Same as last one. Drop it. */
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -338,7 +447,8 @@ void multi_modem_process_rec_frame (int chan, int subchan, unsigned char *fbuf,
|
||||||
dw_printf ("Send the best one along.\n");
|
dw_printf ("Send the best one along.\n");
|
||||||
#endif
|
#endif
|
||||||
app_process_rec_packet (chan, subchan, pp, alevel, retries, spectrum);
|
app_process_rec_packet (chan, subchan, pp, alevel, retries, spectrum);
|
||||||
crc_of_last_to_app[chan] = mycrc;
|
if (crc_queue_append(mycrc, chan) > MAX_STORED_CRC)
|
||||||
|
crc_queue_remove(chan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +507,7 @@ static void pick_best_candidate (int chan)
|
||||||
else if (candidate[chan][subchan].retries == RETRY_NONE) {
|
else if (candidate[chan][subchan].retries == RETRY_NONE) {
|
||||||
spectrum[subchan] = '|';
|
spectrum[subchan] = '|';
|
||||||
}
|
}
|
||||||
else if (candidate[chan][subchan].retries == RETRY_SINGLE) {
|
else if (candidate[chan][subchan].retries == RETRY_SWAP_SINGLE) {
|
||||||
spectrum[subchan] = ':';
|
spectrum[subchan] = ':';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -406,7 +516,7 @@ static void pick_best_candidate (int chan)
|
||||||
|
|
||||||
/* Begining score depends on effort to get a valid frame CRC. */
|
/* Begining score depends on effort to get a valid frame CRC. */
|
||||||
|
|
||||||
candidate[chan][subchan].score = 5000 - ((int)candidate[chan][subchan].retries * 1000);
|
candidate[chan][subchan].score = RETRY_MAX * 1000 - ((int)candidate[chan][subchan].retries * 1000);
|
||||||
|
|
||||||
/* Bump it up slightly if others nearby have the same CRC. */
|
/* Bump it up slightly if others nearby have the same CRC. */
|
||||||
|
|
||||||
|
@ -461,8 +571,8 @@ static void pick_best_candidate (int chan)
|
||||||
candidate[chan][best_subchan].alevel,
|
candidate[chan][best_subchan].alevel,
|
||||||
(int)(candidate[chan][best_subchan].retries),
|
(int)(candidate[chan][best_subchan].retries),
|
||||||
spectrum);
|
spectrum);
|
||||||
crc_of_last_to_app[chan] = candidate[chan][best_subchan].crc;
|
if (crc_queue_append(candidate[chan][best_subchan].crc, chan) > MAX_STORED_CRC)
|
||||||
|
crc_queue_remove(chan);
|
||||||
/* Someone else will delete so don't do it below. */
|
/* Someone else will delete so don't do it below. */
|
||||||
candidate[chan][best_subchan].packet_p = NULL;
|
candidate[chan][best_subchan].packet_p = NULL;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Name: nmea.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ax25_pad.h" /* for packet_t */
|
||||||
|
|
||||||
|
#include "config.h" /* for struct misc_config_s */
|
||||||
|
|
||||||
|
|
||||||
|
void nmea_init (struct misc_config_s *misc_config);
|
||||||
|
|
||||||
|
void nmea_set_debug (int n);
|
||||||
|
|
||||||
|
void nmea_send_waypoint (char *wname_in, double dlat, double dlong, char symtab, char symbol,
|
||||||
|
float alt, float course, float speed, char *comment);
|
||||||
|
|
||||||
|
/* end nmea.h */
|
183
ptt.c
183
ptt.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011,2013 John Langner, WB2OSZ
|
// Copyright (C) 2011,2013,2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -34,6 +34,8 @@
|
||||||
*
|
*
|
||||||
* Version 0.9: Add ability to use GPIO pins on Linux.
|
* Version 0.9: Add ability to use GPIO pins on Linux.
|
||||||
*
|
*
|
||||||
|
* Version 1.1: Add parallel printer port for x86 Linux only.
|
||||||
|
*
|
||||||
* References: http://www.robbayer.com/files/serial-win.pdf
|
* References: http://www.robbayer.com/files/serial-win.pdf
|
||||||
*
|
*
|
||||||
* https://www.kernel.org/doc/Documentation/gpio.txt
|
* https://www.kernel.org/doc/Documentation/gpio.txt
|
||||||
|
@ -86,6 +88,14 @@ typedef int HANDLE;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LPT_IO_ADDR 0x378
|
||||||
|
|
||||||
|
|
||||||
|
#if TEST
|
||||||
|
#define dw_printf printf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------
|
/*-------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
|
@ -108,6 +118,7 @@ static ptt_method_t ptt_method[MAX_CHANS]; /* Method for PTT signal. */
|
||||||
/* PTT_METHOD_NONE - not configured. Could be using VOX. */
|
/* PTT_METHOD_NONE - not configured. Could be using VOX. */
|
||||||
/* PTT_METHOD_SERIAL - serial (com) port. */
|
/* PTT_METHOD_SERIAL - serial (com) port. */
|
||||||
/* PTT_METHOD_GPIO - general purpose I/O. */
|
/* PTT_METHOD_GPIO - general purpose I/O. */
|
||||||
|
/* PTT_METHOD_LPT - Parallel printer port. */
|
||||||
|
|
||||||
static char ptt_device[MAX_CHANS][20]; /* Name of serial port device. */
|
static char ptt_device[MAX_CHANS][20]; /* Name of serial port device. */
|
||||||
/* e.g. COM1 or /dev/ttyS0. */
|
/* e.g. COM1 or /dev/ttyS0. */
|
||||||
|
@ -117,6 +128,10 @@ static ptt_line_t ptt_line[MAX_CHANS]; /* RTS or DTR when using serial port. */
|
||||||
static int ptt_gpio[MAX_CHANS]; /* GPIO number. Only used for Linux. */
|
static int ptt_gpio[MAX_CHANS]; /* GPIO number. Only used for Linux. */
|
||||||
/* Valid only when ptt_method is PTT_METHOD_GPIO. */
|
/* Valid only when ptt_method is PTT_METHOD_GPIO. */
|
||||||
|
|
||||||
|
int ptt_lpt_bit[MAX_CHANS]; /* Bit number for parallel printer port. */
|
||||||
|
/* Bit 0 = pin 2, ..., bit 7 = pin 9. */
|
||||||
|
/* Valid only when ptt_method is PTT_METHOD_LPT. */
|
||||||
|
|
||||||
static int ptt_invert[MAX_CHANS]; /* Invert the signal. */
|
static int ptt_invert[MAX_CHANS]; /* Invert the signal. */
|
||||||
/* Normally higher voltage means transmit. */
|
/* Normally higher voltage means transmit. */
|
||||||
|
|
||||||
|
@ -157,16 +172,18 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
strcpy (ptt_device[ch], p_modem->ptt_device[ch]);
|
strcpy (ptt_device[ch], p_modem->ptt_device[ch]);
|
||||||
ptt_line[ch] = p_modem->ptt_line[ch];
|
ptt_line[ch] = p_modem->ptt_line[ch];
|
||||||
ptt_gpio[ch] = p_modem->ptt_gpio[ch];
|
ptt_gpio[ch] = p_modem->ptt_gpio[ch];
|
||||||
|
ptt_lpt_bit[ch] = p_modem->ptt_lpt_bit[ch];
|
||||||
ptt_invert[ch] = p_modem->ptt_invert[ch];
|
ptt_invert[ch] = p_modem->ptt_invert[ch];
|
||||||
ptt_fd[ch] = INVALID_HANDLE_VALUE;
|
ptt_fd[ch] = INVALID_HANDLE_VALUE;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("ch=%d, method=%d, device=%s, line=%d, gpio=%d, invert=%d\n",
|
dw_printf ("ch=%d, method=%d, device=%s, line=%d, gpio=%d, lpt_bit=%d, invert=%d\n",
|
||||||
ch,
|
ch,
|
||||||
ptt_method[ch],
|
ptt_method[ch],
|
||||||
ptt_device[ch],
|
ptt_device[ch],
|
||||||
ptt_line[ch],
|
ptt_line[ch],
|
||||||
ptt_gpio[ch],
|
ptt_gpio[ch],
|
||||||
|
ptt_lpt_bit[ch],
|
||||||
ptt_invert[ch]);
|
ptt_invert[ch]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -205,8 +222,20 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
char bettername[50];
|
||||||
|
// Bug fix in release 1.1 - Need to munge name for COM10 and up.
|
||||||
|
// http://support.microsoft.com/kb/115831
|
||||||
|
|
||||||
fd = CreateFile(ptt_device[ch],
|
strcpy (bettername, ptt_device[ch]);
|
||||||
|
if (strncasecmp(bettername, "COM", 3) == 0) {
|
||||||
|
int n;
|
||||||
|
n = atoi(bettername+3);
|
||||||
|
if (n >= 10) {
|
||||||
|
strcpy (bettername, "\\\\.\\");
|
||||||
|
strcat (bettername, ptt_device[ch]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fd = CreateFile(bettername,
|
||||||
GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -295,9 +324,10 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
*/
|
*/
|
||||||
if (geteuid() != 0) {
|
if (geteuid() != 0) {
|
||||||
if ( ! (finfo.st_mode & S_IWOTH)) {
|
if ( ! (finfo.st_mode & S_IWOTH)) {
|
||||||
|
int err;
|
||||||
|
|
||||||
/* Try to change protection. */
|
/* Try to change protection. */
|
||||||
system ("sudo chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport");
|
err = system ("sudo chmod go+w /sys/class/gpio/export /sys/class/gpio/unexport");
|
||||||
|
|
||||||
if (stat("/sys/class/gpio/export", &finfo) < 0) {
|
if (stat("/sys/class/gpio/export", &finfo) < 0) {
|
||||||
/* Unexpected because we could do it before. */
|
/* Unexpected because we could do it before. */
|
||||||
|
@ -327,6 +357,7 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
if (ptt_method[ch] == PTT_METHOD_GPIO) {
|
if (ptt_method[ch] == PTT_METHOD_GPIO) {
|
||||||
char stemp[80];
|
char stemp[80];
|
||||||
struct stat finfo;
|
struct stat finfo;
|
||||||
|
int err;
|
||||||
|
|
||||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
@ -355,9 +386,9 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
* We only care about "direction" and "value".
|
* We only care about "direction" and "value".
|
||||||
*/
|
*/
|
||||||
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", ptt_gpio[ch]);
|
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/direction", ptt_gpio[ch]);
|
||||||
system (stemp);
|
err = system (stemp);
|
||||||
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/value", ptt_gpio[ch]);
|
sprintf (stemp, "sudo chmod go+rw /sys/class/gpio/gpio%d/value", ptt_gpio[ch]);
|
||||||
system (stemp);
|
err = system (stemp);
|
||||||
|
|
||||||
sprintf (stemp, "/sys/class/gpio/gpio%d/value", ptt_gpio[ch]);
|
sprintf (stemp, "/sys/class/gpio/gpio%d/value", ptt_gpio[ch]);
|
||||||
|
|
||||||
|
@ -414,12 +445,75 @@ void ptt_init (struct audio_s *p_modem)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up parallel printer port.
|
||||||
|
* Hardcoded for single port.
|
||||||
|
* For x86 Linux only.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
|
||||||
|
|
||||||
|
for (ch=0; ch<ptt_num_channels; ch++) {
|
||||||
|
|
||||||
|
if (ptt_method[ch] == PTT_METHOD_LPT) {
|
||||||
|
|
||||||
|
|
||||||
|
/* Can't open the same device more than once so we */
|
||||||
|
/* need more logic to look for the case of both radio */
|
||||||
|
/* channels using different pins of the same LPT port. */
|
||||||
|
|
||||||
|
/* TODO: Needs to be rewritten in a more general manner */
|
||||||
|
/* if we ever have more than 2 channels. */
|
||||||
|
|
||||||
|
if (ch == 1 && strcmp(ptt_device[0],ptt_device[1]) == 0) {
|
||||||
|
fd = ptt_fd[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fd = open ("/dev/port", O_RDWR | O_NDELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd != INVALID_HANDLE_VALUE) {
|
||||||
|
ptt_fd[ch] = fd;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
int e = errno;
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("ERROR - Can't open /dev/port for parallel printer port PTT control.\n");
|
||||||
|
dw_printf ("%s\n", strerror(errno));
|
||||||
|
dw_printf ("You probably don't have adequate permissions to access I/O ports.\n");
|
||||||
|
dw_printf ("Either run direwolf as root or change these permissions:\n");
|
||||||
|
dw_printf (" sudo chmod go+rw /dev/port\n");
|
||||||
|
dw_printf (" sudo setcap cap_sys_rawio=ep `which direwolf`\n");
|
||||||
|
|
||||||
|
/* Don't try using it later if device open failed. */
|
||||||
|
|
||||||
|
ptt_method[ch] = PTT_METHOD_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set initial state of PTT off.
|
||||||
|
* ptt_set will invert output signal if appropriate.
|
||||||
|
*/
|
||||||
|
ptt_set (ch, 0);
|
||||||
|
|
||||||
|
} /* if parallel printer port method. */
|
||||||
|
|
||||||
|
} /* For each channel. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* x86 Linux */
|
||||||
|
|
||||||
|
|
||||||
/* Why doesn't it transmit? Probably forgot to specify PTT option. */
|
/* Why doesn't it transmit? Probably forgot to specify PTT option. */
|
||||||
|
|
||||||
for (ch=0; ch<ptt_num_channels; ch++) {
|
for (ch=0; ch<ptt_num_channels; ch++) {
|
||||||
if(ptt_method[ch] == PTT_METHOD_NONE) {
|
if(ptt_method[ch] == PTT_METHOD_NONE) {
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf ("Note: PTT not configured for channel %d.\n", ch);
|
dw_printf ("Note: PTT not configured for channel %d. (Ignore this if using VOX.)\n", ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* end ptt_init */
|
} /* end ptt_init */
|
||||||
|
@ -523,6 +617,44 @@ void ptt_set (int chan, int ptt)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using parallel printer port?
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
|
||||||
|
|
||||||
|
if (ptt_method[chan] == PTT_METHOD_LPT &&
|
||||||
|
ptt_fd[chan] != INVALID_HANDLE_VALUE) {
|
||||||
|
|
||||||
|
char lpt_data;
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
lseek (ptt_fd[chan], (off_t)LPT_IO_ADDR, SEEK_SET);
|
||||||
|
if (read (ptt_fd[chan], &lpt_data, (size_t)1) != 1) {
|
||||||
|
int e = errno;
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Error reading current state of LPT for channel %d PTT\n", chan);
|
||||||
|
dw_printf ("%s\n", strerror(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ptt) {
|
||||||
|
lpt_data |= ( 1 << ptt_lpt_bit[chan] );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lpt_data &= ~ ( 1 << ptt_lpt_bit[chan] );
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek (ptt_fd[chan], (off_t)LPT_IO_ADDR, SEEK_SET);
|
||||||
|
if (write (ptt_fd[chan], &lpt_data, (size_t)1) != 1) {
|
||||||
|
int e = errno;
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Error writing to LPT for channel %d PTT\n", chan);
|
||||||
|
dw_printf ("%s\n", strerror(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* x86 Linux */
|
||||||
|
|
||||||
|
|
||||||
} /* end ptt_set */
|
} /* end ptt_set */
|
||||||
|
|
||||||
|
@ -546,6 +678,9 @@ void ptt_term (void)
|
||||||
|
|
||||||
for (n = 0; n < ptt_num_channels; n++) {
|
for (n = 0; n < ptt_num_channels; n++) {
|
||||||
ptt_set (n, 0);
|
ptt_set (n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; n < ptt_num_channels; n++) {
|
||||||
if (ptt_fd[n] != INVALID_HANDLE_VALUE) {
|
if (ptt_fd[n] != INVALID_HANDLE_VALUE) {
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
CloseHandle (ptt_fd[n]);
|
CloseHandle (ptt_fd[n]);
|
||||||
|
@ -572,6 +707,8 @@ void ptt_term (void)
|
||||||
|
|
||||||
void text_color_set (dw_color_t c) { }
|
void text_color_set (dw_color_t c) { }
|
||||||
|
|
||||||
|
#define dw_printf printf
|
||||||
|
|
||||||
main ()
|
main ()
|
||||||
{
|
{
|
||||||
struct audio_s modem;
|
struct audio_s modem;
|
||||||
|
@ -656,8 +793,7 @@ main ()
|
||||||
|
|
||||||
/* Test GPIO */
|
/* Test GPIO */
|
||||||
|
|
||||||
#if __WIN32__
|
#if __arm__
|
||||||
#else
|
|
||||||
|
|
||||||
memset (&modem, 0, sizeof(modem));
|
memset (&modem, 0, sizeof(modem));
|
||||||
modem.num_channels = 1;
|
modem.num_channels = 1;
|
||||||
|
@ -680,6 +816,35 @@ main ()
|
||||||
ptt_term ();
|
ptt_term ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
memset (&modem, 0, sizeof(modem));
|
||||||
|
modem.num_channels = 2;
|
||||||
|
modem.ptt_method[0] = PTT_METHOD_LPT;
|
||||||
|
modem.ptt_lpt_bit[0] = 0;
|
||||||
|
modem.ptt_method[1] = PTT_METHOD_LPT;
|
||||||
|
modem.ptt_lpt_bit[1] = 1;
|
||||||
|
|
||||||
|
dw_printf ("Try LPT bits 0 & 1 a few times...\n");
|
||||||
|
|
||||||
|
ptt_init (&modem);
|
||||||
|
|
||||||
|
for (n=0; n<8; n++) {
|
||||||
|
ptt_set (0, n & 1);
|
||||||
|
ptt_set (1, (n>>1) & 1);
|
||||||
|
SLEEP_SEC(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptt_term ();
|
||||||
|
|
||||||
|
/* Parallel printer port. */
|
||||||
|
|
||||||
|
#if ( defined(__i386__) || defined(__x86_64__) ) && ( defined(__linux__) || defined(__unix__) )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
18
rdq.c
18
rdq.c
|
@ -44,8 +44,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static rrbb_t queue_head; /* Head of linked list for queue. */
|
static rrbb_t queue_head = NULL; /* Head of linked list for queue. */
|
||||||
|
static int rdq_len = 0;
|
||||||
|
#define RDQ_UNDERRUN_THRESHOLD 30 /* A warning will be emitted if there are still this number of packets to decode in the queue and we try to add another one */
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
||||||
static CRITICAL_SECTION rdq_cs; /* Critical section for updating queues. */
|
static CRITICAL_SECTION rdq_cs; /* Critical section for updating queues. */
|
||||||
|
@ -204,7 +205,11 @@ void rdq_append (rrbb_t rrbb)
|
||||||
}
|
}
|
||||||
rrbb_set_nextp (plast, rrbb);
|
rrbb_set_nextp (plast, rrbb);
|
||||||
}
|
}
|
||||||
|
rdq_len++;
|
||||||
|
if (rdq_len > RDQ_UNDERRUN_THRESHOLD) {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Too many packets to decode (%d) in the queue, decrease the FIX_BITS value\n", rdq_len);
|
||||||
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
LeaveCriticalSection (&rdq_cs);
|
LeaveCriticalSection (&rdq_cs);
|
||||||
|
@ -374,7 +379,7 @@ void rdq_wait_while_empty (void)
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("rdq_wait_while_empty () returns\n");
|
dw_printf ("rdq_wait_while_empty () returns (%d buffers remaining)\n", rdq_len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -418,7 +423,10 @@ rrbb_t rdq_remove (void)
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
rdq_len--;
|
||||||
|
#if DEBUG
|
||||||
|
dw_printf ("-rdq_len: %d\n", rdq_len);
|
||||||
|
#endif
|
||||||
if (queue_head == NULL) {
|
if (queue_head == NULL) {
|
||||||
result_p = NULL;
|
result_p = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
This is NOT used for the Linux version.
|
||||||
For Linux and Cygwin, we use the built-in regular expression library.
|
For Linux and Cygwin, we use the built-in regular expression library.
|
||||||
For the Windows version, we need to include our own version.
|
For the Windows version, we need to include our own version.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File: rpack.h
|
||||||
|
*
|
||||||
|
* Purpose: Definition of Garmin Rino message format.
|
||||||
|
*
|
||||||
|
* References: http://www.radio-active.net.au/web3/APRS/Resources/RINO
|
||||||
|
*
|
||||||
|
* http://www.radio-active.net.au/web3/APRS/Resources/RINO/OnAir
|
||||||
|
*
|
||||||
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RPACK_H
|
||||||
|
#define RPACK_H 1
|
||||||
|
|
||||||
|
|
||||||
|
#define RPACK_FRAME_LEN 168
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef RPACK_C /* Expose private details */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Transmission order is LSB first.
|
||||||
|
|
||||||
|
struct __attribute__((__packed__)) rpack_s {
|
||||||
|
|
||||||
|
int lat; // Latitude.
|
||||||
|
// Signed integer. Scaled by 2**30/90.
|
||||||
|
|
||||||
|
int lon; // Longitude. Same encoding.
|
||||||
|
|
||||||
|
char unknown1; // Unproven theory: altitude.
|
||||||
|
char unknown2;
|
||||||
|
|
||||||
|
unsigned name0:6; // 10 character name.
|
||||||
|
unsigned name1:6; // Bit packing is implementation dependent.
|
||||||
|
unsigned name2:6; // Should rewrite to be more portable.
|
||||||
|
unsigned name3:6;
|
||||||
|
unsigned name4:6;
|
||||||
|
unsigned name5:6;
|
||||||
|
unsigned name6:6;
|
||||||
|
unsigned name7:6;
|
||||||
|
unsigned name8:6;
|
||||||
|
unsigned name9:6;
|
||||||
|
|
||||||
|
unsigned symbol:5;
|
||||||
|
|
||||||
|
unsigned unknown3:7;
|
||||||
|
|
||||||
|
|
||||||
|
// unsigned crc:16; // Safe bet this is CRC for error checking.
|
||||||
|
|
||||||
|
unsigned char crc1;
|
||||||
|
unsigned char crc2;
|
||||||
|
|
||||||
|
char dummy[3]; // Total size should be 24 bytes if no gaps.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#else /* Show only public interface. */
|
||||||
|
|
||||||
|
|
||||||
|
struct rpack_s {
|
||||||
|
char stuff[24];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void rpack_set_bit (struct rpack_s *rp, int position, int value);
|
||||||
|
|
||||||
|
int rpack_is_valid (struct rpack_s *rp);
|
||||||
|
|
||||||
|
int rpack_get_bit (struct rpack_s *rp, int position);
|
||||||
|
|
||||||
|
double rpack_get_lat (struct rpack_s *rp);
|
||||||
|
|
||||||
|
double rpack_get_lon (struct rpack_s *rp);
|
||||||
|
|
||||||
|
int rpack_get_symbol (struct rpack_s *rp);
|
||||||
|
|
||||||
|
void rpack_get_name (struct rpack_s *rp, char *str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* end rpack.h */
|
||||||
|
|
72
rrbb.c
72
rrbb.c
|
@ -374,18 +374,13 @@ int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
||||||
#else
|
#else
|
||||||
int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
||||||
{
|
{
|
||||||
unsigned int di, mi;
|
|
||||||
|
|
||||||
assert (b != NULL);
|
assert (b != NULL);
|
||||||
assert (b->magic1 == MAGIC1);
|
assert (b->magic1 == MAGIC1);
|
||||||
assert (b->magic2 == MAGIC2);
|
assert (b->magic2 == MAGIC2);
|
||||||
|
|
||||||
assert (ind < b->len);
|
assert (ind < b->len);
|
||||||
|
|
||||||
di = ind / SOI;
|
if (b->data[ind / SOI] & masks[ind % SOI]) {
|
||||||
mi = ind % SOI;
|
|
||||||
|
|
||||||
if (b->data[di] & masks[mi]) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -393,6 +388,30 @@ int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
unsigned int rrbb_get_computed_bit (rrbb_t b, unsigned int ind)
|
||||||
|
{
|
||||||
|
return b->computed_data[ind];
|
||||||
|
}
|
||||||
|
|
||||||
|
int rrbb_compute_bits (rrbb_t b)
|
||||||
|
{
|
||||||
|
unsigned int i,val;
|
||||||
|
|
||||||
|
assert (b != NULL);
|
||||||
|
assert (b->magic1 == MAGIC1);
|
||||||
|
assert (b->magic2 == MAGIC2);
|
||||||
|
|
||||||
|
for (i=0;i<b->len;i++) {
|
||||||
|
if (b->data[i / SOI] & masks[i % SOI]) {
|
||||||
|
val = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
|
b->computed_data[i] = val;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************
|
/***********************************************************************************
|
||||||
|
@ -572,6 +591,47 @@ int rrbb_get_audio_level (rrbb_t b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************************
|
||||||
|
*
|
||||||
|
* Name: rrbb_set_fix_bits
|
||||||
|
*
|
||||||
|
* Purpose: Set fix bits at time the frame was received.
|
||||||
|
*
|
||||||
|
* Inputs: b Handle for bit array.
|
||||||
|
* a fix_bits.
|
||||||
|
*
|
||||||
|
***********************************************************************************/
|
||||||
|
|
||||||
|
void rrbb_set_fix_bits (rrbb_t b, int a)
|
||||||
|
{
|
||||||
|
assert (b != NULL);
|
||||||
|
assert (b->magic1 == MAGIC1);
|
||||||
|
assert (b->magic2 == MAGIC2);
|
||||||
|
|
||||||
|
b->fix_bits = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************************
|
||||||
|
*
|
||||||
|
* Name: rrbb_get_fix_bits
|
||||||
|
*
|
||||||
|
* Purpose: Get fix bits at time the frame was received.
|
||||||
|
*
|
||||||
|
* Inputs: b Handle for bit array.
|
||||||
|
*
|
||||||
|
***********************************************************************************/
|
||||||
|
|
||||||
|
int rrbb_get_fix_bits (rrbb_t b)
|
||||||
|
{
|
||||||
|
assert (b != NULL);
|
||||||
|
assert (b->magic1 == MAGIC1);
|
||||||
|
assert (b->magic2 == MAGIC2);
|
||||||
|
|
||||||
|
return (b->fix_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************************
|
/***********************************************************************************
|
||||||
*
|
*
|
||||||
* Name: rrbb_get_is_scrambled
|
* Name: rrbb_get_is_scrambled
|
||||||
|
|
11
rrbb.h
11
rrbb.h
|
@ -37,6 +37,9 @@ typedef struct rrbb_s {
|
||||||
int subchan; /* Which modem when more than one per channel. */
|
int subchan; /* Which modem when more than one per channel. */
|
||||||
int audio_level; /* Received audio level at time of frame capture. */
|
int audio_level; /* Received audio level at time of frame capture. */
|
||||||
unsigned int len; /* Current number of samples in array. */
|
unsigned int len; /* Current number of samples in array. */
|
||||||
|
int fix_bits; /* Level of effort to recover from */
|
||||||
|
/* a bad FCS on the frame. */
|
||||||
|
|
||||||
|
|
||||||
int is_scrambled; /* Is data scrambled G3RUH / K9NG style? */
|
int is_scrambled; /* Is data scrambled G3RUH / K9NG style? */
|
||||||
int descram_state; /* Descrambler state before first data bit of frame. */
|
int descram_state; /* Descrambler state before first data bit of frame. */
|
||||||
|
@ -46,6 +49,7 @@ typedef struct rrbb_s {
|
||||||
slice_t data[MAX_NUM_BITS];
|
slice_t data[MAX_NUM_BITS];
|
||||||
#else
|
#else
|
||||||
unsigned int data[(MAX_NUM_BITS+SOI-1)/SOI];
|
unsigned int data[(MAX_NUM_BITS+SOI-1)/SOI];
|
||||||
|
unsigned int computed_data[MAX_NUM_BITS];
|
||||||
#endif
|
#endif
|
||||||
int magic2;
|
int magic2;
|
||||||
} *rrbb_t;
|
} *rrbb_t;
|
||||||
|
@ -79,6 +83,8 @@ void rrbb_set_slice_val (rrbb_t b, slice_t slice_val);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rrbb_get_bit (rrbb_t b, unsigned int ind);
|
int rrbb_get_bit (rrbb_t b, unsigned int ind);
|
||||||
|
unsigned int rrbb_get_computed_bit (rrbb_t b, unsigned int ind);
|
||||||
|
int rrbb_compute_bits (rrbb_t b);
|
||||||
|
|
||||||
//void rrbb_flip_bit (rrbb_t b, unsigned int ind);
|
//void rrbb_flip_bit (rrbb_t b, unsigned int ind);
|
||||||
|
|
||||||
|
@ -99,4 +105,7 @@ int rrbb_get_is_scrambled (rrbb_t b);
|
||||||
|
|
||||||
int rrbb_get_descram_state (rrbb_t b);
|
int rrbb_get_descram_state (rrbb_t b);
|
||||||
|
|
||||||
#endif
|
int rrbb_get_fix_bits(rrbb_t b);
|
||||||
|
void rrbb_set_fix_bits(rrbb_t b, int fix_bits);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
432
server.c
432
server.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011,2012,2013 John Langner, WB2OSZ
|
// Copyright (C) 2011, 2012, 2013, 2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -85,6 +85,12 @@
|
||||||
* Getting Started with Winsock
|
* Getting Started with Winsock
|
||||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb530742(v=vs.85).aspx
|
* http://msdn.microsoft.com/en-us/library/windows/desktop/bb530742(v=vs.85).aspx
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* Major change in 1.1:
|
||||||
|
*
|
||||||
|
* Formerly a single client was allowed.
|
||||||
|
* Now we can have multiple concurrent clients.
|
||||||
|
*
|
||||||
*---------------------------------------------------------------*/
|
*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,21 +128,42 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Previously, we allowed only one network connection at a time to each port.
|
||||||
|
* In version 1.1, we allow multiple concurrent client apps to connect.
|
||||||
|
*/
|
||||||
|
|
||||||
static int client_sock; /* File descriptor for socket for */
|
#define MAX_NET_CLIENTS 3
|
||||||
/* communication with client application. */
|
|
||||||
/* Set to -1 if not connected. */
|
|
||||||
/* (Don't use SOCKET type because it is unsigned.) */
|
|
||||||
|
|
||||||
static int enable_send_raw_to_client; /* Should we send received packets to client app? */
|
static int client_sock[MAX_NET_CLIENTS];
|
||||||
static int enable_send_monitor_to_client;
|
/* File descriptor for socket for */
|
||||||
|
/* communication with client application. */
|
||||||
|
/* Set to -1 if not connected. */
|
||||||
|
/* (Don't use SOCKET type because it is unsigned.) */
|
||||||
|
|
||||||
|
static int enable_send_raw_to_client[MAX_NET_CLIENTS];
|
||||||
|
/* Should we send received packets to client app in raw form? */
|
||||||
|
/* Note that it starts as false for a new connection. */
|
||||||
|
/* the client app must send a command to enable this. */
|
||||||
|
|
||||||
|
static int enable_send_monitor_to_client[MAX_NET_CLIENTS];
|
||||||
|
/* Should we send received packets to client app in monitor form? */
|
||||||
|
/* Note that it starts as false for a new connection. */
|
||||||
|
/* the client app must send a command to enable this. */
|
||||||
|
|
||||||
|
|
||||||
static int num_channels; /* Number of radio ports. */
|
static int num_channels; /* Number of radio ports. */
|
||||||
|
|
||||||
|
|
||||||
static void * connect_listen_thread (void *arg);
|
// TODO: define in one place, use everywhere.
|
||||||
static void * cmd_listen_thread (void *arg);
|
#if __WIN32__
|
||||||
|
#define THREAD_F unsigned __stdcall
|
||||||
|
#else
|
||||||
|
#define THREAD_F void *
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static THREAD_F connect_listen_thread (void *arg);
|
||||||
|
static THREAD_F cmd_listen_thread (void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message header for AGW protocol.
|
* Message header for AGW protocol.
|
||||||
|
@ -169,12 +196,13 @@ struct agwpe_s {
|
||||||
* Purpose: Print message to/from client for debugging.
|
* Purpose: Print message to/from client for debugging.
|
||||||
*
|
*
|
||||||
* Inputs: fromto - Direction of message.
|
* Inputs: fromto - Direction of message.
|
||||||
|
* client - client number, 0 .. MAX_NET_CLIENTS-1
|
||||||
* pmsg - Address of the message block.
|
* pmsg - Address of the message block.
|
||||||
* msg_len - Length of the message.
|
* msg_len - Length of the message.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
static int debug_client = 0; /* Print information flowing from and to client. */
|
static int debug_client = 0; /* Debug option: Print information flowing from and to client. */
|
||||||
|
|
||||||
void server_set_debug (int n)
|
void server_set_debug (int n)
|
||||||
{
|
{
|
||||||
|
@ -208,7 +236,7 @@ void hex_dump (unsigned char *p, int len)
|
||||||
|
|
||||||
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
typedef enum fromto_e { FROM_CLIENT=0, TO_CLIENT=1 } fromto_t;
|
||||||
|
|
||||||
static void debug_print (fromto_t fromto, struct agwpe_s *pmsg, int msg_len)
|
static void debug_print (fromto_t fromto, int client, struct agwpe_s *pmsg, int msg_len)
|
||||||
{
|
{
|
||||||
char direction [10];
|
char direction [10];
|
||||||
char datakind[80];
|
char datakind[80];
|
||||||
|
@ -269,15 +297,15 @@ static void debug_print (fromto_t fromto, struct agwpe_s *pmsg, int msg_len)
|
||||||
text_color_set(DW_COLOR_DEBUG);
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
dw_printf ("%s %s %s AGWPE client application, total length = %d\n",
|
dw_printf ("%s %s %s AGWPE client application %d, total length = %d\n",
|
||||||
prefix[(int)fromto], datakind, direction, msg_len);
|
prefix[(int)fromto], datakind, direction, client, msg_len);
|
||||||
|
|
||||||
dw_printf ("\tportx = %d, port_hi_reserved = %d\n", pmsg->portx, pmsg->port_hi_reserved);
|
dw_printf ("\tportx = %d, port_hi_reserved = %d\n", pmsg->portx, pmsg->port_hi_reserved);
|
||||||
dw_printf ("\tkind_lo = %d = '%c', kind_hi = %d\n", pmsg->kind_lo, pmsg->kind_lo, pmsg->kind_hi);
|
dw_printf ("\tkind_lo = %d = '%c', kind_hi = %d\n", pmsg->kind_lo, pmsg->kind_lo, pmsg->kind_hi);
|
||||||
dw_printf ("\tcall_from = \"%s\", call_to = \"%s\"\n", pmsg->call_from, pmsg->call_to);
|
dw_printf ("\tcall_from = \"%s\", call_to = \"%s\"\n", pmsg->call_from, pmsg->call_to);
|
||||||
dw_printf ("\tdata_len = %d, user_reserved = %d, data =\n", pmsg->data_len, pmsg->user_reserved);
|
dw_printf ("\tdata_len = %d, user_reserved = %d, data =\n", pmsg->data_len, pmsg->user_reserved);
|
||||||
|
|
||||||
hex_dump ((char*)pmsg + sizeof(struct agwpe_s), pmsg->data_len);
|
hex_dump ((unsigned char*)pmsg + sizeof(struct agwpe_s), pmsg->data_len);
|
||||||
|
|
||||||
if (msg_len < 36) {
|
if (msg_len < 36) {
|
||||||
text_color_set (DW_COLOR_ERROR);
|
text_color_set (DW_COLOR_ERROR);
|
||||||
|
@ -303,9 +331,9 @@ static void debug_print (fromto_t fromto, struct agwpe_s *pmsg, int msg_len)
|
||||||
*
|
*
|
||||||
* Outputs:
|
* Outputs:
|
||||||
*
|
*
|
||||||
* Description: This starts two threads:
|
* Description: This starts at least two threads:
|
||||||
* * to listen for a connection from client app.
|
* * one to listen for a connection from client app.
|
||||||
* * to listen for commands from client app.
|
* * one or more to listen for commands from client app.
|
||||||
* so the main application doesn't block while we wait for these.
|
* so the main application doesn't block while we wait for these.
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
@ -313,15 +341,17 @@ static void debug_print (fromto_t fromto, struct agwpe_s *pmsg, int msg_len)
|
||||||
|
|
||||||
void server_init (struct misc_config_s *mc)
|
void server_init (struct misc_config_s *mc)
|
||||||
{
|
{
|
||||||
|
int client;
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
HANDLE connect_listen_th;
|
HANDLE connect_listen_th;
|
||||||
HANDLE cmd_listen_th;
|
HANDLE cmd_listen_th[MAX_NET_CLIENTS];
|
||||||
#else
|
#else
|
||||||
pthread_t connect_listen_tid;
|
pthread_t connect_listen_tid;
|
||||||
pthread_t cmd_listen_tid;
|
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
|
||||||
#endif
|
#endif
|
||||||
int e;
|
int e;
|
||||||
int server_port = mc->agwpe_port;
|
int server_port = mc->agwpe_port; /* Usually 8000 but can be changed. */
|
||||||
|
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -329,16 +359,18 @@ void server_init (struct misc_config_s *mc)
|
||||||
dw_printf ("server_init ( %d )\n", server_port);
|
dw_printf ("server_init ( %d )\n", server_port);
|
||||||
debug_a = 1;
|
debug_a = 1;
|
||||||
#endif
|
#endif
|
||||||
client_sock = -1;
|
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||||
enable_send_raw_to_client = 0;
|
client_sock[client] = -1;
|
||||||
enable_send_monitor_to_client = 0;
|
enable_send_raw_to_client[client] = 0;
|
||||||
|
enable_send_monitor_to_client[client] = 0;
|
||||||
|
}
|
||||||
num_channels = mc->num_channels;
|
num_channels = mc->num_channels;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This waits for a client to connect and sets client_sock.
|
* This waits for a client to connect and sets an available client_sock[n].
|
||||||
*/
|
*/
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
connect_listen_th = _beginthreadex (NULL, 0, connect_listen_thread, (void *)server_port, 0, NULL);
|
connect_listen_th = (HANDLE)_beginthreadex (NULL, 0, connect_listen_thread, (void *)(unsigned int)server_port, 0, NULL);
|
||||||
if (connect_listen_th == NULL) {
|
if (connect_listen_th == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create AGW connect listening thread\n");
|
dw_printf ("Could not create AGW connect listening thread\n");
|
||||||
|
@ -354,23 +386,28 @@ void server_init (struct misc_config_s *mc)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This reads messages from client when client_sock is valid.
|
* These read messages from client when client_sock[n] is valid.
|
||||||
|
* Currently we start up a separate thread for each potential connection.
|
||||||
|
* Possible later refinement. Start one now, others only as needed.
|
||||||
*/
|
*/
|
||||||
|
for (client = 0; client < MAX_NET_CLIENTS; client++) {
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
cmd_listen_th = _beginthreadex (NULL, 0, cmd_listen_thread, NULL, 0, NULL);
|
cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, cmd_listen_thread, (void*)client, 0, NULL);
|
||||||
if (cmd_listen_th == NULL) {
|
if (cmd_listen_th[client] == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create AGW command listening thread\n");
|
dw_printf ("Could not create AGW command listening thread\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
e = pthread_create (&cmd_listen_tid, NULL, cmd_listen_thread, NULL);
|
e = pthread_create (&cmd_listen_tid[client], NULL, cmd_listen_thread, (void *)(long)client);
|
||||||
if (e != 0) {
|
if (e != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror("Could not create AGW command listening thread");
|
perror("Could not create AGW command listening thread");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -393,7 +430,7 @@ void server_init (struct misc_config_s *mc)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
static void * connect_listen_thread (void *arg)
|
static THREAD_F connect_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
|
||||||
|
@ -414,7 +451,7 @@ static void * connect_listen_thread (void *arg)
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("WSAStartup failed: %d\n", err);
|
dw_printf("WSAStartup failed: %d\n", err);
|
||||||
return (NULL);
|
return (NULL); // TODO: what should this be for Windows?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
|
if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 2) {
|
||||||
|
@ -471,46 +508,59 @@ static void * connect_listen_thread (void *arg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
while (client_sock > 0) {
|
int client;
|
||||||
SLEEP_SEC(1); /* Already connected. Try again later. */
|
int c;
|
||||||
|
|
||||||
|
client = -1;
|
||||||
|
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
||||||
|
if (client_sock[c] <= 0) {
|
||||||
|
client = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define QUEUE_SIZE 5
|
/*
|
||||||
|
* Listen for connection if we have not reached maximum.
|
||||||
|
*/
|
||||||
|
if (client >= 0) {
|
||||||
|
|
||||||
if(listen(listen_sock,QUEUE_SIZE) == SOCKET_ERROR)
|
if(listen(listen_sock, MAX_NET_CLIENTS) == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("Listen failed with error: %d\n", WSAGetLastError());
|
dw_printf("Listen failed with error: %d\n", WSAGetLastError());
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("Ready to accept AGW client application on port %s ...\n", server_port_str);
|
dw_printf("Ready to accept AGW client application %d on port %s ...\n", client, server_port_str);
|
||||||
|
|
||||||
client_sock = accept(listen_sock, NULL, NULL);
|
client_sock[client] = accept(listen_sock, NULL, NULL);
|
||||||
|
|
||||||
if (client_sock == -1) {
|
if (client_sock[client] == -1) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
||||||
closesocket(listen_sock);
|
closesocket(listen_sock);
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("\nConnected to AGW client application ...\n\n");
|
dw_printf("\nConnected to AGW client application %d ...\n\n", client);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The command to change this is actually a toggle, not explicit on or off.
|
* The command to change this is actually a toggle, not explicit on or off.
|
||||||
* Make sure it has proper state when we get a new connection.
|
* Make sure it has proper state when we get a new connection.
|
||||||
*/
|
*/
|
||||||
enable_send_raw_to_client = 0;
|
enable_send_raw_to_client[client] = 0;
|
||||||
enable_send_monitor_to_client = 0;
|
enable_send_monitor_to_client[client] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else /* End of Windows case, now Linux */
|
||||||
|
|
||||||
|
|
||||||
struct sockaddr_in sockaddr; /* Internet socket address stuct */
|
struct sockaddr_in sockaddr; /* Internet socket address stuct */
|
||||||
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
|
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
|
||||||
|
@ -547,35 +597,44 @@ static void * connect_listen_thread (void *arg)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
while (client_sock > 0) {
|
int client;
|
||||||
SLEEP_SEC(1); /* Already connected. Try again later. */
|
int c;
|
||||||
|
|
||||||
|
client = -1;
|
||||||
|
for (c = 0; c < MAX_NET_CLIENTS && client < 0; c++) {
|
||||||
|
if (client_sock[c] <= 0) {
|
||||||
|
client = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define QUEUE_SIZE 5
|
if (client >= 0) {
|
||||||
|
|
||||||
if(listen(listen_sock,QUEUE_SIZE) == -1)
|
if(listen(listen_sock,MAX_NET_CLIENTS) == -1)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
perror ("connect_listen_thread: Listen failed");
|
perror ("connect_listen_thread: Listen failed");
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("Ready to accept AGW client application on port %d ...\n", server_port);
|
dw_printf("Ready to accept AGW client application %d on port %d ...\n", client, server_port);
|
||||||
|
|
||||||
client_sock = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
|
client_sock[client] = accept(listen_sock, (struct sockaddr*)(&sockaddr),&sockaddr_size);
|
||||||
|
|
||||||
text_color_set(DW_COLOR_INFO);
|
text_color_set(DW_COLOR_INFO);
|
||||||
dw_printf("\nConnected to AGW client application ...\n\n");
|
dw_printf("\nConnected to AGW client application %d...\n\n", client);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The command to change this is actually a toggle, not explicit on or off.
|
* The command to change this is actually a toggle, not explicit on or off.
|
||||||
* Make sure it has proper state when we get a new connection.
|
* Make sure it has proper state when we get a new connection.
|
||||||
*/
|
*/
|
||||||
enable_send_raw_to_client = 0;
|
enable_send_raw_to_client[client] = 0;
|
||||||
enable_send_monitor_to_client = 0;
|
enable_send_monitor_to_client[client] = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -616,13 +675,15 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
int err;
|
int err;
|
||||||
int info_len;
|
int info_len;
|
||||||
unsigned char *pinfo;
|
unsigned char *pinfo;
|
||||||
|
int client;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAW format
|
* RAW format
|
||||||
*/
|
*/
|
||||||
|
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||||
if (enable_send_raw_to_client
|
|
||||||
&& client_sock > 0){
|
if (enable_send_raw_to_client[client] && client_sock[client] > 0){
|
||||||
|
|
||||||
memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
|
memset (&agwpe_msg.hdr, 0, sizeof(agwpe_msg.hdr));
|
||||||
|
|
||||||
|
@ -642,37 +703,38 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
|
memcpy (agwpe_msg.data + 1, fbuf, (size_t)flen);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = send (client_sock, (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError %d sending message to AGW client application. Closing connection.\n\n", WSAGetLastError());
|
dw_printf ("\nError %d sending message to AGW client application. Closing connection.\n\n", WSAGetLastError());
|
||||||
closesocket (client_sock);
|
closesocket (client_sock[client]);
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
err = write (client_sock, &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError sending message to AGW client application. Closing connection.\n\n");
|
dw_printf ("\nError sending message to AGW client application. Closing connection.\n\n");
|
||||||
close (client_sock);
|
close (client_sock[client]);
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* MONITOR format - only for UI frames. */
|
/* MONITOR format - only for UI frames. */
|
||||||
|
|
||||||
|
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||||
|
|
||||||
if (enable_send_monitor_to_client
|
if (enable_send_monitor_to_client[client] && client_sock[client] > 0
|
||||||
&& client_sock > 0
|
|
||||||
&& ax25_get_control(pp) == AX25_UI_FRAME){
|
&& ax25_get_control(pp) == AX25_UI_FRAME){
|
||||||
|
|
||||||
time_t clock;
|
time_t clock;
|
||||||
|
@ -710,29 +772,30 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
||||||
agwpe_msg.hdr.data_len = strlen(agwpe_msg.data) + 1 /* include null */ ;
|
agwpe_msg.hdr.data_len = strlen(agwpe_msg.data) + 1 /* include null */ ;
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
debug_print (TO_CLIENT, client, &agwpe_msg.hdr, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
err = send (client_sock, (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
err = send (client_sock[client], (char*)(&agwpe_msg), sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len, 0);
|
||||||
if (err == SOCKET_ERROR)
|
if (err == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError %d sending message to AGW client application. Closing connection.\n\n", WSAGetLastError());
|
dw_printf ("\nError %d sending message to AGW client application %d. Closing connection.\n\n", WSAGetLastError(), client);
|
||||||
closesocket (client_sock);
|
closesocket (client_sock[client]);
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
err = write (client_sock, &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
err = write (client_sock[client], &agwpe_msg, sizeof(agwpe_msg.hdr) + agwpe_msg.hdr.data_len);
|
||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
{
|
{
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError sending message to AGW client application. Closing connection.\n\n");
|
dw_printf ("\nError sending message to AGW client application %d. Closing connection.\n\n", client);
|
||||||
close (client_sock);
|
close (client_sock[client]);
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* server_send_rec_packet */
|
} /* server_send_rec_packet */
|
||||||
|
@ -800,9 +863,9 @@ static int read_from_socket (int fd, char *ptr, int len)
|
||||||
*
|
*
|
||||||
* Purpose: Wait for command messages from an application.
|
* Purpose: Wait for command messages from an application.
|
||||||
*
|
*
|
||||||
* Inputs: arg - Not used.
|
* Inputs: arg - client number, 0 .. MAX_NET_CLIENTS-1
|
||||||
*
|
*
|
||||||
* Outputs: client_sock - File descriptor for communicating with client app.
|
* Outputs: client_sock[n] - File descriptor for communicating with client app.
|
||||||
*
|
*
|
||||||
* Description: Process messages from the client application.
|
* Description: Process messages from the client application.
|
||||||
* Note that the client can go away and come back again and
|
* Note that the client can go away and come back again and
|
||||||
|
@ -810,11 +873,10 @@ static int read_from_socket (int fd, char *ptr, int len)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
static void * cmd_listen_thread (void *arg)
|
static THREAD_F cmd_listen_thread (void *arg)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct agwpe_s hdr; /* Command header. */
|
struct agwpe_s hdr; /* Command header. */
|
||||||
|
|
||||||
|
@ -822,44 +884,85 @@ static void * cmd_listen_thread (void *arg)
|
||||||
/* Maximum for 'V': 1 + 8*10 + 256 */
|
/* Maximum for 'V': 1 + 8*10 + 256 */
|
||||||
} cmd;
|
} cmd;
|
||||||
|
|
||||||
|
int client = (int) arg;
|
||||||
|
|
||||||
|
assert (client >= 0 && client < MAX_NET_CLIENTS);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
while (client_sock <= 0) {
|
while (client_sock[client] <= 0) {
|
||||||
SLEEP_SEC(1); /* Not connected. Try again later. */
|
SLEEP_SEC(1); /* Not connected. Try again later. */
|
||||||
}
|
}
|
||||||
|
|
||||||
n = read_from_socket (client_sock, (char *)(&cmd.hdr), sizeof(cmd.hdr));
|
n = read_from_socket (client_sock[client], (char *)(&cmd.hdr), sizeof(cmd.hdr));
|
||||||
if (n != sizeof(cmd.hdr)) {
|
if (n != sizeof(cmd.hdr)) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError getting message header from client application.\n");
|
dw_printf ("\nError getting message header from AGW client application %d.\n", client);
|
||||||
dw_printf ("Tried to read %d bytes but got only %d.\n", (int)sizeof(cmd.hdr), n);
|
dw_printf ("Tried to read %d bytes but got only %d.\n", (int)sizeof(cmd.hdr), n);
|
||||||
dw_printf ("Closing connection.\n\n");
|
dw_printf ("Closing connection.\n\n");
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
closesocket (client_sock);
|
closesocket (client_sock[client]);
|
||||||
#else
|
#else
|
||||||
close (client_sock);
|
close (client_sock[client]);
|
||||||
#endif
|
#endif
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert (cmd.hdr.data_len >= 0 && cmd.hdr.data_len < sizeof(cmd.data));
|
/*
|
||||||
|
* Take some precautions to guard against bad data
|
||||||
|
* which could cause problems later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call to/from must not exceeed 9 characters.
|
||||||
|
* It's not guaranteed that unused bytes will contain 0 so we
|
||||||
|
* don't issue error message in this case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
cmd.hdr.call_from[sizeof(cmd.hdr.call_from)-1] = '\0';
|
||||||
|
cmd.hdr.call_to[sizeof(cmd.hdr.call_to)-1] = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Following data must fit in available buffer.
|
||||||
|
* Leave room for an extra nul byte terminator at end later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cmd.hdr.data_len < 0 || cmd.hdr.data_len > sizeof(cmd.data) - 1) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("\nInvalid message from AGW client application %d.\n", client);
|
||||||
|
dw_printf ("Data Length of %d is out of range.\n", cmd.hdr.data_len);
|
||||||
|
|
||||||
|
/* This is a bad situation. */
|
||||||
|
/* If we tried to read again, the header probably won't be there. */
|
||||||
|
/* No point in trying to continue reading. */
|
||||||
|
|
||||||
|
dw_printf ("Closing connection.\n\n");
|
||||||
|
#if __WIN32__
|
||||||
|
closesocket (client_sock[client]);
|
||||||
|
#else
|
||||||
|
close (client_sock[client]);
|
||||||
|
#endif
|
||||||
|
client_sock[client] = -1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
cmd.data[0] = '\0';
|
cmd.data[0] = '\0';
|
||||||
|
|
||||||
if (cmd.hdr.data_len > 0) {
|
if (cmd.hdr.data_len > 0) {
|
||||||
n = read_from_socket (client_sock, cmd.data, cmd.hdr.data_len);
|
n = read_from_socket (client_sock[client], cmd.data, cmd.hdr.data_len);
|
||||||
if (n != cmd.hdr.data_len) {
|
if (n != cmd.hdr.data_len) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\nError getting message data from client application.\n");
|
dw_printf ("\nError getting message data from AGW client application %d.\n", client);
|
||||||
dw_printf ("Tried to read %d bytes but got only %d.\n", cmd.hdr.data_len, n);
|
dw_printf ("Tried to read %d bytes but got only %d.\n", cmd.hdr.data_len, n);
|
||||||
dw_printf ("Closing connection.\n\n");
|
dw_printf ("Closing connection.\n\n");
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
closesocket (client_sock);
|
closesocket (client_sock[client]);
|
||||||
#else
|
#else
|
||||||
close (client_sock);
|
close (client_sock[client]);
|
||||||
#endif
|
#endif
|
||||||
client_sock = -1;
|
client_sock[client] = -1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
|
@ -872,7 +975,7 @@ static void * cmd_listen_thread (void *arg)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (FROM_CLIENT, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cmd.hdr.kind_lo) {
|
switch (cmd.hdr.kind_lo) {
|
||||||
|
@ -901,15 +1004,15 @@ static void * cmd_listen_thread (void *arg)
|
||||||
assert (sizeof(reply) == 44);
|
assert (sizeof(reply) == 44);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply));
|
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Should have unified function instead of multiple versions everywhere.
|
// TODO: Should have unified function instead of multiple versions everywhere.
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||||
#else
|
#else
|
||||||
write (client_sock, &reply, sizeof(reply));
|
n = write (client_sock[client], &reply, sizeof(reply));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -940,13 +1043,13 @@ static void * cmd_listen_thread (void *arg)
|
||||||
assert (reply.hdr.data_len == 100);
|
assert (reply.hdr.data_len == 100);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply));
|
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||||
#else
|
#else
|
||||||
write (client_sock, &reply, sizeof(reply));
|
n = write (client_sock[client], &reply, sizeof(reply));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -991,13 +1094,13 @@ static void * cmd_listen_thread (void *arg)
|
||||||
assert (sizeof(reply) == 48);
|
assert (sizeof(reply) == 48);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply));
|
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||||
#else
|
#else
|
||||||
write (client_sock, &reply, sizeof(reply));
|
n = write (client_sock[client], &reply, sizeof(reply));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1027,13 +1130,13 @@ static void * cmd_listen_thread (void *arg)
|
||||||
reply.hdr.data_len = strlen(reply.info);
|
reply.hdr.data_len = strlen(reply.info);
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply.hdr) + reply.hdr.data_len);
|
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply.hdr) + reply.hdr.data_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (client_sock, &reply, sizeof(reply.hdr) + reply.hdr.data_len, 0);
|
send (client_sock[client], &reply, sizeof(reply.hdr) + reply.hdr.data_len, 0);
|
||||||
#else
|
#else
|
||||||
write (client_sock, &reply, sizeof(reply.hdr) + reply.hdr.data_len);
|
write (client_sock[client], &reply, sizeof(reply.hdr) + reply.hdr.data_len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1047,14 +1150,14 @@ static void * cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
// Actually it is a toggle so we must be sure to clear it for a new connection.
|
// Actually it is a toggle so we must be sure to clear it for a new connection.
|
||||||
|
|
||||||
enable_send_raw_to_client = ! enable_send_raw_to_client;
|
enable_send_raw_to_client[client] = ! enable_send_raw_to_client[client];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm': /* Ask to start receiving Monitor frames */
|
case 'm': /* Ask to start receiving Monitor frames */
|
||||||
|
|
||||||
// Actually it is a toggle so we must be sure to clear it for a new connection.
|
// Actually it is a toggle so we must be sure to clear it for a new connection.
|
||||||
|
|
||||||
enable_send_monitor_to_client = ! enable_send_monitor_to_client;
|
enable_send_monitor_to_client[client] = ! enable_send_monitor_to_client[client];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1074,6 +1177,8 @@ static void * cmd_listen_thread (void *arg)
|
||||||
//unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
//unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
||||||
//int flen;
|
//int flen;
|
||||||
|
|
||||||
|
// We have already assured these do not exceed 9 characters.
|
||||||
|
|
||||||
strcpy (stemp, cmd.hdr.call_from);
|
strcpy (stemp, cmd.hdr.call_from);
|
||||||
strcat (stemp, ">");
|
strcat (stemp, ">");
|
||||||
strcat (stemp, cmd.hdr.call_to);
|
strcat (stemp, cmd.hdr.call_to);
|
||||||
|
@ -1125,11 +1230,23 @@ static void * cmd_listen_thread (void *arg)
|
||||||
// data length
|
// data length
|
||||||
// data which is raw ax.25 frame.
|
// data which is raw ax.25 frame.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
packet_t pp;
|
packet_t pp;
|
||||||
|
|
||||||
pp = ax25_from_frame ((unsigned char *)cmd.data+1, cmd.hdr.data_len, -1);
|
// Bug fix in version 1.1:
|
||||||
|
//
|
||||||
|
// The first byte of data is described as:
|
||||||
|
//
|
||||||
|
// the “TNC” to use
|
||||||
|
// 00=Port 1
|
||||||
|
// 16=Port 2
|
||||||
|
//
|
||||||
|
// I don't know what that means; we already a port number in the header.
|
||||||
|
// Anyhow, the original code here added one to cmd.data to get the
|
||||||
|
// first byte of the frame. Unfortunately, it did not subtract one from
|
||||||
|
// cmd.hdr.data_len so we ended up sending an extra byte.
|
||||||
|
|
||||||
|
pp = ax25_from_frame ((unsigned char *)cmd.data+1, cmd.hdr.data_len - 1, -1);
|
||||||
|
|
||||||
if (pp == NULL) {
|
if (pp == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
@ -1177,13 +1294,13 @@ static void * cmd_listen_thread (void *arg)
|
||||||
// That's why more cumbersome size expression is used.
|
// That's why more cumbersome size expression is used.
|
||||||
|
|
||||||
if (debug_client) {
|
if (debug_client) {
|
||||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply.hdr) + sizeof(reply.data));
|
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply.hdr) + sizeof(reply.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
send (client_sock, (char*)(&reply), sizeof(reply.hdr) + sizeof(reply.data), 0);
|
send (client_sock[client], (char*)(&reply), sizeof(reply.hdr) + sizeof(reply.data), 0);
|
||||||
#else
|
#else
|
||||||
write (client_sock, &reply, sizeof(reply.hdr) + sizeof(reply.data));
|
n = write (client_sock[client], &reply, sizeof(reply.hdr) + sizeof(reply.data));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1201,7 +1318,7 @@ static void * cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
dw_printf ("Can't process command from AGW client app.\n");
|
dw_printf ("Can't process command from AGW client app %d.\n", client);
|
||||||
dw_printf ("Connected packet mode is not implemented.\n");
|
dw_printf ("Connected packet mode is not implemented.\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1211,9 +1328,10 @@ static void * cmd_listen_thread (void *arg)
|
||||||
|
|
||||||
Not sure what we might want to do here.
|
Not sure what we might want to do here.
|
||||||
AGWterminal sends this for beacon or ask QRA.
|
AGWterminal sends this for beacon or ask QRA.
|
||||||
|
None of the other tested applications use it.
|
||||||
|
|
||||||
|
|
||||||
<<< Send UNPROTO Information from AGWPE client application, total length = 253
|
<<< Send UNPROTO Information from AGWPE client application 0, total length = 253
|
||||||
portx = 0, port_hi_reserved = 0
|
portx = 0, port_hi_reserved = 0
|
||||||
kind_lo = 77 = 'M', kind_hi = 0
|
kind_lo = 77 = 'M', kind_hi = 0
|
||||||
call_from = "SV2AGW-1", call_to = "BEACON"
|
call_from = "SV2AGW-1", call_to = "BEACON"
|
||||||
|
@ -1222,21 +1340,43 @@ static void * cmd_listen_thread (void *arg)
|
||||||
010: 73 20 74 68 65 20 6e 65 77 20 41 47 57 20 50 61 s the new AGW Pa
|
010: 73 20 74 68 65 20 6e 65 77 20 41 47 57 20 50 61 s the new AGW Pa
|
||||||
020: 63 6b 65 74 20 45 6e 67 69 6e 65 20 77 69 6e 73 cket Engine wins
|
020: 63 6b 65 74 20 45 6e 67 69 6e 65 20 77 69 6e 73 cket Engine wins
|
||||||
|
|
||||||
<<< Send UNPROTO Information from AGWPE client application, total length = 37
|
<<< Send UNPROTO Information from AGWPE client application 0, total length = 37
|
||||||
portx = 0, port_hi_reserved = 0
|
portx = 0, port_hi_reserved = 0
|
||||||
kind_lo = 77 = 'M', kind_hi = 0
|
kind_lo = 77 = 'M', kind_hi = 0
|
||||||
call_from = "SV2AGW-1", call_to = "QRA"
|
call_from = "SV2AGW-1", call_to = "QRA"
|
||||||
data_len = 1, user_reserved = 32218432, data =
|
data_len = 1, user_reserved = 32218432, data =
|
||||||
000: 0d .
|
000: 0d .
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
packet_t pp;
|
||||||
|
int pid = cmd.datakind_hi & 0xff;
|
||||||
|
/* "AX.25 PID 0x00 or 0xF0 for AX.25 0xCF NETROM and others" */
|
||||||
|
|
||||||
|
|
||||||
|
This is not right.
|
||||||
|
It needs to be more like "V" Transmit UI data frame
|
||||||
|
except there are no digipeaters involved.
|
||||||
|
|
||||||
|
pp = ax25_from_frame ((unsigned char *)cmd.data, cmd.hdr.data_len, -1);
|
||||||
|
|
||||||
|
if (pp != NULL) {
|
||||||
|
tq_append (cmd.hdr.portx, TQ_PRIO_1_LO, pp);
|
||||||
|
ax25_set_pid (pp, pid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
text_color_set(DW_COLOR_ERROR);
|
||||||
|
dw_printf ("Failed to create frame from AGW 'M' message.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("--- Unexpected Command from application using AGW protocol:\n");
|
dw_printf ("--- Unexpected Command from application %d using AGW protocol:\n", client);
|
||||||
debug_print (FROM_CLIENT, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
APRS SYMBOL OVERLAY and EXTENSION TABLES in APRS 1.2 20 May 2014
|
APRS SYMBOL OVERLAY and EXTENSION TABLES in APRS 1.2 28 Aug 2014
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
BACKGROUND: This file addresses new additions proposals (OVERLAYS)
|
BACKGROUND: This file addresses new additions proposals (OVERLAYS)
|
||||||
|
@ -13,6 +13,7 @@ CORRECT one.
|
||||||
|
|
||||||
UPDATES/REVISIONS/CORRECTIONS:
|
UPDATES/REVISIONS/CORRECTIONS:
|
||||||
|
|
||||||
|
28 Aug 14 Added numerous OpenAPRS symbols see "(new Aug 2014)"
|
||||||
20 May 14 Changed Da to DSTAR (2700 of them) from Dutch Ares
|
20 May 14 Changed Da to DSTAR (2700 of them) from Dutch Ares
|
||||||
19 May 14 Added Submarine&torpedo to ships and lots of Aircraft
|
19 May 14 Added Submarine&torpedo to ships and lots of Aircraft
|
||||||
search for "(new may 2014)"
|
search for "(new may 2014)"
|
||||||
|
@ -113,6 +114,11 @@ letting that define a new graphic just for that combination.
|
||||||
The following tables will attempt to keep track of these and
|
The following tables will attempt to keep track of these and
|
||||||
any other useful generic applications of overlay characters.
|
any other useful generic applications of overlay characters.
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
AIRCRAFT
|
AIRCRAFT
|
||||||
/^ = LARGE Aircraft
|
/^ = LARGE Aircraft
|
||||||
\^ = top-view originally intended to point in direction of flight
|
\^ = top-view originally intended to point in direction of flight
|
||||||
|
@ -121,7 +127,9 @@ E^ = Enemy aircraft (too bad I cant use the original Hostile)
|
||||||
H^ = Hovercraft (new may 2014)
|
H^ = Hovercraft (new may 2014)
|
||||||
J^ = JET (new may 2014)
|
J^ = JET (new may 2014)
|
||||||
M^ = Missle (new may 2014)
|
M^ = Missle (new may 2014)
|
||||||
|
P^ = Prop (new Aug 2014)
|
||||||
V^ = Vertical takeoff (new may 2014)
|
V^ = Vertical takeoff (new may 2014)
|
||||||
|
X^ = Experimental (new Aug 2014)
|
||||||
|
|
||||||
ATM Machine or CURRENCY: #$
|
ATM Machine or CURRENCY: #$
|
||||||
/$ = original primary Phone
|
/$ = original primary Phone
|
||||||
|
@ -130,12 +138,31 @@ U$ = US dollars
|
||||||
L$ = Brittish Pound
|
L$ = Brittish Pound
|
||||||
Y$ = Japanese Yen
|
Y$ = Japanese Yen
|
||||||
|
|
||||||
|
DEPOT
|
||||||
|
/D = was originally undefined
|
||||||
|
\D = was drizzle (moved to ' ovlyD)
|
||||||
|
AD = Airport (new Aug 2014)
|
||||||
|
FD = Ferry Landing (new Aug 2014)
|
||||||
|
HD = Heloport (new Aug 2014)
|
||||||
|
RD = Rail Depot (new Aug 2014)
|
||||||
|
BD = Bus Depot (new Aug 2014)
|
||||||
|
LD = LIght Rail or Subway (new Aug 2014)
|
||||||
|
SD = Seaport Depot (new Aug 2014)
|
||||||
|
|
||||||
|
EMERGENCY: #!
|
||||||
|
/! = Police/Sheriff, etc
|
||||||
|
\! = Emergency!
|
||||||
|
E! = ELT or EPIRB (new Aug 2014)
|
||||||
|
V! = Volcanic Eruption or Lava (new Aug 2014)
|
||||||
|
|
||||||
POWER PLANT: #%
|
POWER PLANT: #%
|
||||||
/% = DX cluster <= the original primary table definition
|
/% = DX cluster <= the original primary table definition
|
||||||
C% = Coal
|
C% = Coal
|
||||||
|
E% = Emergency (new Aug 2014)
|
||||||
G% = Geothermal
|
G% = Geothermal
|
||||||
H% = Hydroelectric
|
H% = Hydroelectric
|
||||||
N% = Nuclear
|
N% = Nuclear
|
||||||
|
P% = Portable (new Aug 2014)
|
||||||
S% = Solar
|
S% = Solar
|
||||||
T% = Turbine
|
T% = Turbine
|
||||||
W% = Wind
|
W% = Wind
|
||||||
|
@ -148,7 +175,8 @@ T& = TX igate with path set to 1 hop only)
|
||||||
2& = TX igate with path set to 2 hops (not generally good idea)
|
2& = TX igate with path set to 2 hops (not generally good idea)
|
||||||
|
|
||||||
INCIDENT SITES: #'
|
INCIDENT SITES: #'
|
||||||
\' = Airplane Crash Site <= the original primary deifinition
|
/' = Small Aircraft (original primary symbol)
|
||||||
|
\' = Airplane Crash Site <= the original alternate deifinition
|
||||||
A' = Automobile crash site
|
A' = Automobile crash site
|
||||||
H' = Hazardous incident
|
H' = Hazardous incident
|
||||||
M' = Multi-Vehicle crash site
|
M' = Multi-Vehicle crash site
|
||||||
|
@ -199,9 +227,10 @@ ADVISORIES: #< (new expansion possibilities)
|
||||||
/< = motorcycle
|
/< = motorcycle
|
||||||
\< = Advisory (single gale flag)
|
\< = Advisory (single gale flag)
|
||||||
|
|
||||||
CARS: #>
|
CARS: #> (Vehicles)
|
||||||
/> = normal car (side view)
|
/> = normal car (side view)
|
||||||
\> = Top view and symbol POINTS in direction of travel
|
\> = Top view and symbol POINTS in direction of travel
|
||||||
|
#> = Reserve overlays 1-9 for numbered cars (new Aug 2014)
|
||||||
E> = Electric
|
E> = Electric
|
||||||
H> = Hybrid
|
H> = Hybrid
|
||||||
S> = Solar powered
|
S> = Solar powered
|
||||||
|
@ -270,13 +299,18 @@ Wa = WinLink
|
||||||
CIVIL DEFENSE or TRIANGLE: #c
|
CIVIL DEFENSE or TRIANGLE: #c
|
||||||
/c = Incident Command Post
|
/c = Incident Command Post
|
||||||
\c = Civil Defense
|
\c = Civil Defense
|
||||||
|
Dc = Decontamination (new Aug 2014)
|
||||||
Rc = RACES
|
Rc = RACES
|
||||||
Sc = SATERN mobile canteen
|
Sc = SATERN mobile canteen
|
||||||
|
|
||||||
BUILDINGS: #h
|
BUILDINGS: #h
|
||||||
/h = Hospital
|
/h = Hospital
|
||||||
\h = Ham Store ** <= now used for HAMFESTS
|
\h = Ham Store ** <= now used for HAMFESTS
|
||||||
|
Fh = HamFest (new Aug 2014)
|
||||||
Hh = Home Dept etc..
|
Hh = Home Dept etc..
|
||||||
|
Mh = Morgue
|
||||||
|
Ch = Clinic
|
||||||
|
Th = Triage
|
||||||
|
|
||||||
SPECIAL VEHICLES: #k
|
SPECIAL VEHICLES: #k
|
||||||
/k = truck
|
/k = truck
|
||||||
|
@ -284,20 +318,36 @@ SPECIAL VEHICLES: #k
|
||||||
4k = 4x4
|
4k = 4x4
|
||||||
Ak = ATV (all terrain vehicle)
|
Ak = ATV (all terrain vehicle)
|
||||||
|
|
||||||
SHIPS: #s
|
SHIPS: #s
|
||||||
/s = Power boat (ship) side view
|
/s = Power boat (ship) side view
|
||||||
\s = Overlay Boat (Top view)
|
\s = Overlay Boat (Top view)
|
||||||
Cs = receive as Canoe but still transmit canoe as /C
|
6s = Shipwreck ("deep6") (new Aug 2014)
|
||||||
|
Bs = Pleasure Boat
|
||||||
|
Cs = Cargo
|
||||||
|
Ds = Diving
|
||||||
|
Es = Emergency or Medical transport
|
||||||
|
Fs = Fishing
|
||||||
|
Hs = High-speed Craft
|
||||||
Js = Jet Ski
|
Js = Jet Ski
|
||||||
Ks = Kayak
|
Ls = Law enforcement
|
||||||
Hs = Hovercraft (new may 2014)
|
Ms = Miltary
|
||||||
Ts = Torpedo (new may 2014)
|
Os = Oil Rig
|
||||||
Us = sUbmarine U-boat (new may 2014)
|
Ps = Pilot Boat (new Aug 2014)
|
||||||
|
Qs = Torpedo
|
||||||
|
Ss = Search and Rescue
|
||||||
|
Ts = Tug (new Aug 2014)
|
||||||
|
Us = Underwater ops or submarine
|
||||||
|
Ws = Wing-in-Ground effect (or Hovercraft)
|
||||||
|
Xs = Passenger (paX)(ferry)
|
||||||
|
Ys = Sailing (large ship)
|
||||||
|
|
||||||
|
|
||||||
TRUCKS: #u
|
TRUCKS: #u
|
||||||
/u = Truck (18 wheeler)
|
/u = Truck (18 wheeler)
|
||||||
\u = truck with overlay
|
\u = truck with overlay
|
||||||
|
Bu = Buldozer/construction (new Aug 2014)
|
||||||
Gu = Gas
|
Gu = Gas
|
||||||
|
Pu = Plow or SnowPlow (new Aug 2014)
|
||||||
Tu = Tanker
|
Tu = Tanker
|
||||||
Cu = Chlorine Tanker
|
Cu = Chlorine Tanker
|
||||||
Hu = Hazardous
|
Hu = Hazardous
|
||||||
|
|
50
symbols.c
50
symbols.c
|
@ -307,20 +307,32 @@ static int new_sym_len = 0; /* Number of elements used. */
|
||||||
void symbols_init (void)
|
void symbols_init (void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct {
|
|
||||||
char overlay;
|
/*
|
||||||
char symbol;
|
* We only care about lines with this format:
|
||||||
char sp1;
|
*
|
||||||
char equal;
|
* Column 1 - overlay character of / \ upper case or digit
|
||||||
char sp2;
|
* Column 2 - symbol in range of ! thru ~
|
||||||
char description[150];
|
* Column 3 - space
|
||||||
} stuff;
|
* Column 4 - equal sign
|
||||||
|
* Column 5 - space
|
||||||
|
* Column 6 - Start of description.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define COL1_OVERLAY 0
|
||||||
|
#define COL2_SYMBOL 1
|
||||||
|
#define COL3_SP 2
|
||||||
|
#define COL4_EQUAL 3
|
||||||
|
#define COL5_SP 4
|
||||||
|
#define COL6_DESC 5
|
||||||
|
|
||||||
|
char stuff[200];
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
#define GOOD_LINE(x) ((x.overlay == '/' || x.overlay == '\\' || isupper(x.overlay) || isdigit(x.overlay)) \
|
#define GOOD_LINE(x) (strlen(x) > 6 && \
|
||||||
&& x.symbol >= '!' && x.symbol <= '~' \
|
(x[COL1_OVERLAY] == '/' || x[COL1_OVERLAY] == '\\' || isupper(x[COL1_OVERLAY]) || isdigit(x[COL1_OVERLAY])) \
|
||||||
&& x.sp1 == ' ' && x.equal == '=' && x.sp2 == ' ')
|
&& x[COL2_SYMBOL] >= '!' && x[COL2_SYMBOL] <= '~' \
|
||||||
|
&& x[COL3_SP] == ' ' && x[COL4_EQUAL] == '=' && x[COL5_SP] == ' ' && x[COL6_DESC] != ' ')
|
||||||
|
|
||||||
if (new_sym_ptr != NULL) {
|
if (new_sym_ptr != NULL) {
|
||||||
return; /* was called already. */
|
return; /* was called already. */
|
||||||
|
@ -350,7 +362,7 @@ void symbols_init (void)
|
||||||
/*
|
/*
|
||||||
* Count number of interesting lines and allocate storage.
|
* Count number of interesting lines and allocate storage.
|
||||||
*/
|
*/
|
||||||
while (fgets((char*)(&stuff), sizeof(stuff), fp) != NULL) {
|
while (fgets(stuff, sizeof(stuff), fp) != NULL) {
|
||||||
if (GOOD_LINE(stuff)) {
|
if (GOOD_LINE(stuff)) {
|
||||||
new_sym_size++;
|
new_sym_size++;
|
||||||
}
|
}
|
||||||
|
@ -363,15 +375,15 @@ void symbols_init (void)
|
||||||
*/
|
*/
|
||||||
rewind (fp);
|
rewind (fp);
|
||||||
|
|
||||||
while (fgets((char*)(&stuff), sizeof(stuff), fp) != NULL) {
|
while (fgets(stuff, sizeof(stuff), fp) != NULL) {
|
||||||
|
|
||||||
if (GOOD_LINE(stuff)) {
|
if (GOOD_LINE(stuff)) {
|
||||||
for (j = strlen(stuff.description) - 1; j>=0 && stuff.description[j] <= ' '; j--) {
|
for (j = strlen(stuff+COL6_DESC) - 1; j>=0 && stuff[COL6_DESC+j] <= ' '; j--) {
|
||||||
stuff.description[j] = '\0';
|
stuff[COL6_DESC+j] = '\0';
|
||||||
}
|
}
|
||||||
new_sym_ptr[new_sym_len].overlay = stuff.overlay;
|
new_sym_ptr[new_sym_len].overlay = stuff[COL1_OVERLAY];
|
||||||
new_sym_ptr[new_sym_len].symbol = stuff.symbol;
|
new_sym_ptr[new_sym_len].symbol = stuff[COL2_SYMBOL];
|
||||||
strncpy(new_sym_ptr[new_sym_len].description, stuff.description, NEW_SYM_DESC_LEN);
|
strncpy(new_sym_ptr[new_sym_len].description, stuff+COL6_DESC, NEW_SYM_DESC_LEN);
|
||||||
new_sym_len++;
|
new_sym_len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
144
symbolsX.txt
144
symbolsX.txt
|
@ -1,20 +1,21 @@
|
||||||
APRS SYMBOLS (Icons) 07 Oct 2013
|
APRS SYMBOLS (Icons) 28 Aug 2014
|
||||||
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
WB4APR
|
WB4APR
|
||||||
|
|
||||||
This original APRS symbol specification is updated periodically with
|
This original APRS symbol specification is updated periodically with
|
||||||
new symbols as they are defined. This is THE master list for APRS. But
|
new symbols as they are defined. This is THE master list for APRS. But
|
||||||
almost all new symbols will be formed as Overlays to the basic set. So
|
almost all new symbols since 2007 will be formed as Overlays to the
|
||||||
be sure to check the symbols-new.txt file noted below!
|
basic set. So be sure to check the symbols-new.txt file noted below!
|
||||||
|
|
||||||
|
http://aprs.org/symbols/symbols-new.txt
|
||||||
|
|
||||||
NEW OVERLAYS ON ALL ALTERNATE SYMBOLS: As of 1 October 2007, the use of
|
NEW OVERLAYS ON ALL ALTERNATE SYMBOLS: As of 1 October 2007, the use of
|
||||||
overlay characters on all alternate symbols was allowed as needed in
|
overlay characters on all alternate symbols was allowed as needed in
|
||||||
order to further expand the APRS symbol set. These overlay expansions
|
order to further expand the APRS symbol set. These overlay expansions
|
||||||
of up to 36 different usages for each of the 94 alternate symbols adds
|
of up to 36 different usages for each of the 94 alternate symbols adds
|
||||||
hundreds of potential new symbols. Since this overlay info will no
|
hundreds of potential new symbols. Since each of the original 94
|
||||||
longer fit in this original document it is found in a new document:
|
symbols can now have up to 36 other definitions, this new overlay info
|
||||||
|
is now found in the above file.
|
||||||
http://aprs.org/symbols/symbols-new.txt
|
|
||||||
|
|
||||||
If an alternate symbol from the table below, contains significant
|
If an alternate symbol from the table below, contains significant
|
||||||
definitions of its overlay characters, then the entry will have an "O"
|
definitions of its overlay characters, then the entry will have an "O"
|
||||||
|
@ -23,10 +24,17 @@ document. The # symbol indicates the original Overlay subset.
|
||||||
|
|
||||||
For details on Upgrading your symbol set, please see the background
|
For details on Upgrading your symbol set, please see the background
|
||||||
information on Symbols prepared by Stephen Smith, WA8LMF:
|
information on Symbols prepared by Stephen Smith, WA8LMF:
|
||||||
http://www.ew.usna.edu/~bruninga/aprs/symbols-background.txt
|
http://aprs.org/symbols/symbols-background.txt
|
||||||
|
|
||||||
UPDATE CHRONOLOGY:
|
UPDATE CHRONOLOGY:
|
||||||
|
|
||||||
|
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
|
||||||
|
Changed #D from "avail" to new family called Depots
|
||||||
|
Changed name of overlay Car to generic Vehicles w overlays
|
||||||
|
Edited name of /E Eyeball to include "Events"
|
||||||
|
19 May 14: Added many new Aircraft and Ship symbols see symbols-new.txt
|
||||||
07 Oct 13: Added JetSki [Js] & Ham Club [C-] ovrlys to symbols-new.txt
|
07 Oct 13: Added JetSki [Js] & Ham Club [C-] ovrlys to symbols-new.txt
|
||||||
19 Sep 11: Added T & 2 overlay for 1 & 2 hop Message TX Igates
|
19 Sep 11: Added T & 2 overlay for 1 & 2 hop Message TX Igates
|
||||||
Updated overlay "portable" (;) overlays for events
|
Updated overlay "portable" (;) overlays for events
|
||||||
|
@ -100,7 +108,9 @@ Alt: >KOSY[^ksuv\ <==[removed /0An]
|
||||||
|
|
||||||
SYMBOLS.TXT APRS DISPLAY SYMBOLS APRSdos ORIGINAL
|
SYMBOLS.TXT APRS DISPLAY SYMBOLS APRSdos ORIGINAL
|
||||||
======================================================================
|
======================================================================
|
||||||
Document dated: 28 Apr 99 FInal APRSdos symbol spec (still updated!)
|
Document dated: 28 Apr 99 FInal APRSdos symbol spec
|
||||||
|
**************: This file Remains CUrrent and is Updated Frequently
|
||||||
|
**************: See date and updates at the top of this file.
|
||||||
Author(s): Bob Bruninga, WB4APR <bruninga@usna.edu>
|
Author(s): Bob Bruninga, WB4APR <bruninga@usna.edu>
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -113,8 +123,8 @@ tables or may be used as an alphanumeric overlay over some symbols:
|
||||||
& RESERVED for possible AUXILLIARY tables (Aug 09)
|
& RESERVED for possible AUXILLIARY tables (Aug 09)
|
||||||
/ Primary symbol Table (Mostly stations)
|
/ Primary symbol Table (Mostly stations)
|
||||||
\ Alternate symbol table (Mostly Objects)
|
\ Alternate symbol table (Mostly Objects)
|
||||||
0-9 Alternate OVERLAY symbol with 0-9 overlayed
|
0-9 Alternate OVERLAY symbols with 0-9 overlayed
|
||||||
A-Z Alternate OVERLAY symbol with A-Z overlayed
|
A-Z Alternate OVERLAY symbols with A-Z overlayed
|
||||||
|
|
||||||
For ease of reference we refer to these as the SYMBOL CHARACTERS and
|
For ease of reference we refer to these as the SYMBOL CHARACTERS and
|
||||||
often abbreviate them as "/$" which refers to the Table character "/"
|
often abbreviate them as "/$" which refers to the Table character "/"
|
||||||
|
@ -128,8 +138,8 @@ symbols through Oct 2007 were:
|
||||||
CIRCLE, SQUARE, CAR, TRUCK, VAN, DIGIS, GATES
|
CIRCLE, SQUARE, CAR, TRUCK, VAN, DIGIS, GATES
|
||||||
Civil-Defense(RACES), NWS sites, WX stations, Triangle
|
Civil-Defense(RACES), NWS sites, WX stations, Triangle
|
||||||
|
|
||||||
After that, provisions should be made in all software to allow for
|
After 2007, provisions should be made in all software to allow for
|
||||||
overlays on any alternate symbol as they may be used in the future.
|
overlays on *any/all* alternate symbols for use in the future.
|
||||||
|
|
||||||
SYMBOLS WITH STAND-ALONE GPS TRACKERS: Stand-alone devices that
|
SYMBOLS WITH STAND-ALONE GPS TRACKERS: Stand-alone devices that
|
||||||
transmit raw GPS have no method to convey their symbol. For this
|
transmit raw GPS have no method to convey their symbol. For this
|
||||||
|
@ -162,16 +172,16 @@ for the stand-alone trackers described above.
|
||||||
|
|
||||||
/$ XYZ BASIC SYMBOL TABLE \$ XYZ OTHER SYMBOL TABLE (\)
|
/$ XYZ BASIC SYMBOL TABLE \$ XYZ OTHER SYMBOL TABLE (\)
|
||||||
-- --- ------------------------ -- --- ----------------------
|
-- --- ------------------------ -- --- ----------------------
|
||||||
/! BB Police, Sheriff \! OB EMERGENCY (!)
|
/! BB Police, Sheriff \! OBO EMERGENCY (and overlays)
|
||||||
/" BC reserved (was rain) \" OC reserved
|
/" BC reserved (was rain) \" OC reserved
|
||||||
/# BD DIGI (white center) \# OD# OVERLAY DIGI (green star)
|
/# BD DIGI (white center) \# OD# OVERLAY DIGI (green star)
|
||||||
/$ BE PHONE \$ OEO Bank or ATM (green box)
|
/$ BE PHONE \$ OEO Bank or ATM (green box)
|
||||||
/% BF DX CLUSTER \% OFO Power Plant with overlay
|
/% BF DX CLUSTER \% OFO Power Plant with overlay
|
||||||
/& BG HF GATEway \& OG# I=Igte R=RX T=1hopTX 2=2hopTX
|
/& 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 = 7) \' OHO Crash (& now Incident sites)
|
||||||
/( BI Mobile Satellite Station \( OI CLOUDY (other clouds w ovrly)
|
/( BI Mobile Satellite Station \( OIO CLOUDY (other clouds w ovrly)
|
||||||
/) BJ Wheelchair (handicapped) \) OJO Firenet MEO, MODIS Earth Obs.
|
/) BJ Wheelchair (handicapped) \) OJO Firenet MEO, MODIS Earth Obs.
|
||||||
/* BK SnowMobile \* OK SNOW (& future ovrly codes)
|
/* BK SnowMobile \* OK AVAIL (SNOW moved to ` ovly S)
|
||||||
/+ BL Red Cross \+ OL Church
|
/+ BL Red Cross \+ OL Church
|
||||||
/, BM Boy Scouts \, OM Girl Scouts
|
/, BM Boy Scouts \, OM Girl Scouts
|
||||||
/- BN House QTH (VHF) \- ONO House (H=HF) (O = Op Present)
|
/- BN House QTH (VHF) \- ONO House (H=HF) (O = Op Present)
|
||||||
|
@ -181,38 +191,38 @@ for the stand-alone trackers described above.
|
||||||
|
|
||||||
/$ XYZ PRIMARY SYMBOL TABLE \$ XYZ ALTERNATE SYMBOL TABLE (\)
|
/$ XYZ PRIMARY SYMBOL TABLE \$ XYZ ALTERNATE SYMBOL TABLE (\)
|
||||||
-- --- ------------------------ -- --- --------------------------
|
-- --- ------------------------ -- --- --------------------------
|
||||||
/0 P0 # circle (obsolete) \0 A0# CIRCLE (E/I/W=IRLP/Echolink/WIRES)
|
/0 P0 # circle (obsolete) \0 A0# CIRCLE (IRLP/Echolink/WIRES)
|
||||||
/1 P1 TBD (these were numbered) \1 A1
|
/1 P1 TBD (these were numbered) \1 A1 AVAIL
|
||||||
/2 P2 TBD (circles like pool) \2 A2
|
/2 P2 TBD (circles like pool) \2 A2 AVAIL
|
||||||
/3 P3 TBD (balls. But with) \3 A3
|
/3 P3 TBD (balls. But with) \3 A3 AVAIL
|
||||||
/4 P4 TBD (overlays, we can) \4 A4
|
/4 P4 TBD (overlays, we can) \4 A4 AVAIL
|
||||||
/5 P5 TBD (put all #'s on one) \5 A5
|
/5 P5 TBD (put all #'s on one) \5 A5 AVAIL
|
||||||
/6 P6 TBD (So 1-9 are available)\6 A6
|
/6 P6 TBD (So 1-9 are available)\6 A6 AVAIL
|
||||||
/7 P7 TBD (for new uses?) \7 A7
|
/7 P7 TBD (for new uses?) \7 A7 AVAIL
|
||||||
/8 P8 TBD (They are often used) \8 A8O 802.11 or other network node
|
/8 P8 TBD (They are often used) \8 A8O 802.11 or other network node
|
||||||
/9 P9 TBD (as mobiles at events)\9 A9 Gas Station (blue pump)
|
/9 P9 TBD (as mobiles at events)\9 A9 Gas Station (blue pump)
|
||||||
/: MR FIRE \: NR Hail (& future ovrly codes)
|
/: MR FIRE \: NR AVAIL (Hail ==> ` ovly H)
|
||||||
/; MS Campground (Portable ops) \; NSO Park/Picnic + overlay events
|
/; 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)
|
/= MU RAILROAD ENGINE \= NUO APRStt Touchtone (DTMF users)
|
||||||
/> MV CAR (SSID = 9) \> NV# OVERLAYED CAR
|
/> MV CAR (SSID = 9) \> NV# OVERLAYED CARs & Vehicles
|
||||||
/? MW SERVER for Files \? NW INFO Kiosk (Blue box with ?)
|
/? MW SERVER for Files \? NW INFO Kiosk (Blue box with ?)
|
||||||
/@ MX HC FUTURE predict (dot) \@ NX HURICANE/Trop-Storm
|
/@ MX HC FUTURE predict (dot) \@ NX HURICANE/Trop-Storm
|
||||||
/A PA Aid Station \A AA# overlayBOX DTMF & RFID & XO
|
/A PA Aid Station \A AA# overlayBOX DTMF & RFID & XO
|
||||||
/B PB BBS or PBBS \B AB Blwng Snow (& future codes)
|
/B PB BBS or PBBS \B AB AVAIL (BlwngSnow ==> E ovly B
|
||||||
/C PC Canoe \C AC Coast Guard
|
/C PC Canoe \C AC Coast Guard
|
||||||
/D PD \D AD Drizzle (proposed APRStt)
|
/D PD \D ADO DEPOTS (Drizzle ==> ' ovly D)
|
||||||
/E PE EYEBALL (Eye catcher!) \E AE Smoke (& other vis codes)
|
/E PE EYEBALL (Events, etc!) \E AE Smoke (& other vis codes)
|
||||||
/F PF Farm Vehicle (tractor) \F AF Freezng rain (&future codes)
|
/F PF Farm Vehicle (tractor) \F AF AVAIL (FrzngRain ==> `F)
|
||||||
/G PG Grid Square (6 digit) \G AG Snow Shwr (& future ovrlys)
|
/G PG Grid Square (6 digit) \G AG AVAIL (Snow Shwr ==> I ovly S)
|
||||||
/H PH HOTEL (blue bed symbol) \H AHO \Haze (& Overlay Hazards)
|
/H PH HOTEL (blue bed symbol) \H AHO \Haze (& Overlay Hazards)
|
||||||
/I PI TcpIp on air network stn \I AI Rain Shower
|
/I PI TcpIp on air network stn \I AI Rain Shower
|
||||||
/J PJ \J AJ Lightening (& future ovrlys)
|
/J PJ \J AJ AVAIL (Lightening ==> I ovly L)
|
||||||
/K PK School \K AK Kenwood HT (W)
|
/K PK School \K AK Kenwood HT (W)
|
||||||
/L PL PC user (Jan 03) \L AL Lighthouse
|
/L PL PC user (Jan 03) \L AL Lighthouse
|
||||||
/M PM MacAPRS \M AMO MARS (A=Army,N=Navy,F=AF)
|
/M PM MacAPRS \M AMO MARS (A=Army,N=Navy,F=AF)
|
||||||
/N PN NTS Station \N AN Navigation Buoy
|
/N PN NTS Station \N AN Navigation Buoy
|
||||||
/O PO BALLOON (SSID =11) \O AO Rocket (new June 2004)
|
/O PO BALLOON (SSID =11) \O AO Overlay Balloon (Rocket = \O)
|
||||||
/P PP Police \P AP Parking
|
/P PP Police \P AP Parking
|
||||||
/Q PQ TBD \Q AQ QUAKE
|
/Q PQ TBD \Q AQ QUAKE
|
||||||
/R PR REC. VEHICLE (SSID =13) \R ARO Restaurant
|
/R PR REC. VEHICLE (SSID =13) \R ARO Restaurant
|
||||||
|
@ -223,18 +233,18 @@ for the stand-alone trackers described above.
|
||||||
/W PW National WX Service Site \W AW# # NWS site (NWS options)
|
/W PW National WX Service Site \W AW# # NWS site (NWS options)
|
||||||
/X PX HELO (SSID = 6) \X AX Pharmacy Rx (Apothicary)
|
/X PX HELO (SSID = 6) \X AX Pharmacy Rx (Apothicary)
|
||||||
/Y PY YACHT (sail) (SSID = 5) \Y AYO Radios and devices
|
/Y PY YACHT (sail) (SSID = 5) \Y AYO Radios and devices
|
||||||
/Z PZ WinAPRS \Z AZ
|
/Z PZ WinAPRS \Z AZ AVAIL
|
||||||
/[ HS Human/Person (HT) \[ DSO W.Cloud (& humans w Ovrly)
|
/[ HS Human/Person (HT) \[ DSO W.Cloud (& humans w Ovrly)
|
||||||
/\ HT TRIANGLE(DF station) \\ DTO New overlayable GPS symbol
|
/\ HT TRIANGLE(DF station) \\ DTO New overlayable GPS symbol
|
||||||
/] HU MAIL/PostOffice(was PBBS) \] DU
|
/] HU MAIL/PostOffice(was PBBS) \] DU AVAIL
|
||||||
/^ HV LARGE AIRCRAFT \^ DV# # Aircraft (shows heading)
|
/^ HV LARGE AIRCRAFT \^ DV# other Aircraft ovrlys (2014)
|
||||||
/_ HW WEATHER Station (blue) \_ DW# # WX site (green digi)
|
/_ HW WEATHER Station (blue) \_ DW# # WX site (green digi)
|
||||||
/` HX Dish Antenna \` DX Rain (all types w ovrly)
|
/` HX Dish Antenna \` DX Rain (all types w ovrly)
|
||||||
|
|
||||||
/$ XYZ LOWER CASE SYMBOL TABLE \$ XYZ SECONDARY SYMBOL TABLE (\)
|
/$ XYZ LOWER CASE SYMBOL TABLE \$ XYZ SECONDARY SYMBOL TABLE (\)
|
||||||
-- --- ------------------------ -- --- --------------------------
|
-- --- ------------------------ -- --- --------------------------
|
||||||
/a LA AMBULANCE (SSID = 1) \a SA#O ARRL, ARES, WinLINK
|
/a LA AMBULANCE (SSID = 1) \a SA#O ARRL,ARES,WinLINK,Dstar, etc
|
||||||
/b LB BIKE (SSID = 4) \b SB Blwng Dst/Snd (& others)
|
/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
|
/c LC Incident Command Post \c SC#O CD triangle RACES/SATERN/etc
|
||||||
/d LD Fire dept \d SD DX spot by callsign
|
/d LD Fire dept \d SD DX spot by callsign
|
||||||
/e LE HORSE (equestrian) \e SE Sleet (& future ovrly codes)
|
/e LE HORSE (equestrian) \e SE Sleet (& future ovrly codes)
|
||||||
|
@ -248,27 +258,28 @@ for the stand-alone trackers described above.
|
||||||
/m LM Mic-E Repeater \m SM Value Sign (3 digit display)
|
/m LM Mic-E Repeater \m SM Value Sign (3 digit display)
|
||||||
/n LN Node (black bulls-eye) \n SN# OVERLAY TRIANGLE
|
/n LN Node (black bulls-eye) \n SN# OVERLAY TRIANGLE
|
||||||
/o LO EOC \o SO small circle
|
/o LO EOC \o SO small circle
|
||||||
/p LP ROVER (puppy, or dog) \p SP Prtly Cldy (& future ovrlys)
|
/p LP ROVER (puppy, or dog) \p SP AVAIL (PrtlyCldy => ( ovly P
|
||||||
/q LQ GRID SQ shown above 128 m \q SQ
|
/q LQ GRID SQ shown above 128 m \q SQ AVAIL
|
||||||
/r LR Repeater (Feb 07) \r SR Restrooms
|
/r LR Repeater (Feb 07) \r SR Restrooms
|
||||||
/s LS SHIP (pwr boat) (SSID-8) \s SS# OVERLAY SHIP/boat (top view)
|
/s LS SHIP (pwr boat) (SSID-8) \s SS# OVERLAY SHIP/boats
|
||||||
/t LT TRUCK STOP \t ST Tornado
|
/t LT TRUCK STOP \t ST Tornado
|
||||||
/u LU TRUCK (18 wheeler) \u SU# OVERLAYED TRUCK
|
/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 SW Flooding
|
/w LW WATER station \w SWO Flooding (Avalanches/Slides)
|
||||||
/x LX xAPRS (Unix) \x SX Wreck or Obstruction ->X<-
|
/x LX xAPRS (Unix) \x SX Wreck or Obstruction ->X<-
|
||||||
/y LY YAGI @ QTH \y SY Skywarn
|
/y LY YAGI @ QTH \y SY Skywarn
|
||||||
/z LZ TBD \z SZ# OVERLAYED Shelter
|
/z LZ TBD \z SZ# OVERLAYED Shelter
|
||||||
/{ J1 \{ Q1 Fog (& future ovrly codes)
|
/{ J1 \{ Q1 AVAIL? (Fog ==> E ovly F)
|
||||||
/| J2 TNC Stream Switch \| Q2 TNC Stream Switch
|
/| J2 TNC Stream Switch \| Q2 TNC Stream Switch
|
||||||
/} J3 \} Q3
|
/} J3 \} Q3 AVAIL? (maybe)
|
||||||
/~ J4 TNC Stream Switch \~ Q4 TNC Stream Switch
|
/~ J4 TNC Stream Switch \~ Q4 TNC Stream Switch
|
||||||
|
|
||||||
HEADING SYMBOLS: Although all symbols are supposed to have a heading
|
HEADING SYMBOLS: Although all symbols are supposed to have a heading
|
||||||
line showing the direction of movement with a length proportional to
|
line showing the direction of movement with a length proportional to
|
||||||
the log of speed, some symbols were desiged as top-down views so that
|
the log of speed, some symbols were desiged as top-down views so that
|
||||||
they could be displayed actually always POINTING in the direction of
|
they could be displayed actually always POINTING in the direction of
|
||||||
movement. These special symbols are:
|
movement. Now All symbols should be oriented (if practical). These
|
||||||
|
original special symbols were:
|
||||||
|
|
||||||
\> OVERLAYED CAR
|
\> OVERLAYED CAR
|
||||||
\s Overlayed Ship
|
\s Overlayed Ship
|
||||||
|
@ -277,10 +288,14 @@ movement. These special symbols are:
|
||||||
/g Glider
|
/g Glider
|
||||||
\n Overlayed Triangle
|
\n Overlayed Triangle
|
||||||
|
|
||||||
AREA SYMBOLS! You can define BOX/CIRCLE/LINE or TRIANGLE areas in all
|
AREA SYMBOLS! The special symbol \l (lower case L) was special. It
|
||||||
colors, either open or filled in, any size from 60 feet to 100 miles.
|
indicates an area definition. You can define these as a BOX, CIRCLE,
|
||||||
Simply move the cursor to the location, press HOME, move the cursor to
|
LINE or TRIANGLE area in all colors, either open or filled in, any
|
||||||
the lower right corner of the AREA and hit INPUT-ADD-OBJECTS-AREA.
|
size from 60 feet to 100 miles. In APRSdos they were generated auto-
|
||||||
|
matically by simply moving the cursor to the location, press HOME,
|
||||||
|
move the cursor to the lower right corner of the AREA and hit INPUT-
|
||||||
|
ADD-OBJECTS-AREA.
|
||||||
|
|
||||||
Enter the type of area, and color. NOTE that AREA shapes can only be
|
Enter the type of area, and color. NOTE that AREA shapes can only be
|
||||||
defined by selecting the upper left corner first, then the lower right
|
defined by selecting the upper left corner first, then the lower right
|
||||||
second. The line is an exception. It is still top to bottom, but the
|
second. The line is an exception. It is still top to bottom, but the
|
||||||
|
@ -294,10 +309,12 @@ cautious in using the color fill option, since all other objects in
|
||||||
that area that occur earlier in your PLIST will be obscured. AND you
|
that area that occur earlier in your PLIST will be obscured. AND you
|
||||||
do NOT know the order of other stations P-lists.
|
do NOT know the order of other stations P-lists.
|
||||||
|
|
||||||
AREAS FORMAT: The new format for specifying special areas uses the
|
AREAS FORMAT: Use of the special AREAS symbol (/l) triggers special
|
||||||
CSE/SPD field to provide the additional information as follows:
|
processing of the next 7 bytes normally used for CSE and SPD. In
|
||||||
|
this special case the processing is as follows:
|
||||||
|
|
||||||
$CSE/SPD... Normal Field description
|
$CSE/SPD... Normal Field description
|
||||||
|
|
||||||
lTyy/Cxx... Where: l (lower case L) is symbol for "LOCATION SHAPES"
|
lTyy/Cxx... Where: l (lower case L) is symbol for "LOCATION SHAPES"
|
||||||
T is Type of shape: 0=circle, 1=line, 2=elipse
|
T is Type of shape: 0=circle, 1=line, 2=elipse
|
||||||
3=triangle 4=box
|
3=triangle 4=box
|
||||||
|
@ -314,7 +331,7 @@ Type of 6 and are drawn down and to the left.
|
||||||
HURRICANES, TROPICAL STORMS and DEPRESSIONS: These symbols will be
|
HURRICANES, TROPICAL STORMS and DEPRESSIONS: These symbols will be
|
||||||
differentiated by colors red, yellos, and blue. Additionally a radius
|
differentiated by colors red, yellos, and blue. Additionally a radius
|
||||||
of Huricane and also Tropical storm winds will also be shown if the
|
of Huricane and also Tropical storm winds will also be shown if the
|
||||||
format detailed in WX.txt is used.
|
special format detailed in WX.txt is used.
|
||||||
|
|
||||||
SYMBOLS ON MAPS! APRS can also be permanently embedded in maps. To
|
SYMBOLS ON MAPS! APRS can also be permanently embedded in maps. To
|
||||||
embed a symbol in a map, simply make the first four characters of the
|
embed a symbol in a map, simply make the first four characters of the
|
||||||
|
@ -325,9 +342,12 @@ same location. An example are the VORTAC nav-aids in Alaska. The
|
||||||
Anchorage VORTAC appears as ANC on all maps below 128 miles. The label
|
Anchorage VORTAC appears as ANC on all maps below 128 miles. The label
|
||||||
entry is #\VFANC,LAT,LONG,128.
|
entry is #\VFANC,LAT,LONG,128.
|
||||||
|
|
||||||
VALUE SIGNPOSTS: Signposts display as a yellow box with a 1-3 letter
|
VALUE SIGNPOSTS: This is another special handling Symbol. Signposts
|
||||||
overlay on them. You specify the 1-3 letter overlay by enclosing them
|
trigger a display as a yellow box with a 1-3 letter overlay on them.
|
||||||
in braces in the comment field. Thus a VALUE Signpost with {55} would
|
The use of this symbol (\m) triggers a search for a 1-3 letter
|
||||||
|
string of characters encolsed in braces in the comment field.
|
||||||
|
|
||||||
|
Thus a VALUE Signpost with {55} in the comment field would
|
||||||
appear as a sign with 55 on it, designed for posting the speed
|
appear as a sign with 55 on it, designed for posting the speed
|
||||||
of traffic past speed measuring devices. APRSdos has a version named
|
of traffic past speed measuring devices. APRSdos has a version named
|
||||||
APRStfc.EXE that monitors traffic speed and posts these speed signs
|
APRStfc.EXE that monitors traffic speed and posts these speed signs
|
||||||
|
@ -336,21 +356,21 @@ map, they ONLY appear at 8 miles and below AND they do not show any
|
||||||
callsign or name. Only the yellow box and the 3 letters or numbers.
|
callsign or name. Only the yellow box and the 3 letters or numbers.
|
||||||
Select them from the OBJECT menu under VALUE...
|
Select them from the OBJECT menu under VALUE...
|
||||||
|
|
||||||
APRS 1.2 OVERLAY TYPE SYMBOLS [April 2007]:
|
APRS 1.2 OVERLAY TYPE SYMBOLS EXPANSION! [April 2007]:
|
||||||
-------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
All alternate symbols have the potential to be overlayed. This was
|
All alternate symbols have the potential to be overlayed. This was
|
||||||
the original intent and was only limited to a few due to limitations
|
the original intent and was only limited to a few due to limitations
|
||||||
in Mac and WinAPRS. Those original "numbered" symbols are marked
|
in Mac and WinAPRS. Those original "numbered" symbols are marked
|
||||||
with a # in the table above. But by 2007, it was time to move on.
|
with a # in the table above. But by 2007, it was time to move on.
|
||||||
In APRS 1.2 it is proposed that any ALTENATE symbol can have overlays.
|
In APRS 1.2 it was proposed that any ALTENATE symbol can have overlays.
|
||||||
Kenwood has already responded with the new D710 that can now display
|
Kenwood has already responded with the new D710 that can now display
|
||||||
these overlays on all symbols.
|
these overlays on all symbols.
|
||||||
|
|
||||||
To help define these hundreds of new symbol combinations, we have
|
To help define these hundreds of new symbol combinations, we have
|
||||||
added a new file called:
|
added a new file called:
|
||||||
|
|
||||||
http://www.ew.usna.edu/~bruninga/aprs/symbols-new.txt
|
http:aprs.org/symbols/symbols-new.txt
|
||||||
|
|
||||||
The overlay symbols may be used in two ways. First, simply as an
|
The overlay symbols may be used in two ways. First, simply as an
|
||||||
overlay on a basic symbol type. Most uses of these symbols will be
|
overlay on a basic symbol type. Most uses of these symbols will be
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
/* telemetry.h */
|
||||||
|
|
||||||
|
void telemetry_data_original (char *station, char *info, char *output, char *comment);
|
||||||
|
|
||||||
|
void telemetry_data_base91 (char *station, char *cdata, char *output);
|
||||||
|
|
||||||
|
void telemetry_name_message (char *station, char *msg);
|
||||||
|
|
||||||
|
void telemetry_unit_label_message (char *station, char *msg);
|
||||||
|
|
||||||
|
void telemetry_coefficents_message (char *station, char *msg);
|
||||||
|
|
||||||
|
void telemetry_bit_sense_message (char *station, char *msg);
|
28
textcolor.c
28
textcolor.c
|
@ -118,7 +118,33 @@ static const char dark_green[] = "\e[0;32m" "\e[5;47m";
|
||||||
static const char clear_eos[] = "\e[0J";
|
static const char clear_eos[] = "\e[0J";
|
||||||
|
|
||||||
|
|
||||||
#else /* Linux */
|
#elif __arm__ /* Linux on Raspberry Pi or similar */
|
||||||
|
|
||||||
|
|
||||||
|
/* We need "blink" (5) rather than the */
|
||||||
|
/* expected bright/bold (1) to get bright white background. */
|
||||||
|
/* Makes no sense but I stumbled across that somewhere. */
|
||||||
|
|
||||||
|
static const char background_white[] = "\e[5;47m";
|
||||||
|
|
||||||
|
/* Whenever a dark color is used, the */
|
||||||
|
/* background is reset and needs to be set again. */
|
||||||
|
|
||||||
|
static const char black[] = "\e[0;30m" "\e[5;47m";
|
||||||
|
static const char red[] = "\e[1;31m";
|
||||||
|
static const char green[] = "\e[1;32m";
|
||||||
|
static const char yellow[] = "\e[1;33m";
|
||||||
|
static const char blue[] = "\e[1;34m";
|
||||||
|
static const char magenta[] = "\e[1;35m";
|
||||||
|
static const char cyan[] = "\e[1;36m";
|
||||||
|
static const char dark_green[] = "\e[0;32m" "\e[5;47m";
|
||||||
|
|
||||||
|
/* Clear from cursor to end of screen. */
|
||||||
|
|
||||||
|
static const char clear_eos[] = "\e[0J";
|
||||||
|
|
||||||
|
|
||||||
|
#else /* Other Linux */
|
||||||
|
|
||||||
static const char background_white[] = "\e[47;1m";
|
static const char background_white[] = "\e[47;1m";
|
||||||
|
|
||||||
|
|
11
tocalls.txt
11
tocalls.txt
|
@ -1,6 +1,10 @@
|
||||||
APRS TO-CALL VERSION NUMBERS 18 Dec 2013
|
APRS TO-CALL VERSION NUMBERS 02 Sep 2014
|
||||||
-------------------------------------------------------------------
|
-------------------------------------------------------------------
|
||||||
WB4APR
|
WB4APR
|
||||||
|
|
||||||
|
02 Sep 14 added APSTMx for W7QO's Balloon trackers
|
||||||
|
21 Aug 14 added APSMSx for Paul Defrusne's SMS gateway
|
||||||
|
11 Aug 14 added APCWP8 for John GM7HHB, WinphoneAPRS
|
||||||
18 Dec 13 added APZWKR for GM1WKR NetSked application
|
18 Dec 13 added APZWKR for GM1WKR NetSked application
|
||||||
22 Oct 13 added APFIxx for APRS.FI OH7LZB, Hessu
|
22 Oct 13 added APFIxx for APRS.FI OH7LZB, Hessu
|
||||||
23 Aug 13 added APOxxx for OSCAR satellites for AMSAT-LU by LU9DO
|
23 Aug 13 added APOxxx for OSCAR satellites for AMSAT-LU by LU9DO
|
||||||
|
@ -56,6 +60,7 @@ a TOCALL number series:
|
||||||
APCLEY EYTraker GPRS/GSM tracker by ZS6EY
|
APCLEY EYTraker GPRS/GSM tracker by ZS6EY
|
||||||
APCLWX EYWeather GPRS/GSM WX station by ZS6EY
|
APCLWX EYWeather GPRS/GSM WX station by ZS6EY
|
||||||
APCLEZ Telit EZ10 GSM application ZS6CEY
|
APCLEZ Telit EZ10 GSM application ZS6CEY
|
||||||
|
APCWP8 John GM7HHB, WinphoneAPRS
|
||||||
APCYxx Cybiko applications
|
APCYxx Cybiko applications
|
||||||
APD APD4xx UP4DAR platform
|
APD APD4xx UP4DAR platform
|
||||||
APDDxx DV-RPTR Modem and Control Center Software
|
APDDxx DV-RPTR Modem and Control Center Software
|
||||||
|
@ -133,11 +138,13 @@ a TOCALL number series:
|
||||||
APRTLM used in MIM's and Mic-lites, etc
|
APRTLM used in MIM's and Mic-lites, etc
|
||||||
APRtfc APRStraffic
|
APRtfc APRStraffic
|
||||||
APRSTx APRStt (Touch tone)
|
APRSTx APRStt (Touch tone)
|
||||||
APS APRS+SA, etc
|
APS APSxxx APRS+SA, etc
|
||||||
APSARx ZL4FOX's SARTRACK
|
APSARx ZL4FOX's SARTRACK
|
||||||
APSCxx aprsc APRS-IS core server (OH7LZB, OH2MQK)
|
APSCxx aprsc APRS-IS core server (OH7LZB, OH2MQK)
|
||||||
APSK63 APRS Messenger -over-PSK63
|
APSK63 APRS Messenger -over-PSK63
|
||||||
APSK25 APRS Messenger GMSK-250
|
APSK25 APRS Messenger GMSK-250
|
||||||
|
APSMSx Paul Defrusne's SMS gateway
|
||||||
|
APSTMx for W7QO's Balloon trackers
|
||||||
APT APTIGR TigerTrack
|
APT APTIGR TigerTrack
|
||||||
APTTxx Tiny Track
|
APTTxx Tiny Track
|
||||||
APT2xx Tiny Track II
|
APT2xx Tiny Track II
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
|
||||||
Most of the files in this directory copied from
|
The other files in this directory were copied from
|
||||||
|
|
||||||
http://www.gpsy.com/gpsinfo/geotoutm/
|
http://www.gpsy.com/gpsinfo/geotoutm/
|
||||||
|
|
||||||
|
See attachments to message from Chuck Gantz.
|
||||||
|
There is no obvious copyright on the source code.
|
||||||
|
The links in the message are no longer valid.
|
||||||
|
|
||||||
|
|
||||||
A few minor modifications were made:
|
A few minor modifications were made:
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
/* Dire Wolf version 1.0 */
|
/* Dire Wolf version 1.1 */
|
||||||
|
|
||||||
#define APP_TOCALL "APDW"
|
#define APP_TOCALL "APDW"
|
||||||
|
|
||||||
#define MAJOR_VERSION 1
|
#define MAJOR_VERSION 1
|
||||||
#define MINOR_VERSION 0
|
#define MINOR_VERSION 1
|
||||||
|
|
55
xmit.c
55
xmit.c
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2011,2013 John Langner, WB2OSZ
|
// Copyright (C) 2011,2013,2014 John Langner, WB2OSZ
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -110,14 +110,21 @@ static int xmit_bits_per_sec[MAX_CHANS]; /* Data transmission rate. */
|
||||||
/* this case but could be different with other */
|
/* this case but could be different with other */
|
||||||
/* modulation techniques. */
|
/* modulation techniques. */
|
||||||
|
|
||||||
|
static int g_debug_xmit_packet; /* print packet in hexadecimal form for debugging. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define BITS_TO_MS(b,ch) (((b)*1000)/xmit_bits_per_sec[(ch)])
|
#define BITS_TO_MS(b,ch) (((b)*1000)/xmit_bits_per_sec[(ch)])
|
||||||
|
|
||||||
#define MS_TO_BITS(ms,ch) (((ms)*xmit_bits_per_sec[(ch)])/1000)
|
#define MS_TO_BITS(ms,ch) (((ms)*xmit_bits_per_sec[(ch)])/1000)
|
||||||
|
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
static unsigned __stdcall xmit_thread (void *arg);
|
||||||
|
#else
|
||||||
static void * xmit_thread (void *arg);
|
static void * xmit_thread (void *arg);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int wait_for_clear_channel (int channel, int nowait, int slotttime, int persist);
|
static int wait_for_clear_channel (int channel, int nowait, int slotttime, int persist);
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,7 +149,7 @@ static int wait_for_clear_channel (int channel, int nowait, int slotttime, int p
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void xmit_init (struct audio_s *p_modem)
|
void xmit_init (struct audio_s *p_modem, int debug_xmit_packet)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
|
@ -159,6 +166,8 @@ void xmit_init (struct audio_s *p_modem)
|
||||||
dw_printf ("xmit_init ( ... )\n");
|
dw_printf ("xmit_init ( ... )\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
g_debug_xmit_packet = debug_xmit_packet;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Push to Talk (PTT) control.
|
* Push to Talk (PTT) control.
|
||||||
*/
|
*/
|
||||||
|
@ -202,7 +211,7 @@ void xmit_init (struct audio_s *p_modem)
|
||||||
// underrun on the audio output device.
|
// underrun on the audio output device.
|
||||||
|
|
||||||
#if __WIN32__
|
#if __WIN32__
|
||||||
xmit_th = _beginthreadex (NULL, 0, xmit_thread, NULL, 0, NULL);
|
xmit_th = (HANDLE)_beginthreadex (NULL, 0, xmit_thread, NULL, 0, NULL);
|
||||||
if (xmit_th == NULL) {
|
if (xmit_th == NULL) {
|
||||||
text_color_set(DW_COLOR_ERROR);
|
text_color_set(DW_COLOR_ERROR);
|
||||||
dw_printf ("Could not create xmit thread\n");
|
dw_printf ("Could not create xmit thread\n");
|
||||||
|
@ -377,7 +386,11 @@ void xmit_set_txtail (int channel, int value)
|
||||||
*
|
*
|
||||||
*--------------------------------------------------------------------*/
|
*--------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if __WIN32__
|
||||||
|
static unsigned __stdcall xmit_thread (void *arg)
|
||||||
|
#else
|
||||||
static void * xmit_thread (void *arg)
|
static void * xmit_thread (void *arg)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
packet_t pp;
|
packet_t pp;
|
||||||
unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
||||||
|
@ -455,14 +468,25 @@ static void * xmit_thread (void *arg)
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
||||||
dw_printf ("%s", stemp); /* stations followed by : */
|
dw_printf ("%s", stemp); /* stations followed by : */
|
||||||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
flen = ax25_pack (pp, fbuf);
|
/* Optional hex dump of packet. */
|
||||||
assert (flen <= sizeof(fbuf));
|
|
||||||
|
if (g_debug_xmit_packet) {
|
||||||
|
|
||||||
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
ax25_hex_dump (pp);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transmit the frame.
|
* Transmit the frame.
|
||||||
*/
|
* 1.1J fixed order.
|
||||||
|
*/
|
||||||
|
flen = ax25_pack (pp, fbuf);
|
||||||
|
assert (flen >= 1 && flen <= sizeof(fbuf));
|
||||||
num_bits += hdlc_send_frame (c, fbuf, flen);
|
num_bits += hdlc_send_frame (c, fbuf, flen);
|
||||||
numframe = 1;
|
numframe = 1;
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
|
@ -483,14 +507,21 @@ static void * xmit_thread (void *arg)
|
||||||
text_color_set(DW_COLOR_XMIT);
|
text_color_set(DW_COLOR_XMIT);
|
||||||
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
||||||
dw_printf ("%s", stemp); /* stations followed by : */
|
dw_printf ("%s", stemp); /* stations followed by : */
|
||||||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
|
|
||||||
flen = ax25_pack (pp, fbuf);
|
if (g_debug_xmit_packet) {
|
||||||
assert (flen <= sizeof(fbuf));
|
text_color_set(DW_COLOR_DEBUG);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
ax25_hex_dump (pp);
|
||||||
|
dw_printf ("------\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transmit the frame.
|
* Transmit the frame.
|
||||||
*/
|
*/
|
||||||
|
flen = ax25_pack (pp, fbuf);
|
||||||
|
assert (flen >= 1 && flen <= sizeof(fbuf));
|
||||||
num_bits += hdlc_send_frame (c, fbuf, flen);
|
num_bits += hdlc_send_frame (c, fbuf, flen);
|
||||||
numframe++;
|
numframe++;
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
|
@ -559,7 +590,7 @@ static void * xmit_thread (void *arg)
|
||||||
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
||||||
|
|
||||||
dw_printf ("%s", stemp); /* stations followed by : */
|
dw_printf ("%s", stemp); /* stations followed by : */
|
||||||
ax25_safe_print ((char *)pinfo, info_len, 0);
|
ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
|
||||||
dw_printf ("\n");
|
dw_printf ("\n");
|
||||||
ax25_delete (pp);
|
ax25_delete (pp);
|
||||||
|
|
||||||
|
|
2
xmit.h
2
xmit.h
|
@ -6,7 +6,7 @@
|
||||||
#include "audio.h" /* for struct audio_s */
|
#include "audio.h" /* for struct audio_s */
|
||||||
|
|
||||||
|
|
||||||
extern void xmit_init (struct audio_s *p_modem);
|
extern void xmit_init (struct audio_s *p_modem, int debug_xmit_packet);
|
||||||
|
|
||||||
extern void xmit_set_txdelay (int channel, int value);
|
extern void xmit_set_txdelay (int channel, int value);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue