esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%NAME% ID32SY127.MAC
#
#%DESCRIPTION%
# This file contains all macros for controlling the CAEN High Voltage
# multichannel supply (model SY127) through an RS232 serial line
#
# The serial line can be handled by a OS9 device server and a VME IBAM
# board.
#
# parameters for serial line : 9600b ; 7 bits; no parity.
#
# %BR% %BR%
# These macros have been tested with 20 channels installed on a SY127
# controller.
# %BR% %BR%
# Last Modifications : %BR%
#
# TODO : change for a macro motors.
#
#%BR% 08/12/98 (MP) Initial Revision
#

global SY127_DBG
global SY127_SERDEV
global SY127_CH
global SY127_TO_OLD
global SY127_LIST
global SY127_ON

global SL_RAW
global SL_LINE

global ESRF_ERR_MSG



######################################################################
##############################          ##############################
##############################  CONFIG  ##############################
##############################          ##############################
######################################################################

#%UU% <serial_ds_name>
#%MDESC%
# Must always be called in the setup of the SPEC session.
#
def sy127_setup'{
    local _argins

    printf ("CAEN SY127 ->")
    # set this variable to get debug messages
    SY127_DBG = 0

    # ???
    # values from serial line device server include file
    SL_RAW  = 0
    SL_LINE = 2

    # Configuration for SPEC
    SY127_CH = 0

    # Configuration for Serial line Device Server
    SY127_SERDEV = "$1"
    esrf_io(SY127_SERDEV, "tcp")

    # Decrease timeout for SPEC.
    SY127_TO_OLD = ser_par(SY127_CH, "timeout")
    ser_par(SY127_CH, "timeout", 0.4)

    # Decrease timeout for Device Server (cf in DSUG, SL_TIMEOUT=3)
    _argins[0] = 3
    _argins[1] = 0.2*256
    esrf_io(SY127_SERDEV, "DevSerSetParameter", _argins)

    # Initialize list used for controling channels as pseudomotors.
    list_init SY127_LIST

    printf (" Configured - serialline : %s\n", SY127_SERDEV)
}'


#%UU%
#%MDESC%
#    Removes cdefs and globals.
def sy127_unsetup '{
    local ii _mne

    for(ii=1 ; ii<= list_n(SY127_LIST) ; i++) {
        _mne = list_item(SY127_LIST, ii)
        cdef("", "", _mne, "delete")
    }

    cdef("----", "", "sy127", "delete");

    unglobal SY127_DBG
    unglobal SY127_SERDEV
    unglobal SY127_CH
    unglobal SY127_TO_OLD
    unglobal SY127_LIST
    unglobal SY127_ON

}'


#%UU% <mnemonic> <channel> <parameter>
#%MDESC%
# Add the definition of a SY127 %B%channel%B% as a pseudomotor %B%mnemonic%B%
# and select the %B%parameter%B% that will be changed.
#
def sy127_hvadd '{
    local _mne _ch _param

    if(SY127_SERDEV == "") {
        printf("Error, sy127_setup must be called before using $0, exiting\n")
        exit
    }

    _mne   = "$1"
    _ch    = $2
    _param = "$3"

    if(($# != 3) ||                                                     \
        ((_param!="v0") && (_param!="v1") && (_param!="i0") && (_param!="i1"))) {
           printf("Usage: $0 mnemonic channel parameter\n")
           printf("\tmnemonic  : name of the HV pseudomotor\n")
           printf("\tchannel   : on the SY127 (0 to 19)\n")
           printf("\tparameter : that will be changed (v0, v1, i0, i1)\n")
           exit
    }

    list_add(SY127_LIST, _mne)
    list_setpar(SY127_LIST, _mne, "ch", _ch)
    list_setpar(SY127_LIST, _mne, "param", _param)

    if(list_n(SY127_LIST) == 1) {
        blmenuadd("SY127 HV pseudomotors", "", "sy127_body", "_sy127_")
    }

}'

#%UU% <mnemonic>
#%MDESC%
# Switch ON the channel associated with the HV pseudomotor %B%mnemonic%B%
#
def sy127_hvon '{

    if($# != 1) {
       printf("Usage: $0 mnemonic\n")
       printf("\tmnemonic: name of the HV pseudomotor\n")
       exit
    }

    sy127_hvonoff $1 "on"

}'

