Skip to content
Snippets Groups Projects
Commit a0858b6c authored by BRONES Romain's avatar BRONES Romain
Browse files

Add DAQ related application

parent c9ade5a2
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env python3
import numpy as np
import deviceaccess as da
import logging
import os
import struct
import mmap
import multiprocessing as mp
import argparse
import datetime
###################################################################################################
# LOGGER
###################################################################################################
# Install a BasicLogger
logger = logging.getLogger("FofbArchiver")
sh=logging.StreamHandler()
sh.setLevel(logging.DEBUG)
sh.setFormatter(logging.Formatter("%(processName)s-%(process)d %(levelname)s: %(message)s"))
###################################################################################################
# DEVICE ACCESS
###################################################################################################
da.setDMapFilePath("/opt/fofb/opcua-server/devices.dmap")
app = da.Device("APPUIO")
app.open()
actbuffer = app.getScalarRegisterAccessor(np.int32, "APP.daq_0.ACTIVE_BUF")
###################################################################################################
# INTERRUPT HANDLING
###################################################################################################
def irq_wait(irqfd):
"""
Re-arm and wait on a UIO IRQ
"""
logger.debug("Re-Arm IRQ")
os.write( irqfd, struct.pack( "I", 1 ) )
logger.debug("Wait IRQ")
try:
r = os.read(irqfd, 4)
except KeyboardInterrupt:
logger.warning("Waiting IRQ stopped by user")
return False
logger.debug("Reads IRQ: {}".format(int.from_bytes(r, "little")))
return True
def irq_disable(irqfd):
logger.debug("Disable IRQ")
os.write( irqfd, struct.pack( "I", 0 ) )
def irq_flush(irqfd):
"""
Flush all IRQ until reads nothing.
"""
os.set_blocking(irqfd, False)
r=1
while True:
logger.debug("Flushing IRQ...")
os.write( irqfd, struct.pack( "I", 1 ) )
try:
r = os.read(irqfd, 4)
except BlockingIOError:
break
os.set_blocking(irqfd, True)
###################################################################################################
# DAQ HANDLING
###################################################################################################
def daq_configure():
"""
Configure DAQ engine to use the continuous region (region 0)
"""
logger.info("Configure DAQ")
app.write("APP.daq_0.DOUBLE_BUF_ENA", np.uint(1))
app.write("APP.daq_0.TAB_SEL", np.int(1), 0)
def daq_enable(ena):
if ena:
logger.info("Enable DAQ, region 0")
app.write("APP.daq_0.ENABLE", np.int(1))
app.write("APP.DAQ_CONTROL", np.int(0))
else:
logger.info("Disable DAQ, all regions")
app.write("APP.daq_0.ENABLE", np.int(0))
app.write("APP.DAQ_CONTROL", np.int(2))
def daq_trigger():
logger.info("Fire a DAQ trigger")
app.write("APP.DAQ_CONTROL", np.uint32(1))
app.write("APP.DAQ_CONTROL", np.uint32(0))
def daq_status():
# Read registers with one bit per region
for reg in ["DOUBLE_BUF_ENA", "ACTIVE_BUF", "ENABLE"]:
vals = app.read("APP.daq_0."+reg, np.uint32)
logger.info("{:20} {:10} {:10}".format(reg, vals&1, (vals>>1)&1))
# Read registers with one element per region
for reg in ["TAB_SEL", "STROBE_CNT", "SENT_BURST_CNT", "FIFO_STATUS"]:
vals = app.read("APP.daq_0."+reg, np.uint32)
logger.info("{:20} {:10} {:10}".format(reg, *vals))
def daq_current_buffer():
actbuffer.read()
return actbuffer[0]&1
###################################################################################################
# DDR HANDLING
###################################################################################################
daqmmap = mmap.mmap(os.open("/dev/ddrpl", os.O_RDONLY | os.O_SYNC),
0x2000_0000, mmap.MAP_SHARED, (mmap.PROT_READ)) # | mmap.PROT_WRITE))
daqmem = [np.ndarray(0x10000000, buffer=daqmmap, dtype='b', offset=o) for o in [0x00000000, 0x10000000]]
###################################################################################################
# TASKERS
###################################################################################################
def tasker_filer(filepath, buf):
logger.info("Start a filer tasker.")
t1 = datetime.datetime.now()
# Dump to file
try:
with open(filepath, "wb") as fd:
fd.write(buf.tobytes())
except KeyboardInterrupt:
logger.warning("File writing stopped by user on '{}'.".format(filepath))
return
t2 = datetime.datetime.now()
logger.debug("Writing time: {}".format((t2-t1).total_seconds()))
###################################################################################################
# ARCHIVER LOOP
###################################################################################################
def archiver_loop(path):
logger.info("Start an archiver loop")
irq_filepath = "/dev/ddrpl"
logger.debug("Opening FD on {}".format(irq_filepath))
irqfd = os.open(irq_filepath, os.O_RDWR | os.O_CLOEXEC)
# Prepare reception buffer
rbuf = np.empty((4, daqmem[0].size), dtype='b')
idxbuf = 0
# Flush
irq_flush(irqfd)
# Ignore first IRQ, but note the buffer
logger.debug("Wait for first IRQ...")
if not irq_wait(irqfd):
logger.error("Error while waiting first IRQ.")
os.close(irqfd)
return False
tp=datetime.datetime.now()
nbuf = daq_current_buffer()
logger.debug("Current buffer is {}, will read it on next IRQ.".format(nbuf))
try:
while True:
if not irq_wait(irqfd):
logger.error("Error while waiting IRQ.")
break
t0 = datetime.datetime.now()
logger.debug("IRQ period : {}".format((t0-tp).total_seconds()))
tp=t0
# Copy to buffer
rbuf[idxbuf] = daqmem[nbuf]
t1 = datetime.datetime.now()
logger.debug("Copy time: {}".format((t1-t0).total_seconds()))
# Launch job on rbuf
p = mp.Process(
name="archiver_filer",
target=tasker_filer,
args=(
path+"/Archive_{}.bin".format(t0.strftime("%Y%m%d_%H%M%S")),
rbuf[idxbuf],
))
p.start()
# Increment buffer pointers
idxbuf = (idxbuf+1)%4
nbuf = (nbuf+1)%2
except KeyboardInterrupt:
logger.warning("Archiver loop ended by user.")
os.close(irqfd)
###################################################################################################
# CLI INTERFACE
###################################################################################################
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("--config", action="store_true", help="Config DAQ.")
parser.add_argument("--stop", action="store_true", help="Stop DAQ.")
parser.add_argument("--start", action="store_true", help="Start DAQ.")
parser.add_argument("--arch", action="store_true", help="Start an archiver loop")
parser.add_argument("-S", action="store_true", help="Display DAQ status and quit.")
parser.add_argument("--path", type=str, help="Path to write file", default="./")
parser.add_argument("--log", help="Log level", default="INFO")
args = parser.parse_args()
#### Install logger
# Remove handler previously attached
for hdlr in logger.handlers:
logger.removeHandler(hdlr)
# Attach this handler
logger.addHandler(sh)
logger.setLevel(getattr(logging, args.log.upper()))
if args.S:
daq_status()
exit(0)
if args.arch:
archiver_loop(args.path)
exit(0)
if args.config:
daq_configure()
if args.stop:
daq_enable(False)
if args.start:
daq_enable(True)
daq_trigger()
#!/usr/bin/env python3
import time
import argparse
import numpy as np
import os, mmap, ctypes
import glob
import deviceaccess
# DAQ memory zone
daqmem = mmap.mmap(os.open("/dev/ddrpl", os.O_RDWR | os.O_SYNC),
0x40000000, mmap.MAP_SHARED, (mmap.PROT_READ | mmap.PROT_WRITE))
# DAQ device
deviceaccess.setDMapFilePath("/opt/fofb/map/devices.dmap")
appdev = deviceaccess.Device("APPUIO")
appdev.open()
# Number of Bytes Per Sample
NBPS=8
def configure(ena, N):
"""
Configure DAQ regions.
ena: int
bitsel for enabling region (one bit per region)
N: int, list(int)
Number of samples. If int, same number for both region.
"""
# Select tab 1 for both regions
appdev.write("APP.daq_0.TAB_SEL", np.int(1), 0)
appdev.write("APP.daq_0.TAB_SEL", np.int(1), 1)
# Set N samples for both regions
if type(N) == int:
appdev.write("APP.daq_0.SAMPLES", np.int(N), 0)
appdev.write("APP.daq_0.SAMPLES", np.int(N), 1)
else:
appdev.write("APP.daq_0.SAMPLES", np.int(N[0]), 0)
appdev.write("APP.daq_0.SAMPLES", np.int(N[1]), 1)
# Enable regions
appdev.write("APP.daq_0.ENABLE", np.int(ena))
def trigger():
appdev.write("APP.DAQ_CONTROL", np.int(1))
appdev.write("APP.DAQ_CONTROL", np.int(0))
def stop(b=True):
appdev.write("APP.DAQ_CONTROL", np.int(3*b))
def status():
for r in ["ENABLE", "ACTIVE_BUF"]:
print("{:>20} {:10}".format(r,
appdev.read("APP.daq_0."+r, np.dtype('u4'))))
for r in ["TAB_SEL", "STROBE_CNT", "SAMPLES", "FIFO_STATUS", "SENT_BURST_CNT", "TRG_CNT_BUF0", "TRG_CNT_BUF1"]:
r0, r1 =appdev.read("APP.daq_0."+r, np.dtype('u4'))
print("{:>20} {:10} {:10}".format(r, r0, r1))
def write_capture(path="./", region=[0,1]):
d=time.strftime("%m%d_%H%M%S")
for r, b, o in zip((0,1), NBPS*appdev.read("APP.daq_0.SAMPLES", np.dtype('u4')), [0,0x20000000]):
if r in region:
with open(path+"DAQCAPT_{}_R{}.bin".format(d, r), 'wb') as fp:
fp.write(daqmem[o:o+b])
return path+"DAQCAPT_{}_R{}.bin".format(d, r)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="DAQ capture and status")
parser.add_argument("--configure", action="store_true", help="Configure")
parser.add_argument("--stop", action="store_true", help="Send stop signal")
parser.add_argument("-t", action="store_true", help="Trigger DAQ")
parser.add_argument("-c", action="store_true", help="Dump memory to file")
parser.add_argument("-R", type=int, choices=(0,1), help="Region selector, default is both")
parser.add_argument("-N", type=int, default=1024, help="Number of samples to capture")
parser.add_argument("--path", type=str, default="./", help="Output path")
parser.add_argument("-s", action="store_true", help="Print status (after other actions)")
args=parser.parse_args()
if args.configure:
if args.R is None:
configure(3, args.N)
else:
configure(int(args.R)+1, args.N)
if args.stop:
stop()
exit(0)
else:
stop(False)
if args.t:
trigger()
if args.c:
if args.R is None:
fn=write_capture(args.path)
else:
fn=write_capture(args.path, [args.R, ])
print(fn)
if args.s:
status()
SUMMARY = "Simple python tool to use DESY DAQ"
SECTION = "opt"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = " file://daqcapt"
RDEPENDS_${PN}=" deviceaccess-mapfiles deviceaccess-python-bindings"
FILES_${PN}+="/usr/bin/daqcapt"
FILES_${PN}+="/usr/bin/daqarchiver"
do_install() {
# Add FPGA version reader and FoFb Configurator
install -d ${D}/usr/bin/
install -m 0755 ${WORKDIR}/daqcapt ${D}/usr/bin/daqcapt
install -m 0755 ${WORKDIR}/daqcapt ${D}/usr/bin/daqarchiver
}
......@@ -28,6 +28,7 @@ IMAGE_INSTALL_append = " deviceaccess"
IMAGE_INSTALL_append = " deviceaccess-python-bindings"
IMAGE_INSTALL_append = " fofb-opcua-server"
IMAGE_INSTALL_append = " fofb-init"
IMAGE_INSTALL_append = " fofb-daqcapt"
IMAGE_INSTALL_append = " nfs-utils"
# We do not need that
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment