Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- #-------------------------------------------
- # GENERAL NOTES
- #
- #-------------------------------------------
- #
- # Fairly major improvements added as of
- # 2020-02-24 though this is still very much
- # a very crude and simple simplex repeater
- # script written in bash. Requires sox,
- # espeak, sed, tr, grep, morse (or cw),
- # and multimon-ng.
- #
- # This version allows for remote DTMF
- # controls. (2020/02/22)
- #
- # Now has automagic conversion of
- # espeak spoken call sign into NATO
- # Phonetics. (2020/02/23)
- #
- # Added several more variables to control
- # settings for various parts. (2020/02/23)
- #
- # Made the terminal output a bit more bold
- # so you can see what the parrot script
- # is doing at a glance. (2020/02/24)
- #-------------------------------------------
- # Save in its own directory as simplex.sh
- # and run:
- #
- # ./simplex.sh
- #-------------------------------------------
- # Use pavucontrol to select input and output
- # or however is easiest/best for your
- # working environment.
- #
- # Raspberry Pi may use alsa instead of
- # pulse. You'll have to configure things
- # with alsamixer or similar. It does seem
- # to use pulseaudio nicely when pulse is
- # installed.
- #-------------------------------------------
- # Code by Phillip J Rhoades
- #-------------------------------------------
- #-------------------------------------------
- # HARDWARE NOTES
- #
- #-------------------------------------------
- # I use an HT with an APRS cable and a
- # mic/headphones splitter on one end
- # to patch the radio into a Linux computer
- # or a Raspberry Pi. The Pi will need a
- # cheap USB soundcard. A USB soundcard
- # could also help with ground issues
- # (buzzing) on computers/laptops.
- #
- # You'll have to adjust input and output
- # volumes on the computer and the output
- # volume on the radio. I also set the
- # radio to use VOX in this setup.
- #
- # You could improve on this basic setup
- # in a number of ways but that's outside
- # the scope of this "simple" project.
- #
- # If you're reading this script in monospace
- # then this rough ASCII diagram of the setup
- # might help you get a clearer idea:
- #
- # -->[PC Mic In]
- # [HT]<-APRS->SPLIT-||
- # <--[PC Sound Card Out]
- #
- # In some cases, a ground loop noise
- # isolator or two might help with buzzing
- # sounds between the computer and the HT.
- #-------------------------------------------
- #-------------------------------------------
- # VARIABLES TO CONTROL THINGS
- #
- #-------------------------------------------
- # Set SECONDS to greater than 600 to trigger
- # repeater ID at startup.
- #-------------------------------------------
- # Set DTMFCONTROLS to 1 in order to be able
- # to control remotely via DTMF commands or
- # set DTMFCONTROLS to 0 in order to disable
- # that functionality.
- #-------------------------------------------
- # Leave IDLOOPING set to 1 in most cases.
- # Since identifying a station every 10
- # minutes is legally required.
- #
- # You might want to turn off the ID Loop
- # while testing on your sound card only.
- # To do that, set IDLOOPING to 0.
- #-------------------------------------------
- # Set CALLSIGN to your call sign.
- #-------------------------------------------
- # Set CALLSIGN_SPEAK to 1 to have espeak
- # say your call sign in NATO Phonetics
- # during each 10 minute ID announcement.
- #-------------------------------------------
- # Set CALLSIGN_MORSE to 1 to have morse
- # (usually from the bsdgames package)
- # or cw beep out your call sign during each
- # 10 minute ID announcement.
- #-------------------------------------------
- # Set MORSEPROG to whichever text to morse
- # program you prefer to use. You can
- # uncomment for EITHER morse from bsdgames
- # or cw from the cw package.
- #-------------------------------------------
- # Set MULTIMONPROG to either multimon or
- # multimon-ng, depending on what you have
- # installed or prefer. Both seem to work
- # just fine for DTMF decoding.
- # (2020/02/23)
- #-------------------------------------------
- # Setting PARROT to 0 will disable the
- # repeat of audio received by the script.
- # Setting PARROT to 1 will enable the
- # repeat of audio received by the script.
- #
- # This way, a menu item in dtmfactions
- # can be used to turn on and off just the
- # audio repeat part of this script while
- # keeping the DTMF processing in place.
- # (2020/02/24)
- #-------------------------------------------
- # Some radios and radio/computer combos
- # seem to have a slow vox. In those cases
- # activating a sound just loud enough to
- # trip the vox on can help the radio be
- # ready to transmit the first second of
- # the recorded audio.
- #
- # Set PREVOX to 1 in order to activate this
- # feature or set PREVOX to 0 in order to
- # deactivate it. (2020/02/25)
- #-------------------------------------------
- # It might be useful to save/log all audio
- # traffic that passes through your simplex
- # repeater. In order to keep the size down
- # I convert the wav file to ogg in the
- # background. You could easily set that to
- # mp3 instead or you could skip conversion
- # and just keep the original wavs, if you
- # have plenty of disk space.
- #
- # Setting SAVERECS to 1 activates this
- # feature and setting SAVERECS to 0
- # disables it. (2020/02/26)
- #-------------------------------------------
- # Just a few refinements, more comments,
- # and some more DTMF command examples.
- # (2020/02/29)
- #-------------------------------------------
- # Considering a "Dead Man's Switch" option
- # that would require a DTMF sequence every
- # N amount of time in order to keep the
- # repeater running. That way, no spurious
- # parrots continue operation if they
- # can't be reached within a certain time.
- # (2020/02/29)
- #-------------------------------------------
- # Considering a rec -t wav | play -t wav
- # pass-through option for use of this script
- # as a duplex repeater controller...
- # (2020/02/29)
- #-------------------------------------------
- SECONDS=1000
- DTMFCONTROLS=1
- PARROT=1
- PREVOX=1
- SAVERECS=0
- CALLSIGN="YOURCALLSIGN"
- IDLOOPING=1
- CALLSIGN_SPEAK=1
- CALLSIGN_MORSE=0
- #MORSEPROG="cw"
- MORSEPROG="morse"
- MULTIMONPROG="multimon-ng"
- #MULTIMONPROG="multimon"
- TIMEOUT=120
- #-------------------------------------------
- # MORE "ELEGANT" EXITING
- # (but still pretty much a hammer)
- #
- # Trap ctrl-c and call ctrl_c()
- # to exit somewhat gracefully...
- #-------------------------------------------
- trap ctrl_c INT
- function ctrl_c() {
- voxy
- if test -f "./recording.wav"; then
- rm recording.wav
- fi
- echo
- echo "#-------------------------------"
- echo "# Terminating the simplex Parrot"
- echo "#-------------------------------"
- espeak "Terminating the simplex parrot"
- #-------------------------------------------
- # Kill the parrot and its parent process
- # since exiting any other way via DTMF
- # commands seems to leave the script
- # running in the background right now.
- # Will try for more elegance later.
- # (2020/02/23)
- #
- # Could issue shutdown -h instead in order
- # to shut down Linux/Pi computer completely.
- #-------------------------------------------
- kill -9 $PPID
- #shutdown -h now
- }
- #-------------------------------------------
- # VOX ACTIVATOR
- #
- # See notes in the settings area about
- # the PREVOX variable which turns this
- # on and off.
- #
- # Adjust this sound to something that
- # is not annoying/bothersome/crude.
- #
- # Sine sounds a tone and "brownnoise" has
- # the "benefit" of sounding like radio
- # static... So... A bit more natural?
- #
- # Less lossy. More bossy. (2020/02/25)
- #
- #-------------------------------------------
- voxy () {
- if [ $PREVOX -eq 1 ]; then
- play -V1 -n -c1 synth .4 sine 179.9 #time and tone to activate vox are radio dependent
- #play -n -c1 synth .4 brownnoise
- fi
- }
- #-------------------------------------------
- # NATO PHONETICS
- #
- #-------------------------------------------
- # Pipe output into this function and it will
- # return the string as NATO Phonetics, at
- # least for letters and numbers.
- #-------------------------------------------
- # Used for espeak to speak CALLSIGN
- # in NATO Phonetics
- #-------------------------------------------
- natophonetics () {
- echo $* | sed -e 's/\(.\)/\1\n/g' | natophonetics_sub
- }
- natophonetics_sub () {
- while read data; do
- case "$data" in
- A) echo -n "Alpha " ;;
- B) echo -n "Bravo " ;;
- C) echo -n "Charlie " ;;
- D) echo -n "Delta " ;;
- E) echo -n "Echo " ;;
- F) echo -n "Foxtrot " ;;
- G) echo -n "Golf " ;;
- H) echo -n "Hotel " ;;
- I) echo -n "India " ;;
- J) echo -n "Juliet " ;;
- K) echo -n "Kilo " ;;
- L) echo -n "Lima " ;;
- M) echo -n "Mike " ;;
- N) echo -n "November " ;;
- O) echo -n "Oscar " ;;
- P) echo -n "Papa " ;;
- Q) echo -n "Quebec " ;;
- R) echo -n "Romeo " ;;
- S) echo -n "Sierra " ;;
- T) echo -n "Tango " ;;
- U) echo -n "Uniform " ;;
- V) echo -n "Victor " ;;
- W) echo -n "Whiskey " ;;
- X) echo -n "X-ray " ;;
- Y) echo -n "Yankee " ;;
- Z) echo -n "Zulu " ;;
- 0) echo -n "Zero " ;;
- 1) echo -n "One " ;;
- 2) echo -n "Two " ;;
- 3) echo -n "Three " ;;
- 4) echo -n "Four " ;;
- 5) echo -n "Five " ;;
- 6) echo -n "Six " ;;
- 7) echo -n "Seven " ;;
- 8) echo -n "Eight " ;;
- 9) echo -n "Nine " ;;
- " ") echo -n ". " ;;
- esac
- done
- }
- #-------------------------------------------
- # DTMF CONTROLS (using multimon-ng)
- #
- #-------------------------------------------
- # scandtmf runs after every recording to
- # check for dtmf codes and passes those to
- # dtmfactions to be processed.
- #-------------------------------------------
- # Complex DTMF Actions could have their own
- # functions to call.
- #-------------------------------------------
- scandtmf () {
- dtmfactions $($MULTIMONPROG -q -t wav -a DTMF ./recording.wav 2>/dev/null |grep "DTMF" |grep -v "Enabled" |sed 's/^.\{6\}//'|tr -d '\n')
- }
- dtmfactions () {
- if [ $# -eq 1 ]; then
- rm recording.wav
- voxy
- echo
- echo "#-------------------------------"
- echo "# Received DTMF Command: $1"
- echo "#-------------------------------"
- espeak "Received D T M F Command: $(echo $1| sed -e 's/\(.\)/\1 /g')"
- if [ $1 = "#0" ]; then
- espeak "The DTMF commands are"
- espeak "#0 for help"
- espeak "#1 for date and time"
- espeak "#2 will toggle saving recordings"
- espeak "#3 Weather report"
- espeak "#4 Repeater controller uptime"
- espeak "#73 to terminate the simplex parrot"
- espeak "#99 to toggle the audio parrot"
- return
- fi
- if [ $1 = "#1" ]; then
- espeak "`date +"%A, %B %d, %Y, %I:%M %p"`"
- return
- fi
- if [ $1 = "#2" ]; then
- if [ $SAVERECS -eq 1 ]; then
- espeak "Recordings will not be saved."
- SAVERECS=0
- else
- espeak "Recordings will be saved."
- SAVERECS=1
- fi
- return
- fi
- if [ $1 = "#3" ]; then
- theweather #call the weather function
- return
- fi
- if [ $1 = "#4" ]; then
- espeak "This parrot has been `uptime -p | sed "s/^up /squawking for /g"`"
- return
- fi
- if [ $1 = "#73" ]; then
- ctrl_c
- exit
- fi
- if [ $1 = "#99" ]; then
- if [ $PARROT -eq 1 ]; then
- espeak "Parrot will now be silent."
- PARROT=0
- else
- espeak "Parrot will now repeat traffic."
- PARROT=1
- fi
- return
- fi
- espeak "No such code. Send D T M F Code #0 for help." #should say if no matching DTMF code
- fi
- }
- # Just an example of calling another
- # function for a received DTMF command.
- # DTMF Command "#3"
- theweather () {
- espeak "`ansiweather -p false -a false -s false -l "Kalamazoo, MI" -u imperial |tr "-" "\n" \
- |tr "=>" "\n" |sed -e 's/°F/degrees/g' |sed -e 's/mph/miles per hour/g' |sed -e 's/$/./'`"
- return
- }
- #-------------------------------------------
- # REPEATER ID LOOP
- #
- #-------------------------------------------
- # Loop in background to identify repeater
- # no matter what else is going on.
- #-------------------------------------------
- while [ $IDLOOPING -eq 1 ]; do
- if [ $SECONDS -gt 600 ]; then
- #-------------------------------------------
- # By checking the value of SECONDS we can
- # identify the repeater every 10 minutes
- # (600 seconds).
- #
- # Why the loop and not just sleep for 600
- # seconds? This way an "emergency" ID could
- # be triggered via menu option etc.
- #-------------------------------------------
- #-------------------------------------------
- # Identify repeater using espeak, morse,
- # or both (or cw instead of morse).
- #-------------------------------------------
- if [ $CALLSIGN_SPEAK -eq 1 ] || [ $CALLSIGN_MORSE -eq 1 ]; then
- voxy
- fi
- if [ $CALLSIGN_SPEAK -eq 1 ]; then
- espeak "This is simplex repeater $(natophonetics $CALLSIGN) / R" &
- fi
- if [ $CALLSIGN_MORSE -eq 1 ]; then
- echo "$CALLSIGN/R" |$MORSEPROG &
- fi
- #-------------------------------------------
- # Always reset SECONDS to 0 here
- # so we can begin watching for 600 seconds
- # again and ID every 10-ish minutes.
- #-------------------------------------------
- SECONDS=0
- fi
- sleep 30 #If we loop this less often, it's easier on the CPU
- done &
- #-------------------------------------------
- # REPEATER PARROT LOOP
- #
- #-------------------------------------------
- # Loop until ctrl-c on keyboard or the
- # DTMF command to terminate the repeater
- #-------------------------------------------
- while [ 1 ]; do
- echo
- echo "#-------------------------------"
- echo "# WAITING FOR AUDIO INPUT:"
- echo "#-------------------------------"
- rec -V1 -c1 recording.wav rate 64k silence 1 0.1 1% 1 3.0 1% trim 0 $TIMEOUT
- # Potential command for pass-through for duplex repeater
- # while still recording a wav for scandtmf to check and
- # still enforcing the transmit timeout.
- # Some latency dependent on computer, but basically live.
- # Making the mic hot in alsa or pulse would have
- # less latency but other issues.
- #
- #rec -V1 -c1 -t wav - rate 64k silence 1 0.1 1% 1 3.0 1% trim 0 $TIMEOUT |tee recording.wav |play -t wav -
- if [ $DTMFCONTROLS -eq 1 ]; then
- scandtmf
- fi
- if [ $PARROT -eq 1 ]; then
- if test -f "./recording.wav"; then
- #sleep 2 # wait a second or two (radio dependent) so receive closes first (not always needed)
- voxy
- echo
- echo "#-------------------------------"
- echo "# PLAYING BACK CAPTURED AUDIO:"
- echo "#-------------------------------"
- play -V1 recording.wav #play back what was said, activating vox
- if [ $SAVERECS = 1 ]; then
- #If you decided to save the recordings
- TIMESTAMP=$(date)
- mv recording.wav "./$TIMESTAMP.wav" #moving a file on the same filesystem is fast and cheap
- (ffmpeg -loglevel quiet -i "./$TIMESTAMP.wav" "./$TIMESTAMP.ogg"; rm "./$TIMESTAMP.wav") & #Takes time. Do in background
- else
- rm recording.wav #cleanup before restarting loop
- fi
- fi
- fi
- done
Advertisement
Comments
-
- Any chance this could be updated to allow Raspberry PI GPIO for COS and PTT to get away from VOX?
-
- Someone who knows how to do that could do that. It's a bash script, so just about any change is possible.
-
- Update: This script seems to work very well with the new "vptt" option in the AIOC (All-In-One-Cable).
Add Comment
Please, Sign In to add comment
Advertisement