Skip to content

Commit

Permalink
Merge pull request #26 from SiLab-Bonn/development
Browse files Browse the repository at this point in the history
FIX: online monitor version and duplicate requirements
  • Loading branch information
leloup314 committed Oct 29, 2023
2 parents 2053e27 + 2c5ded5 commit 32b2b5e
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 58 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Software tests

on: push

jobs:
tests:
name: Test
runs-on: ubuntu-20.04
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- name: Set up Anaconda
uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
python-version: 3.9
- name: Install Conda dependencies
shell: bash -l {0}
run: |
conda info -a
conda install pytest numpy psutil qtpy pyyaml pyzmq pytables
- name: Install basil
shell: bash -l {0}
run: |
pip install basil-daq>=3.0.0
- name: Install Python dependencies
shell: bash -l {0}
run: |
pip install cocotb cocotb_bus xvfbwrapper pyqt5
- name: Install iverilog
run: |
sudo apt-get install -qq libhdf5-serial-dev libxkbcommon-x11-0
sudo apt-get install '^libxcb.*-dev'
# sudo apt-get -y install iverilog-daily
sudo apt-get install gperf
git clone https://github.com/steveicarus/iverilog.git
cd iverilog; autoconf; ./configure; make; sudo make install; cd ..
- name: Install EUDAQ
shell: bash -l {0}
run: |
source tests/setup_eudaq.sh
- name: Install package
shell: bash -l {0}
run: |
pip install -e .
- name: Test
shell: bash -l {0}
run: |
cd tests
pytest -s -v
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ output_data
*.lprof

*.history
.

sim_build
results.xml
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ Example:
pytlu -t 10000 -c 10000 -oe CH1 --timeout 2
```

## Test beam usage

A detailed description of the TLU can be found [here](https://www.eudet.org/e26/e28/e42441/e57298/EUDET-MEMO-2009-04.pdf). Do not forget to adjust the trigger threshold using the small screw on the front side of the TLU (counter clockwise increases the threshold).

## EUDAQ integration

Pytlu can connect to the data acquisition framework [EUDAQ 1](https://github.com/eudaq/eudaq/tree/v1.x-dev), which is the common run control software used at *pixel test beams*. For the installation of EUDAQ 1.x please follow this [wiki](https://telescopes.desy.de/EUDAQ). To use the EUDAQ libraries within pytlu a [python wrapper](https://github.com/eudaq/eudaq/blob/v1.x-dev/python/PyEUDAQWrapper.py) is used. This wrapper is not build with default settings, thus the following cmake option must be specified when building EUDAQ `-DBUILD_python=ON`.
Expand Down Expand Up @@ -150,8 +154,8 @@ If you did not add the EUDAQ directory to the `PYTHONPATH` explicitly after inst
pytlu_eudaq --path /home/user/git/eudaq
```