#%UU% <mnemonic>
#%MDESC%
# Switch OFF the channel associated with the HV pseudomotor %B%mnemonic%B%
#
def sy127_hvoff '{

    if($# != 1) {
       printf("Usage: $0 mnemonic\n")
       printf("\tmnemonic: name of the HV pseudomotor\n")
       exit
    }

    sy127_hvonoff $1 "off"
}'

#%IU% on|off mnemonic
#%MDESC%
# Switch ON or OFF the channel associated with the HV pseudomotor
# %B%mnemonic%B%.
#
def sy127_hvonoff '{
 local mne
 local cmd

 cmd = "$2"
 if(($# != 2) || ((cmd != "on") && (cmd != "off"))) {
     printf("Usage: $0 mnemonic on|off\n")
     printf("\tmnemonic: name of the HV pseudomotor\n")
     exit
 }

 mne = "$1"
 if(motor_num(mne) == -1) {
     printf("Unknown motor %s, exiting\n", mne)
     exit
 }

 if(list_n(SY127_LIST) <= 0) {
     printf("Error, sy127_hvadd must be called before using $0, exiting\n")
     exit
 }

 if(!SY127_ON) {
     printf("Error, HV pseudomotors have to be activated using blmenu, exiting\n")
     exit
 }

 ch = list_getpar(SY127_LIST, mne, "ch")
 sy127_write_f(ch, "status", cmd)
}'

#%UU%
#%MDESC%
# Shows, for all the HV pseudomotors defined, the status of their associated
# channels.
#
def sy127_hvshow '{
    local no ch ii

    if(!SY127_ON) {
        print "Error, HV pseudomotors have to be activated using blmenu, exiting."
        exit
    }

    no = list_n(SY127_LIST)
    if(no <= 0) {
        print "Error, sy127_hvadd must be called before using $0, exiting."
        exit
    }

    printf("%10s \t%s\n\n", "motor", "HV status")

    for(i=1 ; i<=no ; i++) {
        mne = list_item(SY127_LIST, i)
        ch = list_getpar(SY127_LIST, mne, "ch")
        printf("%10s \t%s\n", mne, sy127_read_f(ch, "status"))
    }
}'


#%IU%
#%MDESC%
# Activate use of SY127 HV channel pseudomotors.
#
def sy127_on '{
    local no
    local i
    local mne

    no = list_n(SY127_LIST)

    for(ii=1;ii <= no;ii++) {
        mne = list_item(SY127_LIST, ii)

        cdef("user_checkall",   sprintf("sy127_checkall %s\n",   mne), mne, 0x01)
        cdef("user_getpangles", sprintf("sy127_getpangles %s\n", mne), mne, 0x01)
    }

    cdef("user_prescan_head", "sy127_prescan_head", "sy127", 0);

    SY127_ON = 1
}'


#%IU%
#%MDESC%
# Desactivate use of SY127 HV channel pseudomotors.
#
def sy127_off '{
    local no
    local i
    local mne

    no = list_n(SY127_LIST)
    for(i=1;i <= no;i++) {
        mne = list_item(SY127_LIST, i)

        cdef("------", "", mne, "delete")
    }

    cdef("-------", "", "sy127", "delete");

    SY127_ON = 0
}'


#%IU%
#%MDESC%
# Called by blmenu.
#
def sy127_body(mode) '{

    if (mode == 1) {
        if (SY127_ON)
            sy127_off
        else
            sy127_on
    }

    return(SY127_ON?"On":"Off")
}'


######################################################################
########################                       #######################
########################  SCAN RELATED MACROS  #######################
########################                       #######################
######################################################################

#%IU%
#%MDESC%
# Called once at the begining of any scan to check if HV has been enabled.
#
def sy127_prescan_head'{
    local i num mne

    if(list_n(SY127_LIST) <= 0) {
        print "Error, sy127_hvadd must be called before using HV pseudomotors"
        print "\t->Exiting"
        exit
    }

    if(!SY127_ON) {
        printf("Error, HV pseudomotors have to be activated using blmenu, exiting\n")
        exit
    }

    # Check for each motor used for the scan.
    for(i=0; i < _nm;i++) {
        num = _m[i]
        mne = motor_mne(num)
        ch  = list_getpar(SY127_LIST, mne, "ch")

        if(sy127_read_f(ch, "status") != "ON") {
            printf("Error, sy127_hvon must be called before using %s, exiting\n", \
                   mne)
            exit
        }
    }
}'

