Skip to content
Snippets Groups Projects
rs485_pulse_rtm.py 12.8 KiB
Newer Older
##_______________________________________________________________________________________________
##
##                                      CONV-TTL-RS485 PTS
##
##                                         CERN,BE/CO-HT
##_______________________________________________________________________________________________
##
##-----------------------------------------------------------------------------------------------
##
##                                     CONV-TTL-RS485 LEDs test
##
##-----------------------------------------------------------------------------------------------
##
## Description  Testing the rear-transition module interface of the CONV-TTL-RS485 front module
##              board. This is done in conjunction with gateware implemented on the
##              CONV-TTL-RS485 FPGA.
##
##              The gateware implements pulse repeaters which are controlled by this script to
##              send pulses back to inputs. Externally to the RTM, there should be two boards
##              containing differential multiplexers, and these are controlled by the FPGA HDL
##              through this script such that each channel sends pulses back to itself, in the
##              sequence O1->I, O2->I, O3->I.
##
##              In short, what this script does is to turn on pulse repetition, sleep for a
##              predefined amount of time, and then check that the same number of pulses that has
##              been sent at the channel output are received at its input. The checking is done by
##              reading the input and output channel pulse counters, implemented in the FPGA HDL.
##              Checking is done with input and output terminations ON and OFF (one run of the same
##              test sequence for both).
##
## Authors      Julian Lewis (Julian.Lewis@cern.ch)
##              Theodor-Adrian Stana (t.stana@cern.ch)
## Website      http://www.ohwr.org/projects/pts
## Date         11/11/2014
##-----------------------------------------------------------------------------------------------
##
##------------------------------------------------------------------------------------------------
##                               GNU LESSER GENERAL PUBLIC LICENSE
##                              ------------------------------------
## This source file is free software; you can redistribute it and/or modify it under the terms of
## the GNU Lesser General Public License as published by the Free Software Foundation; either
## version 2.1 of the License, or (at your option) any later version.
## This source 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 Lesser General Public License for more details.
## You should have received a copy of the GNU Lesser General Public License along with this
## source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html
##-------------------------------------------------------------------------------------------------
# Import system modules
import sys
sys.path.append("pyts")
import time

# Import common modules
from ptsexcept import *
from vv_pts import *
from ptsdefine import *

#--------------------------------------------------------------------------------------------------
# Pulse counter class
#--------------------------------------------------------------------------------------------------
class CPulseCounter:

    def __init__(self, bus, base):
        self.bus  = bus
        self.base = base

    def wr_reg(self, addr, val):
        self.bus.vv_write(self.base + addr,val)

    def rd_reg(self, addr):
        return self.bus.vv_read(self.base + addr)

    def wr_out_cnt(self, chan, val):
        return self.wr_reg((chan-1)*8, val)

    def wr_in_cnt(self, chan, val):
        return self.wr_reg((chan-1)*8 + 4, val)

    def rd_out_cnt(self, chan):
        return self.rd_reg((chan-1)*8)

    def rd_in_cnt(self, chan):
        return self.rd_reg((chan-1)*8 + 4)

#--------------------------------------------------------------------------------------------------
# Test sequences
#--------------------------------------------------------------------------------------------------
def mux_sel(bus, sel):
    val = bus.vv_read(CSR)
    val &= ~(1 << CSR_TESTER_MUX_S0_OFS)
    val &= ~(1 << CSR_TESTER_MUX_S1_OFS)
    if (sel & 0x1):
        val |= (1 << CSR_TESTER_MUX_S0_OFS)
    if (sel & 0x2):
        val |= (1 << CSR_TESTER_MUX_S1_OFS)
    bus.vv_write(CSR, val)

def en_pulse_gen(bus):
    val = bus.vv_read(CSR)
    val |= (1 << CSR_REAR_EN_OFS)
    bus.vv_write(CSR, val)

def dis_pulse_gen(bus):
    val = bus.vv_read(CSR)
    val &= ~(1 << CSR_REAR_EN_OFS)
    bus.vv_write(CSR, val)

