7.5.2 Tandberg-Alteia Example

    //
    // Device driver for the Tandberg Alteia and Alteia Plus DVB receivers.
    //
    // CHANGE HISTORY:
    //
    // 1.00 020505 created.
    // 

    COMMENT   "Tandberg-Alteia 1.00 020505"
    PROTOCOL  Tandberg-Alteia
    INCLUDE   "drivers/Standard.inc"

    /** identification variables **********************************************/

    VAR info.type             CYCLE 0 TEXT READONLY INIT "Tandberg-Alteia"
    VAR info.port             CYCLE 0 TEXT READONLY
    VAR info.frame            CYCLE 0 TEXT READONLY INIT "IRD-Alteia"
    VAR info.model            CYCLE 0 TEXT READONLY
    VAR info.serial           CYCLE 0 TEXT READONLY
    VAR info.ca.casid         CYCLE 0 TEXT READONLY
    VAR info.ca.codeversion   CYCLE 0 TEXT READONLY
    VAR info.ca.bootversion   CYCLE 0 TEXT READONLY
    VAR info.ca.modelno       CYCLE 0 TEXT READONLY
    VAR info.ca.hardware      CYCLE 0 TEXT READONLY
    VAR info.ca.manufacturer  CYCLE 0 TEXT READONLY
    VAR info.ca.download      CYCLE 0 TEXT READONLY

    /** configuration variables ***********************************************/

    VAR config.lbandInputs    CYCLE 0 CHOICE "4,2" SETUP SAVE
    VAR config.lnbPower       CYCLE 0 CHOICE "OFF,ON.,BST" SETUP
    VAR config.loFreq         CYCLE 0 FLOAT 0 0 1 "MHz" SETUP
    VAR config.berThreshold   CYCLE 0 TEXT SETUP
    VAR config.sigThreshold   CYCLE 0 INTEGER 0 255 ""  SETUP
    VAR config.errFrame       CYCLE 0 CHOICE "FREEZE,BLACK" SETUP

    /** internal variables ****************************************************/

    VAR internal.numServices  CYCLE 0 INTEGER 0 0 ""  READONLY
    VAR internal.numAudio     CYCLE 0 INTEGER 0 0 ""  READONLY
    VAR internal.ack          CYCLE 0 TEXT            READONLY
    VAR internal.flags        CYCLE 0 HEX     0 0 ""  READONLY
    VAR internal.scnt         CYCLE 0 INTEGER 0 0 ""  READONLY INIT "0"


    /** MNC variables *********************************************************/


    VAR input                 CYCLE 300 CHOICE "1,2,3,4"
    VAR polarization          CYCLE 0   CHOICE "HOR,VER" 
    VAR frequency             CYCLE 0   FLOAT 0 0 1 "MHz"
    VAR dataRate              CYCLE 0   FLOAT 0 0 3 "Mbps" READONLY
    VAR symbolRate            CYCLE 300 FLOAT 0 0 3 "Msps"
    VAR modulation            CYCLE 0   CHOICE "BPSK,QPSK,8PSK"
    VAR fec                   CYCLE 0   CHOICE "1/2,2/3,3/4,4/5,5/6,6/7,7/8,8/9"
    VAR programNo             CYCLE 0   INTEGER 0 99 ""

    VAR programList           CYCLE 2   TEXT READONLY
    VAR audioList             CYCLE 3   TEXT READONLY
    VAR actualProgram         CYCLE 2   TEXT READONLY

    VAR video.fmt625          CYCLE 300 CHOICE "PALI,PALB,PALN"
    VAR video.fmt525          CYCLE 0   CHOICE "NTSC,NTSN,PALM"
    VAR video.level           CYCLE 0   INTEGER -30 30 "%"
    VAR video.test            CYCLE 0   CHOICE "NRM,625.1,625.2,625.3,625.4"
                                               "625.5,625.6,625.7,625.8,625.9"
                                               "625.10,625.11,625.12,625.13"
                                               "625.14,625.15,625.16,525.1"
                                               "525.2,525.3,525.4,525.5,525.6"
                                               "525.7,525.8,525.9,525.10,525.11"
                                               "525.12,525.13,525.14,525.15,525.16"

    VAR audio.1.program       CYCLE 0   INTEGER 0 0 ""
    VAR audio.1.routing       CYCLE 0   CHOICE "NRM,MON,LFT,RGT"
    VAR audio.1.output        CYCLE 0   CHOICE "ANALOG,AES/EBU,SPDIF,AC3"
    VAR audio.1.level         CYCLE 0   INTEGER 6 18 "dB"
    VAR audio.1.language      CYCLE 0   TEXT
    VAR audio.1.test          CYCLE 0   CHOICE "NRM,TEST-1,TEST-2,TEST-3,TEST-4,TEST-5"
    VAR audio.1.info          CYCLE 4   TEXT READONLY

    VAR audio.2.program       CYCLE 0   INTEGER 0 0 ""
    VAR audio.2.routing       CYCLE 0   CHOICE "NRM,MON,LFT,RGT"
    VAR audio.2.output        CYCLE 0   CHOICE "ANALOG,AES/EBU,SPDIF,AC3"
    VAR audio.2.level         CYCLE 0   INTEGER 6 18 "dB"
    VAR audio.2.language      CYCLE 0   TEXT
    VAR audio.2.test          CYCLE 0   CHOICE "NRM,TEST-1,TEST-2,TEST-3,TEST-4,TEST-5"
    VAR audio.2.info          CYCLE 4   TEXT READONLY

    VAR tsout.routing         CYCLE 300 CHOICE "PRE-CA,POST-CA"
    VAR tsout.fibre           CYCLE 0   CHOICE "ON,OFF"

    VAR flags.lock            CYCLE 1   BOOL READONLY
    VAR flags.ca              CYCLE 0   BOOL READONLY
    VAR flags.video           CYCLE 0   BOOL READONLY
    VAR flags.audio           CYCLE 0   BOOL READONLY
    VAR flags.ber             CYCLE 0   BOOL READONLY

    VAR state.ber             CYCLE 0   TEXT             READONLY
    VAR state.signal          CYCLE 0   INTEGER 0 255 "" READONLY
    VAR state.aspect          CYCLE 3   TEXT             READONLY
    VAR state.lines           CYCLE 3   TEXT             READONLY
    VAR state.state           CYCLE 2   TEXT             READONLY

    VAR ca.status             CYCLE 4   TEXT READONLY
    VAR ca.service            CYCLE 0   TEXT READONLY
    VAR ca.rasmode            CYCLE 0   CHOICE "DISABLED,FIXED,DSNG,SEC-CA"
    VAR ca.bissmode           CYCLE 0   CHOICE "DISABLED,MODE 1,MODE E"
    VAR ca.bisskey1           CYCLE 0   TEXT
    VAR ca.bisskey2           CYCLE 0   TEXT
    VAR ca.bissbits           CYCLE 0   TEXT
    VAR ca.dsngkey            CYCLE 0   TEXT

    VAR reset                 CYCLE 0   TEXT

    /** alarm flags ***********************************************************/

    ALARM faults.01 TEXT "Temperature"
    ALARM faults.02 TEXT "Signal level"
    ALARM faults.03 TEXT "Video lock"
    ALARM faults.04 TEXT "Audio lock"
    ALARM faults.05 TEXT "High BER"
    ALARM faults.06 TEXT "Demodulator Lock"
    ALARM faults.07 TEXT "Conditional Access"


    /** translation tables ****************************************************/

    TABLE tModulation   "BPSK=BPS,QPSK=QPS,8PSK=8PS"
    TABLE tErrFrame     "FREEZE=FRZ,BLACK=BLK"
    TABLE tVideoLevel   "-30=NEG30,-29=NEG29,-28=NEG28,-27=NEG27,-26=NEG26"
                        "-25=NEG25,-24=NEG24,-23=NEG23,-22=NEG22,-21=NEG21"
                        "-20=NEG20,-19=NEG19,-18=NEG18,-17=NEG17,-16=NEG16"
                        "-15=NEG15,-14=NEG14,-13=NEG13,-12=NEG12,-11=NEG11"
                        "-10=NEG10,-9=NEG09,-8=NEG08,-7=NEG07,-6=NEG06"
                        "-5=NEG05,-4=NEG04,-3=NEG03,-2=NEG02,-1=NEG01"
                        "0=POS00,1=POS01,2=POS02,3=POS03,4=POS04"
                        "5=POS05,6=POS06,7=POS07,8=POS08,9=POS09"
                        "10=POS10,11=POS11,12=POS12,13=POS13,14=POS14"
                        "15=POS15,16=POS16,17=POS17,18=POS18,19=POS19"
                        "20=POS20,21=POS21,22=POS22,23=POS23,24=POS24"
                        "25=POS25,26=POS26,27=POS27,28=POS28,29=POS29,30=POS30"
    TABLE tVideoTest    "NRM=00,625.1=01,625.2=02,625.3=03,625.4=04,625.5=05"
                        "625.6=06,625.7=07,625.8=08,625.9=09,625.10=10,625.11=11"
                        "625.12=12,625.13=13,625.14=14,625.15=15,625.16=16"
                        "525.1=17,525.2=18,525.3=19,525.4=20,525.5=21,525.6=22"
                        "525.7=23,525.8=24,525.9=25,525.10=26,525.11=27,525.12=28"
                        "525.13=29,525.14=30,525.15=31,525.16=32"
    TABLE tTsRouting    "PRE-CA=PRE,POST-CA=PST"
    TABLE tTsFibre      "ON=ENA,OFF=DIS"
    TABLE tAudioRouting "NRM=ST,MON=M1,LFT=M2,RGT=M3"
    TABLE tAudioOutput  "ANALOG=ANA,AES/EBU=PRO,SPDIF=SPD,AC3=AC3"
    TABLE tAudioTest    "NRM=0,TEST-1=1,TEST-2=2,TEST-3=3,TEST-4=4,TEST-5=5"
    TABLE tRasMode      "DISABLED=DIS,FIXED=FIX,DSNG=DSN,SEC-CA=SCA"
    TABLE tBissMode     "DISABLED=DIS,MODE 1=MO1,MODE E=MOE"
    TABLE tCaStatus     "UNKNOWN CODE=FF"
                        "CARD INSERTED=00"
                        "CARD REMOVED=01"
                        "CARD INVALID=04"
                        "SERVICE BLOCKED=05"
                        "INVALID PACKET=06"
                        "CARD UNAUTHORIZED=07"
                        "HARDWARE FAILURE=08"
                        "CLEAR BUT RESTRICTED=09"
                        "SERVICE BLACKED OUT=10"
                        "SERVICE EXPIRED=11"
                        "CA WARNING=12"
                        "CA WARNING=13"
                        "PAIRING ERROR=14"
                        "CA WARNING=15"
                        "CA WARNING=16"
                        "CA WARNING=17"
                        "CA WARNING=21"
                        "CA WARNING=22"
    TABLE tCaService    "UNKNOWN CODE=XXX"
                        "NO SERVICE SELECTED=NSS"
                        "CLEAR=CLR"
                        "RAS AUTHORIZED=RAS"
                        "RAS UNAUTHORIZED=RAU"
                        "BISS AUTHORIZED=BIA"
                        "BISS UNAUTHORIZED=BIU"
                        "VGUARD AUTHORIZED=GVA"
                        "VGUARD UNAUTHORIZED=VGU"
                        "NO CA INSTALLED=NCA"

    /** procedures  ***********************************************************/


    // called after sending a command to the IRD. checks the ACK response which is
    // expected.
    // 
    PROC SUBROUTINE getAck
        INPUT "=" TRM "_" internal.ack
        IF internal.ack = "ACK" GOTO endif
            SET faults.commstat = "ACK expected"
            SET faults.99 = "true"
        :endif


    // called if the number of l-band inputs gets changed. sets the range for the
    // "input" parameter
    //
    PROC PUT WATCH config.lbandInputs
        IF config.lbandInputs = "2" GOTO else
            RANGESET input CHOICES "1,2,3,4"
            GOTO endif
        :else
            RANGESET input CHOICES "1,2"
        :endif
        
    // this procedure is executed once after the communication to the receiver ahs
    // been established. it get the device identification parameters and sets the
    // LNB frequency according to the position of the input switch.
    // 
    PROC GET WATCH info.serial info.model
        PRINT "REM;MOD"
        INPUT "MOD=" TRM "_" info.model
        PRINT "REM;SNM"
        INPUT "SNM=" TRM "_" info.serial

    // reads the fault flags and derived the "LED flags" from these values
    //
    // 
    PROC GET WATCH flags.lock
        PRINT "OPR;SRQ"
        INPUT 
           "SIG="           state.signal
           "ALR=" TRM "_"   internal.flags
           "BER=" TRM "_"   state.ber
        BITSET faults.01 = internal.flags  4  // Temperature
        BITSET faults.02 = internal.flags  5  // Signal level
        BITSET faults.03 = internal.flags  11 // Video lock
        BITSET faults.04 = internal.flags  9  // Audio lock
        BITSET faults.05 = internal.flags  13 // High BER
        BITSET faults.06 = internal.flags  15 // Demodulator lock
        BITSET faults.07 = internal.flags  14 // Conditional Access
        IF faults.06 = "true" SET flags.lock = "false"
        IF faults.07 = "true" SET flags.ca = "false"
        IF faults.03 = "true" SET flags.video = "false"
        IF faults.04 = "true" SET flags.audio = "false"
        IF faults.05 = "true" SET flags.ber = "false"
        IF faults.06 = "false" SET flags.lock = "true"
        IF faults.07 = "false" SET flags.ca = "true"
        IF faults.03 = "false" SET flags.video = "true"
        IF faults.04 = "false" SET flags.audio = "true"
        IF faults.05 = "false" SET flags.ber = "true"


    // reads the service status message. this also is used to select a service
    // after the IRD has decoded the signal
    //
    PROC GET WATCH state.state
    {
        "SER;SRQ" prt inp
        "SRQ=" find ! state.state
        
        state.state "WAIT.PMT" = if
          internal.scnt 1 + !internal.scnt
          internal.scnt 6 > if
            "SER;SEL=00" prt inp
          else
            internal.scnt 3 > if
              "SER;SEL=" programNo "d02" fmt strcat prt inp
            endif
          endif
        else
          0 !internal.scnt
        endif
    }    

    // reads the information from the TUN:SRQ request.
    // 
    PROC GET WATCH 
        input frequency modulation polarization
        config.lnbPower config.loFreq
        PRINT "TUN;SRQ"
        INPUT 
            "FRQ=" SCALE 0.125            frequency
            "LNB=" SCALE 0.125            config.loFreq
            "PWR=" CUT 3                  config.lnbPower
            "POL=" CUT 3                  polarization
            "RFI=" CUT 1                  input
            "MOD=" CUT 3 XLT tModulation  modulation
        DRATE dataRate = symbolRate modulation fec "188"

    // sets the RF input and the frequency. we switch both together to ensure that
    // the input is set before the frequency is tuned.
    // 
    PROC PUT WATCH input frequency
        PRINT "TUN;RFI=NO " input
        CALL getAck
        DELAY 3.0
        PRINT "TUN;FRQ=" SCALE 8.0 FMT "d06" frequency
        CALL getAck

    // sets LO frequency (of the input actually set)
    // 
    PROC PUT WATCH config.loFreq
        PRINT "TUN;LNB=" SCALE 8.0 FMT "d06" config.loFreq
        CALL getAck

    // sets the modulation type
    // 
    PROC PUT WATCH modulation
        PRINT "TUN;MOD=" XLT tModulation modulation
        CALL getAck

    // sets the polarization by a 22kHz pulse
    // 
    PROC PUT WATCH polarization
        PRINT "TUN;POL=" polarization
        CALL getAck

    // reads the information from the DEM;SRQ request.
    // 
    PROC GET WATCH fec symbolRate config.berThreshold config.sigThreshold
        PRINT "DEM;SRQ"
        INPUT 
            "FEC=" CUT 3                 fec
            "SYM=" TRM "_" SCALE 0.0001  symbolRate
            "BER=" TRM "_"               config.berThreshold
            "SIG=" CUT 3                 config.sigThreshold
        DRATE dataRate = symbolRate modulation fec "188"

    // sets the symbol rate
    // 
    PROC PUT WATCH symbolRate
        PRINT "DEM;SYM=" SCALE 10000.0 FMT "d06" symbolRate
        CALL getAck

    // sets the FEC
    // 
    PROC PUT WATCH fec
        PRINT "DEM;FEC=" fec
        CALL getAck

    // sets the BER threshold configuration parameter
    // 
    PROC PUT WATCH config.berThreshold
        PRINT "DEM;BER=" config.berThreshold
        CALL getAck

    // sets the signal level configuration parameter
    // 
    PROC PUT WATCH config.sigThreshold
        PRINT "DEM;SIG=" FMT "d03" config.sigThreshold
        CALL getAck

    // sets the LNB power configuration parameter
    // 
    PROC PUT WATCH config.lnbPower
        PRINT "TUN;PWR=" config.lnbPower
        CALL getAck

    ///////////////////// VIDEO PARAMETERS /////////////////////////

    // gets the video state (and the video settings)
    // 
    PROC GET WATCH video.fmt625 video.fmt525 video.level video.test
                   state.aspect state.lines config.errFrame
        PRINT "VID;SRQ"
        INPUT 
            "625=" TRM "_" video.fmt625
            "525=" TRM "_" video.fmt525
            "ERR=" TRM "_" XLT tErrFrame config.errFrame
            "LVL=" TRM "_" XLT tVideoLevel video.level
            "OPS=" TRM "_" XLT tVideoTest video.test
            "VLS=" TRM "_" state.lines
            "SAR=" TRM "_" state.aspect

    // sets the 625 lines default video mode
    // 
    PROC PUT WATCH video.fmt625
        PRINT "VID;625=" video.fmt625
        CALL getAck

    // sets the 525 lines default video mode
    // 
    PROC PUT WATCH video.fmt525
        PRINT "VID;525=" video.fmt525
        CALL getAck
        
    // sets what to show is video is missing
    // 
    PROC PUT WATCH config.errFrame      
        PRINT "VID;ERR=" XLT tErrFrame config.errFrame
        CALL getAck

    // sets the video level
    // 
    PROC PUT WATCH video.level
        PRINT "VID;LVL=" XLT tVideoLevel video.level
        CALL getAck
        
    // sets the video test mode
    // 
    PROC PUT WATCH video.test
        PRINT "VID;OPS=" XLT tVideoTest video.test
        CALL getAck

    ////////////////////// AUDIO CHANNEL 1 //////////////////////////////

    // gets the audio channel 1 parameters
    // 
    PROC GET WATCH audio.1.routing audio.1.output audio.1.level audio.1.language
        audio.1.test audio.1.info
        PRINT "AUD;SRQ"
        INPUT
            "ROU="  CUT 2 XLT tAudioRouting audio.1.routing
            "LEV=M" CUT 2 audio.1.level
            "OUT="  CUT 3 XLT tAudioOutput audio.1.output
            "DFL="  CUT 3 audio.1.language
            "OPS="  CUT 1 XLT tAudioTest audio.1.test
            "CLN="  audio.1.info
            
    // set the audio channel 1 output routing
    // 
    PROC PUT WATCH audio.1.routing
        PRINT "AUD;ROU=" XLT tAudioRouting audio.1.routing
        CALL getAck

    // set the audio channel 1 level
    // 
    PROC PUT WATCH audio.1.level
        PRINT "AUD;LEV=M" FMT "d02" audio.1.level
        CALL getAck

    // set the audio channel 1 output (hardware)
    // 
    PROC PUT WATCH audio.1.output
        PRINT "AUD;OUT=" XLT tAudioOutput audio.1.output
        CALL getAck

    // set the audio channel 1 default language
    // 
    PROC PUT WATCH audio.1.language
        PRINT "AUD;DFL=" audio.1.language
        CALL getAck

    // set the audio channel 1 test mode
    // 
    PROC PUT WATCH audio.1.test
        PRINT "AUD;OPS=" XLT tAudioTest audio.1.test
        CALL getAck


    ////////////////////// AUDIO CHANNEL 2 //////////////////////////////

    // gets the audio channel 2 parameters
    // 
    PROC GET WATCH audio.2.routing audio.2.output audio.2.level audio.2.language
        audio.2.test audio.2.info
        PRINT "AU2;SRQ"
        INPUT
            "ROU="  CUT 2 XLT tAudioRouting audio.2.routing
            "LEV=M" CUT 2 audio.2.level
            "OUT="  CUT 3 XLT tAudioOutput audio.2.output
            "DFL="  CUT 3 audio.2.language
            "OPS="  CUT 1 XLT tAudioTest audio.2.test
            "CLN="  audio.2.info
            
    // set the audio channel 2 output routing
    // 
    PROC PUT WATCH audio.2.routing
        PRINT "AU2;ROU=" XLT tAudioRouting audio.2.routing
        CALL getAck

    // set the audio channel 2 level
    // 
    PROC PUT WATCH audio.2.level
        PRINT "AU2;LEV=M" FMT "d02" audio.2.level
        CALL getAck

    // set the audio channel 2 output (hardware)
    // 
    PROC PUT WATCH audio.2.output
        PRINT "AU2;OUT=" XLT tAudioOutput audio.2.output
        CALL getAck

    // set the audio channel 2 default language
    // 
    PROC PUT WATCH audio.2.language
        PRINT "AU2;DFL=" audio.2.language
        CALL getAck

    // set the audio channel 2 test mode
    // 
    PROC PUT WATCH audio.2.test
        PRINT "AU2;OPS=" XLT tAudioTest audio.2.test
        CALL getAck


    //////////////////// TRANSPORT STREAM OUTPUT ////////////////////////

    // reads the transport stream parameters
    // 
    PROC GET WATCH tsout.routing tsout.fibre
        PRINT "TSO;SRQ"
        INPUT
            "CAM=" CUT 3 XLT tTsRouting tsout.routing
            "ENA=" CUT 3 XLT tTsFibre   tsout.fibre

    // sets the transport stream pre/post CA routing
    // 
    PROC PUT WATCH tsout.routing
        PRINT "TSO;CAM=" XLT tTsRouting tsout.routing
        CALL getAck

    // enables / disable the ASI fibre output
    // 
    PROC PUT WATCH tsout.fibre
        PRINT "TSO;ENA=" XLT tTsFibre tsout.fibre
        CALL getAck

    //////////////////// CONDITIONAL ACCESS /////////////////////////////


    // reads the conditional access parameters. uses an RPN command sequence for
    // this as - depending on the purchased configuration - the Alteia does not
    // report all of these parameters all the time. RPN assigns empty strings to
    // parameters which do not exist in the reply.
    // 
    PROC GET WATCH ca.status ca.rasmode ca.bissmode 
        ca.dsngkey ca.bisskey1 ca.bisskey2 ca.bissbits
    {
        "CAS;SRQ" prt inp
        dup "CSS=" find "_" trm tCaService rxlt ! ca.service
        dup "CST=" find "_" trm tCaStatus rxlt ! ca.status
        dup "CID=" find "_" trm ! info.ca.casid
        dup "CAC=" find "_" trm ! info.ca.codeversion
        dup "BCV=" find "_" trm ! info.ca.bootversion
        dup "CMN=" find "_" trm ! info.ca.modelno
        dup "CHT=" find "_" trm ! info.ca.hardware
        dup "CMA=" find "_" trm ! info.ca.manufacturer
        dup "CDS=" find "_" trm ! info.ca.download
        dup "RAM=" find "_" trm ! tRasMode rxlt ca.rasmode
        dup "BIS=" find "_" trm ! tBissMode rxlt ca.bissmode
        dup "BM1=" find "_" trm ! ca.bisskey1
        dup "BM2=" find "_" trm ! ca.bisskey2
        dup "BKE=" find "_" trm ! ca.bissbits
        dup "DSK=" find "_" trm ! ca.dsngkey
        clr
    }

    // sets the RAS mode parameter
    // 
    PROC PUT WATCH  ca.rasmode
        PRINT "CAS;RAM=" XLT tRasMode ca.rasmode
        CALL getAck

    // sets the DSNG key used with one of the RAS modes
    // 
    PROC PUT WATCH  ca.dsngkey
        PRINT "CAS;DSK=" ca.dsngkey
        CALL getAck

    // sets the BISS mode parameter
    // 
    PROC PUT WATCH  ca.bissmode
        PRINT "CAS;BIS=" XLT tBissMode ca.bissmode
        CALL getAck

    // sets the BISS mode 1 key
    // 
    PROC PUT WATCH  ca.bisskey1
        PRINT "CAS;BM1=" ca.bisskey1
        CALL getAck

    // sets the BISS mode 2 key
    // 
    PROC PUT WATCH  ca.bisskey2
        PRINT "CAS;BM2=" ca.bisskey2
        CALL getAck

    // sets the BISS key length for modes 2/3
    // 
    PROC PUT WATCH  ca.bissbits
        PRINT "CAS;BKE=" ca.bissbits
        CALL getAck

    ////////////////// SERVICE SELECTION ////////////////////////////////


    // reads the name of the actually selected service
    // 
    PROC GET WATCH actualProgram
        PRINT "ENQ;NAM"
        INPUT "NAM=" actualProgram
        

    // reads the service list (the bouquet) from the IRD and distributes the list
    // as the variable programList. this proc is completely written in RPN language
    // as this supports more flexible building the list from the particular
    // entries.
    // 
    PROC GET WATCH programList 
    {

        state.state "WAIT.DEM" = if               // in WAIT.DEM state,
          0 !internal.numServices                 // no services are available
        else
          "ENQ;NUM" prt                           // request the number of
          inp "=" find                            // services, get the reply
          !internal.numServices                   // and store it
        endif
        
        internal.numServices if
          "ENQ;NET" prt inp "NET=" find           // network name
          "\n" strcat                             // as the first line of the list
          0                                       // loop counter
          do
            "ENQ;SER=" over "d02" fmt strcat prt  // request one entry
            swap                                  // get the list on top
            inp "=" find dup                      // get the reply (2x)
            "," trm                               // the service index
            " " strcat                            // append " " to it
            swap "," find strcat                  // append the service name
            strcat                                // append list entry
            "\n" strcat                           // trailing NL
            swap                                  // loop counter on top
            1 +                                   // increment it
            internal.numServices 1 -              // decrement numServices,
            !internal.numServices                 // loop until there are more
          internal.numServices while              // services
          drop                                    // the loop counter
        else
          "NO PROGRAMS AVAILABLE\n"
        endif
        !programList
        clr                                       // due to paranoia ;-)
    }


    // selects a service. 
    // 
    PROC PUT WATCH programNo
        PRINT "SER;SEL=" FMT "d02" programNo
        CALL getAck


    // reads the audio list of the actually selected service from the IRD and 
    // distributes the list as the variable audioList. this proc is completely 
    // written in RPN language as this supports more flexible building the list
    // from the particular entries.
    // 
    PROC GET WATCH audioList 
    {
        "ENQ;AUN" prt                             // request the number of
        inp "=" find                              // audio streams, get the reply
        !internal.numAudio                        // and store it

        internal.numAudio if
          ""                                      // audio stream list
          0                                       // loop counter
          do
            "ENQ;AUX=" over "d04" fmt strcat prt  // request one entry
            swap                                  // get the list on top
            inp "=" find                          // the complete entry
            dup "," trm 2 substr                  // entry number 2 digits
            " " strcat                            // delimiter
            swap "," find "," find                // language description
            strcat strcat "\n" strcat             // append the reply
            swap                                  // loop counter on top
            1 +                                   // increment it
            internal.numAudio 1 -                 // decrement numAudio,
            !internal.numAudio                    // loop until there are more
          internal.numAudio while                 // audio streams
          drop                                    // the loop counter
        else
          "NONE\n"
        endif
        !audioList
        clr                                       // due to paranoia ;-)
    }

    // selects the audio 1 stream
    // 
    PROC PUT WATCH audio.1.program
        PRINT "SER;A1L=" FMT "d05" audio.1.program
        CALL getAck

    // selects the audio 2 stream
    // 
    PROC PUT WATCH audio.2.program
        PRINT "SER;A2L=" FMT "d05" audio.2.program
        CALL getAck