#%IU% mnemonic
#%MDESC%
#
def sy127_checkall '{
    local old_pos
    local mne
    local num
    local ch
    local param


    mne = "$1"
    num = motor_num(mne)

    # check if we need to move
    old_pos = list_getpar(SY127_LIST, mne, "pos")
    if (A[num] != old_pos) {
        # select the SY127 channel and the parameter to change
        ch    = list_getpar(SY127_LIST, mne, "ch")
        param = list_getpar(SY127_LIST, mne, "param")
        sy127_write_f(ch, param, A[num])

        list_getpar(SY127_LIST, mne, "pos", A[num])
    }

}'

#%IU% mnemonic
#%MDESC%
#
def sy127_getpangles'{
    local newpos
    local mne
    local num

    mne = "$1"
    num = motor_num(mne)

    # select the SY127 channel and the parameter to change
    ch    = list_getpar(SY127_LIST, mne, "ch")
    param = list_getpar(SY127_LIST, mne, "param")
    newpos = sy127_read_f(ch, param)

    A[num] = newpos
    list_getpar(SY127_LIST, mne, "pos", newpos)
}'


######################################################################
#######################                        #######################
#######################  COMMUNICATION MACROS  #######################
#######################                        #######################
######################################################################


#%IU%
#%MDESC%
def sy127_flush'{
    ESRF_ERR = -1
    while(esrf_io(SY127_SERDEV, "DevSerReadString", SL_RAW) != "");
}'

#%IU%
#%MDESC%
# Used to communicate directly with the SY127 and its menus.
#
def sy127_talk'{
    local userkey
    local answerkey
    local one_char
    local SY127_SERDEV

    global NCHAR
    NCHAR = 0

    printf("\nTo exit terminal mode type <Ctrl-C>\n\n")

    while(1) {
        userkey = input(-1)
        if(userkey != "") {
            if(userkey == "\n") userkey = "\r";

            if(esrf_io(SY127_SERDEV, "DevSerWriteString", userkey) == -1) {
                printf("\nArret Ecriture char by char\n")
                exit
            }
        }

        answerkey = esrf_io(SY127_SERDEV, "DevSerReadString", SL_RAW)
        NCHAR += length(answerkey)

        # Needed to not loose characters, min 0.02
        sleep(0.02)

        if(answerkey != "") {
            printf("%s", answerkey)
        }
    }
}'

#%IU%
#%MDESC%
# Read from serialline a single line but with error checking.
#
def sy127_readline()'{
    local _linerd

    ESRF_ERR     = -1
    ESRF_ERR_MSG = ""

    _linerd = esrf_io(SY127_SERDEV, "DevSerReadString", SL_LINE)
    # if(SY127_DBG) { printf ("Line read: %s\n", _linerd)}

    # sleep(0.14)

    # if it was DevErr_DeviceRead error then retry
    if((ESRF_ERR == 75) || (ESRF_ERR == 2)) {
        if(SY127_DBG) print "Error 75 or 2, retrying";

        sleep(1)
        ESRF_ERR     = -1
        ESRF_ERR_MSG = ""

        _linerd = esrf_io(SY127_SERDEV, "DevSerReadString", SL_LINE)
        #sleep(0.14)
    }

    # if it was DevErr_DeviceTimedOut error then stop, nothing else to read
    if((ESRF_ERR == 75) || (ESRF_ERR == 2)) {
        if(SY127_DBG) print "Page read";
        sy127_flush
#    sleep(0.14)
        return("")
    }

    if(ESRF_ERR) {
        printf("SY127 : exiting, ESRF_ERR: %d (0x%x)\n", ESRF_ERR, ESRF_ERR)
        print ESRF_ERR_MSG
        exit
    }

    return(_linerd)
}'

#%IU%
#%MDESC%
# Read from serialline a single line but without error checking
#
def sy127_readline2()'{
    local _linerd

    ESRF_ERR     = -1
    ESRF_ERR_MSG = ""
    _linerd      = esrf_io(SY127_SERDEV, "DevSerReadString", SL_LINE)

    return(_linerd)
}'