def clear_counters(pc):
    # Clear pulse counters for the TTL channels
    for i in range(11, 17):
        pc.wr_out_cnt(i, 0)
        pc.wr_in_cnt(i, 0)

def check_counters(pc, inf, pel):
    ic_arr = []
    oc_arr = []
    for i in range(11, 17):
        ic_arr.append(pc.rd_in_cnt(i))
        oc_arr.append(pc.rd_out_cnt(i))
    for i in range(len(ic_arr)):
        if (ic_arr[i] == oc_arr[i]):
            msg = "Ch%d input counter (%d) matches the output counter (%d) - good\n" % (i+1,
                    ic_arr[i], oc_arr[i])
            inf.write(msg)
        else:
            msg = "ERROR: Ch%d input counter (%d) does not match output counter (%d)"% (i+1,
                    ic_arr[i], oc_arr[i])
            pel.set(msg)


##-------------------------------------------------------------------------------------------------
##                                             main                                              --
##-------------------------------------------------------------------------------------------------
def main(bus, tname, inf, log):

    """
    tests : RS-485 pulse repetition, RS-485 transceivers IC31-IC56,
            solid-state switches IC56-IC75, solid-state switches
            IC23-IC28, RS-485 transceivers IC16-IC21, Schmitt trigger
            inputs IC30, IC45, NAND gate IC8, IC69 Schmitt trigger for
            the RTM detection lines
    uses  : pts.bit and rs485_pulse_rtm.py
    """

    pel = PTS_ERROR_LOGGER(inf, log)

    try:
        # Read RTM lines
        rtm = (bus.vv_read(CSR) >> CSR_RTM_OFS) & 0x3f
        if (rtm == 0x09):
            msg = "RTM detection lines read correctly: 0x%02X" % rtm
            inf.write(msg+'\n')
        else:
            msg = "ERROR: RTM detection lines readout (0x%02X) incorrect - expected 0x09. Check RTM presence or IC69" % rtm
            pel.set(msg)
            return pel.get()
        # Initialize a pulse counter object
        pc = CPulseCounter(bus, PULSE_CNT_BASE)

        clear_counters(pc)

        # Ask the user to make the daisy-chain
        print("Connect the LEMO cable as follows:")
        print("  - BLU cable to INV-TTL CH A")
        print("  - GRN cable to INV-TTL CH B")
        print("  - RED cable to INV-TTL CH C")
        print("  - YEL cable to INV-TTL CH D")

        reply = raw_input("Have the connections been made? (yes/no) ")
        while (1):
            if "yes" in reply.lower():
                break
            if "no" in reply.lower():
                msg = "ERROR: Control connections to RS485 tester not made"
                pel.set(msg)
            else:
                reply = raw_input('Please type "yes" or "no" to continue: ')

        # Power on the tester card
        val = bus.vv_read(CSR)
        val |= (1 << CSR_TESTER_VCC_OFS)
        bus.vv_write(CSR, val)

    #---------------------------
    # Test with terminations OFF
    #---------------------------

        # Read out fail-safe lines -- should now be high, since the MUXes are
        # powered but not enabled
        val = bus.vv_read(LSR)
        val >>= LSR_REARFS_OFS
        if (val == 0x3f):
            msg = "RS-485 failsafe lines read as expected: 0x%02X\n" % val
            inf.write(msg)
        else:
            msg = "ERROR: Failsafe lines readout (0x%02X) incorrect - expected 0x3F" % val
            pel.set(msg)

        # Enable multiplexer
        print("Enabling multiplexers")
        val = bus.vv_read(CSR)
        val |= (1 << CSR_TESTER_MUX_EN_OFS)
        bus.vv_write(CSR, val)

        # Generate pulses from different outputs to inputs
        msg = "Testing channel connections (term. OFF): O1 -> I"
        print(msg)
        mux_sel(bus, 0x0)
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing channel connections (term. OFF): O2 -> I"
        print(msg)
        mux_sel(bus, 0x1)
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing channel connections (term. OFF): O3 -> I"
        print(msg)
        mux_sel(bus, 0x2)
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing RS-485 fail-safe on short-circuit case (term. OFF)"
        print(msg)
        mux_sel(bus, 0x3)
        inf.write(msg+'\n')
        val = bus.vv_read(LSR)
        val >>= LSR_REARFS_OFS
        if (val == 0x3f):
            msg = "RS-485 failsafe lines read as expected: 0x%02X\n" % val
            inf.write(msg)
        else:
            msg = "ERROR: Failsafe lines readout (0x%02X) incorrect - expected 0x3F" % val
            pel.set(msg)
        # Disable multiplexer
        print("Disabling multiplexers")
        val = bus.vv_read(CSR)
        val &= ~(1 << CSR_TESTER_MUX_EN_OFS)
        bus.vv_write(CSR, val)

    #--------------------------
    # Test with terminations ON
    #--------------------------
        # Read out fail-safe lines -- should now be high, since the MUXes are
        # powered but not enabled
        val = bus.vv_read(LSR)
        val >>= LSR_REARFS_OFS
        if (val == 0x3f):
            msg = "RS-485 failsafe lines read as expected: 0x%02X\n" % val
            inf.write(msg)
        else:
            msg = "ERROR: Failsafe lines readout (0x%02X) incorrect - expected 0x3F" % val
            pel.set(msg)

        inf.write('\n')

        msg = "Enabling input and output terminations"
        print(msg)
        inf.write(msg + '\n')
        bus.vv_write(TER, (0x3f << TER_OTERM_OFS) | (0x3f << TER_ITERM_OFS))
        time.sleep(2)

        # Enable multiplexer
        print("Enabling multiplexers")
        val = bus.vv_read(CSR)
        val |= (1 << CSR_TESTER_MUX_EN_OFS)
        bus.vv_write(CSR, val)

        # Generate pulses from different outputs to inputs
        msg = "Testing channel connections (term. ON): O1 -> I"
        print(msg)
        mux_sel(bus, 0x0)
        inf.write('\n')
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing channel connections (term. ON): O2 -> I"
        print(msg)
        mux_sel(bus, 0x1)
        inf.write('\n')
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing channel connections (term. ON): O3 -> I"
        print(msg)
        mux_sel(bus, 0x2)
        inf.write('\n')
        inf.write(msg+'\n')
        en_pulse_gen(bus)
        time.sleep(2)
        dis_pulse_gen(bus)
        check_counters(pc, inf, pel)
        clear_counters(pc)

        msg = "Testing RS-485 fail-safe on short-circuit case (term. ON)"
        print(msg)
        mux_sel(bus, 0x3)
        inf.write('\n')
        inf.write(msg+'\n')
        val = bus.vv_read(LSR)
        val >>= LSR_REARFS_OFS
        if (val == 0x3f):
            msg = "RS-485 failsafe lines read as expected: 0x%02X\n" % val
            inf.write(msg)
        else:
            msg = "ERROR: Failsafe lines readout (0x%02X) incorrect - expected 0x3F" % val
            pel.set(msg)

        # Disable multiplexer
        print("Disabling multiplexers")
        val = bus.vv_read(CSR)
        val &= ~(1 << CSR_TESTER_MUX_EN_OFS)
        bus.vv_write(CSR, val)

        return pel.get()

    except BusException, e:
        raise PtsError("SKT Exception: %s" % e)

    except BusWarning, e:
        raise PtsError("SKT Warning: %s" % e)

    finally:
        val = bus.vv_read(CSR)
        val &= ~(1 << CSR_TESTER_VCC_OFS)
        val &= ~(1 << CSR_TESTER_MUX_EN_OFS)
        val &= ~(1 << CSR_TESTER_MUX_S0_OFS)
        val &= ~(1 << CSR_TESTER_MUX_S1_OFS)
        bus.vv_write(CSR, val)