### Debugging and testing
#### Replay feature
## Debugging and testing
### Replay feature
It is possible to replay a recorded pytlu raw data file with correct timing to test the system. This allows development and debugging without hardware. To replay a [pytlu raw data file](https://github.com/SiLab-Bonn/pytlu/blob/development/data/tlu_example_data.h5) one has to type:

```
Expand Down
3 changes: 3 additions & 0 deletions firmware/src/tlu.v
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
`include "utils/ddr_des.v"
`include "utils/cdc_syncfifo.v"
`include "utils/generic_fifo.v"
`include "utils/ramb_8_to_n.v"

`include "gpio/gpio.v"
`include "gpio/gpio_core.v"


`include "i2c/i2c.v"
`include "i2c/i2c_core.v"
Expand Down
21 changes: 9 additions & 12 deletions pytlu/online_monitor/pytlu_receiver.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import time

from PyQt5 import Qt
from PyQt5 import QtWidgets
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from pyqtgraph.dockarea import DockArea, Dock
import pyqtgraph.ptime as ptime

from online_monitor.utils import utils
from online_monitor.receiver.receiver import Receiver
from zmq.utils import jsonapi


class PyTLU(Receiver):
Expand All @@ -26,17 +23,17 @@ def setup_widgets(self, parent, name):
dock_area.addDock(dock_status, 'top')

# Status dock on top
cw = QtGui.QWidget()
cw = QtWidgets.QWidget()
cw.setStyleSheet("QWidget {background-color:white}")
layout = QtGui.QGridLayout()
layout = QtWidgets.QGridLayout()
cw.setLayout(layout)
self.rate_label = QtGui.QLabel("Readout Rate\n0 Hz")
self.timestamp_label = QtGui.QLabel("Data Timestamp\n")
self.plot_delay_label = QtGui.QLabel("Plot Delay\n")
self.spin_box = Qt.QSpinBox(value=0)
self.rate_label = QtWidgets.QLabel("Readout Rate\n0 Hz")
self.timestamp_label = QtWidgets.QLabel("Data Timestamp\n")
self.plot_delay_label = QtWidgets.QLabel("Plot Delay\n")
self.spin_box = QtWidgets.QSpinBox(value=0)
self.spin_box.setMaximum(1000000)
self.spin_box.setSuffix(" Readouts")
self.reset_button = QtGui.QPushButton('Reset')
self.reset_button = QtWidgets.QPushButton('Reset')
layout.addWidget(self.timestamp_label, 0, 0, 0, 1)
layout.addWidget(self.plot_delay_label, 0, 1, 0, 1)
layout.addWidget(self.rate_label, 0, 2, 0, 1)
Expand Down Expand Up @@ -104,6 +101,6 @@ def handle_data_if_active(self, data):
# set timestamp, plot delay and readour rate
self.rate_label.setText("Readout Rate\n%d Hz" % data['fps'])
self.timestamp_label.setText("Data Timestamp\n%s" % time.asctime(time.localtime(data['timestamp_stop'])))
now = ptime.time()
now = time.time()
self.plot_delay = self.plot_delay * 0.9 + (now - data['timestamp_stop']) * 0.1
self.plot_delay_label.setText("Plot Delay\n%s" % 'not realtime' if abs(self.plot_delay) > 5 else "%1.2f ms" % (self.plot_delay * 1.e3))
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
basil_daq>=3.0.0
online_monitor>=0.4.1<0.5
online-monitor>=0.6
numpy
psutil
qtpy
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
packages=find_packages(),
include_package_data=True,
install_requires=install_requires,
setup_requires=['online_monitor>=0.4.1<0.5'],
entry_points={
'console_scripts': [
'pytlu = pytlu.tlu:main',
Expand Down
76 changes: 37 additions & 39 deletions tests/StreamDriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@

import cocotb
from cocotb.binary import BinaryValue
from cocotb.triggers import RisingEdge, ReadOnly, Timer
from cocotb.drivers import BusDriver
from cocotb.result import ReturnValue
from cocotb.triggers import RisingEdge, Timer
from cocotb.clock import Clock
from cocotb_bus.drivers import BusDriver


class StreamDriver(BusDriver):
Expand All @@ -25,37 +24,37 @@ class StreamDriver(BusDriver):
_optional_signals = ["BUS_BYTE_ACCESS"]

def __init__(self, entity):
BusDriver.__init__(self, entity, "", entity.BUS_CLK)
BusDriver.__init__(self, entity, "", entity.BUS_CLK, case_insensitive=False)

# Create an appropriately sized high-impedence value
self._high_impedence = BinaryValue(bits=len(self.bus.BUS_DATA))
self._high_impedence = BinaryValue(n_bits=len(self.bus.BUS_DATA))
self._high_impedence.binstr = "Z" * len(self.bus.BUS_DATA)

# Create an appropriately sized high-impedence value
self._x = BinaryValue(bits=len(self.bus.BUS_ADD))
self._x = BinaryValue(n_bits=len(self.bus.BUS_ADD))
self._x.binstr = "x" * len(self.bus.BUS_ADD)

self._has_byte_acces = False

self.BASE_ADDRESS_STREAM = 0x0001000000000000

# Kick off a clock generator
cocotb.fork(Clock(self.clock, 20830).start())
cocotb.fork(Clock(self.clock, 20000).start())

@cocotb.coroutine
def init(self):
# Defaults
self.bus.BUS_RST <= 1
self.bus.BUS_RD <= 0
self.bus.BUS_WR <= 0
self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA <= self._high_impedence
self.bus.STREAM_READY <= 0
self.bus.BUS_RST.value = 1
self.bus.BUS_RD.value = 0
self.bus.BUS_WR.value = 0
self.bus.BUS_ADD.value = self._x
self.bus.BUS_DATA.value = self._high_impedence
self.bus.STREAM_READY.value = 0

for _ in range(8):
yield RisingEdge(self.clock)

self.bus.BUS_RST <= 0
self.bus.BUS_RST.value = 0

for _ in range(2):
yield RisingEdge(self.clock)
Expand All @@ -75,20 +74,20 @@ def read(self, address, size):
if address >= self.BASE_ADDRESS_STREAM:
result = yield self.read_stream(address, size)
else:
self.bus.BUS_DATA <= self._high_impedence
self.bus.BUS_ADD <= self._x
self.bus.BUS_RD <= 0
self.bus.BUS_DATA.value = self._high_impedence
self.bus.BUS_ADD.value = self._x
self.bus.BUS_RD.value = 0

yield RisingEdge(self.clock)

byte = 0
while(byte <= size):
if(byte == size):
self.bus.BUS_RD <= 0
self.bus.BUS_RD.value = 0
else:
self.bus.BUS_RD <= 1
self.bus.BUS_RD.value = 1

self.bus.BUS_ADD <= address + byte
self.bus.BUS_ADD.value = address + byte

yield RisingEdge(self.clock)

Expand All @@ -113,38 +112,38 @@ def read(self, address, size):
else:
byte += 1

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA <= self._high_impedence
self.bus.BUS_ADD.value = self._x
self.bus.BUS_DATA.value = self._high_impedence
yield RisingEdge(self.clock)

raise ReturnValue(result)
return result

@cocotb.coroutine
def write(self, address, data):

self.bus.BUS_ADD <= self._x
self.bus.BUS_DATA <= self._high_impedence
self.bus.BUS_WR <= 0
self.bus.BUS_ADD.value = self._x
self.bus.BUS_DATA.value = self._high_impedence
self.bus.BUS_WR.value = 0

yield RisingEdge(self.clock)

for index, byte in enumerate(data):
self.bus.BUS_DATA <= byte
self.bus.BUS_WR <= 1
self.bus.BUS_ADD <= address + index
self.bus.BUS_DATA.value = byte
self.bus.BUS_WR.value = 1
self.bus.BUS_ADD.value = address + index
yield Timer(1) # This is hack for iverilog
self.bus.BUS_DATA <= byte
self.bus.BUS_WR <= 1
self.bus.BUS_ADD <= address + index
self.bus.BUS_DATA.value = byte
self.bus.BUS_WR.value = 1
self.bus.BUS_ADD.value = address + index

yield RisingEdge(self.clock)

if(self._has_byte_acces and self.bus.BUS_BYTE_ACCESS.value.integer == 0):
raise NotImplementedError("BUS_BYTE_ACCESS for write to be implemented.")

self.bus.BUS_DATA <= self._high_impedence
self.bus.BUS_ADD <= self._x
self.bus.BUS_WR <= 0
self.bus.BUS_DATA.value = self._high_impedence
self.bus.BUS_ADD.value = self._x
self.bus.BUS_WR.value = 0

yield RisingEdge(self.clock)

Expand All @@ -153,7 +152,7 @@ def read_stream(self, address, size):
result = []

yield RisingEdge(self.clock)
self.bus.STREAM_READY <= 1
self.bus.STREAM_READY.value = 1

for _ in range(size // 2):

Expand All @@ -169,8 +168,7 @@ def read_stream(self, address, size):
yield RisingEdge(self.clock)
yield RisingEdge(self.clock)
yield RisingEdge(self.clock)
self.bus.STREAM_READY <= 0
self.bus.STREAM_READY.value = 0
yield RisingEdge(self.clock)

raise ReturnValue(result)

return result
4 changes: 2 additions & 2 deletions tests/test_Sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def setUp(self):
include_dirs=(root_dir, root_dir + "/firmware/src", root_dir + "/tests"))

with open(root_dir + '/pytlu/tlu.yaml', 'r') as f:
cnfg = yaml.load(f)
cnfg = yaml.safe_load(f)
cnfg['transfer_layer'][0]['type'] = 'SiSim'
cnfg['hw_drivers'].append({'name': 'SEQ_GEN_TB', 'type': 'seq_gen', 'interface': 'intf', 'base_addr': 0xc000})
cnfg['hw_drivers'].append({'name': 'TLU_TB', 'type': 'tlu', 'interface': 'intf', 'base_addr': 0xf000})
Expand Down Expand Up @@ -362,7 +362,7 @@ def test_tlu_veto(self):
while not self.dut['test_pulser'].is_ready:
pass

expected_vetoed_triggers = 29 # 29 triggers will not be accepted due to veto signal
expected_vetoed_triggers = 28 # 28 triggers will not be accepted due to veto signal
self.check_data(how_many_triggers - expected_vetoed_triggers)

def tearDown(self):
Expand Down

0 comments on commit 32b2b5e

Please sign in to comment.