diff --git a/ChangeLog b/ChangeLog index ded6db1b..b3de49d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20712,3 +20712,9 @@ * Added code to print the value of the detected CartChunk CutID when using both the '--use-cartchunk-cutid' and '--verbose' flags in rdimport(1). +2021-04-05 Eric Adler + * Created pypad_ino713_tcp based upon pypad_ino713, converting from + UDP to TCP. Added an adjustable delay to account for broadcast air + delays. + * Created pypad_nautel based upon pypad_ino713_tcp, including RDS + parameters from documentation. Includes delay. diff --git a/apis/pypad/scripts/pypad_ino713_tcp.exemplar b/apis/pypad/scripts/pypad_ino713_tcp.exemplar new file mode 100644 index 00000000..d4a3f1ca --- /dev/null +++ b/apis/pypad/scripts/pypad_ino713_tcp.exemplar @@ -0,0 +1,100 @@ +; This is the configuration for the 'pypad_ino713_tcp.py' script for +; Rivendell, which can be used to output Now & Next data to one or more +; Inovonics model 713 RDS encoders or Nautel VS transmitters in TCP mode. + +; Section Header +; +; One section per remote RDS unit is configured, starting with 'Rds1' and +; working up consecutively +[Rds1] + +; ***************************************************************************** +; TCP/IP Connection Settings +; IP Address +; +; The IP address of the TCP port to send updates to, in dotted-quad notation. +; If using a serial connection, leave this entry blank! +IpAddress=127.0.0.1 + +; TCP Port +; +; The TCP port number to send updates to, in the range 0 - 65,535. +TcpPort=10001 + +; ***************************************************************************** + +; Delay in seconds before sending the update +Delay=30 + +; ***************************************************************************** + +; Output Strings. The PAD data to output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; +; For the list of supported wildcards. see the 'Metadata Wildcards' section +; of the Rivendell Operations Guide. +PsString= +DynamicPsString=%t - %a +RadiotextString=%t - %a + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Onair +Aux1Log=No +Aux2Log=No +VLog101=No +VLog102=No +VLog103=No +VLog104=No +VLog105=No +VLog106=No +VLog107=No +VLog108=No +VLog109=No +VLog110=No +VLog111=No +VLog112=No +VLog113=No +VLog114=No +VLog115=No +VLog116=No +VLog117=No +VLog118=No +VLog119=No +VLog120=No + +; Additional RDS encoders can be configured by adding new sections... +;[Rds2] +;IpAddress=192.168.10.22 +;TcpPort=6789 +;Delay=20 +;PsString= +;DynamicPsString=%t +;RadiotextString=%a +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair +;VLog101=No +;VLog102=No +;VLog103=No +;VLog104=No +;VLog105=No +;VLog106=No +;VLog107=No +;VLog108=No +;VLog109=No +;VLog110=No +;VLog111=No +;VLog112=No +;VLog113=No +;VLog114=No +;VLog115=No +;VLog116=No +;VLog117=No +;VLog118=No +;VLog119=No +;VLog120=No diff --git a/apis/pypad/scripts/pypad_ino713_tcp.py b/apis/pypad/scripts/pypad_ino713_tcp.py new file mode 100644 index 00000000..95aa8f4f --- /dev/null +++ b/apis/pypad/scripts/pypad_ino713_tcp.py @@ -0,0 +1,86 @@ +#!/usr/bin/python3 + +# pypad_ino713_tcp.py +# +# Send Now & Next updates to an Inovonics 713 RDS encoder as TCP +# +# (C) Copyright 2018 Fred Gleason +# 2020 Eric Adler +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import sys +import socket +import configparser +import pypad +import time + +def eprint(*args,**kwargs): + print(*args,file=sys.stderr,**kwargs) + + +def ProcessPad(update): + n=1 + section='Rds'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): + dps='' + if(len(update.config().get(section,'DynamicPsString'))!=0): + dps='DPS='+update.resolvePadFields(update.config().get(section,'DynamicPsString'),pypad.ESCAPE_NONE)+'\r\n' + ps='' + if(len(update.config().get(section,'PsString'))!=0): + ps='PS='+update.resolvePadFields(update.config().get(section,'PsString'),pypad.ESCAPE_NONE)+'\r\n' + text='' + if(len(update.config().get(section,'RadiotextString'))!=0): + text='TEXT='+update.resolvePadFields(update.config().get(section,'RadiotextString'),pypad.ESCAPE_NONE)+'\r\n' + # + # Use TCP output + # + waittime=int(update.config().get(section,'Delay')) + time.sleep(waittime) + ipaddr=update.config().get(section,'IpAddress') + port=int(update.config().get(section,'TcpPort')) + if(len(dps)!=0): + send_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) + send_sock.connect((ipaddr,port)) + send_sock.sendall(dps.encode('utf-8')) + send_sock.close() + if(len(ps)!=0): + send_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) + send_sock.connect((ipaddr,port)) + send_sock.sendall(ps.encode('utf-8')) + send_sock.close() + if(len(text)!=0): + send_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) + send_sock.connect((ipaddr,port)) + send_sock.sendall(text.encode('utf-8')) + send_sock.close() + n=n+1 + section='Rds'+str(n) + +# +# 'Main' function +# +# Create Send Socket +# + +rcvr=pypad.Receiver() +try: + rcvr.setConfigFile(sys.argv[3]) +except IndexError: + eprint('pypad_inno713.py: USAGE: cmd ') + sys.exit(1) +rcvr.setPadCallback(ProcessPad) +rcvr.start(sys.argv[1],int(sys.argv[2])) diff --git a/apis/pypad/scripts/pypad_nautel.exemplar b/apis/pypad/scripts/pypad_nautel.exemplar new file mode 100644 index 00000000..619cbc41 --- /dev/null +++ b/apis/pypad/scripts/pypad_nautel.exemplar @@ -0,0 +1,190 @@ +; This is the configuration for the 'pypad_nautel.py' script for +; Rivendell, which can be used to output Now & Next data to one or more +; Nautel VS transmitters as RDP in ASCII TCP mode. + +; Section Header +; +; One section per remote transmitter unit is configured, starting with 'Rds1' and +; working up consecutively +[Rds1] + +; ***************************************************************************** +; TCP/IP Connection Settings +; IP Address +; +; The IP address of the TCP port to send updates to, in dotted-quad notation. +; If using a serial connection, leave this entry blank! +IpAddress=127.0.0.1 + +; TCP Port +; +; The TCP port number to send updates to, in the range 0 - 65,535. +TcpPort=10001 + +; ***************************************************************************** + +; Delay in seconds before sending the update +Delay=30 + +; ***************************************************************************** + +; Output Strings. The PAD data to output each time RDAirPlay changes +; play state, including any wildcards as placeholders for metadata values. +; +; For the list of supported wildcards. see the 'Metadata Wildcards' section +; of the Rivendell Operations Guide. +; +; I recommend setting just these three unless you really know what you're doing +; documentation is in section 2 of the VS OPS Manual. +; In issue 10.0 for the NV2.5 this is on page 2-69 + +;Program Service - 8 character ASCII tagline, often callsign or a short name +ProgramService= +;Dynamic PS - +DynamicPS=%t - %a +;Radio Text - up to 64 characters +RadioText=%t - %a + +;; These settings are not recommended to be changed unless you really know +;; what you are doing and why you are doing it. +;; Per the manual, not all values can be unset by the TCP ASCII connection. +;;PICode= ***SET THIS IN YOUR TRANSMITTER PER THE RDS/RDBS SPEC*** +;ProgramType=0 +;ProgramTypeName= +;TrafficProgram=0 +;TrafficAnnouncement=0 +;AltFreq1=107 +;AltFreq2=107 +;AltFreq3=107 +;AltFreq4=107 +;AltFreq5=107 +;AltFreq6=107 +;AltFreq7=107 +;AltFreq8=107 +;AltFreq9=107 +;AltFreq10=107 +;AltFreq11=107 +;AltFreq12=107 +;AltFreq13=107 +;AltFreq14=107 +;AltFreq15=107 +;AltFreq16=107 +;AltFreq17=107 +;AltFreq18=107 +;AltFreq19=107 +;AltFreq20=107 +;AltFreq21=107 +;AltFreq22=107 +;AltFreq23=107 +;AltFreq24=107 +;AltFreq25=107 +;DecoderInfo=3 +;MusicSpeech=1 +;Date= +;Time= +;UTCOffset=39 +;Cont= +;DPSRate=0 +;DPSMode=0 + + + +; Log Selection +; +; Set the status for each log to 'Yes', 'No' or 'Onair' to indicate whether +; state changes on that log should be output on this udp port. If set +; to 'Onair', then output will be generated only if RDAirPlays OnAir flag +; is active. +MasterLog=Onair +Aux1Log=No +Aux2Log=No +VLog101=No +VLog102=No +VLog103=No +VLog104=No +VLog105=No +VLog106=No +VLog107=No +VLog108=No +VLog109=No +VLog110=No +VLog111=No +VLog112=No +VLog113=No +VLog114=No +VLog115=No +VLog116=No +VLog117=No +VLog118=No +VLog119=No +VLog120=No + +; Additional RDS encoders can be configured by adding new sections... +;[Rds2] +;IpAddress=192.168.10.22 +;TcpPort=6789 +;Delay=20 +;ProgramService= +;DynamicPS=%t +;RadioText=%a +;;PICode= ***SET THIS IN YOUR TRANSMITTER PER THE RDS/RDBS SPEC*** +;ProgramType=0 +;ProgramTypeName= +;TrafficProgram=0 +;TrafficAnnouncement=0 +;AltFreq1=107 +;AltFreq2=107 +;AltFreq3=107 +;AltFreq4=107 +;AltFreq5=107 +;AltFreq6=107 +;AltFreq7=107 +;AltFreq8=107 +;AltFreq9=107 +;AltFreq10=107 +;AltFreq11=107 +;AltFreq12=107 +;AltFreq13=107 +;AltFreq14=107 +;AltFreq15=107 +;AltFreq16=107 +;AltFreq17=107 +;AltFreq18=107 +;AltFreq19=107 +;AltFreq20=107 +;AltFreq21=107 +;AltFreq22=107 +;AltFreq23=107 +;AltFreq24=107 +;AltFreq25=107 +;DecoderInfo=3 +;MusicSpeech=1 +;Date= +;Time= +;UTCOffset=39 +;Cont= +;DPSRate=0 +;DPSMode=0 +;MasterLog=Yes +;Aux1Log=No +;Aux2Log=Onair +;VLog101=No +;VLog102=No +;VLog103=No +;VLog104=No +;VLog105=No +;VLog106=No +;VLog107=No +;VLog108=No +;VLog109=No +;VLog110=No +;VLog111=No +;VLog112=No +;VLog113=No +;VLog114=No +;VLog115=No +;VLog116=No +;VLog117=No +;VLog118=No +;VLog119=No +;VLog120=No diff --git a/apis/pypad/scripts/pypad_nautel.py b/apis/pypad/scripts/pypad_nautel.py new file mode 100644 index 00000000..a88d7359 --- /dev/null +++ b/apis/pypad/scripts/pypad_nautel.py @@ -0,0 +1,175 @@ +#!/usr/bin/python3 + +# pypad_nautel.py +# +# Send Now & Next updates to an Nautel FM Transmitter as TCP for RDS +# +# (C) Copyright 2018 Fred Gleason +# 2020 Eric Adler +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# 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, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +import sys +import socket +import configparser +import pypad +import time + +def eprint(*args,**kwargs): + print(*args,file=sys.stderr,**kwargs) + + +def sendvar(var): + if(len(var)!=0): + send_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) + send_sock.connect((ipaddr,port)) + send_sock.sendall(var.encode('utf-8')) + send_sock.close() + +def getval(val, update, section): + try: + configval = update.config().get(section,val) + except: + configval = '' + return configval + +def encode(srcdata, fieldname, update): + if(len(srcdata)!=0): + enc=fieldname+'='+update.resolvePadFields(srcdata,pypad.ESCAPE_NONE)+'\r\n' + else: + enc='' + return enc + +def getval_encode(sourcename, fieldname, update, section): + return encode(getval(sourcename, update, section), fieldname, update) + +def ProcessPad(update): + n=1 + section='Rds'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): + dps='' + dps=getval_encode('DynamicPS',"DPS",update,section) + ps=getval_encode('ProgramService',"PS",update,section) + text=getval_encode('RadioText',"TEXT",update,section) + picode=getval_encode('PICode',"PI",update,section) + pty=getval_encode('ProgramType',"PTY",update,section) + ptyn=getval_encode('ProgramTypeName',"PTYN",update,section) + trp=getval_encode('TrafficProgram',"TP",update,section) + tra=getval_encode('TrafficAnnouncement',"TA",update,section) + af1=getval_encode('AltFreq1',"AF1",update,section) + af2=getval_encode('AltFreq2',"AF2",update,section) + af3=getval_encode('AltFreq3',"AF3",update,section) + af4=getval_encode('AltFreq4',"AF4",update,section) + af5=getval_encode('AltFreq5',"AF5",update,section) + af6=getval_encode('AltFreq6',"AF6",update,section) + af7=getval_encode('AltFreq7',"AF7",update,section) + af8=getval_encode('AltFreq8',"AF8",update,section) + af9=getval_encode('AltFreq9',"AF9",update,section) + af10=getval_encode('AltFreq10',"AF10",update,section) + af11=getval_encode('AltFreq11',"AF11",update,section) + af12=getval_encode('AltFreq12',"AF12",update,section) + af13=getval_encode('AltFreq13',"AF13",update,section) + af14=getval_encode('AltFreq14',"AF14",update,section) + af15=getval_encode('AltFreq15',"AF15",update,section) + af16=getval_encode('AltFreq16',"AF16",update,section) + af17=getval_encode('AltFreq17',"AF17",update,section) + af18=getval_encode('AltFreq18',"AF18",update,section) + af19=getval_encode('AltFreq19',"AF19",update,section) + af20=getval_encode('AltFreq20',"AF20",update,section) + af21=getval_encode('AltFreq21',"AF21",update,section) + af22=getval_encode('AltFreq22',"AF22",update,section) + af23=getval_encode('AltFreq23',"AF23",update,section) + af24=getval_encode('AltFreq24',"AF24",update,section) + af25=getval_encode('AltFreq25',"AF25",update,section) + di=getval_encode('DecoderInfo',"DI",update,section) + mus=getval_encode('MusicSpeech',"MS",update,section) + dat=getval_encode('Date',"DATE",update,section) + tim=getval_encode('Time',"DATE",update,section) + utco=getval_encode('UTCOffset',"UTC",update,section) + cont=getval_encode('Cont',"CT",update,section) + dpsr=getval_encode('DPSRate',"DPSR",update,section) + dpsm=getval_encode('DPSMode',"DPSM",update,section) + + + + # + # Use TCP output + # + waittime=int(update.config().get(section,'Delay')) + time.sleep(waittime) + ipaddr=update.config().get(section,'IpAddress') + port=int(update.config().get(section,'TcpPort')) + sendvar(dps) + sendvar(ps) + sendvar(text) + + sendvar(picode) + sendvar(pty) + sendvar(ptyn) + sendvar(trp) + sendvar(tra) + sendvar(af1) + sendvar(af2) + sendvar(af3) + sendvar(af4) + sendvar(af5) + sendvar(af6) + sendvar(af7) + sendvar(af8) + sendvar(af9) + sendvar(af10) + sendvar(af11) + sendvar(af12) + sendvar(af13) + sendvar(af14) + sendvar(af15) + sendvar(af16) + sendvar(af17) + sendvar(af18) + sendvar(af19) + sendvar(af20) + sendvar(af21) + sendvar(af22) + sendvar(af23) + sendvar(af24) + sendvar(af25) + sendvar(di) + sendvar(mus) + sendvar(dat) + sendvar(tim) + sendvar(utco) + sendvar(cont) + sendvar(dpsr) + sendvar(dpsm) + + + n=n+1 + section='Rds'+str(n) + +# +# 'Main' function +# +# Create Send Socket +# + +rcvr=pypad.Receiver() +try: + rcvr.setConfigFile(sys.argv[3]) +except IndexError: + eprint('pypad_inno713.py: USAGE: cmd ') + sys.exit(1) +rcvr.setPadCallback(ProcessPad) +rcvr.start(sys.argv[1],int(sys.argv[2]))