#%IU% string_to_find
#%MDESC%
#
def sy127_findinline(tofind)'{
    local answerline

    answerline = ""
    answerline = sy127_readline()

    if(SY127_DBG) {
        printf("%d:%s\n", length(answerline), answerline)
    }

    while(!index(answerline, tofind) && (answerline != "")) {
        answerline = sy127_readline()
        if(SY127_DBG) printf("%d:%s\n", length(answerline), answerline);
    }

    if(answerline != ""){
        return(answerline)
    }
    else{
        return("")
    }
}'

#%UU%
#%MDESC%
# Read for all the channels available all their parameters.
#
def sy127_readall'{
    local one_line
    local _wdog


    if(SY127_SERDEV == "") {
        printf("Error, sy127_setup must be called before using $0, exiting\n")
        exit
    }

    # go back to main menu
    if(SY127_DBG) print "go back to main menu";
    ser_put(SY127_CH, "1")
    sy127_flush

    # get in the DISPLAY STATUS menu
    if(SY127_DBG){
        print "get in the DISPLAY STATUS menu"
    }

    ser_put(SY127_CH, "a")

    _wdog = 10
    while(((one_line=sy127_findinline("GROUP ALL")) == "") && _wdog)
    {
        # get next group
        if(SY127_DBG) print "not found, changing group ";
        ser_put(SY127_CH, "r")
        _wdog -= 1
    }

    if(!_wdog) {
        printf("Unable to find GROUP ALL, exiting\n")
        exit
    }

    _wdog = 2

    while(_wdog) {
        if((one_line=sy127_findinline("CH")) == "") {
            printf("No channel not found, exiting\n")
            exit
        }

        if(index(one_line, "CH00")) {
            if(_wdog == 1) {
                _wdog = 0
            }
            if(_wdog == 2) {
                _wdog = 1
                print "           VMON  IMON    V0     V1    I0    I1    RUP   RDW TRIP  STATUS"
            }
        }

        if(_wdog) {
            printf("%s", one_line);

            for(i=0;i<9;i++) {
                one_line = sy127_readline()
                printf("%s", one_line);
            }

            # get the NEXT PAGE
            if(SY127_DBG) {
                print "get the NEXT PAGE"
            }
            ser_put(SY127_CH, "p")
        }
    }

}'


#%UU% channel parameter
#%MDESC%
# Read for the specified %B%channel%B% the %B%parameter%B% specified.
#
def sy127_read'{
    local ch
    local param_name

    if(SY127_SERDEV == "") {
        printf("Error, sy127_setup must be called before using $0, exiting\n")
        exit
    }

    ch = $1
    param_name = "$2"
    if($#!=2) {
       printf("Usage: $0 channel_number parameter_to_read\n")
       printf("\tchannel_number: 0 to 19\n")
       printf("\tparameter_to_read: vmon, imon, v0, v1, i0, i1, rup, rdw, status\n")
       exit
    }

    if((ch<0) || (ch>19)) {
        printf("1st argument not correct, allowed values are:\n")
        printf("\tchannel_number: 0 to 19\n")
        exit
    }

    if((param_name != "vmon") &&                \
       (param_name != "imon") &&                \
       (param_name != "v0")   &&                \
       (param_name != "v1")   &&                \
       (param_name != "i0")   &&                \
       (param_name != "i1")   &&                \
       (param_name != "rup")  &&                \
       (param_name != "rdw")  &&                \
       (param_name != "status"))  {
        printf("2nd argument not correct, allowed values are:\n")
        printf("\tparameter_to_read: vmon, imon, v0, v1, i0, i1, rup, rdw, status\n")
        exit
    }

    print sy127_read_f(ch, param_name)
}'

