EchoLink® software allows licensed Amateur Radio stations to communicate with one another over the Internet, using streaming-audio technology.

http://echolink.org

Cross-linking with BrandMeister

To create cross-link you need several things:

  • An valid EchoLink node account
  • Patched version of SVXLink software that should be deployed on the same server with BrandMeister
  • One of supported AMBE Dongles

Patch is available here - https://git.brandmeister.network/public/AutoPatch.git
Patched version of SVXLink is available here = https://github.com/stefansaraev/svxlink/tree/autopatch

Compiling

  1. # create user and group
  2. groupadd svxlink
  3. useradd -r -g nogroup -s /sbin/nologin -d /opt/SVXLink -c "SvxLink Daemon" svxlink
  4. usermod -G audio,nogroup,svxlink svxlink
  5.  
  6. # fetch patched sources, compile and install into /opt/SVXLink
  7. cd /usr/src
  8. git clone https://github.com/stefansaraev/svxlink.git -b autopatch
  9. cd svxlink
  10. ./build.sh
  11.  
  12. # install the systemd unit if you want to run svxlink as systemd service
  13. cp bm/svxlink.service /etc/systemd/system/
  14. systemctl enable svxlink
  15.  

System configuration

The supplied patch used to translate callsigns that come from EchoLink into DMR IDs.

svxlink.conf

  1. [GLOBAL]
  2. LOGICS=SimplexLogic
  3. CFG_DIR=svxlink.d
  4. TIMESTAMP_FORMAT="%c"
  5. # CARD_SAMPLE_RATE should be 8000
  6. CARD_SAMPLE_RATE=8000
  7. CARD_CHANNELS=1
  8.  
  9. [SimplexLogic]
  10. TYPE=Simplex
  11. RX=Rx1
  12. TX=Tx1
  13. MODULES=ModuleEchoLink
  14. CALLSIGN=NOCALL
  15. EVENT_HANDLER=/opt/SVXLink/share/svxlink/events.tcl
  16.  
  17. [Rx1]
  18. TYPE=Local
  19. AUDIO_DEV=alsa:hw:Loopback,1,2
  20. AUDIO_CHANNEL=0
  21. SQL_DET=VOX
  22. SQL_START_DELAY=0
  23. SQL_HANGTIME=1500
  24. SQL_TIMEOUT=180
  25. VOX_FILTER_DEPTH=20
  26. VOX_THRESH=50
  27.  
  28. [Tx1]
  29. TYPE=Local
  30. AUDIO_DEV=alsa:hw:Loopback,0,0
  31. AUDIO_CHANNEL=0
  32. PTT_TYPE=NONE
  33. TIMEOUT=180
  34.  

ModuleEchoLink.conf

  1. [ModuleEchoLink]
  2. # DMR ID to use as a default when SVXLink cannot provide a source callsign
  3. BRIDGE_DEFAULT=nnn
  4. # MASTER ID : AUTOPATCH ID
  5. BRIDGE_PROXY=xxx1:10
  6. # Encoding of text used by EchoLink in your region
  7. BRIDGE_ENCODING=cp1251
  8.  
  9. NAME=EchoLink
  10. ID=2
  11. TIMEOUT=0
  12. SERVERS=servers.echolink.org
  13. CALLSIGN=N0CALL-L
  14. PASSWORD=trololol
  15. SYSOPNAME=N0CALL
  16. LOCATION=BrandMeister TGxxx0
  17. MAX_QSOS=50
  18. MAX_CONNECTIONS=51
  19. LINK_IDLE_TIMEOUT=300
  20. DESCRIPTION="Link to BrandMeister TGxxx0\n"

optional registry plugin for SQL_DET=PTY: 991-SvxLink.lua

  1. require('Global')
  2.  
  3. local bit = require('bit')
  4. local fio = require('fio')
  5. local log = require('log')
  6.  
  7. --[[
  8.  
  9. SvxLink PTY SQL_DET Plug-In
  10.  
  11. ]]--
  12.  
  13. local cfg = {
  14. [2840] = { 20, '/tmp/sql.2840', nil },
  15. [28430] = { 10, '/tmp/sql.28430', nil },
  16. [284359] = { 11, '/tmp/sql.284359', nil }
  17. }
  18.  
  19. local function setSquelch(destination, state)
  20. local file = fio.readlink(cfg[destination][2])
  21. if file ~= nil then
  22. local handle = fio.open(file, { 'O_WRONLY' })
  23. handle:write(state)
  24. handle:close()
  25. end
  26. end
  27.  
  28. local function resetSquelch(state)
  29. for k, v in pairs(cfg) do
  30. -- log.info("SvxLink: reset %s %s %s", k, v[1], v[2], v[3])
  31. setSquelch(k, state)
  32. end
  33. end
  34.  
  35. local function checkSquelch(destination, state, newSessionID)
  36. if state == 'O' and cfg[destination][3] == nil then
  37. setSquelch(destination, state)
  38. cfg[destination][3] = newSessionID
  39. -- log.info("SvxLink: open %d %s", destination, newSessionID)
  40. end
  41.  
  42. if state == 'Z' and cfg[destination][3] == newSessionID then
  43. setSquelch(destination, state)
  44. cfg[destination][3] = nil
  45. -- log.info("SvxLink: close %d %s", destination, newSessionID)
  46. end
  47. end
  48.  
  49. local SvxLink = { }
  50.  
  51. function SvxLink.start()
  52. resetSquelch('Z')
  53. end
  54.  
  55. function SvxLink.handleSystemEvent(network, data)
  56. -- work around to detect brandmeister core restart
  57. if data['Event'] == 'Initialize' and
  58. data['LinkName'] == 'FastForward'
  59. then
  60. resetSquelch('Z')
  61. end
  62. end
  63.  
  64. function SvxLink.handleSessionEvent(network, data)
  65. if data['Event'] == 'Session-Start-Extended' or
  66. data['Event'] == 'Session-Stop-Extended'
  67. then
  68. local kind = tonumber(data['LinkType' ])
  69. local flavor = tonumber(data['SessionType' ])
  70. local number = tonumber(data['Number' ])
  71. local destination = tonumber(data['DestinationID'])
  72. local sessionid = data['SessionID' ]
  73.  
  74. if cfg[destination] ~= nil then
  75. if number ~= cfg[destination][1] and
  76. bit.band(flavor, SESSION_TYPE_FLAG_VOICE) ~= 0 and
  77. bit.band(flavor, SESSION_TYPE_FLAG_GROUP) ~= 0
  78. then
  79. if data['Event'] == 'Session-Start-Extended' then
  80. checkSquelch(destination, 'O', sessionid)
  81. else
  82. checkSquelch(destination, 'Z', sessionid)
  83. end
  84. end
  85. end
  86. end
  87. end
  88.  
  89. return SvxLink