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
|
||||
*.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
|
||||
-----------
|
||||
|
@ -36,6 +108,13 @@ Improved support for UTF-8 character set.
|
|||
|
||||
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.
|
||||
|
|
134
Makefile.linux
134
Makefile.linux
|
@ -2,7 +2,7 @@
|
|||
# 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
|
||||
|
||||
|
@ -81,18 +81,30 @@ CC = gcc
|
|||
arch := $(shell echo | gcc -E -dM - | grep __i386__)
|
||||
|
||||
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
|
||||
CFLAGS := -DUSE_ALSA -O3 -pthread
|
||||
CFLAGS := -O3 -pthread -Iutm
|
||||
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
|
||||
#LDLIBS += -lgps
|
||||
|
||||
|
||||
|
||||
# Name of current directory.
|
||||
# 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 \
|
||||
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 \
|
||||
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
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread -lrt -lasound $(LDLIBS) -lm
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lpthread -lrt $(LDLIBS) -lm
|
||||
|
||||
|
||||
# Optimization for slow processors.
|
||||
|
@ -132,40 +144,51 @@ LatLong-UTMconversion.o : utm/LatLong-UTMconversion.c
|
|||
$(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: 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
|
||||
sudo install direwolf /usr/local/bin
|
||||
sudo install decode_aprs /usr/local/bin
|
||||
sudo install text2tt /usr/local/bin
|
||||
sudo install tt2text /usr/local/bin
|
||||
sudo install ll2utm /usr/local/bin
|
||||
sudo install utm2ll /usr/local/bin
|
||||
sudo install aclients /usr/local/bin
|
||||
sudo install -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||
sudo install -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||
sudo install -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||
sudo install -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||
sudo install -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||
cp direwolf.conf ~
|
||||
install direwolf /usr/local/bin
|
||||
install decode_aprs /usr/local/bin
|
||||
install text2tt /usr/local/bin
|
||||
install tt2text /usr/local/bin
|
||||
install ll2utm /usr/local/bin
|
||||
install utm2ll /usr/local/bin
|
||||
install aclients /usr/local/bin
|
||||
install log2gpx /usr/local/bin
|
||||
install -D --mode=644 tocalls.txt /usr/share/direwolf/tocalls.txt
|
||||
install -D --mode=644 symbols-new.txt /usr/share/direwolf/symbols-new.txt
|
||||
install -D --mode=644 symbolsX.txt /usr/share/direwolf/symbolsX.txt
|
||||
install -D --mode=644 dw-icon.png /usr/share/direwolf/dw-icon.png
|
||||
install -D --mode=644 direwolf.desktop /usr/share/applications/direwolf.desktop
|
||||
install -D --mode=644 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 ~
|
||||
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
|
||||
|
||||
install-conf : direwolf.conf
|
||||
cp direwolf.conf ~
|
||||
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
|
@ -182,23 +205,29 @@ tt2text : tt_text.c
|
|||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c utm.a
|
||||
$(CC) $(CFLAGS) -I utm -o $@ $^ -lm
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
|
||||
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.
|
||||
|
||||
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_afsk.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
|
||||
./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
|
||||
|
||||
|
||||
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
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm
|
||||
atest : atest.c demod.c dsp.c demod_afsk.c demod_9600.c hdlc_rec.c hdlc_rec2.o multi_modem.o rrbb.o \
|
||||
fcs_calc.c ax25_pad.c decode_aprs.c telemetry.c latlong.c symbols.c textcolor.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lm -lrt
|
||||
time ./atest ../direwolf-0.2/02_Track_2.wav
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
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 \
|
||||
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)
|
||||
|
@ -256,12 +294,12 @@ clean :
|
|||
# Package it up for distribution.
|
||||
|
||||
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
|
||||
echo " " > tune.h
|
||||
rm -f ../$z-src.zip
|
||||
(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/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||
$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
|
||||
# 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 :
|
||||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
cp -r . /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
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"
|
||||
#
|
||||
|
|
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.
|
||||
|
@ -25,8 +25,8 @@ all : direwolf decode_aprs text2tt tt2text ll2utm utm2ll aclients
|
|||
#TODO: put -Ofast back in.
|
||||
|
||||
CC = gcc
|
||||
#CFLAGS = -g -Wall -Ofast -march=pentium3 -msse -Iregex -mthreads -DUSE_REGEX_STATIC
|
||||
CFLAGS = -g -Wall -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 -Iutm -mthreads -DUSE_REGEX_STATIC
|
||||
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 \
|
||||
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 \
|
||||
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
|
||||
$(CC) $(CFLAGS) -g -o $@ $^ -lwinmm -lws2_32
|
||||
|
||||
|
@ -137,7 +137,7 @@ strcasestr.o : misc/strcasestr.c
|
|||
|
||||
# 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 $^
|
||||
|
||||
|
||||
|
@ -153,10 +153,16 @@ tt2text : tt_text.c
|
|||
# Convert between Latitude/Longitude and UTM coordinates.
|
||||
|
||||
ll2utm : ll2utm.c utm.a
|
||||
$(CC) $(CFLAGS) -I utm -o $@ $^
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
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.
|
||||
|
@ -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 \
|
||||
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
|
||||
rm -f atest.exe
|
||||
$(CC) $(CFLAGS) -DNOFIX -o atest $^
|
||||
|
@ -183,7 +189,7 @@ noisy3.wav : gen_packets
|
|||
./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 \
|
||||
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
|
||||
rm -f atest.exe
|
||||
$(CC) $(CFLAGS) -o atest $^
|
||||
|
@ -194,7 +200,7 @@ noisy96.wav : gen_packets
|
|||
./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 \
|
||||
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
|
||||
rm -f atest.exe
|
||||
$(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 \
|
||||
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
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
echo " " > tune.h
|
||||
./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 \
|
||||
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
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
./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
|
||||
|
||||
|
||||
# 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.
|
||||
|
||||
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 \
|
||||
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 \
|
||||
encode_aprs.c latlong.c \
|
||||
encode_aprs.c latlong.c telemetry.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 \
|
||||
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
|
||||
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 \
|
||||
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 \
|
||||
APRStt-Implementation-Notes.pdf \
|
||||
Raspberry-Pi-APRS-Tracker.pdf APRStt-Implementation-Notes.pdf \
|
||||
direwolf.desktop dw-start.sh \
|
||||
tocalls.txt symbols-new.txt symbolsX.txt
|
||||
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 \
|
||||
$z/CHANGES.txt $z/LICENSE* \
|
||||
$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/*.conf $z/tocalls.txt $z/symbols-new.txt $z/symbolsX.txt \
|
||||
$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
|
||||
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
|
||||
echo "***** APRStt-Implementation-Notes.pdf is out of date *****"
|
||||
|
||||
|
@ -317,6 +335,16 @@ backup :
|
|||
mkdir /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
cp -r . /cygdrive/e/backup-cygwin-home/`date +"%Y-%m-%d"`
|
||||
|
||||
#
|
||||
# The locations below appear to be the most recent.
|
||||
# The copy at http://www.aprs.org/tocalls.txt is out of date.
|
||||
#
|
||||
|
||||
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"
|
||||
#
|
||||
|
|
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__
|
||||
send (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd), 0);
|
||||
#else
|
||||
(void)write (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
||||
err = write (server_sock, (char*)(&mon_cmd), sizeof(mon_cmd));
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -649,6 +649,8 @@ static void * client_thread_serial (void *arg)
|
|||
DCB dcb;
|
||||
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,
|
||||
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 */
|
||||
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.BaudRate = 9600;
|
||||
dcb.fBinary = 1;
|
||||
dcb.fParity = 0;
|
||||
|
|
15
aprs_tt.c
15
aprs_tt.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// This file is part of Dire Wolf, an amateur radio packet TNC.
|
||||
//
|
||||
// Copyright (C) 2013,2014 John Langner, WB2OSZ
|
||||
// Copyright (C) 2013, 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
|
||||
|
@ -32,6 +32,9 @@
|
|||
*
|
||||
*---------------------------------------------------------------*/
|
||||
|
||||
#define APRS_TT_C 1
|
||||
|
||||
|
||||
// TODO: clean up terminolgy.
|
||||
// "Message" has a specific meaning in APRS and this is not it.
|
||||
// Touch Tone sequence might be appropriate.
|
||||
|
@ -872,6 +875,7 @@ static int parse_symbol (char *e)
|
|||
*
|
||||
* Outputs: m_latitude
|
||||
* m_longitude
|
||||
* m_dao
|
||||
*
|
||||
* 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! */
|
||||
/* 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);
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#ifndef APRS_TT_H
|
||||
#define APRS_TT_H 1
|
||||
|
||||
|
||||
/*
|
||||
* For holding location format specifications from config file.
|
||||
* 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
|
||||
|
@ -78,6 +79,8 @@ struct tt_config_s {
|
|||
};
|
||||
|
||||
|
||||
|
||||
|
||||
void aprs_tt_init (struct tt_config_s *p_config);
|
||||
|
||||
void aprs_tt_button (int chan, char button);
|
||||
|
@ -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 APRSTT_LOC_DESC_LEN 32 /* Need at least 26 */
|
||||
|
||||
void aprs_tt_dao_to_desc (char *dao, char *str);
|
||||
|
||||
#endif
|
||||
|
||||
/* 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.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. */
|
||||
/* Results v0.9: 971/69, 990/64, 992/65, 992/67, 1004/476 */
|
||||
|
||||
modem.fix_bits = RETRY_NONE;
|
||||
modem.fix_bits = RETRY_SINGLE;
|
||||
modem.fix_bits = RETRY_DOUBLE;
|
||||
//modem.fix_bits = RETRY_TRIPLE;
|
||||
//modem.fix_bits = RETRY_TWO_SEP;
|
||||
//modem.fix_bits = RETRY_SWAP_SINGLE;
|
||||
//modem.fix_bits = RETRY_SWAP_DOUBLE;
|
||||
//modem.fix_bits = RETRY_SWAP_TRIPLE;
|
||||
//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++) {
|
||||
|
||||
|
@ -162,6 +212,7 @@ int main (int argc, char *argv[])
|
|||
modem.space_freq[channel] = DEFAULT_SPACE_FREQ;
|
||||
modem.baud[channel] = DEFAULT_BAUD;
|
||||
strcpy (modem.profiles[channel], "C");
|
||||
//strcpy (modem.profiles[channel], "ABC");
|
||||
// temp
|
||||
// strcpy (modem.profiles[channel], "F");
|
||||
modem.num_subchan[channel] = strlen(modem.profiles[channel]);
|
||||
|
@ -334,7 +385,6 @@ int main (int argc, char *argv[])
|
|||
/* process_rec_frame, below, is called. */
|
||||
|
||||
}
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
printf ("\n\n");
|
||||
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);
|
||||
printf ("\n");
|
||||
|
||||
printf("DECODED[%d] ", packets_decoded );
|
||||
if (h != AX25_SOURCE) {
|
||||
printf ("Digipeater ");
|
||||
}
|
||||
|
|
78
audio.c
78
audio.c
|
@ -50,15 +50,13 @@
|
|||
*
|
||||
* 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
|
||||
*
|
||||
* Release 1.1: Gabor Berczi provided fixes for the OSS code
|
||||
* which had fallen into decay.
|
||||
*
|
||||
* Future: Will probably rip out the OSS code.
|
||||
* 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
|
||||
#include <alsa/asoundlib.h>
|
||||
#else
|
||||
#ifdef __OpenBSD__
|
||||
#include <soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "direwolf.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);
|
||||
#else
|
||||
|
||||
static int set_oss_params (int fd, struct audio_s *pa);
|
||||
static int oss_audio_device_fd = -1; /* Single device, both directions. */
|
||||
|
||||
#endif
|
||||
|
@ -180,11 +187,11 @@ int audio_open (struct audio_s *pa)
|
|||
int err;
|
||||
int chan;
|
||||
|
||||
#if USE_ALSA
|
||||
|
||||
char audio_in_name[30];
|
||||
char audio_out_name[30];
|
||||
|
||||
#if USE_ALSA
|
||||
|
||||
assert (audio_in_handle == NULL);
|
||||
assert (audio_out_handle == NULL);
|
||||
|
||||
|
@ -234,11 +241,10 @@ int audio_open (struct audio_s *pa)
|
|||
outbuf_ptr = NULL;
|
||||
outbuf_len = 0;
|
||||
|
||||
#if USE_ALSA
|
||||
|
||||
/*
|
||||
* Determine the type of audio input.
|
||||
*/
|
||||
|
||||
audio_in_type = AUDIO_IN_TYPE_SOUNDCARD;
|
||||
|
||||
if (strcasecmp(pa->adevice_in, "stdin") == 0 || strcmp(pa->adevice_in, "-") == 0) {
|
||||
|
@ -246,7 +252,7 @@ int audio_open (struct audio_s *pa)
|
|||
/* Change - to stdin for readability. */
|
||||
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;
|
||||
/* Supply default port if none specified. */
|
||||
if (strcasecmp(pa->adevice_in,"udp") == 0 ||
|
||||
|
@ -285,7 +291,7 @@ int audio_open (struct audio_s *pa)
|
|||
* Soundcard - ALSA.
|
||||
*/
|
||||
case AUDIO_IN_TYPE_SOUNDCARD:
|
||||
|
||||
#if USE_ALSA
|
||||
err = snd_pcm_open (&audio_in_handle, audio_in_name, SND_PCM_STREAM_CAPTURE, 0);
|
||||
if (err < 0) {
|
||||
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");
|
||||
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.
|
||||
|
@ -353,6 +376,8 @@ int audio_open (struct audio_s *pa)
|
|||
/*
|
||||
* 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);
|
||||
|
||||
if (err < 0) {
|
||||
|
@ -368,34 +393,7 @@ int audio_open (struct audio_s *pa)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#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 */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Finally allocate buffer for each direction.
|
||||
|
@ -811,7 +809,7 @@ int audio_get (void)
|
|||
this_time = time(NULL);
|
||||
if (this_time >= last_time + duration) {
|
||||
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);
|
||||
last_time = this_time;
|
||||
sample_count = 0;
|
||||
|
|
8
audio.h
8
audio.h
|
@ -22,7 +22,8 @@
|
|||
enum ptt_method_e {
|
||||
PTT_METHOD_NONE, /* VOX or no transmit. */
|
||||
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;
|
||||
|
||||
|
@ -94,6 +95,9 @@ struct audio_s {
|
|||
|
||||
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 slottime[MAX_CHANS]; /* Slot time in 10 mS units for persistance algorithm. */
|
||||
|
@ -153,7 +157,7 @@ struct audio_s {
|
|||
|
||||
#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.
|
||||
|
|
|
@ -744,7 +744,7 @@ int audio_get (void)
|
|||
this_time = time(NULL);
|
||||
if (this_time >= last_time + duration) {
|
||||
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);
|
||||
last_time = this_time;
|
||||
sample_count = 0;
|
||||
|
|
676
ax25_pad.c
676
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)
|
||||
*/
|
||||
|
||||
/* 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 )
|
||||
|
||||
|
@ -77,20 +78,17 @@ struct packet_s {
|
|||
|
||||
struct packet_s *nextp; /* Pointer to next in queue. */
|
||||
|
||||
int num_addr; /* Number of elements used in two below. */
|
||||
/* Range of 0 .. AX25_MAX_ADDRS. */
|
||||
int num_addr; /* Number of addresses in frame. */
|
||||
/* 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
|
||||
*
|
||||
* H for digipeaters set to 0 intially.
|
||||
|
@ -118,13 +116,12 @@ struct packet_s {
|
|||
#define SSID_LAST_MASK 0x01
|
||||
|
||||
|
||||
int the_rest_len; /* Frame length minus the address part. */
|
||||
int frame_len; /* Frame length without CRC. */
|
||||
|
||||
|
||||
unsigned char frame_data[AX25_MAX_PACKET_LEN+1];
|
||||
/* Raw frame contents, without the CRC. */
|
||||
|
||||
unsigned char the_rest[2 + 3 + AX25_MAX_INFO_LEN + 1];
|
||||
/* The rest after removing the addresses. */
|
||||
/* Includes control, protocol ID, Information, */
|
||||
/* and throw in one more for a character */
|
||||
/* string nul terminator. */
|
||||
|
||||
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)
|
||||
{
|
||||
return (0);
|
||||
//return (0);
|
||||
return (this_p->num_addr*7);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -182,12 +180,12 @@ static int ax25_get_num_pid (packet_t this_p)
|
|||
int c;
|
||||
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 */
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = this_p->the_rest_len - ax25_get_num_control(this_p) - ax25_get_num_pid(this_p);
|
||||
/* assuming AX.25 frame. */
|
||||
|
||||
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) {
|
||||
len = 0; /* print error? */
|
||||
}
|
||||
|
||||
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 void ax25_hex_dump (packet_t this_p);
|
||||
|
||||
extern int ax25_is_aprs (packet_t pp);
|
||||
|
||||
extern int ax25_get_control (packet_t this_p);
|
||||
|
|
159
beacon.c
159
beacon.c
|
@ -57,6 +57,7 @@
|
|||
#include "beacon.h"
|
||||
#include "latlong.h"
|
||||
#include "dwgps.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
|
||||
|
@ -83,6 +84,16 @@ static unsigned __stdcall beacon_thread (void *arg);
|
|||
static void * beacon_thread (void *arg);
|
||||
#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.
|
||||
*/
|
||||
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. */
|
||||
|
||||
|
@ -177,7 +188,7 @@ void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi)
|
|||
|
||||
case BEACON_TRACKER:
|
||||
|
||||
#if defined(GPS_ENABLED) || defined(DEBUG_SIM)
|
||||
#if defined(ENABLE_GPS) || defined(DEBUG_SIM)
|
||||
g_using_gps++;
|
||||
#else
|
||||
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))
|
||||
|
||||
|
||||
|
@ -360,7 +369,8 @@ static void * beacon_thread (void *arg)
|
|||
float my_course = 0; /* degrees */
|
||||
float my_speed_knots = 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.
|
||||
|
@ -439,15 +449,40 @@ static void * beacon_thread (void *arg)
|
|||
fprintf (stderr, "Can't read /tmp/cs.\n");
|
||||
}
|
||||
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_lon = 71.99;
|
||||
my_alt = 100;
|
||||
my_alt_m = 100;
|
||||
#else
|
||||
if (g_using_gps) {
|
||||
|
||||
fix = dwgps_read (&my_lat, &my_lon, &my_speed_knots, &my_course, &my_alt);
|
||||
my_speed_mph = KNOTS_TO_MPH * my_speed_knots;
|
||||
fix = dwgps_read (&my_lat, &my_lon, &my_speed_knots, &my_course, &my_alt_m);
|
||||
my_speed_mph = DW_KNOTS_TO_MPH(my_speed_knots);
|
||||
|
||||
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. */
|
||||
/* Possibly at the point where about to transmit. */
|
||||
|
@ -461,13 +496,25 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
if (my_speed_mph > g_misc_config_p->sb_fast_speed) {
|
||||
sb_every = g_misc_config_p->sb_fast_rate;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f > fast %d mph, interval = %d sec\n", my_speed_mph, g_misc_config_p->sb_fast_speed, sb_every);
|
||||
}
|
||||
}
|
||||
else if (my_speed_mph < g_misc_config_p->sb_slow_speed) {
|
||||
sb_every = g_misc_config_p->sb_slow_rate;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f < slow %d mph, interval = %d sec\n", my_speed_mph, g_misc_config_p->sb_slow_speed, sb_every);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Can't divide by 0 assuming sb_slow_speed > 0. */
|
||||
sb_every = ( g_misc_config_p->sb_fast_rate * g_misc_config_p->sb_fast_speed ) / my_speed_mph;
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("my speed %.1f mph, interval = %d sec\n", my_speed_mph, sb_every);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_SIM
|
||||
|
@ -493,6 +540,13 @@ static void * beacon_thread (void *arg)
|
|||
if (heading_change(my_course, sb_prev_course) > turn_threshold &&
|
||||
now >= sb_prev_time + g_misc_config_p->sb_turn_time) {
|
||||
|
||||
if (g_tracker_debug_level >= 2) {
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("heading change (%.0f, %.0f) > threshold %d and %d since last >= turn time %d\n",
|
||||
my_course, sb_prev_course, turn_threshold,
|
||||
(int)(now - sb_prev_time), g_misc_config_p->sb_turn_time);
|
||||
}
|
||||
|
||||
/* Send it now. */
|
||||
for (j=0; j<g_misc_config_p->num_beacons; j++) {
|
||||
if (g_misc_config_p->beacon[j].btype == BEACON_TRACKER) {
|
||||
|
@ -517,6 +571,7 @@ static void * beacon_thread (void *arg)
|
|||
char beacon_text[AX25_MAX_PACKET_LEN];
|
||||
packet_t pp = NULL;
|
||||
char mycall[AX25_MAX_ADDR_LEN];
|
||||
int alt_ft;
|
||||
|
||||
/*
|
||||
* Obtain source call for the beacon.
|
||||
|
@ -524,15 +579,15 @@ static void * beacon_thread (void *arg)
|
|||
* When sending to IGate server, use call from first radio channel.
|
||||
*
|
||||
* 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");
|
||||
|
||||
if (g_misc_config_p->beacon[j].chan == -1) {
|
||||
strcpy (mycall, g_digi_config_p->mycall[0]);
|
||||
}
|
||||
else {
|
||||
strcpy (mycall, g_digi_config_p->mycall[g_misc_config_p->beacon[j].chan]);
|
||||
}
|
||||
assert (g_misc_config_p->beacon[j].sendto_chan >= 0);
|
||||
|
||||
strcpy (mycall, g_digi_config_p->mycall[g_misc_config_p->beacon[j].sendto_chan]);
|
||||
|
||||
if (strlen(mycall) == 0 || strcmp(mycall, "NOCALL") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -542,13 +597,22 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
/*
|
||||
* Prepare the monitor format header.
|
||||
*
|
||||
* src > dest [ , via ]
|
||||
*/
|
||||
|
||||
strcpy (beacon_text, mycall);
|
||||
strcat (beacon_text, ">");
|
||||
|
||||
if (g_misc_config_p->beacon[j].dest != NULL) {
|
||||
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) {
|
||||
}
|
||||
|
||||
if (g_misc_config_p->beacon[j].via != NULL) {
|
||||
strcat (beacon_text, ",");
|
||||
strcat (beacon_text, g_misc_config_p->beacon[j].via);
|
||||
}
|
||||
|
@ -561,7 +625,10 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
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].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 */
|
||||
|
@ -594,8 +661,9 @@ static void * beacon_thread (void *arg)
|
|||
if (coarse == 0) {
|
||||
coarse = 360;
|
||||
}
|
||||
encode_position (g_misc_config_p->beacon[j].compress,
|
||||
my_lat, my_lon,
|
||||
encode_position (g_misc_config_p->beacon[j].messaging,
|
||||
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].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),
|
||||
|
@ -617,6 +685,34 @@ static void * beacon_thread (void *arg)
|
|||
else {
|
||||
g_misc_config_p->beacon[j].next = now + g_misc_config_p->beacon[j].every;
|
||||
}
|
||||
|
||||
/* Write to log file for testing. */
|
||||
/* The idea is to run log2gpx and map the result rather than */
|
||||
/* actually transmitting and relying on someone else to receive */
|
||||
/* 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 {
|
||||
g_misc_config_p->beacon[j].next = now + 2;
|
||||
|
@ -650,18 +746,33 @@ static void * beacon_thread (void *arg)
|
|||
|
||||
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
|
||||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[ig] %s\n", beacon_text);
|
||||
#endif
|
||||
igate_send_rec_packet (0, pp);
|
||||
ax25_delete (pp);
|
||||
}
|
||||
else {
|
||||
tq_append (g_misc_config_p->beacon[j].chan, TQ_PRIO_1_LO, pp);
|
||||
break;
|
||||
|
||||
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 {
|
||||
|
|
2
beacon.h
2
beacon.h
|
@ -2,3 +2,5 @@
|
|||
/* beacon.h */
|
||||
|
||||
void beacon_init (struct misc_config_s *pconfig, struct digi_config_s *pdigi);
|
||||
|
||||
void beacon_tracker_set_debug (int level);
|
||||
|
|
301
config.c
301
config.c
|
@ -54,6 +54,7 @@
|
|||
#include "igate.h"
|
||||
#include "latlong.h"
|
||||
#include "symbols.h"
|
||||
#include "LatLong-UTMconversion.h"
|
||||
|
||||
|
||||
//#include "tq.h"
|
||||
|
@ -415,6 +416,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
strcpy (p_modem->ptt_device[channel], "");
|
||||
p_modem->ptt_line[channel] = PTT_LINE_RTS;
|
||||
p_modem->ptt_gpio[channel] = 0;
|
||||
p_modem->ptt_lpt_bit[channel] = 0;
|
||||
p_modem->ptt_invert[channel] = 0;
|
||||
|
||||
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, "");
|
||||
strcpy (p_misc_config->nmea_port, "");
|
||||
strcpy (p_misc_config->logdir, "");
|
||||
|
||||
|
||||
/*
|
||||
|
@ -642,11 +646,21 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
continue;
|
||||
}
|
||||
else {
|
||||
|
||||
// Definitely set for current channel.
|
||||
// Set for other channels which have not been set yet.
|
||||
|
||||
int c;
|
||||
|
||||
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[channel], t, sizeof(p_digi_config->mycall[channel])-1);
|
||||
strncpy (p_digi_config->mycall[c], t, sizeof(p_digi_config->mycall[c])-1);
|
||||
|
||||
for (p = p_digi_config->mycall[channel]; *p != '\0'; p++) {
|
||||
for (p = p_digi_config->mycall[c]; *p != '\0'; p++) {
|
||||
if (islower(*p)) {
|
||||
*p = toupper(*p); /* silently force upper case. */
|
||||
}
|
||||
|
@ -654,6 +668,8 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
// 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 GPIO [-]gpio-num
|
||||
* PTT LPT [-]bit-num
|
||||
*/
|
||||
|
||||
else if (strcasecmp(t, "PTT") == 0) {
|
||||
|
@ -910,7 +927,60 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
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. */
|
||||
|
||||
|
@ -949,34 +1019,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
|
||||
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 ====================
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -2029,7 +2144,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
|
@ -2050,6 +2165,7 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
|
||||
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 ("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, "TBEACON") == 0 ||
|
||||
strcasecmp(t, "CBEACON") == 0) {
|
||||
#if __WIN32__
|
||||
if (strcasecmp(t, "TBEACON") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: TBEACON is available only in Linux version.\n", line);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_GPS
|
||||
if (strcasecmp(t, "TBEACON") == 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Config file, line %d: Rebuild with GPS support for TBEACON to be available.\n", line);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (p_misc_config->num_beacons < MAX_BEACONS) {
|
||||
|
||||
memset (&(p_misc_config->beacon[p_misc_config->num_beacons]), 0, sizeof(struct beacon_s));
|
||||
|
@ -2201,12 +2331,14 @@ void config_init (char *fname, struct audio_s *p_modem,
|
|||
|
||||
b = 0;
|
||||
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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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;
|
||||
char temp_symbol[100];
|
||||
int ok;
|
||||
char zone[8];
|
||||
double easting = G_UNKNOWN;
|
||||
double northing = G_UNKNOWN;
|
||||
|
||||
strcpy (temp_symbol, "");
|
||||
strcpy (zone, "");
|
||||
|
||||
b->chan = 0;
|
||||
b->sendto_type = SENDTO_XMIT;
|
||||
b->sendto_chan = 0;
|
||||
b->delay = 60;
|
||||
b->every = 600;
|
||||
//b->delay = 6; // TODO: temp. remove
|
||||
//b->delay = 6; // temp test.
|
||||
//b->every = 3600;
|
||||
b->lat = G_UNKNOWN;
|
||||
b->lon = G_UNKNOWN;
|
||||
b->alt_m = G_UNKNOWN;
|
||||
b->symtab = '/';
|
||||
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) {
|
||||
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 {
|
||||
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) {
|
||||
|
@ -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) {
|
||||
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) {
|
||||
/* Defer processing in case overlay appears later. */
|
||||
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) {
|
||||
b->compress = atoi(value);
|
||||
}
|
||||
else if (strcasecmp(keyword, "MESSAGING") == 0) {
|
||||
b->messaging = atoi(value);
|
||||
}
|
||||
else {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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.
|
||||
*/
|
||||
|
|
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 sendto_type_e { SENDTO_XMIT, SENDTO_IGATE, SENDTO_RECV };
|
||||
|
||||
|
||||
#define MAX_BEACONS 30
|
||||
|
||||
struct misc_config_s {
|
||||
|
@ -40,6 +43,11 @@ struct misc_config_s {
|
|||
char nullmodem[40]; /* Serial port name for our end of the */
|
||||
/* virtual null modem for native Windows apps. */
|
||||
|
||||
char nmea_port[40]; /* Serial port name for NMEA communication with GPS */
|
||||
/* receiver and/or mapping application. */
|
||||
|
||||
char logdir[80]; /* Directory for saving activity logs. */
|
||||
|
||||
int sb_configured; /* TRUE if SmartBeaconing is configured. */
|
||||
int sb_fast_speed; /* MPH */
|
||||
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 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. */
|
||||
|
||||
|
@ -68,6 +87,9 @@ struct misc_config_s {
|
|||
|
||||
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? */
|
||||
|
||||
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. */
|
||||
/* 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 lon;
|
||||
float alt_m; /* Altitude in meters. */
|
||||
|
||||
char symtab; /* Symbol table: / or \ or overlay character. */
|
||||
char symbol; /* Symbol code. */
|
||||
|
|
1825
decode_aprs.c
1825
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 */
|
||||
|
||||
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))
|
||||
static inline void push_sample (float val, float *buff, int size)
|
||||
{
|
||||
int j;
|
||||
|
||||
// TODO: memmove any faster?
|
||||
for (j = size - 1; j >= 1; j--) {
|
||||
buff[j] = buff[j-1];
|
||||
}
|
||||
memmove(buff+1,buff,(size-1)*sizeof(float));
|
||||
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
|
||||
|
@ -509,7 +547,7 @@ static void test (char *in, char *out)
|
|||
|
||||
if (strcmp(in, rec) != 0) {
|
||||
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) {
|
||||
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];
|
||||
|
||||
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);
|
||||
|
||||
void digi_regen (int from_chan, packet_t pp);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* end digipeater.h */
|
||||
|
|
144
direwolf.c
144
direwolf.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -42,6 +42,7 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#if __WIN32__
|
||||
#else
|
||||
|
@ -49,7 +50,11 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <soundcard.h>
|
||||
#else
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
|
@ -72,6 +77,7 @@
|
|||
#include "server.h"
|
||||
#include "kiss.h"
|
||||
#include "kissnet.h"
|
||||
#include "nmea.h"
|
||||
#include "gen_tone.h"
|
||||
#include "digipeater.h"
|
||||
#include "tq.h"
|
||||
|
@ -86,8 +92,12 @@
|
|||
#include "igate.h"
|
||||
#include "symbols.h"
|
||||
#include "dwgps.h"
|
||||
#include "nmea.h"
|
||||
#include "log.h"
|
||||
|
||||
|
||||
//static int idx_decoded = 0;
|
||||
|
||||
#if __WIN32__
|
||||
static BOOL cleanup_win (int);
|
||||
#else
|
||||
|
@ -130,8 +140,10 @@ static void __cpuid(int cpuinfo[4], int infotype){
|
|||
|
||||
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[])
|
||||
|
@ -145,11 +157,18 @@ int main (int argc, char *argv[])
|
|||
struct digi_config_s digi_config;
|
||||
struct tt_config_s tt_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. */
|
||||
char l_opt[80];
|
||||
char input_file[80];
|
||||
|
||||
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__
|
||||
|
@ -195,12 +214,9 @@ int main (int argc, char *argv[])
|
|||
|
||||
text_color_init(t_opt);
|
||||
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) Development version\n", MAJOR_VERSION, MINOR_VERSION, __DATE__);
|
||||
|
||||
// Note "a" for fix with beacon sent to IGate Server.
|
||||
|
||||
dw_printf ("Dire Wolf version %d.%da\n", MAJOR_VERSION, MINOR_VERSION);
|
||||
//dw_printf ("Dire Wolf version %d.%d (%s) Beta Test 1\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);
|
||||
|
||||
|
||||
#if __WIN32__
|
||||
|
@ -272,6 +288,7 @@ int main (int argc, char *argv[])
|
|||
int this_option_optind = optind ? optind : 1;
|
||||
int option_index = 0;
|
||||
int c;
|
||||
char *p;
|
||||
static struct option long_options[] = {
|
||||
{"future1", 1, 0, 0},
|
||||
{"future2", 0, 0, 0},
|
||||
|
@ -281,7 +298,7 @@ int main (int argc, char *argv[])
|
|||
|
||||
/* ':' 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);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
@ -380,13 +397,27 @@ int main (int argc, char *argv[])
|
|||
|
||||
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 '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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 't': /* Was handled earlier. */
|
||||
|
@ -403,6 +434,10 @@ int main (int argc, char *argv[])
|
|||
exit (0);
|
||||
break;
|
||||
|
||||
case 'l': /* -l for log file directory name */
|
||||
|
||||
strncpy (l_opt, optarg, sizeof(l_opt)-1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
|
@ -471,6 +506,10 @@ int main (int argc, char *argv[])
|
|||
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;
|
||||
|
||||
if (strlen(input_file) > 0) {
|
||||
|
@ -521,7 +560,7 @@ int main (int argc, char *argv[])
|
|||
* Initialize the transmit queue.
|
||||
*/
|
||||
|
||||
xmit_init (&modem);
|
||||
xmit_init (&modem, d_p_opt);
|
||||
|
||||
/*
|
||||
* If -x option specified, transmit alternating tones for transmitter
|
||||
|
@ -565,6 +604,11 @@ int main (int argc, char *argv[])
|
|||
*/
|
||||
kiss_init (&misc_config);
|
||||
|
||||
/*
|
||||
* Open port for communication with GPS.
|
||||
*/
|
||||
nmea_init (&misc_config);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
log_init(misc_config.logdir);
|
||||
|
||||
/*
|
||||
* Get sound samples and decode them.
|
||||
* Use hot attribute for all functions called for every audio sample.
|
||||
|
@ -662,6 +708,7 @@ void app_process_rec_packet (int chan, int subchan, packet_t pp, int alevel, ret
|
|||
|
||||
assert (chan >= 0 && chan < MAX_CHANS);
|
||||
assert (subchan >= -1 && subchan < MAX_SUBCHANS);
|
||||
assert (pp != NULL); // 1.1J+
|
||||
|
||||
|
||||
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);
|
||||
dw_printf ("\n");
|
||||
//idx_decoded++;
|
||||
//dw_printf ("DECODED[%d] " , idx_decoded);
|
||||
|
||||
if (h != -1 && h != AX25_SOURCE) {
|
||||
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 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 : */
|
||||
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");
|
||||
|
||||
// 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) {
|
||||
|
||||
|
@ -767,11 +825,43 @@ 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. */
|
||||
|
||||
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. */
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
/* Again, use only those with correct CRC. */
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
ax25_delete (pp);
|
||||
|
||||
} /* end app_process_rec_packet */
|
||||
|
@ -814,6 +910,7 @@ static BOOL cleanup_win (int ctrltype)
|
|||
if (ctrltype == CTRL_C_EVENT || ctrltype == CTRL_CLOSE_EVENT) {
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("\nQRT\n");
|
||||
log_term ();
|
||||
ptt_term ();
|
||||
dwgps_term ();
|
||||
SLEEP_SEC(1);
|
||||
|
@ -829,8 +926,10 @@ static void cleanup_linux (int x)
|
|||
{
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("\nQRT\n");
|
||||
log_term ();
|
||||
ptt_term ();
|
||||
dwgps_term ();
|
||||
SLEEP_SEC(1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
@ -848,6 +947,7 @@ static void usage (char **argv)
|
|||
dw_printf ("Usage: direwolf [options]\n");
|
||||
dw_printf ("Options:\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 (" -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 (" Otherwise, AFSK tones are set to 1200 & 2200.\n");
|
||||
|
||||
dw_printf (" -d Debug communication with client application, one of\n");
|
||||
dw_printf (" a a = AGWPE network protocol.\n");
|
||||
dw_printf (" k k = KISS serial port.\n");
|
||||
dw_printf (" n n = KISS network.\n");
|
||||
dw_printf (" -d Debug options:\n");
|
||||
dw_printf (" a a = AGWPE network protocol client.\n");
|
||||
dw_printf (" k k = KISS serial port client.\n");
|
||||
dw_printf (" n n = KISS network client.\n");
|
||||
dw_printf (" u u = Display non-ASCII text in hexadecimal.\n");
|
||||
dw_printf (" p p = dump Packets in hexadecimal.\n");
|
||||
dw_printf (" t t = gps Tracker.\n");
|
||||
|
||||
dw_printf (" -t n Text colors. 1=normal, 0=disabled.\n");
|
||||
|
||||
|
|
118
direwolf.conf
118
direwolf.conf
|
@ -24,7 +24,7 @@
|
|||
# (3) DIGIPEATER - configure digipeating rules.
|
||||
#
|
||||
# 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
|
||||
# to enable it.
|
||||
#
|
||||
|
@ -115,6 +115,7 @@
|
|||
# ADEVICE - plughw:1,0
|
||||
# ADEVICE UDP:7355 default
|
||||
|
||||
|
||||
#
|
||||
# This is the sound card audio sample rate.
|
||||
# The default is 44100. Other standard values are 22050 or 11025.
|
||||
|
@ -165,6 +166,8 @@ CHANNEL 0
|
|||
|
||||
MYCALL NOCALL
|
||||
|
||||
|
||||
|
||||
#
|
||||
# VHF FM operation normally uses 1200 baud data with AFSK tones of 1200 and 2200 Hz.
|
||||
#
|
||||
|
@ -277,7 +280,7 @@ TXTAIL 10
|
|||
#
|
||||
# Dire Wolf acts as a virtual TNC and can communicate with
|
||||
# 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 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
|
||||
# to recover frames with a bad FCS. Several levels of effort
|
||||
# are possible.
|
||||
# It is sometimes possible to recover frames with a bad FCS.
|
||||
#
|
||||
# 0 [NONE] - Don't try to repair.
|
||||
# 1 [SINGLE] - Attempt to fix single bit error. (default)
|
||||
# 2 [DOUBLE] - Also attempt to fix two adjacent bits.
|
||||
# 3 [TRIPLE] - Also attempt to fix three adjacent bits.
|
||||
# 4 [TWO_SEP] - Also attempt to fix two non-adjacent (separated) bits.
|
||||
# ... see User Guide for more values and in-depth discussion.
|
||||
#
|
||||
|
||||
FIX_BITS 1
|
||||
|
@ -358,10 +358,16 @@ FIX_BITS 1
|
|||
# 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=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"
|
||||
|
||||
# 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
|
||||
# the # comment character from the beginning of the lines above.
|
||||
|
@ -374,97 +380,15 @@ 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
|
||||
# the "#" from the beginning of the line.
|
||||
# To disable digipeating, put # at the beginning of the line.
|
||||
# the "#" from the beginning of the line below.
|
||||
#
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# during 1 minute and 5 minute intervals. If a limit would
|
||||
# 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)
|
||||
# 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
|
||||
|
||||
# Compact messages - Fixed locations xx and object yyy where
|
||||
# Object numbers 100 – 199 = bicycle
|
||||
# Object numbers 200 – 299 = fire truck
|
||||
# Object numbers 100 - 199 = bicycle
|
||||
# Object numbers 200 - 299 = fire truck
|
||||
# Others = dog
|
||||
|
||||
TTMACRO xx1yy B9xx*AB166*AA2B4C5B3B0A1yy
|
||||
|
|
20
direwolf.h
20
direwolf.h
|
@ -29,7 +29,6 @@
|
|||
#define SLEEP_MS(n) usleep((n)*1000)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if __WIN32__
|
||||
#define PTW32_STATIC_LIB
|
||||
|
@ -37,3 +36,22 @@
|
|||
#else
|
||||
#include <pthread.h>
|
||||
#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)
|
||||
{
|
||||
int j;
|
||||
float lp_sum;
|
||||
float G;
|
||||
|
||||
|
||||
#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.
|
||||
*/
|
||||
lp_sum = 0;
|
||||
G = 0;
|
||||
for (j=0; j<filter_size; j++) {
|
||||
lp_sum += lp_filter[j];
|
||||
G += lp_filter[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)
|
||||
{
|
||||
int j;
|
||||
float bp_sum;
|
||||
float w;
|
||||
float G;
|
||||
|
||||
|
||||
#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.
|
||||
* 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++) {
|
||||
bp_sum += bp_filter[j];
|
||||
G += bp_filter[j]; // TBD
|
||||
}
|
||||
for (j=0; j<filter_size; j++) {
|
||||
bp_filter[j] = bp_filter[j] / bp_sum;
|
||||
bp_filter[j] = bp_filter[j] / G;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
100
dwgps.c
100
dwgps.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -108,6 +108,10 @@ int dwgps_init (void)
|
|||
|
||||
#if __WIN32__
|
||||
|
||||
/*
|
||||
* Windows version. Not implemented yet.
|
||||
*/
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPS interface not yet available in Windows version.\n");
|
||||
init_status = INIT_FAILED;
|
||||
|
@ -117,11 +121,39 @@ int dwgps_init (void)
|
|||
|
||||
int err;
|
||||
|
||||
#if USE_GPS_SHM
|
||||
|
||||
/*
|
||||
* Linux - Shared memory interface to gpsd.
|
||||
*
|
||||
* I wanted to use this method because it is simpler and more efficient.
|
||||
*
|
||||
* The current version of gpsd, supplied with Raspian, is 3.6 from back in
|
||||
* May 2012, is missing support for the shared memory interface.
|
||||
* https://github.com/raspberrypi/linux/issues/523
|
||||
*
|
||||
* I tried to download a newer source and build with shared memory support
|
||||
* but ran into a couple other issues.
|
||||
*
|
||||
* sudo apt-get install libncurses5-dev
|
||||
* sudo apt-get install scons
|
||||
* cd ~
|
||||
* wget http://download-mirror.savannah.gnu.org/releases/gpsd/gpsd-3.11.tar.gz
|
||||
* tar xfz gpsd-3.11.tar.gz
|
||||
* cd gpsd-3.11
|
||||
* scons prefix=/usr libdir=lib/arm-linux-gnueabihf shm_export=True python=False
|
||||
* sudo scons udev-install
|
||||
*
|
||||
* For now, we will use the socket interface.
|
||||
* Maybe get back to this again someday.
|
||||
*/
|
||||
|
||||
err = gps_open (GPSD_SHARED_MEMORY, NULL, &gpsdata);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unable to connect to GPS receiver.\n");
|
||||
dw_printf ("Unable to connect to GPSD shared memory interface, status=%d.\n", err);
|
||||
if (err == NL_NOHOST) {
|
||||
// I don't think this is right but we are not using it anyhow.
|
||||
dw_printf ("Shared memory interface is not enabled in libgps.\n");
|
||||
dw_printf ("Download the gpsd source and build with 'shm_export=True' option.\n");
|
||||
}
|
||||
|
@ -133,8 +165,31 @@ int dwgps_init (void)
|
|||
}
|
||||
init_status = INIT_SUCCESS;
|
||||
return (0);
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Linux - Socket interface to gpsd.
|
||||
*/
|
||||
|
||||
err = gps_open ("localhost", DEFAULT_GPSD_PORT, &gpsdata);
|
||||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Unable to connect to GPSD stream, status%d.\n", err);
|
||||
dw_printf ("%s\n", gps_errstr(errno));
|
||||
init_status = INIT_FAILED;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
|
||||
init_status = INIT_SUCCESS;
|
||||
return (0);
|
||||
|
||||
#endif
|
||||
|
||||
#else /* end ENABLE_GPS */
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("GPS interface not enabled in this version.\n");
|
||||
dw_printf ("See documentation on how to rebuild with ENABLE_GPS.\n");
|
||||
|
@ -160,7 +215,7 @@ int dwgps_init (void)
|
|||
* *palt - Altitude, meters.
|
||||
*
|
||||
* Returns: -1 = error
|
||||
* 0 = data not available (no fix)
|
||||
* 0 = location currently not available (no fix)
|
||||
* 2 = 2D fix, lat/lon, speed, and course are set.
|
||||
* 3 - 3D fix, altitude is also set.
|
||||
*
|
||||
|
@ -184,12 +239,42 @@ int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float
|
|||
return (-1);
|
||||
}
|
||||
|
||||
#if USE_GPS_SHM
|
||||
|
||||
/*
|
||||
* Shared memory version.
|
||||
*/
|
||||
|
||||
err = gps_read (&gpsdata);
|
||||
|
||||
#if DEBUG
|
||||
dw_printf ("gps_read returns %d bytes\n", err);
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Socket version.
|
||||
*/
|
||||
|
||||
// Wait for up to 1000 milliseconds.
|
||||
// This should only happen in the beaconing thread so
|
||||
// I'm not worried about other functions hanging.
|
||||
|
||||
if (gps_waiting(&gpsdata, 1000)) {
|
||||
|
||||
err = gps_read (&gpsdata);
|
||||
}
|
||||
else {
|
||||
gps_stream(&gpsdata, WATCH_ENABLE | WATCH_JSON, NULL);
|
||||
sleep (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (err > 0) {
|
||||
/* Data is available. */
|
||||
|
||||
if (gpsdata.status >= STATUS_FIX && gpsdata.fix.mode >= MODE_2D) {
|
||||
|
||||
*plat = gpsdata.fix.latitude;
|
||||
|
@ -208,10 +293,12 @@ int dwgps_read (double *plat, double *plon, float *pspeed, float *pcourse, float
|
|||
return (0);
|
||||
}
|
||||
else if (err == 0) {
|
||||
/* No data available */
|
||||
|
||||
/* No data available at the present time. */
|
||||
return (0);
|
||||
}
|
||||
else {
|
||||
|
||||
/* More serious error. */
|
||||
return (-1);
|
||||
}
|
||||
|
@ -244,6 +331,10 @@ void dwgps_term (void) {
|
|||
#elif ENABLE_GPS
|
||||
|
||||
if (init_status == INIT_SUCCESS) {
|
||||
|
||||
#ifndef USE_GPS_SHM
|
||||
gps_stream(&gpsdata, WATCH_DISABLE, NULL);
|
||||
#endif
|
||||
gps_close (&gpsdata);
|
||||
}
|
||||
#else
|
||||
|
@ -264,6 +355,7 @@ void dwgps_term (void) {
|
|||
* Description: Compile with -DTEST option.
|
||||
*
|
||||
* gcc -DTEST dwgps.c textcolor.c -lgps
|
||||
* ./a.out
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// 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.
|
||||
*
|
||||
* 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.
|
||||
* lon - Longitude.
|
||||
* alt_ft - Altitude in feet.
|
||||
* symtab - Symbol table id or overlay.
|
||||
* symbol - Symbol id.
|
||||
*
|
||||
|
@ -494,7 +497,7 @@ typedef struct aprs_compressed_pos_s {
|
|||
} 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,
|
||||
int power, int height, int gain, char *dir,
|
||||
int course, int speed,
|
||||
|
@ -507,7 +510,7 @@ int encode_position (int compressed, double lat, double lon,
|
|||
if (compressed) {
|
||||
aprs_compressed_pos_t *p = (aprs_compressed_pos_t *)presult;
|
||||
|
||||
p->dti = '!';
|
||||
p->dti = messaging ? '=' : '!';
|
||||
set_comp_position (symtab, symbol, lat, lon,
|
||||
power, height, gain,
|
||||
course, speed,
|
||||
|
@ -517,7 +520,7 @@ int encode_position (int compressed, double lat, double lon,
|
|||
else {
|
||||
aprs_ll_pos_t *p = (aprs_ll_pos_t *)presult;
|
||||
|
||||
p->dti = '!';
|
||||
p->dti = messaging ? '=' : '!';
|
||||
set_norm_position (symtab, symbol, lat, lon, &(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';
|
||||
|
||||
/* 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. */
|
||||
|
||||
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.
|
||||
*
|
||||
* $ 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
|
||||
|
||||
void text_color_set ( enum dw_color_e c )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
|
@ -716,75 +728,86 @@ int main (int argc, char *argv[])
|
|||
|
||||
/*********** 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);
|
||||
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. */
|
||||
|
||||
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);
|
||||
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. */
|
||||
|
||||
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);
|
||||
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! */
|
||||
|
||||
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);
|
||||
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 */
|
||||
|
||||
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);
|
||||
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. ***********/
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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. ***********/
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
int power, int height, int gain, char *dir,
|
||||
int course, int speed,
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
#ifndef FSK_DEMOD_STATE_H
|
||||
|
||||
#include "rpack.h"
|
||||
|
||||
|
||||
/*
|
||||
* Demodulator state.
|
||||
* 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_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
|
||||
|
|
|
@ -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);
|
||||
|
||||
rrbb_set_audio_level (H->rrbb, alevel);
|
||||
rrbb_set_fix_bits (H->rrbb, H->fix_bits);
|
||||
hdlc_rec2_block (H->rrbb, H->fix_bits);
|
||||
/* Now owned by someone else who will free it. */
|
||||
H->rrbb = rrbb_new (chan, subchan, is_scrambled, descram_state); /* Allocate a new one. */
|
||||
|
|
576
hdlc_rec2.c
576
hdlc_rec2.c
|
@ -1,7 +1,6 @@
|
|||
//
|
||||
// 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
|
||||
// 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
|
||||
* 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 <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
//Optimize processing by accessing directly to decoded bits
|
||||
#define RRBB_C 1
|
||||
#include "direwolf.h"
|
||||
#include "hdlc_rec2.h"
|
||||
#include "fcs_calc.h"
|
||||
|
@ -40,6 +59,9 @@
|
|||
#include "rrbb.h"
|
||||
#include "rdq.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_t bits_flipped, int flip_a, int flip_b, int flip_c);
|
||||
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_conf_t retry_conf);
|
||||
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);
|
||||
#if DEBUG
|
||||
#if DEBUG_LATER
|
||||
static double dtime_now (void);
|
||||
#endif
|
||||
|
||||
|
@ -161,8 +183,19 @@ void hdlc_rec2_block (rrbb_t block, retry_t fix_bits)
|
|||
rrbb_set_slice_val (block, 0);
|
||||
|
||||
#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 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.
|
||||
*/
|
||||
|
||||
if (fix_bits < RETRY_TWO_SEP) {
|
||||
if (fix_bits < RETRY_SWAP_TWO_SEP) {
|
||||
rrbb_delete (block);
|
||||
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)
|
||||
{
|
||||
int ok;
|
||||
int len, i;
|
||||
int len, i,j;
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
if (fix_bits < RETRY_SINGLE) {
|
||||
if (fix_bits < RETRY_SWAP_SINGLE) {
|
||||
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++) {
|
||||
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 DEBUG
|
||||
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.
|
||||
*/
|
||||
if (fix_bits < RETRY_DOUBLE) {
|
||||
if (fix_bits < RETRY_SWAP_DOUBLE) {
|
||||
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++) {
|
||||
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 DEBUG
|
||||
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.
|
||||
*/
|
||||
if (fix_bits < RETRY_TRIPLE) {
|
||||
if (fix_bits < RETRY_SWAP_TRIPLE) {
|
||||
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++) {
|
||||
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 DEBUG
|
||||
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;
|
||||
}
|
||||
|
||||
void hdlc_rec2_try_to_fix_later (rrbb_t block, int chan, int subchan, int alevel)
|
||||
{
|
||||
int ok;
|
||||
int len, i;
|
||||
#if DEBUG
|
||||
int len, i, j;
|
||||
retry_t fix_bits;
|
||||
#if DEBUG_LATER
|
||||
double tstart, tend;
|
||||
#endif
|
||||
|
||||
retry_conf_t retry_cfg;
|
||||
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.
|
||||
* 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.
|
||||
*/
|
||||
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();
|
||||
dw_printf ("*** Try flipping 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++) {
|
||||
ok = try_decode (block, chan, subchan, alevel, RETRY_TWO_SEP, i, j, -1);
|
||||
if (ok)
|
||||
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
|
||||
tend = dtime_now();
|
||||
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
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if DEBUGx
|
||||
#if DEBUG_LATER
|
||||
tend = dtime_now();
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("*** No luck flipping TWO SEPARATED bits of %d *** %.3f sec.\n", len, tend-tstart);
|
||||
#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;
|
||||
}
|
||||
/* 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_t bits_flipped, int flip_a, int flip_b, int flip_c)
|
||||
static int try_decode (rrbb_t block, int chan, int subchan, int alevel, retry_conf_t retry_conf)
|
||||
{
|
||||
struct hdlc_state_s H;
|
||||
int blen; /* Block length in bits. */
|
||||
int i;
|
||||
int raw; /* From demodulator. */
|
||||
int dbit; /* Data bit after undoing NRZI. */
|
||||
unsigned int raw; /* From demodulator. */
|
||||
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 */
|
||||
/* 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. */
|
||||
/* If it was corrupted we wouldn't have detected */
|
||||
/* the start of frame. */
|
||||
|
||||
if (0 == flip_a || 0 == flip_b || 0 == flip_c){
|
||||
if (retry_conf.mode == RETRY_MODE_CONTIGUOUS && is_contig_bit_modified(0, retry_conf) ||
|
||||
retry_conf.mode == RETRY_MODE_SEPARATED && is_sep_bit_modified(0, retry_conf)) {
|
||||
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.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
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
if (retry_conf.type == RETRY_TYPE_NONE)
|
||||
dw_printf ("try_decode: blen=%d\n", blen);
|
||||
#endif
|
||||
|
||||
for (i=1; i<blen; i++) {
|
||||
|
||||
raw = rrbb_get_bit (block, i);
|
||||
|
||||
if (i == flip_a || i == flip_b || i == flip_c){
|
||||
/* Get the value for the current bit */
|
||||
raw = get_bit (block, i);
|
||||
/* If swap two sep mode , swap the bit if needed */
|
||||
if (retry_conf_retry == RETRY_SWAP_TWO_SEP) {
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Using NRZI encoding,
|
||||
* A '0' bit is represented by an inversion since previous bit.
|
||||
* A '1' bit is represented by no change.
|
||||
*/
|
||||
|
||||
dbit = (raw == H.prev_raw);
|
||||
H.prev_raw = raw;
|
||||
|
||||
} else {
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("try_decode: found flag, i=%d\n", i);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if (H.pat_det == 0xfe) {
|
||||
/* Valid data will never have 7 one bits in a row. */
|
||||
/*
|
||||
* Using NRZI encoding,
|
||||
* A '0' bit is represented by an inversion since previous bit.
|
||||
* 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) {
|
||||
H.pat_det |= 0x80;
|
||||
/* Valid data will never have 7 one bits in a row: exit. */
|
||||
if (H.pat_det == 0xfe) {
|
||||
#if DEBUGx
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("try_decode: found abort, i=%d\n", i);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else if ( (H.pat_det & 0xfc) == 0x7c ) {
|
||||
H.oacc >>= 1;
|
||||
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
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("try_decode: found flag, i=%d\n", i);
|
||||
#endif
|
||||
return 0;
|
||||
/*
|
||||
* 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
|
||||
* "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.
|
||||
*/
|
||||
|
||||
H.oacc >>= 1;
|
||||
if (dbit) {
|
||||
H.oacc |= 0x80;
|
||||
}
|
||||
H.olen++;
|
||||
|
||||
if (H.olen == 8) {
|
||||
if (H.olen & 8) {
|
||||
H.olen = 0;
|
||||
|
||||
if (H.frame_len < MAX_FRAME_LEN) {
|
||||
H.frame_buf[H.frame_len] = H.oacc;
|
||||
H.frame_len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} /* end of loop on all bits in block */
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
#if DEBUGx
|
||||
if (retry_conf.type == RETRY_TYPE_NONE) {
|
||||
int j;
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
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 ("\n");
|
||||
|
||||
}
|
||||
#endif
|
||||
/* 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);
|
||||
|
||||
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
|
||||
|
@ -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_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 */
|
||||
} 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. */
|
||||
|
||||
} /* 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. */
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
||||
static double dtime_now (void)
|
||||
{
|
||||
|
@ -658,4 +1075,3 @@ static double dtime_now (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
64
hdlc_rec2.h
64
hdlc_rec2.h
|
@ -3,15 +3,59 @@
|
|||
#define HDLC_REC2_H 1
|
||||
|
||||
|
||||
#include "rrbb.h"
|
||||
#include "ax25_pad.h" /* for packet_t */
|
||||
#include "rrbb.h"
|
||||
|
||||
typedef enum retry_e {
|
||||
RETRY_NONE=0,
|
||||
RETRY_SINGLE=1,
|
||||
RETRY_DOUBLE=2,
|
||||
RETRY_TRIPLE=3,
|
||||
RETRY_TWO_SEP=4 } retry_t;
|
||||
RETRY_SWAP_SINGLE=1,
|
||||
RETRY_SWAP_DOUBLE=2,
|
||||
RETRY_SWAP_TRIPLE=3,
|
||||
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)
|
||||
|
||||
|
@ -20,7 +64,15 @@ static const char * retry_text[] = {
|
|||
"SINGLE",
|
||||
"DOUBLE",
|
||||
"TRIPLE",
|
||||
"TWO_SEP" };
|
||||
"REMOVE_SINGLE",
|
||||
"REMOVE_DOUBLE",
|
||||
"REMOVE_TRIPLE",
|
||||
"INSERT_SINGLE",
|
||||
"INSERT_DOUBLE",
|
||||
"TWO_SEP",
|
||||
"MANY",
|
||||
"REMOVE_MANY",
|
||||
"REMOVE_SEP"};
|
||||
#endif
|
||||
|
||||
void hdlc_rec2_block (rrbb_t block, retry_t fix_bits);
|
||||
|
|
201
kiss.c
201
kiss.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -129,8 +129,12 @@
|
|||
#include <termios.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <sys/errno.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <assert.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_slave_fd = MYFDERROR; /* File descriptor for pseudo terminal */
|
||||
/* for use by application. */
|
||||
static char pt_slave_name[32]; /* Pseudo terminal slave name */
|
||||
/* like /dev/pts/999 */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Symlink to pseudo terminal name which changes.
|
||||
*/
|
||||
|
||||
#define DEV_KISS_TNC "/tmp/kisstnc"
|
||||
#define TMP_KISSTNC_SYMLINK "/tmp/kisstnc"
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -186,9 +192,14 @@ static MYFDTYPE nullmodem_fd = MYFDERROR;
|
|||
#endif
|
||||
|
||||
|
||||
// TODO: define in one place, use everywhere.
|
||||
#if __WIN32__
|
||||
#define THREAD_F unsigned __stdcall
|
||||
#else
|
||||
#define THREAD_F void *
|
||||
#endif
|
||||
|
||||
|
||||
static void * kiss_listen_thread (void *arg);
|
||||
static THREAD_F kiss_listen_thread (void *arg);
|
||||
|
||||
|
||||
|
||||
|
@ -262,7 +273,7 @@ void kiss_init (struct misc_config_s *mc)
|
|||
pt_master_fd = kiss_open_pt ();
|
||||
|
||||
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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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 __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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create kiss nullmodem thread\n");
|
||||
return;
|
||||
}
|
||||
#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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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)
|
||||
{
|
||||
int fd;
|
||||
char *slave_device;
|
||||
char *pts;
|
||||
struct termios ts;
|
||||
int e;
|
||||
//int flags;
|
||||
|
@ -357,12 +368,13 @@ static MYFDTYPE kiss_open_pt (void)
|
|||
if (fd == MYFDERROR
|
||||
|| grantpt (fd) == MYFDERROR
|
||||
|| unlockpt (fd) == MYFDERROR
|
||||
|| (slave_device = ptsname (fd)) == NULL) {
|
||||
|| (pts = ptsname (fd)) == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR - Could not create pseudo terminal for KISS TNC.\n");
|
||||
return (MYFDERROR);
|
||||
}
|
||||
|
||||
strcpy (pt_slave_name, pts);
|
||||
|
||||
e = tcgetattr (fd, &ts);
|
||||
if (e != 0) {
|
||||
|
@ -416,9 +428,29 @@ static MYFDTYPE kiss_open_pt (void)
|
|||
}
|
||||
#endif
|
||||
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");
|
||||
|
||||
|
||||
#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.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//TODO: remove symlink on exit.
|
||||
unlink (DEV_KISS_TNC);
|
||||
unlink (TMP_KISSTNC_SYMLINK);
|
||||
|
||||
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 {
|
||||
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 ("");
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -471,7 +493,7 @@ static MYFDTYPE kiss_open_nullmodem (char *devicename)
|
|||
MYFDTYPE fd;
|
||||
DCB dcb;
|
||||
int ok;
|
||||
|
||||
char bettername[50];
|
||||
|
||||
#if 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
|
||||
|
||||
// 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);
|
||||
|
||||
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 */
|
||||
|
||||
// dcb.BaudRate ? shouldn't matter
|
||||
dcb.DCBlength = sizeof(DCB);
|
||||
dcb.BaudRate = CBR_9600; // shouldn't matter
|
||||
dcb.fBinary = 1;
|
||||
dcb.fParity = 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)
|
||||
{
|
||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN];
|
||||
unsigned char kiss_buff[2 * AX25_MAX_PACKET_LEN + 2];
|
||||
int kiss_len;
|
||||
int j;
|
||||
int err;
|
||||
|
@ -637,31 +672,28 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
|||
}
|
||||
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];
|
||||
|
||||
if (fbuf[j] == FEND) {
|
||||
kiss_buff[kiss_len++] = FESC;
|
||||
kiss_buff[kiss_len++] = TFEND;
|
||||
}
|
||||
else if (fbuf[j] == FESC) {
|
||||
kiss_buff[kiss_len++] = FESC;
|
||||
kiss_buff[kiss_len++] = TFESC;
|
||||
}
|
||||
else {
|
||||
kiss_buff[kiss_len++] = fbuf[j];
|
||||
}
|
||||
assert (kiss_len < sizeof (kiss_buff));
|
||||
}
|
||||
kiss_buff[kiss_len++] = FEND;
|
||||
assert (flen < sizeof(stemp));
|
||||
|
||||
/* This has the escapes but not the surrounding FENDs. */
|
||||
stemp[0] = (chan << 4) + 0;
|
||||
memcpy (stemp+1, fbuf, flen);
|
||||
|
||||
if (kiss_debug >= 2) {
|
||||
/* AX.25 frame with the CRC removed. */
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\n");
|
||||
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
||||
hex_dump ((char*)fbuf, flen);
|
||||
}
|
||||
|
||||
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
||||
|
||||
/* This has KISS framing and escapes for sending to client app. */
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (nwritten != flen)
|
||||
else if (nwritten != kiss_len)
|
||||
{
|
||||
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);
|
||||
|
@ -770,22 +802,16 @@ void kiss_send_rec_packet (int chan, unsigned char *fbuf, int flen)
|
|||
*
|
||||
* Purpose: Wait for messages from an application.
|
||||
*
|
||||
* Inputs: arg - File descriptor for reading.
|
||||
*
|
||||
* Outputs: pt_slave_fd - File descriptor for communicating with client app.
|
||||
* Global In: nullmodem_fd or pt_master_fd
|
||||
*
|
||||
* 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. */
|
||||
|
||||
|
||||
static int kiss_get (MYFDTYPE fd)
|
||||
static int kiss_get (/* MYFDTYPE fd*/ void )
|
||||
{
|
||||
unsigned char ch;
|
||||
|
||||
|
@ -808,7 +834,7 @@ static int kiss_get (MYFDTYPE fd)
|
|||
|
||||
while (n == 0) {
|
||||
|
||||
if ( ! ReadFile (fd, &ch, 1, &n, &ov_rd))
|
||||
if ( ! ReadFile (nullmodem_fd, &ch, 1, &n, &ov_rd))
|
||||
{
|
||||
int err1 = GetLastError();
|
||||
|
||||
|
@ -818,7 +844,7 @@ static int kiss_get (MYFDTYPE fd)
|
|||
|
||||
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();
|
||||
|
||||
|
@ -835,8 +861,8 @@ static int kiss_get (MYFDTYPE fd)
|
|||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nKISS ReadFile error %d. Closing connection.\n\n", err1);
|
||||
//CloseHandle (fd);
|
||||
//fd = MYFDERROR;
|
||||
CloseHandle (nullmodem_fd);
|
||||
nullmodem_fd = MYFDERROR;
|
||||
//pthread_exit (NULL);
|
||||
}
|
||||
}
|
||||
|
@ -857,19 +883,33 @@ static int kiss_get (MYFDTYPE fd)
|
|||
|
||||
#else /* Linux/Cygwin version */
|
||||
|
||||
int n;
|
||||
int n = 0;
|
||||
|
||||
n = read(fd, &ch, (size_t)1);
|
||||
while ( n == 0 ) {
|
||||
|
||||
n = read(pt_master_fd, &ch, (size_t)1);
|
||||
|
||||
if (n != 1) {
|
||||
//text_color_set(DW_COLOR_ERROR);
|
||||
//dw_printf ("\nError receiving kiss message from client application. Closing connection %d.\n\n", fd);
|
||||
|
||||
close (fd);
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nError receiving kiss message from client application. Closing %s.\n\n", pt_slave_name);
|
||||
perror ("");
|
||||
|
||||
fd = MYFDERROR;
|
||||
/* 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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
#if DEBUG
|
||||
|
@ -910,14 +948,15 @@ static void * kiss_listen_thread (void *arg)
|
|||
|
||||
|
||||
while (1) {
|
||||
ch = kiss_get(fd);
|
||||
|
||||
if (kiss_frame (&kf, ch, kiss_debug, kiss_send_rec_packet)) {
|
||||
kiss_process_msg (&kf, kiss_debug);
|
||||
ch = kiss_get();
|
||||
kiss_rec_byte (&kf, ch, kiss_debug, kiss_send_rec_packet);
|
||||
}
|
||||
} /* while (1) */
|
||||
|
||||
return (NULL); /* Unreachable but avoids compiler warning. */
|
||||
#if __WIN32__
|
||||
return(0);
|
||||
#else
|
||||
return; /* Unreachable but avoids compiler warning. */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* end kiss.c */
|
||||
|
|
370
kiss_frame.c
370
kiss_frame.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -84,13 +84,181 @@
|
|||
#include "tq.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.
|
||||
* ch - A byte from the input stream.
|
||||
|
@ -100,10 +268,8 @@
|
|||
* Outputs: kf - Current state is updated.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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) {
|
||||
|
||||
case KS_SEARCHING: /* Searching for starting FEND. */
|
||||
default:
|
||||
|
||||
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_msg[kf->kiss_len++] = ch;
|
||||
kf->state = KS_COLLECTING;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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';
|
||||
}
|
||||
|
||||
/* 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 ||
|
||||
strcasecmp("reset\r", (char*)(kf->noise)) == 0) {
|
||||
(*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;
|
||||
}
|
||||
return 0;
|
||||
return;
|
||||
break;
|
||||
|
||||
case KS_COLLECTING: /* Frame collection in progress. */
|
||||
|
||||
|
||||
if (ch == FEND) {
|
||||
|
||||
unsigned char unwrapped[AX25_MAX_PACKET_LEN];
|
||||
int ulen;
|
||||
|
||||
/* End of frame. */
|
||||
|
||||
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. */
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
kf->kiss_msg[kf->kiss_len++] = ch;
|
||||
if (debug) {
|
||||
/* As received over the wire from client app. */
|
||||
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;
|
||||
return 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (kf->kiss_len < MAX_KISS_LEN) {
|
||||
|
@ -202,35 +402,15 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
|||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("KISS message exceeded maximum length.\n");
|
||||
}
|
||||
return 0;
|
||||
|
||||
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;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
return; /* unreachable but suppress compiler warning. */
|
||||
|
||||
kf->state = KS_COLLECTING;
|
||||
return 0;
|
||||
}
|
||||
} /* end kiss_rec_byte */
|
||||
|
||||
return 0; /* unreachable but suppress compiler warning. */
|
||||
|
||||
} /* end kiss_frame */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
|
@ -239,21 +419,23 @@ int kiss_frame (kiss_frame_t *kf, unsigned char ch, int debug, void (*sendfun)(i
|
|||
*
|
||||
* Purpose: Process a message from the KISS client.
|
||||
*
|
||||
* Inputs: kf - Current state of building a frame.
|
||||
* Should be complete.
|
||||
* Inputs: kiss_msg - Kiss frame with FEND and escapes removed.
|
||||
* The first byte contains channel and command.
|
||||
*
|
||||
* kiss_len - Number of bytes including the command.
|
||||
*
|
||||
* 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 cmd;
|
||||
packet_t pp;
|
||||
|
||||
port = (kf->kiss_msg[0] >> 4) & 0xf;
|
||||
cmd = kf->kiss_msg[0] & 0xf;
|
||||
port = (kiss_msg[0] >> 4) & 0xf;
|
||||
cmd = kiss_msg[0] & 0xf;
|
||||
|
||||
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. */
|
||||
|
||||
if ((port == 2 || port == 8) &&
|
||||
kf->kiss_msg[1] == 'Q' << 1 &&
|
||||
kf->kiss_msg[2] == 'S' << 1 &&
|
||||
kf->kiss_msg[3] == 'T' << 1 &&
|
||||
kf->kiss_msg[4] == ' ' << 1 &&
|
||||
kf->kiss_msg[15] == 3 &&
|
||||
kf->kiss_msg[16] == 0xcd) {
|
||||
kiss_msg[1] == 'Q' << 1 &&
|
||||
kiss_msg[2] == 'S' << 1 &&
|
||||
kiss_msg[3] == 'T' << 1 &&
|
||||
kiss_msg[4] == ' ' << 1 &&
|
||||
kiss_msg[15] == 3 &&
|
||||
kiss_msg[16] == 0xcd) {
|
||||
|
||||
if (debug) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
|
@ -276,7 +458,16 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
|||
return;
|
||||
}
|
||||
|
||||
pp = ax25_from_frame (kf->kiss_msg+1, kf->kiss_len-1, -1);
|
||||
// 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 (kiss_msg+1, kiss_len-1, -1);
|
||||
if (pp == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("ERROR - Invalid KISS data frame from client app.\n");
|
||||
|
@ -302,35 +493,35 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
|||
case 1: /* TXDELAY */
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("KISS protocol set TXDELAY = %d, port %d\n", kf->kiss_msg[1], port);
|
||||
xmit_set_txdelay (port, kf->kiss_msg[1]);
|
||||
dw_printf ("KISS protocol set TXDELAY = %d, port %d\n", kiss_msg[1], port);
|
||||
xmit_set_txdelay (port, kiss_msg[1]);
|
||||
break;
|
||||
|
||||
case 2: /* Persistence */
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("KISS protocol set Persistence = %d, port %d\n", kf->kiss_msg[1], port);
|
||||
xmit_set_persist (port, kf->kiss_msg[1]);
|
||||
dw_printf ("KISS protocol set Persistence = %d, port %d\n", kiss_msg[1], port);
|
||||
xmit_set_persist (port, kiss_msg[1]);
|
||||
break;
|
||||
|
||||
case 3: /* SlotTime */
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("KISS protocol set SlotTime = %d, port %d\n", kf->kiss_msg[1], port);
|
||||
xmit_set_slottime (port, kf->kiss_msg[1]);
|
||||
dw_printf ("KISS protocol set SlotTime = %d, port %d\n", kiss_msg[1], port);
|
||||
xmit_set_slottime (port, kiss_msg[1]);
|
||||
break;
|
||||
|
||||
case 4: /* TXtail */
|
||||
|
||||
text_color_set(DW_COLOR_INFO);
|
||||
dw_printf ("KISS protocol set TXtail = %d, port %d\n", kf->kiss_msg[1], port);
|
||||
xmit_set_txtail (port, kf->kiss_msg[1]);
|
||||
dw_printf ("KISS protocol set TXtail = %d, port %d\n", kiss_msg[1], port);
|
||||
xmit_set_txtail (port, kiss_msg[1]);
|
||||
break;
|
||||
|
||||
case 5: /* FullDuplex */
|
||||
|
||||
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;
|
||||
|
||||
case 6: /* TNC specific */
|
||||
|
@ -348,7 +539,7 @@ void kiss_process_msg (kiss_frame_t *kf, int debug)
|
|||
default:
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
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");
|
||||
|
||||
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",
|
||||
prefix[(int)fromto], function[pmsg[0] & 0xf], direction[(int)fromto],
|
||||
(pmsg[0] >> 4) & 0xf, msg_len);
|
||||
prefix[(int)fromto], function[p[0] & 0xf], direction[(int)fromto],
|
||||
(p[0] >> 4) & 0xf, msg_len);
|
||||
}
|
||||
else {
|
||||
dw_printf ("%s %s %s KISS client application, total length = %d\n",
|
||||
prefix[(int)fromto], special, direction[(int)fromto],
|
||||
msg_len);
|
||||
}
|
||||
hex_dump ((char*)pmsg, msg_len);
|
||||
hex_dump (pmsg, msg_len);
|
||||
|
||||
} /* 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 */
|
||||
|
|
14
kiss_frame.h
14
kiss_frame.h
|
@ -12,13 +12,14 @@
|
|||
#define TFESC 0xDD
|
||||
|
||||
|
||||
|
||||
enum kiss_state_e {
|
||||
KS_SEARCHING, /* Looking for FEND to start KISS frame. */
|
||||
KS_COLLECTING, /* In process of collecting KISS frame. */
|
||||
KS_ESCAPE }; /* FESC found in frame. */
|
||||
KS_COLLECTING}; /* In process of collecting KISS frame. */
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
@ -27,6 +28,8 @@ typedef struct kiss_frame_s {
|
|||
enum kiss_state_e state;
|
||||
|
||||
unsigned char kiss_msg[MAX_KISS_LEN];
|
||||
/* Leading FEND is optional. */
|
||||
/* Contains escapes and ending FEND. */
|
||||
int kiss_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;
|
||||
|
||||
|
|
45
kissnet.c
45
kissnet.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// 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. */
|
||||
// TODO: multiple instances if multiple KISS network clients!
|
||||
|
||||
|
||||
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 {
|
||||
|
||||
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];
|
||||
|
||||
if (fbuf[j] == FEND) {
|
||||
kiss_buff[kiss_len++] = FESC;
|
||||
kiss_buff[kiss_len++] = TFEND;
|
||||
}
|
||||
else if (fbuf[j] == FESC) {
|
||||
kiss_buff[kiss_len++] = FESC;
|
||||
kiss_buff[kiss_len++] = TFESC;
|
||||
}
|
||||
else {
|
||||
kiss_buff[kiss_len++] = fbuf[j];
|
||||
}
|
||||
assert (kiss_len < sizeof (kiss_buff));
|
||||
}
|
||||
kiss_buff[kiss_len++] = FEND;
|
||||
assert (flen < sizeof(stemp));
|
||||
|
||||
/* Bug: This has the escapes but not the surrounding FENDs. */
|
||||
stemp[0] = (chan << 4) + 0;
|
||||
memcpy (stemp+1, fbuf, flen);
|
||||
|
||||
if (kiss_debug >= 2) {
|
||||
/* AX.25 frame with the CRC removed. */
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\n");
|
||||
dw_printf ("Packet content before adding KISS framing and any escapes:\n");
|
||||
hex_dump ((char*)fbuf, flen);
|
||||
}
|
||||
|
||||
kiss_len = kiss_encapsulate (stemp, flen+1, kiss_buff);
|
||||
|
||||
/* This has the escapes and the surrounding FENDs. */
|
||||
|
||||
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) {
|
||||
ch = kiss_get();
|
||||
|
||||
if (kiss_frame (&kf, ch, kiss_debug, kissnet_send_rec_packet)) {
|
||||
kiss_process_msg (&kf, kiss_debug);
|
||||
kiss_rec_byte (&kf, ch, kiss_debug, kissnet_send_rec_packet);
|
||||
}
|
||||
} /* while (1) */
|
||||
|
||||
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.
|
||||
//
|
||||
// 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
|
||||
// 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[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 longitude_to_str (double dlong, int ambiguity, char *slong);
|
||||
|
||||
void latitude_to_comp_str (double dlat, char *clat);
|
||||
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.
|
||||
For the Windows version we need to include our own copy.
|
||||
|
||||
|
|
134
multi_modem.c
134
multi_modem.c
|
@ -60,8 +60,18 @@
|
|||
* part is picking the best one when there is more than one
|
||||
* 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
|
||||
|
||||
|
||||
|
@ -97,8 +107,14 @@ static struct {
|
|||
int score;
|
||||
|
||||
} 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
|
||||
|
||||
|
@ -139,12 +155,99 @@ void multi_modem_init (struct audio_s *pmodem)
|
|||
|
||||
for (chan=0; chan<modem.num_channels; 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;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
if (retries == RETRY_TWO_SEP) {
|
||||
if (retries >= RETRY_SWAP_TWO_SEP) {
|
||||
int mycrc;
|
||||
char spectrum[MAX_SUBCHANS+1];
|
||||
int dropped = 0;
|
||||
|
||||
memset (spectrum, 0, sizeof(spectrum));
|
||||
memset (spectrum, '_', (size_t)modem.num_subchan[chan]);
|
||||
spectrum[subchan] = '.';
|
||||
|
||||
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
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("\n%s\n%d.%d: ptr=%p, retry=%d, age=, crc=%04x, score= \n",
|
||||
spectrum, chan, subchan, pp, (int)retries, mycrc);
|
||||
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,dropped);
|
||||
#endif
|
||||
if (mycrc == crc_of_last_to_app[chan]) {
|
||||
if (dropped) {
|
||||
/* Same as last one. Drop it. */
|
||||
ax25_delete (pp);
|
||||
#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");
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -397,7 +507,7 @@ static void pick_best_candidate (int chan)
|
|||
else if (candidate[chan][subchan].retries == RETRY_NONE) {
|
||||
spectrum[subchan] = '|';
|
||||
}
|
||||
else if (candidate[chan][subchan].retries == RETRY_SINGLE) {
|
||||
else if (candidate[chan][subchan].retries == RETRY_SWAP_SINGLE) {
|
||||
spectrum[subchan] = ':';
|
||||
}
|
||||
else {
|
||||
|
@ -406,7 +516,7 @@ static void pick_best_candidate (int chan)
|
|||
|
||||
/* 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. */
|
||||
|
||||
|
@ -461,8 +571,8 @@ static void pick_best_candidate (int chan)
|
|||
candidate[chan][best_subchan].alevel,
|
||||
(int)(candidate[chan][best_subchan].retries),
|
||||
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. */
|
||||
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.
|
||||
//
|
||||
// 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
|
||||
// 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 1.1: Add parallel printer port for x86 Linux only.
|
||||
*
|
||||
* References: http://www.robbayer.com/files/serial-win.pdf
|
||||
*
|
||||
* https://www.kernel.org/doc/Documentation/gpio.txt
|
||||
|
@ -86,6 +88,14 @@ typedef int HANDLE;
|
|||
|
||||
#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_SERIAL - serial (com) port. */
|
||||
/* 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. */
|
||||
/* 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. */
|
||||
/* 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. */
|
||||
/* 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]);
|
||||
ptt_line[ch] = p_modem->ptt_line[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_fd[ch] = INVALID_HANDLE_VALUE;
|
||||
#if 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,
|
||||
ptt_method[ch],
|
||||
ptt_device[ch],
|
||||
ptt_line[ch],
|
||||
ptt_gpio[ch],
|
||||
ptt_lpt_bit[ch],
|
||||
ptt_invert[ch]);
|
||||
#endif
|
||||
}
|
||||
|
@ -205,8 +222,20 @@ void ptt_init (struct audio_s *p_modem)
|
|||
}
|
||||
else {
|
||||
#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);
|
||||
#else
|
||||
|
||||
|
@ -295,9 +324,10 @@ void ptt_init (struct audio_s *p_modem)
|
|||
*/
|
||||
if (geteuid() != 0) {
|
||||
if ( ! (finfo.st_mode & S_IWOTH)) {
|
||||
int err;
|
||||
|
||||
/* 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) {
|
||||
/* 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) {
|
||||
char stemp[80];
|
||||
struct stat finfo;
|
||||
int err;
|
||||
|
||||
fd = open("/sys/class/gpio/export", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
|
@ -355,9 +386,9 @@ void ptt_init (struct audio_s *p_modem)
|
|||
* We only care about "direction" and "value".
|
||||
*/
|
||||
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]);
|
||||
system (stemp);
|
||||
err = system (stemp);
|
||||
|
||||
sprintf (stemp, "/sys/class/gpio/gpio%d/value", ptt_gpio[ch]);
|
||||
|
||||
|
@ -414,12 +445,75 @@ void ptt_init (struct audio_s *p_modem)
|
|||
#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. */
|
||||
|
||||
for (ch=0; ch<ptt_num_channels; ch++) {
|
||||
if(ptt_method[ch] == PTT_METHOD_NONE) {
|
||||
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 */
|
||||
|
@ -523,6 +617,44 @@ void ptt_set (int chan, int ptt)
|
|||
}
|
||||
#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 */
|
||||
|
||||
|
@ -546,6 +678,9 @@ void ptt_term (void)
|
|||
|
||||
for (n = 0; n < ptt_num_channels; n++) {
|
||||
ptt_set (n, 0);
|
||||
}
|
||||
|
||||
for (n = 0; n < ptt_num_channels; n++) {
|
||||
if (ptt_fd[n] != INVALID_HANDLE_VALUE) {
|
||||
#if __WIN32__
|
||||
CloseHandle (ptt_fd[n]);
|
||||
|
@ -572,6 +707,8 @@ void ptt_term (void)
|
|||
|
||||
void text_color_set (dw_color_t c) { }
|
||||
|
||||
#define dw_printf printf
|
||||
|
||||
main ()
|
||||
{
|
||||
struct audio_s modem;
|
||||
|
@ -656,8 +793,7 @@ main ()
|
|||
|
||||
/* Test GPIO */
|
||||
|
||||
#if __WIN32__
|
||||
#else
|
||||
#if __arm__
|
||||
|
||||
memset (&modem, 0, sizeof(modem));
|
||||
modem.num_channels = 1;
|
||||
|
@ -680,6 +816,35 @@ main ()
|
|||
ptt_term ();
|
||||
#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
|
||||
|
|
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__
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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__
|
||||
LeaveCriticalSection (&rdq_cs);
|
||||
|
@ -374,7 +379,7 @@ void rdq_wait_while_empty (void)
|
|||
|
||||
#if 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
|
||||
|
||||
}
|
||||
|
@ -418,7 +423,10 @@ rrbb_t rdq_remove (void)
|
|||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
rdq_len--;
|
||||
#if DEBUG
|
||||
dw_printf ("-rdq_len: %d\n", rdq_len);
|
||||
#endif
|
||||
if (queue_head == 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 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
|
||||
int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
||||
{
|
||||
unsigned int di, mi;
|
||||
|
||||
assert (b != NULL);
|
||||
assert (b->magic1 == MAGIC1);
|
||||
assert (b->magic2 == MAGIC2);
|
||||
|
||||
assert (ind < b->len);
|
||||
|
||||
di = ind / SOI;
|
||||
mi = ind % SOI;
|
||||
|
||||
if (b->data[di] & masks[mi]) {
|
||||
if (b->data[ind / SOI] & masks[ind % SOI]) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
@ -393,6 +388,30 @@ int rrbb_get_bit (rrbb_t b, unsigned int ind)
|
|||
}
|
||||
}
|
||||
#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
|
||||
|
|
9
rrbb.h
9
rrbb.h
|
@ -37,6 +37,9 @@ typedef struct rrbb_s {
|
|||
int subchan; /* Which modem when more than one per channel. */
|
||||
int audio_level; /* Received audio level at time of frame capture. */
|
||||
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 descram_state; /* Descrambler state before first data bit of frame. */
|
||||
|
@ -46,6 +49,7 @@ typedef struct rrbb_s {
|
|||
slice_t data[MAX_NUM_BITS];
|
||||
#else
|
||||
unsigned int data[(MAX_NUM_BITS+SOI-1)/SOI];
|
||||
unsigned int computed_data[MAX_NUM_BITS];
|
||||
#endif
|
||||
int magic2;
|
||||
} *rrbb_t;
|
||||
|
@ -79,6 +83,8 @@ void rrbb_set_slice_val (rrbb_t b, slice_t slice_val);
|
|||
#endif
|
||||
|
||||
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);
|
||||
|
||||
|
@ -99,4 +105,7 @@ int rrbb_get_is_scrambled (rrbb_t b);
|
|||
|
||||
int rrbb_get_descram_state (rrbb_t b);
|
||||
|
||||
int rrbb_get_fix_bits(rrbb_t b);
|
||||
void rrbb_set_fix_bits(rrbb_t b, int fix_bits);
|
||||
|
||||
#endif
|
362
server.c
362
server.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -85,6 +85,12 @@
|
|||
* Getting Started with Winsock
|
||||
* 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"
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
static int client_sock[MAX_NET_CLIENTS];
|
||||
/* 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; /* Should we send received packets to client app? */
|
||||
static int enable_send_monitor_to_client;
|
||||
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 void * connect_listen_thread (void *arg);
|
||||
static void * cmd_listen_thread (void *arg);
|
||||
// TODO: define in one place, use everywhere.
|
||||
#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.
|
||||
|
@ -169,12 +196,13 @@ struct agwpe_s {
|
|||
* Purpose: Print message to/from client for debugging.
|
||||
*
|
||||
* Inputs: fromto - Direction of message.
|
||||
* client - client number, 0 .. MAX_NET_CLIENTS-1
|
||||
* pmsg - Address of the message block.
|
||||
* 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)
|
||||
{
|
||||
|
@ -208,7 +236,7 @@ void hex_dump (unsigned char *p, int len)
|
|||
|
||||
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 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);
|
||||
dw_printf ("\n");
|
||||
|
||||
dw_printf ("%s %s %s AGWPE client application, total length = %d\n",
|
||||
prefix[(int)fromto], datakind, direction, msg_len);
|
||||
dw_printf ("%s %s %s AGWPE client application %d, total length = %d\n",
|
||||
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 ("\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 ("\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) {
|
||||
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:
|
||||
*
|
||||
* Description: This starts two threads:
|
||||
* * to listen for a connection from client app.
|
||||
* * to listen for commands from client app.
|
||||
* Description: This starts at least two threads:
|
||||
* * one to listen for a connection 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.
|
||||
*
|
||||
*--------------------------------------------------------------------*/
|
||||
|
@ -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)
|
||||
{
|
||||
int client;
|
||||
|
||||
#if __WIN32__
|
||||
HANDLE connect_listen_th;
|
||||
HANDLE cmd_listen_th;
|
||||
HANDLE cmd_listen_th[MAX_NET_CLIENTS];
|
||||
#else
|
||||
pthread_t connect_listen_tid;
|
||||
pthread_t cmd_listen_tid;
|
||||
pthread_t cmd_listen_tid[MAX_NET_CLIENTS];
|
||||
#endif
|
||||
int e;
|
||||
int server_port = mc->agwpe_port;
|
||||
int server_port = mc->agwpe_port; /* Usually 8000 but can be changed. */
|
||||
|
||||
|
||||
#if DEBUG
|
||||
|
@ -329,16 +359,18 @@ void server_init (struct misc_config_s *mc)
|
|||
dw_printf ("server_init ( %d )\n", server_port);
|
||||
debug_a = 1;
|
||||
#endif
|
||||
client_sock = -1;
|
||||
enable_send_raw_to_client = 0;
|
||||
enable_send_monitor_to_client = 0;
|
||||
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||
client_sock[client] = -1;
|
||||
enable_send_raw_to_client[client] = 0;
|
||||
enable_send_monitor_to_client[client] = 0;
|
||||
}
|
||||
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__
|
||||
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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create AGW connect listening thread\n");
|
||||
|
@ -354,23 +386,28 @@ void server_init (struct misc_config_s *mc)
|
|||
#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__
|
||||
cmd_listen_th = _beginthreadex (NULL, 0, cmd_listen_thread, NULL, 0, NULL);
|
||||
if (cmd_listen_th == NULL) {
|
||||
cmd_listen_th[client] = (HANDLE)_beginthreadex (NULL, 0, cmd_listen_thread, (void*)client, 0, NULL);
|
||||
if (cmd_listen_th[client] == NULL) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("Could not create AGW command listening thread\n");
|
||||
return;
|
||||
}
|
||||
#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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
perror("Could not create AGW command listening thread");
|
||||
return;
|
||||
}
|
||||
#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__
|
||||
|
||||
|
@ -414,7 +451,7 @@ static void * connect_listen_thread (void *arg)
|
|||
if (err != 0) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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) {
|
||||
|
@ -472,13 +509,22 @@ static void * connect_listen_thread (void *arg)
|
|||
|
||||
while (1) {
|
||||
|
||||
while (client_sock > 0) {
|
||||
SLEEP_SEC(1); /* Already connected. Try again later. */
|
||||
int client;
|
||||
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);
|
||||
dw_printf("Listen failed with error: %d\n", WSAGetLastError());
|
||||
|
@ -486,11 +532,11 @@ static void * connect_listen_thread (void *arg)
|
|||
}
|
||||
|
||||
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);
|
||||
dw_printf("Accept failed with error: %d\n", WSAGetLastError());
|
||||
closesocket(listen_sock);
|
||||
|
@ -499,18 +545,22 @@ static void * connect_listen_thread (void *arg)
|
|||
}
|
||||
|
||||
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.
|
||||
* Make sure it has proper state when we get a new connection.
|
||||
*/
|
||||
enable_send_raw_to_client = 0;
|
||||
enable_send_monitor_to_client = 0;
|
||||
|
||||
enable_send_raw_to_client[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 */
|
||||
socklen_t sockaddr_size = sizeof(struct sockaddr_in);
|
||||
|
@ -548,13 +598,19 @@ static void * connect_listen_thread (void *arg)
|
|||
|
||||
while (1) {
|
||||
|
||||
while (client_sock > 0) {
|
||||
SLEEP_SEC(1); /* Already connected. Try again later. */
|
||||
int client;
|
||||
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);
|
||||
perror ("connect_listen_thread: Listen failed");
|
||||
|
@ -562,20 +618,23 @@ static void * connect_listen_thread (void *arg)
|
|||
}
|
||||
|
||||
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);
|
||||
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.
|
||||
* Make sure it has proper state when we get a new connection.
|
||||
*/
|
||||
enable_send_raw_to_client = 0;
|
||||
enable_send_monitor_to_client = 0;
|
||||
|
||||
enable_send_raw_to_client[client] = 0;
|
||||
enable_send_monitor_to_client[client] = 0;
|
||||
}
|
||||
else {
|
||||
SLEEP_SEC(1); /* wait then check again if more clients allowed. */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -616,13 +675,15 @@ void server_send_rec_packet (int chan, packet_t pp, unsigned char *fbuf, int fl
|
|||
int err;
|
||||
int info_len;
|
||||
unsigned char *pinfo;
|
||||
int client;
|
||||
|
||||
|
||||
/*
|
||||
* 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));
|
||||
|
||||
|
@ -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);
|
||||
|
||||
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__
|
||||
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)
|
||||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nError %d sending message to AGW client application. Closing connection.\n\n", WSAGetLastError());
|
||||
closesocket (client_sock);
|
||||
client_sock = -1;
|
||||
closesocket (client_sock[client]);
|
||||
client_sock[client] = -1;
|
||||
WSACleanup();
|
||||
}
|
||||
#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)
|
||||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nError sending message to AGW client application. Closing connection.\n\n");
|
||||
close (client_sock);
|
||||
client_sock = -1;
|
||||
close (client_sock[client]);
|
||||
client_sock[client] = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* MONITOR format - only for UI frames. */
|
||||
|
||||
for (client=0; client<MAX_NET_CLIENTS; client++) {
|
||||
|
||||
if (enable_send_monitor_to_client
|
||||
&& client_sock > 0
|
||||
if (enable_send_monitor_to_client[client] && client_sock[client] > 0
|
||||
&& ax25_get_control(pp) == AX25_UI_FRAME){
|
||||
|
||||
time_t clock;
|
||||
|
@ -710,30 +772,31 @@ 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 */ ;
|
||||
|
||||
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__
|
||||
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)
|
||||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nError %d sending message to AGW client application. Closing connection.\n\n", WSAGetLastError());
|
||||
closesocket (client_sock);
|
||||
client_sock = -1;
|
||||
dw_printf ("\nError %d sending message to AGW client application %d. Closing connection.\n\n", WSAGetLastError(), client);
|
||||
closesocket (client_sock[client]);
|
||||
client_sock[client] = -1;
|
||||
WSACleanup();
|
||||
}
|
||||
#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)
|
||||
{
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("\nError sending message to AGW client application. Closing connection.\n\n");
|
||||
close (client_sock);
|
||||
client_sock = -1;
|
||||
dw_printf ("\nError sending message to AGW client application %d. Closing connection.\n\n", client);
|
||||
close (client_sock[client]);
|
||||
client_sock[client] = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} /* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
|
||||
struct {
|
||||
struct agwpe_s hdr; /* Command header. */
|
||||
|
||||
|
@ -822,44 +884,85 @@ static void * cmd_listen_thread (void *arg)
|
|||
/* Maximum for 'V': 1 + 8*10 + 256 */
|
||||
} cmd;
|
||||
|
||||
int client = (int) arg;
|
||||
|
||||
assert (client >= 0 && client < MAX_NET_CLIENTS);
|
||||
|
||||
while (1) {
|
||||
|
||||
while (client_sock <= 0) {
|
||||
while (client_sock[client] <= 0) {
|
||||
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)) {
|
||||
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 ("Closing connection.\n\n");
|
||||
#if __WIN32__
|
||||
closesocket (client_sock);
|
||||
closesocket (client_sock[client]);
|
||||
#else
|
||||
close (client_sock);
|
||||
close (client_sock[client]);
|
||||
#endif
|
||||
client_sock = -1;
|
||||
client_sock[client] = -1;
|
||||
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';
|
||||
|
||||
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) {
|
||||
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 ("Closing connection.\n\n");
|
||||
#if __WIN32__
|
||||
closesocket (client_sock);
|
||||
closesocket (client_sock[client]);
|
||||
#else
|
||||
close (client_sock);
|
||||
close (client_sock[client]);
|
||||
#endif
|
||||
client_sock = -1;
|
||||
client_sock[client] = -1;
|
||||
return NULL;
|
||||
}
|
||||
if (n > 0) {
|
||||
|
@ -872,7 +975,7 @@ static void * cmd_listen_thread (void *arg)
|
|||
*/
|
||||
|
||||
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) {
|
||||
|
@ -901,15 +1004,15 @@ static void * cmd_listen_thread (void *arg)
|
|||
assert (sizeof(reply) == 44);
|
||||
|
||||
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.
|
||||
|
||||
#if __WIN32__
|
||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
||||
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||
#else
|
||||
write (client_sock, &reply, sizeof(reply));
|
||||
n = write (client_sock[client], &reply, sizeof(reply));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -940,13 +1043,13 @@ static void * cmd_listen_thread (void *arg)
|
|||
assert (reply.hdr.data_len == 100);
|
||||
|
||||
if (debug_client) {
|
||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply));
|
||||
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply));
|
||||
}
|
||||
|
||||
#if __WIN32__
|
||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
||||
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||
#else
|
||||
write (client_sock, &reply, sizeof(reply));
|
||||
n = write (client_sock[client], &reply, sizeof(reply));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -991,13 +1094,13 @@ static void * cmd_listen_thread (void *arg)
|
|||
assert (sizeof(reply) == 48);
|
||||
|
||||
if (debug_client) {
|
||||
debug_print (TO_CLIENT, &reply.hdr, sizeof(reply));
|
||||
debug_print (TO_CLIENT, client, &reply.hdr, sizeof(reply));
|
||||
}
|
||||
|
||||
#if __WIN32__
|
||||
send (client_sock, (char*)(&reply), sizeof(reply), 0);
|
||||
send (client_sock[client], (char*)(&reply), sizeof(reply), 0);
|
||||
#else
|
||||
write (client_sock, &reply, sizeof(reply));
|
||||
n = write (client_sock[client], &reply, sizeof(reply));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -1027,13 +1130,13 @@ static void * cmd_listen_thread (void *arg)
|
|||
reply.hdr.data_len = strlen(reply.info);
|
||||
|
||||
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__
|
||||
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
|
||||
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
|
||||
|
@ -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.
|
||||
|
||||
enable_send_raw_to_client = ! enable_send_raw_to_client;
|
||||
enable_send_raw_to_client[client] = ! enable_send_raw_to_client[client];
|
||||
break;
|
||||
|
||||
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.
|
||||
|
||||
enable_send_monitor_to_client = ! enable_send_monitor_to_client;
|
||||
enable_send_monitor_to_client[client] = ! enable_send_monitor_to_client[client];
|
||||
break;
|
||||
|
||||
|
||||
|
@ -1074,6 +1177,8 @@ static void * cmd_listen_thread (void *arg)
|
|||
//unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
||||
//int flen;
|
||||
|
||||
// We have already assured these do not exceed 9 characters.
|
||||
|
||||
strcpy (stemp, cmd.hdr.call_from);
|
||||
strcat (stemp, ">");
|
||||
strcat (stemp, cmd.hdr.call_to);
|
||||
|
@ -1126,10 +1231,22 @@ static void * cmd_listen_thread (void *arg)
|
|||
// data which is raw ax.25 frame.
|
||||
//
|
||||
|
||||
|
||||
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) {
|
||||
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.
|
||||
|
||||
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__
|
||||
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
|
||||
write (client_sock, &reply, sizeof(reply.hdr) + sizeof(reply.data));
|
||||
n = write (client_sock[client], &reply, sizeof(reply.hdr) + sizeof(reply.data));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
@ -1201,7 +1318,7 @@ static void * cmd_listen_thread (void *arg)
|
|||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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");
|
||||
|
||||
break;
|
||||
|
@ -1211,9 +1328,10 @@ static void * cmd_listen_thread (void *arg)
|
|||
|
||||
Not sure what we might want to do here.
|
||||
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
|
||||
kind_lo = 77 = 'M', kind_hi = 0
|
||||
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
|
||||
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
|
||||
kind_lo = 77 = 'M', kind_hi = 0
|
||||
call_from = "SV2AGW-1", call_to = "QRA"
|
||||
data_len = 1, user_reserved = 32218432, data =
|
||||
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;
|
||||
|
||||
#endif
|
||||
default:
|
||||
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
dw_printf ("--- Unexpected Command from application using AGW protocol:\n");
|
||||
debug_print (FROM_CLIENT, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
||||
dw_printf ("--- Unexpected Command from application %d using AGW protocol:\n", client);
|
||||
debug_print (FROM_CLIENT, client, &cmd.hdr, sizeof(cmd.hdr) + cmd.hdr.data_len);
|
||||
|
||||
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)
|
||||
|
@ -13,6 +13,7 @@ CORRECT one.
|
|||
|
||||
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
|
||||
19 May 14 Added Submarine&torpedo to ships and lots of Aircraft
|
||||
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
|
||||
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
|
||||
/^ = LARGE Aircraft
|
||||
\^ = 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)
|
||||
J^ = JET (new may 2014)
|
||||
M^ = Missle (new may 2014)
|
||||
P^ = Prop (new Aug 2014)
|
||||
V^ = Vertical takeoff (new may 2014)
|
||||
X^ = Experimental (new Aug 2014)
|
||||
|
||||
ATM Machine or CURRENCY: #$
|
||||
/$ = original primary Phone
|
||||
|
@ -130,12 +138,31 @@ U$ = US dollars
|
|||
L$ = Brittish Pound
|
||||
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: #%
|
||||
/% = DX cluster <= the original primary table definition
|
||||
C% = Coal
|
||||
E% = Emergency (new Aug 2014)
|
||||
G% = Geothermal
|
||||
H% = Hydroelectric
|
||||
N% = Nuclear
|
||||
P% = Portable (new Aug 2014)
|
||||
S% = Solar
|
||||
T% = Turbine
|
||||
W% = Wind
|
||||
|
@ -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)
|
||||
|
||||
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
|
||||
H' = Hazardous incident
|
||||
M' = Multi-Vehicle crash site
|
||||
|
@ -199,9 +227,10 @@ ADVISORIES: #< (new expansion possibilities)
|
|||
/< = motorcycle
|
||||
\< = Advisory (single gale flag)
|
||||
|
||||
CARS: #>
|
||||
CARS: #> (Vehicles)
|
||||
/> = normal car (side view)
|
||||
\> = Top view and symbol POINTS in direction of travel
|
||||
#> = Reserve overlays 1-9 for numbered cars (new Aug 2014)
|
||||
E> = Electric
|
||||
H> = Hybrid
|
||||
S> = Solar powered
|
||||
|
@ -270,13 +299,18 @@ Wa = WinLink
|
|||
CIVIL DEFENSE or TRIANGLE: #c
|
||||
/c = Incident Command Post
|
||||
\c = Civil Defense
|
||||
Dc = Decontamination (new Aug 2014)
|
||||
Rc = RACES
|
||||
Sc = SATERN mobile canteen
|
||||
|
||||
BUILDINGS: #h
|
||||
/h = Hospital
|
||||
\h = Ham Store ** <= now used for HAMFESTS
|
||||
Fh = HamFest (new Aug 2014)
|
||||
Hh = Home Dept etc..
|
||||
Mh = Morgue
|
||||
Ch = Clinic
|
||||
Th = Triage
|
||||
|
||||
SPECIAL VEHICLES: #k
|
||||
/k = truck
|
||||
|
@ -287,17 +321,33 @@ Ak = ATV (all terrain vehicle)
|
|||
SHIPS: #s
|
||||
/s = Power boat (ship) side 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
|
||||
Ks = Kayak
|
||||
Hs = Hovercraft (new may 2014)
|
||||
Ts = Torpedo (new may 2014)
|
||||
Us = sUbmarine U-boat (new may 2014)
|
||||
Ls = Law enforcement
|
||||
Ms = Miltary
|
||||
Os = Oil Rig
|
||||
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
|
||||
/u = Truck (18 wheeler)
|
||||
\u = truck with overlay
|
||||
Bu = Buldozer/construction (new Aug 2014)
|
||||
Gu = Gas
|
||||
Pu = Plow or SnowPlow (new Aug 2014)
|
||||
Tu = Tanker
|
||||
Cu = Chlorine Tanker
|
||||
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)
|
||||
{
|
||||
FILE *fp;
|
||||
struct {
|
||||
char overlay;
|
||||
char symbol;
|
||||
char sp1;
|
||||
char equal;
|
||||
char sp2;
|
||||
char description[150];
|
||||
} stuff;
|
||||
|
||||
/*
|
||||
* We only care about lines with this format:
|
||||
*
|
||||
* Column 1 - overlay character of / \ upper case or digit
|
||||
* Column 2 - symbol in range of ! thru ~
|
||||
* Column 3 - space
|
||||
* 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;
|
||||
|
||||
#define GOOD_LINE(x) ((x.overlay == '/' || x.overlay == '\\' || isupper(x.overlay) || isdigit(x.overlay)) \
|
||||
&& x.symbol >= '!' && x.symbol <= '~' \
|
||||
&& x.sp1 == ' ' && x.equal == '=' && x.sp2 == ' ')
|
||||
|
||||
#define GOOD_LINE(x) (strlen(x) > 6 && \
|
||||
(x[COL1_OVERLAY] == '/' || x[COL1_OVERLAY] == '\\' || isupper(x[COL1_OVERLAY]) || isdigit(x[COL1_OVERLAY])) \
|
||||
&& x[COL2_SYMBOL] >= '!' && x[COL2_SYMBOL] <= '~' \
|
||||
&& x[COL3_SP] == ' ' && x[COL4_EQUAL] == '=' && x[COL5_SP] == ' ' && x[COL6_DESC] != ' ')
|
||||
|
||||
if (new_sym_ptr != NULL) {
|
||||
return; /* was called already. */
|
||||
|
@ -350,7 +362,7 @@ void symbols_init (void)
|
|||
/*
|
||||
* 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)) {
|
||||
new_sym_size++;
|
||||
}
|
||||
|
@ -363,15 +375,15 @@ void symbols_init (void)
|
|||
*/
|
||||
rewind (fp);
|
||||
|
||||
while (fgets((char*)(&stuff), sizeof(stuff), fp) != NULL) {
|
||||
while (fgets(stuff, sizeof(stuff), fp) != NULL) {
|
||||
|
||||
if (GOOD_LINE(stuff)) {
|
||||
for (j = strlen(stuff.description) - 1; j>=0 && stuff.description[j] <= ' '; j--) {
|
||||
stuff.description[j] = '\0';
|
||||
for (j = strlen(stuff+COL6_DESC) - 1; j>=0 && stuff[COL6_DESC+j] <= ' '; j--) {
|
||||
stuff[COL6_DESC+j] = '\0';
|
||||
}
|
||||
new_sym_ptr[new_sym_len].overlay = stuff.overlay;
|
||||
new_sym_ptr[new_sym_len].symbol = stuff.symbol;
|
||||
strncpy(new_sym_ptr[new_sym_len].description, stuff.description, NEW_SYM_DESC_LEN);
|
||||
new_sym_ptr[new_sym_len].overlay = stuff[COL1_OVERLAY];
|
||||
new_sym_ptr[new_sym_len].symbol = stuff[COL2_SYMBOL];
|
||||
strncpy(new_sym_ptr[new_sym_len].description, stuff+COL6_DESC, NEW_SYM_DESC_LEN);
|
||||
new_sym_len++;
|
||||
}
|
||||
}
|
||||
|
|
138
symbolsX.txt
138
symbolsX.txt
|
@ -1,20 +1,21 @@
|
|||
APRS SYMBOLS (Icons) 07 Oct 2013
|
||||
APRS SYMBOLS (Icons) 28 Aug 2014
|
||||
-----------------------------------------------------------------------
|
||||
WB4APR
|
||||
|
||||
This original APRS symbol specification is updated periodically with
|
||||
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
|
||||
be sure to check the symbols-new.txt file noted below!
|
||||
almost all new symbols since 2007 will be formed as Overlays to the
|
||||
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
|
||||
overlay characters on all alternate symbols was allowed as needed in
|
||||
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
|
||||
hundreds of potential new symbols. Since this overlay info will no
|
||||
longer fit in this original document it is found in a new document:
|
||||
|
||||
http://aprs.org/symbols/symbols-new.txt
|
||||
hundreds of potential new symbols. Since each of the original 94
|
||||
symbols can now have up to 36 other definitions, this new overlay info
|
||||
is now found in the above file.
|
||||
|
||||
If an alternate symbol from the table below, contains significant
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
19 Sep 11: Added T & 2 overlay for 1 & 2 hop Message TX Igates
|
||||
Updated overlay "portable" (;) overlays for events
|
||||
|
@ -100,7 +108,9 @@ Alt: >KOSY[^ksuv\ <==[removed /0An]
|
|||
|
||||
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>
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -113,8 +123,8 @@ tables or may be used as an alphanumeric overlay over some symbols:
|
|||
& RESERVED for possible AUXILLIARY tables (Aug 09)
|
||||
/ Primary symbol Table (Mostly stations)
|
||||
\ Alternate symbol table (Mostly Objects)
|
||||
0-9 Alternate OVERLAY symbol with 0-9 overlayed
|
||||
A-Z Alternate OVERLAY symbol with A-Z overlayed
|
||||
0-9 Alternate OVERLAY symbols with 0-9 overlayed
|
||||
A-Z Alternate OVERLAY symbols with A-Z overlayed
|
||||
|
||||
For ease of reference we refer to these as the SYMBOL CHARACTERS and
|
||||
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
|
||||
Civil-Defense(RACES), NWS sites, WX stations, Triangle
|
||||
|
||||
After that, provisions should be made in all software to allow for
|
||||
overlays on any alternate symbol as they may be used in the future.
|
||||
After 2007, provisions should be made in all software to allow for
|
||||
overlays on *any/all* alternate symbols for use in the future.
|
||||
|
||||
SYMBOLS WITH STAND-ALONE GPS TRACKERS: Stand-alone devices that
|
||||
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 (\)
|
||||
-- --- ------------------------ -- --- ----------------------
|
||||
/! BB Police, Sheriff \! OB EMERGENCY (!)
|
||||
/! BB Police, Sheriff \! OBO EMERGENCY (and overlays)
|
||||
/" BC reserved (was rain) \" OC reserved
|
||||
/# BD DIGI (white center) \# OD# OVERLAY DIGI (green star)
|
||||
/$ BE PHONE \$ OEO Bank or ATM (green box)
|
||||
/% BF DX CLUSTER \% OFO Power Plant with overlay
|
||||
/& BG HF GATEway \& OG# I=Igte R=RX T=1hopTX 2=2hopTX
|
||||
/' BH Small AIRCRAFT (SSID = 7) \' OHO Crash (& now Incident sites)
|
||||
/( 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.
|
||||
/* BK SnowMobile \* OK SNOW (& future ovrly codes)
|
||||
/* BK SnowMobile \* OK AVAIL (SNOW moved to ` ovly S)
|
||||
/+ BL Red Cross \+ OL Church
|
||||
/, BM Boy Scouts \, OM Girl Scouts
|
||||
/- 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 (\)
|
||||
-- --- ------------------------ -- --- --------------------------
|
||||
/0 P0 # circle (obsolete) \0 A0# CIRCLE (E/I/W=IRLP/Echolink/WIRES)
|
||||
/1 P1 TBD (these were numbered) \1 A1
|
||||
/2 P2 TBD (circles like pool) \2 A2
|
||||
/3 P3 TBD (balls. But with) \3 A3
|
||||
/4 P4 TBD (overlays, we can) \4 A4
|
||||
/5 P5 TBD (put all #'s on one) \5 A5
|
||||
/6 P6 TBD (So 1-9 are available)\6 A6
|
||||
/7 P7 TBD (for new uses?) \7 A7
|
||||
/0 P0 # circle (obsolete) \0 A0# CIRCLE (IRLP/Echolink/WIRES)
|
||||
/1 P1 TBD (these were numbered) \1 A1 AVAIL
|
||||
/2 P2 TBD (circles like pool) \2 A2 AVAIL
|
||||
/3 P3 TBD (balls. But with) \3 A3 AVAIL
|
||||
/4 P4 TBD (overlays, we can) \4 A4 AVAIL
|
||||
/5 P5 TBD (put all #'s on one) \5 A5 AVAIL
|
||||
/6 P6 TBD (So 1-9 are available)\6 A6 AVAIL
|
||||
/7 P7 TBD (for new uses?) \7 A7 AVAIL
|
||||
/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)
|
||||
/: MR FIRE \: NR Hail (& future ovrly codes)
|
||||
/: MR FIRE \: NR AVAIL (Hail ==> ` ovly H)
|
||||
/; MS Campground (Portable ops) \; NSO Park/Picnic + overlay events
|
||||
/< MT Motorcycle (SSID =10) \< NTO ADVISORY (one WX flag)
|
||||
/= 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 ?)
|
||||
/@ MX HC FUTURE predict (dot) \@ NX HURICANE/Trop-Storm
|
||||
/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
|
||||
/D PD \D AD Drizzle (proposed APRStt)
|
||||
/E PE EYEBALL (Eye catcher!) \E AE Smoke (& other vis codes)
|
||||
/F PF Farm Vehicle (tractor) \F AF Freezng rain (&future codes)
|
||||
/G PG Grid Square (6 digit) \G AG Snow Shwr (& future ovrlys)
|
||||
/D PD \D ADO DEPOTS (Drizzle ==> ' ovly D)
|
||||
/E PE EYEBALL (Events, etc!) \E AE Smoke (& other vis codes)
|
||||
/F PF Farm Vehicle (tractor) \F AF AVAIL (FrzngRain ==> `F)
|
||||
/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)
|
||||
/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)
|
||||
/L PL PC user (Jan 03) \L AL Lighthouse
|
||||
/M PM MacAPRS \M AMO MARS (A=Army,N=Navy,F=AF)
|
||||
/N PN NTS Station \N AN Navigation Buoy
|
||||
/O PO BALLOON (SSID =11) \O AO Rocket (new June 2004)
|
||||
/O PO BALLOON (SSID =11) \O AO Overlay Balloon (Rocket = \O)
|
||||
/P PP Police \P AP Parking
|
||||
/Q PQ TBD \Q AQ QUAKE
|
||||
/R PR REC. VEHICLE (SSID =13) \R ARO Restaurant
|
||||
|
@ -223,18 +233,18 @@ for the stand-alone trackers described above.
|
|||
/W PW National WX Service Site \W AW# # NWS site (NWS options)
|
||||
/X PX HELO (SSID = 6) \X AX Pharmacy Rx (Apothicary)
|
||||
/Y PY YACHT (sail) (SSID = 5) \Y AYO Radios and devices
|
||||
/Z PZ WinAPRS \Z AZ
|
||||
/Z PZ WinAPRS \Z AZ AVAIL
|
||||
/[ HS Human/Person (HT) \[ DSO W.Cloud (& humans w Ovrly)
|
||||
/\ HT TRIANGLE(DF station) \\ DTO New overlayable GPS symbol
|
||||
/] HU MAIL/PostOffice(was PBBS) \] DU
|
||||
/^ HV LARGE AIRCRAFT \^ DV# # Aircraft (shows heading)
|
||||
/] HU MAIL/PostOffice(was PBBS) \] DU AVAIL
|
||||
/^ HV LARGE AIRCRAFT \^ DV# other Aircraft ovrlys (2014)
|
||||
/_ HW WEATHER Station (blue) \_ DW# # WX site (green digi)
|
||||
/` HX Dish Antenna \` DX Rain (all types w ovrly)
|
||||
|
||||
/$ XYZ LOWER CASE SYMBOL TABLE \$ XYZ SECONDARY SYMBOL TABLE (\)
|
||||
-- --- ------------------------ -- --- --------------------------
|
||||
/a LA AMBULANCE (SSID = 1) \a SA#O ARRL, ARES, WinLINK
|
||||
/b LB BIKE (SSID = 4) \b SB Blwng Dst/Snd (& others)
|
||||
/a LA AMBULANCE (SSID = 1) \a SA#O ARRL,ARES,WinLINK,Dstar, etc
|
||||
/b LB BIKE (SSID = 4) \b SB AVAIL(Blwng Dst/Snd => E ovly)
|
||||
/c LC Incident Command Post \c SC#O CD triangle RACES/SATERN/etc
|
||||
/d LD Fire dept \d SD DX spot by callsign
|
||||
/e LE HORSE (equestrian) \e SE Sleet (& future ovrly codes)
|
||||
|
@ -248,27 +258,28 @@ for the stand-alone trackers described above.
|
|||
/m LM Mic-E Repeater \m SM Value Sign (3 digit display)
|
||||
/n LN Node (black bulls-eye) \n SN# OVERLAY TRIANGLE
|
||||
/o LO EOC \o SO small circle
|
||||
/p LP ROVER (puppy, or dog) \p SP Prtly Cldy (& future ovrlys)
|
||||
/q LQ GRID SQ shown above 128 m \q SQ
|
||||
/p LP ROVER (puppy, or dog) \p SP AVAIL (PrtlyCldy => ( ovly P
|
||||
/q LQ GRID SQ shown above 128 m \q SQ AVAIL
|
||||
/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
|
||||
/u LU TRUCK (18 wheeler) \u SU# OVERLAYED TRUCK
|
||||
/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<-
|
||||
/y LY YAGI @ QTH \y SY Skywarn
|
||||
/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
|
||||
/} J3 \} Q3
|
||||
/} J3 \} Q3 AVAIL? (maybe)
|
||||
/~ J4 TNC Stream Switch \~ Q4 TNC Stream Switch
|
||||
|
||||
HEADING SYMBOLS: Although all symbols are supposed to have a heading
|
||||
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
|
||||
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
|
||||
\s Overlayed Ship
|
||||
|
@ -277,10 +288,14 @@ movement. These special symbols are:
|
|||
/g Glider
|
||||
\n Overlayed Triangle
|
||||
|
||||
AREA SYMBOLS! You can define BOX/CIRCLE/LINE or TRIANGLE areas in all
|
||||
colors, either open or filled in, any size from 60 feet to 100 miles.
|
||||
Simply move the cursor to the location, press HOME, move the cursor to
|
||||
the lower right corner of the AREA and hit INPUT-ADD-OBJECTS-AREA.
|
||||
AREA SYMBOLS! The special symbol \l (lower case L) was special. It
|
||||
indicates an area definition. You can define these as a BOX, CIRCLE,
|
||||
LINE or TRIANGLE area in all colors, either open or filled in, any
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
do NOT know the order of other stations P-lists.
|
||||
|
||||
AREAS FORMAT: The new format for specifying special areas uses the
|
||||
CSE/SPD field to provide the additional information as follows:
|
||||
AREAS FORMAT: Use of the special AREAS symbol (/l) triggers special
|
||||
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
|
||||
|
||||
lTyy/Cxx... Where: l (lower case L) is symbol for "LOCATION SHAPES"
|
||||
T is Type of shape: 0=circle, 1=line, 2=elipse
|
||||
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
|
||||
differentiated by colors red, yellos, and blue. Additionally a radius
|
||||
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
|
||||
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
|
||||
entry is #\VFANC,LAT,LONG,128.
|
||||
|
||||
VALUE SIGNPOSTS: Signposts display as a yellow box with a 1-3 letter
|
||||
overlay on them. You specify the 1-3 letter overlay by enclosing them
|
||||
in braces in the comment field. Thus a VALUE Signpost with {55} would
|
||||
VALUE SIGNPOSTS: This is another special handling Symbol. Signposts
|
||||
trigger a display as a yellow box with a 1-3 letter overlay on them.
|
||||
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
|
||||
of traffic past speed measuring devices. APRSdos has a version named
|
||||
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.
|
||||
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
|
||||
the original intent and was only limited to a few due to limitations
|
||||
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.
|
||||
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
|
||||
these overlays on all symbols.
|
||||
|
||||
To help define these hundreds of new symbol combinations, we have
|
||||
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
|
||||
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";
|
||||
|
||||
|
||||
#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";
|
||||
|
||||
|
|
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
|
||||
|
||||
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
|
||||
22 Oct 13 added APFIxx for APRS.FI OH7LZB, Hessu
|
||||
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
|
||||
APCLWX EYWeather GPRS/GSM WX station by ZS6EY
|
||||
APCLEZ Telit EZ10 GSM application ZS6CEY
|
||||
APCWP8 John GM7HHB, WinphoneAPRS
|
||||
APCYxx Cybiko applications
|
||||
APD APD4xx UP4DAR platform
|
||||
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
|
||||
APRtfc APRStraffic
|
||||
APRSTx APRStt (Touch tone)
|
||||
APS APRS+SA, etc
|
||||
APS APSxxx APRS+SA, etc
|
||||
APSARx ZL4FOX's SARTRACK
|
||||
APSCxx aprsc APRS-IS core server (OH7LZB, OH2MQK)
|
||||
APSK63 APRS Messenger -over-PSK63
|
||||
APSK25 APRS Messenger GMSK-250
|
||||
APSMSx Paul Defrusne's SMS gateway
|
||||
APSTMx for W7QO's Balloon trackers
|
||||
APT APTIGR TigerTrack
|
||||
APTTxx Tiny Track
|
||||
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/
|
||||
|
||||
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:
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
/* Dire Wolf version 1.0 */
|
||||
/* Dire Wolf version 1.1 */
|
||||
|
||||
#define APP_TOCALL "APDW"
|
||||
|
||||
#define MAJOR_VERSION 1
|
||||
#define MINOR_VERSION 0
|
||||
#define MINOR_VERSION 1
|
||||
|
|
53
xmit.c
53
xmit.c
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// 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
|
||||
// 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 */
|
||||
/* 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 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);
|
||||
#endif
|
||||
|
||||
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;
|
||||
#if __WIN32__
|
||||
|
@ -159,6 +166,8 @@ void xmit_init (struct audio_s *p_modem)
|
|||
dw_printf ("xmit_init ( ... )\n");
|
||||
#endif
|
||||
|
||||
g_debug_xmit_packet = debug_xmit_packet;
|
||||
|
||||
/*
|
||||
* Push to Talk (PTT) control.
|
||||
*/
|
||||
|
@ -202,7 +211,7 @@ void xmit_init (struct audio_s *p_modem)
|
|||
// underrun on the audio output device.
|
||||
|
||||
#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) {
|
||||
text_color_set(DW_COLOR_ERROR);
|
||||
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)
|
||||
#endif
|
||||
{
|
||||
packet_t pp;
|
||||
unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
|
||||
|
@ -455,14 +468,25 @@ static void * xmit_thread (void *arg)
|
|||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
||||
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");
|
||||
|
||||
flen = ax25_pack (pp, fbuf);
|
||||
assert (flen <= sizeof(fbuf));
|
||||
/* Optional hex dump of packet. */
|
||||
|
||||
if (g_debug_xmit_packet) {
|
||||
|
||||
text_color_set(DW_COLOR_DEBUG);
|
||||
dw_printf ("------\n");
|
||||
ax25_hex_dump (pp);
|
||||
dw_printf ("------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
numframe = 1;
|
||||
ax25_delete (pp);
|
||||
|
@ -483,14 +507,21 @@ static void * xmit_thread (void *arg)
|
|||
text_color_set(DW_COLOR_XMIT);
|
||||
dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
|
||||
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");
|
||||
|
||||
flen = ax25_pack (pp, fbuf);
|
||||
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.
|
||||
*/
|
||||
flen = ax25_pack (pp, fbuf);
|
||||
assert (flen >= 1 && flen <= sizeof(fbuf));
|
||||
num_bits += hdlc_send_frame (c, fbuf, flen);
|
||||
numframe++;
|
||||
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 ("%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");
|
||||
ax25_delete (pp);
|
||||
|
||||
|
|
Loading…
Reference in New Issue