#%IU%
#
#
def sy127_read_f(ch, param_name) '{
    local one_line
    local ch_name
    local params
    local param
    local _wdog

    param = 0
    if(param_name == "vmon")   param = 1;
    if(param_name == "imon")   param = 2;
    if(param_name == "v0")     param = 3;
    if(param_name == "v1")     param = 4;
    if(param_name == "i0")     param = 5;
    if(param_name == "i1")     param = 6;
    if(param_name == "rup")    param = 7;
    if(param_name == "rdw")    param = 8;
    if(param_name == "status") param = 10;

    # go back to main menu.
    if(SY127_DBG) { print "go back to main menu" }
    ser_put(SY127_CH, "1")
    sy127_flush
    sleep(0.14)

    # get in the DISPLAY STATUS menu.
    if(SY127_DBG) { print "get in the DISPLAY STATUS menu" }
    ser_put(SY127_CH, "a")
    sleep(1.14)

    _wdog = 10

    while(((one_line = sy127_findinline("GROUP ALL")) == "") && _wdog) {
        # get next group
        if(SY127_DBG) {print "not found, changing group "}
        ser_put(SY127_CH, "r")
        _wdog -= 1
        sleep(0.314)
    }

    sleep(0.14)

    if(!_wdog) {
        printf("Unable to find GROUP ALL, exiting\n")
        exit
    }
    else{
        if(SY127_DBG) {print "SY127 : ok :  GROUP ALL found "}
    }

    ch_name = sprintf("CH%02d", ch)

    if(SY127_DBG) {printf ("SY127 : ch_name = %s \n", ch_name)}

    # only 9 channels display on a page
    if(ch > 9) {
        # get next page
        if(SY127_DBG) { print "greater than 9, changing page"}
        ser_put(SY127_CH, "p")
        sleep(0.314)
    }

    if((one_line = sy127_findinline(ch_name)) == "") {
        printf("Channel %s not found, exiting\n", ch_name)
        exit
    }

    if(SY127_DBG) {
        print one_line
    }

    split(one_line, params)
    return(params[param])
}'

#%UU% <channel> <parameter> <value>
#%MDESC%
# Set for the specified %B%channel%B%, the specified %B%parameter%B% with
# the %B%value%B% given.
#
def sy127_write'{
    local args
    local ch
    local param_name
    local var

    if(SY127_SERDEV == "") {
        printf("Error, sy127_setup must be called before using $0, exiting\n")
        exit
    }

    if($#!=3) {
       printf("Usage: $0 channel_number parameter_to_write value\n")
       printf("\tchannel_number: 0 to 19\n")
       printf("\tparameter_to_read: v0, v1, i0, i1, rup, rdw, status\n")
       printf("\tvalue: value to set (number or on, off)\n")
       exit
    }

    split("$*", args)
    sscanf(args[0], "%d", ch)

    if((ch<0) || (ch>19)) {
        printf("1st argument not correct, allowed values are:\n")
        printf("\tchannel_number: 0 to 19\n")
        exit
    }

    param_name = args[1]
    if((param_name != "v0")                     \
       && (param_name != "v1")                  \
       && (param_name != "i0")                  \
       && (param_name != "i1")                  \
       && (param_name != "rup")                 \
       && (param_name != "rdw")                 \
       && (param_name != "status")) {
        printf("2nd argument (%s) not correct, allowed values are:\n", param_name)
        printf("\tparameter_to_read: v0, v1, i0, i1, rup, rdw, status\n")
        exit
    }

    if(param_name == "status") {
        var = args[2]
    }
    else {
        sscanf(args[2], "%d", var)
    }

    sy127_write_f(ch, param_name, var)
}'

#%IU%
#
#
def sy127_write_f(ch, param_name, var)'{
    local one_line
    local bidon
    local ch_name
    local param
    local var_name
    local i

    param = ""

    if(param_name == "v0")     param = "c";
    if(param_name == "v1")     param = "d";
    if(param_name == "i0")     param = "f";
    if(param_name == "i1")     param = "g";
    if(param_name == "rup")    param = "i";
    if(param_name == "rdw")    param = "j";
    if(param_name == "status") param = "n";

    # get out of any input case
    if(SY127_DBG) {
        print "get out of any input case"
    }

    ser_put(SY127_CH, "\r")
    sy127_flush

    # go back to main menu
    if(SY127_DBG) {
        print "go back to main menu"
    }
    ser_put(SY127_CH, "1")
    sy127_flush

    # get in the MODIFY PARAMETERS menu
    if(SY127_DBG) {
        print "get in the MODIFY PARAMETERS menu"
    }

    ser_put(SY127_CH, "b")
    sy127_flush

    # get in the SINGLE CHANNEL menu
    if(SY127_DBG) {
        print "get in the SINGLE CHANNEL menu"
    }
    ser_put(SY127_CH, "a")
    sy127_flush

    # get in the CHANNEL NAME selection
    if(SY127_DBG) {
        print "get in the CHANNEL NAME selection"
    }
    ser_put(SY127_CH, "a")
    sleep(1)

    # check that we are in the good location by getting the
    # current line (line not ended with CR or LF)
    one_line = ""
    bidon    = ""
    ESRF_ERR = -1

    while((bidon = esrf_io(SY127_SERDEV, "DevSerReadString", SL_RAW)) != ""){
        one_line = sprintf("%s%s", one_line, bidon)
    }

    #bidon=esrf_io(SY127_SERDEV, "DevSerReadString", SL_RAW)
    #one_line = sprintf("%s%s", one_line, bidon);

    if(SY127_DBG) {
        printf("Current line: \n%s\n", one_line)
    }

    if(!index(one_line, "CHANNEL NAME [CH")) {
        print date()
        printf("Expected line \"CHANNEL NAME [CH\" not found, exiting\n")
        printf("Current line: \n%s\n", one_line);
        exit
    }

    # select the channel requested (char by char, to give time for reception)
    ch_name = sprintf("CH%02d\r", ch)
    if(SY127_DBG) {
        printf("select the channel %s\n", ch_name)
    }

    for(i=1;i<=length(ch_name);i++){
        ser_put(SY127_CH, substr(ch_name, i, 1))
    }
    sy127_flush

    # no value to send for changing channel status
    if(param_name == "status") {
        if((one_line=sy127_findinline("STATUS")) == "") {
            print date()
            printf("Expected line STATUS not found, exiting\n")
            exit
        }

        if((index(one_line, "ON")  && (var == "off")) ||        \
           (index(one_line, "OFF") && (var == "on")))  {
            # switch the current status of the channel
            if(SY127_DBG) printf("select the parameter to modify, sending _%s_\n", param);
            ser_put(SY127_CH, param)
        }

        sy127_flush
        exit
    }

    # select the parameter to modify
    if(SY127_DBG) printf("select the parameter to modify, sending _%s_\n", param);
    ser_put(SY127_CH, param)

    # get the input line prompt
    one_line = ""
    bidon    = ""
    ESRF_ERR = -1

    while((bidon=esrf_io(SY127_SERDEV, "DevSerReadString", SL_RAW)) != ""){
        one_line = sprintf("%s%s", one_line, bidon)
    }

    if(SY127_DBG) printf("Current line: \n%s\n", one_line);

    if(!index(one_line, ":")) {
        print date()
        printf("Expected input line not found, exiting\n")
        printf("Current line: \n%s\n", one_line);
        exit
    }

    # set the new value (char by char, to give time for reception)
    var_name = sprintf("%d\r", var)
    if(SY127_DBG) printf("sending the string %s\n", var_name);

    for(i=1;i<=length(var_name);i++){
        ser_put(SY127_CH, substr(var_name, i, 1))
    }

    sy127_flush
}'

#%MACROS%
#%IMACROS%
#%AUTHORS% Manuel Perez


#------->   1

# MAIN MENU   H.S. CAENET  V1.2
#  SELECT OPTIONS
# 
# A  DISPLAY STATUS
# B  DISPLAY/MODIFY PARAMETERS
# C  FORMAT
# 
# E  STREAMER TUBES CONDITIONING
# 
# G  HV MODULES MAP
# 
# I  CRATE #[3]
# 
# 
# L  SET PROTECTIONS
# 
# N  CLEAR ALARM
# 
# 
# 
# 
# 
#  ALSO VALID   1=TOP     2=BACK




# -----> "A"

# DISPLAY STATUS
# 
# GROUP ALL       ACTIVE V0 I0    ; HV-ENABLE OFF
# 
#            VMON  IMON    V0     V1    I0    I1    RUP   RDW TRIP  STATUS RAMP
# 
# CH08        0.0   0.0  200.0    0.0 200.0 200.0  25.0  25.0   10  OFF
# CH09        1.5   0.1  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH10        0.0   0.0  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH11        1.5   0.1  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH12        0.0   0.0  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH13        1.5   0.4  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH14        0.0   0.3  200.0    0.0 100.0 100.0  50.0  50.0   10  OFF
# CH15        1.0   0.0  200.0    0.0 200.0 200.0  25.0  25.0   10  OFF
# CH16        0.0   0.0  200.0    0.0 200.0 200.0  25.0  25.0   10  OFF
# CH17        2.0   0.1  200.0    0.0 200.0 200.0  25.0  25.0   10  OFF
# 
# O  REDISPLAY
# P  NEXT PAGE
# Q  NEXT GROUP
# R  PREVIOUS GROUP
# 
#  ALSO VALID   1=TOP     2=BACK