LArPix-Control Software Documentation¶
Here is the documentation for LArPix Control.
LArPix Control Core¶
A module to control the LArPix chip.
-
class
larpix.larpix.
Key
(*args)[source]¶ A unique specification for routing data to a particular detector sub-system. At the core, a key is represented by 3-unsigned 1-byte integer fields which refer to an id code within a layer of the LArPix DAQ system heirarchy. Field 0 represents the io group id number, field 1 represents the io channel connecting to a MISO/MOSI pair, and field 2 represents the chip id. The io group is the device controlling a set of MOSI/MISO pairs, the io channel is a single MOSI/MISO pair controlling a collection of LArPix asics, and the chip id uniquely identifies a chip on a single MISO/MISO network.
Each field should be a 1-byte unsigned integer (0-255) providing a unique lookup value for each component in the system. The id values of 0 and 255 are reserved for special functionality.
A key can be specified by a string of
'<io group>-<io channel>-<chip id>'
, by io group, io channel, and chip id, or by using other Keys.Keys are hashed by their string representation and are equivalent to their string representation so:
key = Key(1,1,1) # io group, io channel, chip id key == Key('1-1-1') # True key == Key(key) # True key == '1-1-1' # True d = { key: 'example' } d[key] == 'example' # True d['1-1-1'] == 'example' # True
-
keystring
¶ Key string specifying key io group, io channel, and chip id in the format:
'<io group>-<io channel>-<chip id>'
-
chip_id
¶ 1-byte unsigned integer representing the physical chip id (hardwired for v1 ASICs, assigned dynamically for v2 ASICs)
-
io_channel
¶ 1-byte unsigned integer representing the physical io channel. This identifies a single MOSI/MISO pair used to communicate with a single network of up to 254 chips.
-
io_group
¶ 1-byte unsigned integer representing the physical device used to read out up to 254 io channels.
-
static
is_valid_keystring
(keystring)[source]¶ Check if keystring can be interpreted as a larpix.Key
Returns: True
if the keystring can be interpreted as a larpix.Key
-
-
class
larpix.larpix.
Chip
(chip_key)[source]¶ Represents one LArPix chip and helps with configuration and packet generation.
-
get_configuration_packets
(packet_type, registers=None)[source]¶ Return a list of Packet objects to read or write (depending on
packet_type
) the specified configuration registers (or all registers by default).
-
-
class
larpix.larpix.
Configuration
[source]¶ Represents the desired configuration state of a LArPix chip.
-
register_names
= ['pixel_trim_thresholds', 'global_threshold', 'csa_gain', 'csa_bypass', 'internal_bypass', 'csa_bypass_select', 'csa_monitor_select', 'csa_testpulse_enable', 'csa_testpulse_dac_amplitude', 'test_mode', 'cross_trigger_mode', 'periodic_reset', 'fifo_diagnostic', 'sample_cycles', 'test_burst_length', 'adc_burst_length', 'channel_mask', 'external_trigger_mask', 'reset_cycles']¶ This attribute lists the names of all available configuration registers. Each register name is available as its own attribute for inspecting and setting the value of the corresponding register.
Certain configuration values are set channel-by-channel. These are represented by a list of values. For example:
>>> conf.pixel_trim_thresholds[2:5] [16, 16, 16] >>> conf.channel_mask[20] = 1 >>> conf.external_trigger_mask = [0] * 32
Additionally, other configuration values take up more than or less than one complete register. These are still set by referencing the appropriate name. For example,
cross_trigger_mode
shares a register with a few other values, and adjusting the value of thecross_trigger_mode
attribute will leave the other values unchanged.
-
compare
(config)[source]¶ Returns a dict containing pairs of each differently valued register Pair order is (self, other)
-
get_nondefault_registers
()[source]¶ Return a dict of all registers that are not set to the default configuration (i.e. of the ASIC on power-up). The keys are the register name where there’s a difference, and the values are tuples of (current, default) configuration values.
-
enable_channels
(list_of_channels=None)[source]¶ Shortcut for changing the channel mask for the given channels to “enable” (i.e. 0).
-
disable_channels
(list_of_channels=None)[source]¶ Shortcut for changing the channel mask for the given channels to “disable” (i.e. 1).
-
enable_external_trigger
(list_of_channels=None)[source]¶ Shortcut for enabling the external trigger functionality for the given channels. (I.e. disabling the mask.)
-
disable_external_trigger
(list_of_channels=None)[source]¶ Shortcut for disabling the external trigger functionality for the given channels. (I.e. enabling the mask.)
-
enable_testpulse
(list_of_channels=None)[source]¶ Shortcut for enabling the test pulser for the given channels.
-
disable_testpulse
(list_of_channels=None)[source]¶ Shortcut for disabling the test pulser for the given channels.
-
enable_analog_monitor
(channel)[source]¶ Shortcut for enabling the analog monitor on the given channel.
-
from_dict
(d)[source]¶ Use a dict of
{register_name, value}
to update the current configuration. Not all registers must be in the dict - only those present will be updated.
-
-
class
larpix.larpix.
Controller
[source]¶ Controls a collection of LArPix Chip objects.
Reading data:
The specific interface for reading data is selected by specifying the
io
attribute. These objects all have similar behavior for reading in new data. On initialization, the object will discard any LArPix packets sent from ASICs. To begin saving incoming packets, callstart_listening()
. Data will then build up in some form of internal register or queue. The queue can be emptied with a call toread()
, which empties the queue and returns a list of Packet objects that were in the queue. Theio
object will still be listening for new packets during and after this process. If the queue/register fills up, data may be discarded/lost. To stop saving incoming packets and retrieve any packets still in the queue, callstop_listening()
. While the Controller is listening, packets can be sent using the appropriate methods without interrupting the incoming data stream.Properties and attributes:
chips
: theChip
objects that the controller controlsall_chips
: all possibleChip
objects (considering there are a finite number of chip IDs), initialized on object constructionreads
: list of all the PacketCollections that have been sent back to this controller. PacketCollections are created byrun
,write_configuration
,read_configuration
,multi_write_configuration
,multi_read_configuration
, andstore_packets
.use_all_chips
: ifTrue
, look up chip objects inself.all_chips
, else look up inself.chips
(default:False
)
-
get_chip
(chip_key)[source]¶ Retrieve the Chip object that this Controller associates with the given
chip_key
.
-
add_chip
(chip_key)[source]¶ Add a specified chip to the Controller chips.
param: chip_key: chip key to specify unique chip
Returns: Chip
that was added
-
load
(filename)[source]¶ Loads the specified file that describes the chip ids and IO network
Parameters: filename – File path to configuration file
-
load_controller
(filename)[source]¶ Loads the specified file using the basic key, chip format The key, chip file format is: `` {
“name”: “<system name>”, “chip_list”: [<chip keystring>,…]The chip key is the Controller access key that gets communicated to/from the io object when sending and receiving packets.
Parameters: filename – File path to configuration file
-
load_daisy_chain
(filename, io_group=1)[source]¶ Loads the specified file in a basic daisy chain format Daisy chain file format is: `` {
“name”: “<board name>”, “chip_list”: [[<chip id>,<daisy chain>],…]Position in daisy chain is specified by position in chip_set list returns board name of the loaded chipset configuration
Parameters: - filename – File path to configuration file
- io_group – IO group to use for chip keys
-
read
()[source]¶ Read any packets that have arrived and return (packets, bytestream) where bytestream is the bytes that were received.
The returned list will contain packets that arrived since the last call to
read
orstart_listening
, whichever was most recent.
-
write_configuration
(chip_key, registers=None, write_read=0, message=None)[source]¶ Send the configurations stored in chip.config to the LArPix ASIC.
By default, sends all registers. If registers is an int, then only that register is sent. If registers is an iterable, then all of the registers in the iterable are sent.
If write_read == 0 (default), the configurations will be sent and the current listening state will not be affected. If the controller is currently listening, then the listening state will not change and the value of write_read will be ignored. If write_read > 0 and the controller is not currently listening, then the controller will listen for
write_read
seconds beginning immediately before the packets are sent out, read the io queue, and save the packets into thereads
data member. Note that the controller will only read the queue once, so if a lot of data is expected, you should handle the reads manually and set write_read to 0 (default).
-
read_configuration
(chip_key, registers=None, timeout=1, message=None)[source]¶ Send “configuration read” requests to the LArPix ASIC.
By default, request all registers. If registers is an int, then only that register is reqeusted. If registers is an iterable, then all of the registers in the iterable are requested.
If the controller is currently listening, then the requests will be sent and no change to the listening state will occur. (The value of
timeout
will be ignored.) If the controller is not currently listening, then the controller will listen fortimeout
seconds beginning immediately before the first packet is sent out, and will save any received packets in thereads
data member.
-
multi_write_configuration
(chip_reg_pairs, write_read=0, message=None)[source]¶ Send multiple write configuration commands at once.
chip_reg_pairs
should be a list/iterable whose elements are an valid arguments toController.write_configuration
, excluding thewrite_read
argument. Just like in the singleController.write_configuration
, settingwrite_read > 0
will have the controller read data during and after it writes, for however many seconds are specified.Examples:
These first 2 are equivalent and write the full configurations
>>> controller.multi_write_configuration([chip_key1, chip_key2, ...]) >>> controller.multi_write_configuration([(chip_key1, None), chip_key2, ...])
These 2 write the specified registers for the specified chips in the specified order
>>> controller.multi_write_configuration([(chip_key1, 1), (chip_key2, 2), ...]) >>> controller.multi_write_configuration([(chip_key1, range(10)), chip_key2, ...])
-
multi_read_configuration
(chip_reg_pairs, timeout=1, message=None)[source]¶ Send multiple read configuration commands at once.
chip_reg_pairs
should be a list/iterable whose elements are chip keys (to read entire configuration) or (chip_key, registers) tuples to read only the specified register(s). Registers could beNone
(i.e. all), anint
for that register only, or an iterable of ints.Examples:
These first 2 are equivalent and read the full configurations
>>> controller.multi_read_configuration([chip_key1, chip_key2, ...]) >>> controller.multi_read_configuration([(chip_key1, None), chip_key2, ...])
These 2 read the specified registers for the specified chips in the specified order
>>> controller.multi_read_configuration([(chip_key1, 1), (chip_key2, 2), ...]) >>> controller.multi_read_configuration([(chip_key1, range(10)), chip_key2, ...])
-
run
(timelimit, message)[source]¶ Read data from the LArPix ASICs for the given
timelimit
and associate the received Packets with the givenmessage
.
-
verify_configuration
(chip_keys=None, timeout=0.1)[source]¶ Read chip configuration from specified chip(s) and return
True
if the read chip configuration matches the current configuration stored in chip instance.chip_keys
can be a single chip key, a list of chip keys, orNone
. Ifchip_keys
isNone
all chips will be verified.Also returns a dict containing the values of registers that are different (read register, stored register)
-
read_channel_pedestal
(chip_key, channel, run_time=0.1)[source]¶ Set channel threshold to 0 and report back on the recieved adcs from channel Returns mean, rms, and packet collection
-
enable_analog_monitor
(chip_key, channel)[source]¶ Enable the analog monitor on a single channel on the specified chip. Note: If monitoring a different chip, call disable_analog_monitor first to ensure that the monitor to that chip is disconnected.
-
disable_analog_monitor
(chip_key=None, channel=None)[source]¶ Disable the analog monitor for a specified chip and channel, if none are specified disable the analog monitor for all chips in self.chips and all channels
-
enable_testpulse
(chip_key, channel_list, start_dac=255)[source]¶ Prepare chip for pulsing - enable testpulser and set a starting dac value for specified chip/channel
-
issue_testpulse
(chip_key, pulse_dac, min_dac=0)[source]¶ Reduce the testpulser dac by pulse_dac and write_read to chip for 0.1s
-
disable_testpulse
(chip_key=None, channel_list=range(0, 32))[source]¶ Disable testpulser for specified chip/channels. If none specified, disable for all chips/channels
-
disable
(chip_key=None, channel_list=range(0, 32))[source]¶ Update channel mask to disable specified chips/channels. If none specified, disable all chips/channels
-
enable
(chip_key=None, channel_list=range(0, 32))[source]¶ Update channel mask to enable specified chips/channels. If none specified, enable all chips/channels
-
class
larpix.larpix.
TimestampPacket
(timestamp=None, code=None)[source]¶ A packet-like object which just contains an integer timestamp.
This class implements many methods used by Packet, so it functions smoothly in lists of packets and in PacketCollection.
If neither
timestamp
norcode
is provided then this TimestampPacket will have a timestamp ofNone
until it is manually set.Parameters: - timestamp – optional, integer timestamp of this packet
- code – optional, encoded timestamp as a 7-byte unsigned int
obtainable from calling the
bytes
method.
-
class
larpix.larpix.
MessagePacket
(message, timestamp)[source]¶ A packet-like object which contains a string message and timestamp.
Parameters: - message – a string message of length less than 64
- timestamp – the timestamp of the message
-
class
larpix.larpix.
Packet
(bytestream=None)[source]¶ A single 54-bit LArPix UART data packet.
LArPix Packet objects have attributes for inspecting and modifying the contents of the packet.
Internally, packets are represented as an array of bits, and the different attributes use Python “properties” to seamlessly convert between the bits representation and a more intuitive integer representation. The bits representation can be inspected with the
bits
attribute.Packet objects do not restrict you from adjusting an attribute for an inappropriate packet type. For example, you can create a data packet and then set
packet.register_address = 5
. This will adjust the packet bits corresponding to a configuration packet’s “register_address” region, which is probably not what you want for your data packet.Packets have a parity bit which enforces odd parity, i.e. the sum of all the individual bits in a packet must be an odd number. The parity bit can be accessed as above using the
parity_bit_value
attribute. The correct parity bit can be computed usingcompute_parity()
, and the validity of a packet’s parity can be checked usinghas_valid_parity()
. When constructing a new packet, the correct parity bit can be assigned usingassign_parity()
.Individual packets can be printed to show a human-readable interpretation of the packet contents. The printed version adjusts its output based on the packet type, so a data packet will show the data word, timestamp, etc., while a configuration packet will show the register address and register data.
-
bytes
()[source]¶ Construct the bytes that make up the packet.
Byte 0 is the first byte that would be sent out and contains the first 8 bits of the packet (i.e. packet type and part of the chip ID).
Note: The internal bits representation of the packet has a different endian-ness compared to the output of this method.
-
-
class
larpix.larpix.
PacketCollection
(packets, bytestream=None, message='', read_id=None, skipped=None)[source]¶ Represents a group of packets that were sent to or received from LArPix.
Index into the PacketCollection as if it were a list:
>>> collection[0] Packet(b' ') >>> first_ten = collection[:10] >>> len(first_ten) 10 >>> type(first_ten) larpix.larpix.PacketCollection >>> first_ten.message 'my packets | subset slice(None, 10, None)'
To view the bits representation, add ‘bits’ to the index:
>>> collection[0, 'bits'] '00000000 00000000 00000000 00000000 00000000 00000000 000111' >>> bits_format_first_10 = collection[:10, 'bits'] >>> type(bits_format_first_10[0]) str
-
extract
(attr, **selection)[source]¶ Extract the given attribute from packets specified by selection and return a list.
Any key used in Packet.export is a valid attribute or selection:
- all packets:
- chip_key
- bits
- type_str (data, test, config read, config write)
- type (0, 1, 2, 3)
- chipid
- parity
- valid_parity
- data packets:
- channel
- timestamp
- adc_counts
- fifo_half
- fifo_full
- test packets:
- counter
- config packets:
- register
- value
Usage:
>>> # Return a list of adc counts from any data packets >>> adc_data = collection.extract('adc_counts') >>> # Return a list of timestamps from chip 2 data >>> timestamps = collection.extract('timestamp', chipid=2) >>> # Return the most recently read global threshold from chip 5 >>> threshold = collection.extract('value', register=32, type='config read', chip=5)[-1]
Note
selecting on
timestamp
will also select TimestampPacket values.
-
Configuration registers¶
-
Configuration.
register_names
= ['pixel_trim_thresholds', 'global_threshold', 'csa_gain', 'csa_bypass', 'internal_bypass', 'csa_bypass_select', 'csa_monitor_select', 'csa_testpulse_enable', 'csa_testpulse_dac_amplitude', 'test_mode', 'cross_trigger_mode', 'periodic_reset', 'fifo_diagnostic', 'sample_cycles', 'test_burst_length', 'adc_burst_length', 'channel_mask', 'external_trigger_mask', 'reset_cycles'] This attribute lists the names of all available configuration registers. Each register name is available as its own attribute for inspecting and setting the value of the corresponding register.
Certain configuration values are set channel-by-channel. These are represented by a list of values. For example:
>>> conf.pixel_trim_thresholds[2:5] [16, 16, 16] >>> conf.channel_mask[20] = 1 >>> conf.external_trigger_mask = [0] * 32
Additionally, other configuration values take up more than or less than one complete register. These are still set by referencing the appropriate name. For example,
cross_trigger_mode
shares a register with a few other values, and adjusting the value of thecross_trigger_mode
attribute will leave the other values unchanged.
LArPix IO¶
-
class
larpix.io.
IO
[source]¶ Base class for IO objects that explicitly describes the necessary functions required by any IO class implementation. Additional functions are not used by the larpix core classes.
-
__init__
()[source]¶ Declaration of IO object
Variables: - is_listening – flag for
start_listening
andstop_listening
- default_filepath – default configuration path to load
- is_listening – flag for
-
load
(filepath=None)[source]¶ Loads a specified IO configuration
Parameters: filepath – path to io configuration file (JSON)
-
encode
(packets)[source]¶ Encodes a list of packets into a list of IO message objects
Parameters: packets – list
of larpixPacket
objects to encode into IO messagesReturns: list
of IO messages
-
decode
(msgs, **kwargs)[source]¶ Decodes a list of IO message objects into respective larpix
Packet
objectsParameters: - msgs –
list
of IO messages - kwargs – additional contextual information required to decode messages (implementation specific)
Returns: list
of larpixPacket
objects- msgs –
-
parse_chip_key
(key)[source]¶ Translate a chip key into a dict of contained information
Parameters: key – chip key to parse Returns: dict
of IO information contained in key
-
generate_chip_key
(**kwargs)[source]¶ Create a chip key based on supplied info, raise an error if not enough information is provided
Returns: chip key of an immutable python type and not tuple
-
send
(packets)[source]¶ Function for sending larpix packet objects
Parameters: packets – list
of larpixPacket
objects to send via IOReturns: None
-
empty_queue
()[source]¶ Read and remove the current items in the internal queue. The details of the queue implementation is left up to the specific IO class. Generally returns all packets that have been read since last call to
start_listening
orempty_queue
, whichever was most recent.Returns: tuple
of (list
ofPacket
objects, raw bytestream)
-
Implementations¶
Here is the documentation for various implemented IO classes.
Serial Port IO Interface¶
The serial port IO interface.
-
class
larpix.io.serialport.
SerialPort
(port=None, baudrate=1000000, timeout=0)[source]¶ Wrapper for various serial port interfaces across platforms.
Automatically loads correct driver based on the supplied port name:
'/dev/anything'
==> Linux ==> pySerial'scan-ftdi'
==> MacOS ==> libFTDI
-
classmethod
is_valid_chip_key
(key)[source]¶ Valid chip keys must be strings formatted as:
'<io_chain>-<chip_id>'
-
classmethod
parse_chip_key
(key)[source]¶ Decodes a chip key into
'chip_id'
andio_chain
Returns: dict
with keys('chip_id', 'io_chain')
-
classmethod
generate_chip_key
(**kwargs)[source]¶ Generates a valid
SerialPort
chip keyParameters: - chip_id –
int
corresponding to internal chip id - io_chain –
int
corresponding to daisy chain number
- chip_id –
ZeroMQ IO Interface¶
-
class
larpix.io.zmq_io.
ZMQ_IO
(config_filepath=None, **kwargs)[source]¶ The ZMQ_IO object interfaces with the Bern LArPix v2 module using the ZeroMQ communications protocol. This class wraps the
io.multizmq_io.MultiZMQ_IO
class, and enables a slightly simpler chip key formatting in the special case that you are only interfacing with a single daq board.This object handles the required communications, and also has extra methods for additional functionality, including system reset, packet count, clock frequency, and more.
-
load
(filepath=None)[source]¶ Loads a specified IO configuration
Parameters: filepath – path to io configuration file (JSON)
-
generate_chip_key
(**kwargs)[source]¶ Generates a valid
ZMQ_IO
chip keyParameters: - chip_id –
int
corresponding to internal chip id - io_chain –
int
corresponding to daisy chain number
- chip_id –
-
set_clock
(freq_khz)[source]¶ Set the LArPix CLK2X freqency (in kHz).
Parameters: freq_khz – CLK2X freq in khz to set
-
set_testpulse_freq
(divisor)[source]¶ Set the testpulse frequency, computed by dividing the CLK2X frequency by
divisor
.
-
Multi-ZeroMQ IO Interface¶
-
class
larpix.io.multizmq_io.
MultiZMQ_IO
(config_filepath=None, miso_map=None, mosi_map=None)[source]¶ The MultiZMQ_IO object interfaces with a network of Bern LArPix v2 modules using Igor’s ZeroMQ communications protocol.
This object handles the required communications, and also has extra methods for additional functionality, including system reset, packet count, clock frequency, and more.
By default, when creating a MultiZMQ_IO object, the
io/default.json
configuration will attempt to be loaded unless otherwise specified. The path relative to the pwd is checked first, followed by the path of the larpix-control installation.-
send
(packets)[source]¶ Function for sending larpix packet objects
Parameters: packets – list
of larpixPacket
objects to send via IOReturns: None
-
parse_chip_key
(key)[source]¶ Decodes a chip key into
'chip_id'
,'io_chain'
, and'address'
Returns: dict
with keys('chip_id', 'io_chain', 'addresss')
-
generate_chip_key
(**kwargs)[source]¶ Generates a valid
MultiZMQ_IO
chip keyParameters: - chip_id –
int
corresponding to internal chip id - io_chain –
int
corresponding to daisy chain number - address –
str
corresponding to the address of the DAQ board
- chip_id –
-
empty_queue
()[source]¶ Process any awaiting messages from all ZMQ connections. Will continue to read until the hwm is reached or there are no more awaiting messages.
Returns: 2-tuple containing a list of received packets and the full bytestream
-
reset
(addresses=None)[source]¶ Send a reset pulse to the LArPix ASICs.
Parameters: addresses – list
of daq board addresses to reset, ifNone
reset all addresses
-
set_clock
(freq_khz, addresses=None)[source]¶ Set the LArPix CLK2X freqency (in kHz).
Parameters: - freq_khz – CLK2X freq in khz to set
- addresses –
list
of daq board addresses to change frequency, ifNone
modifies all addresses
-
set_testpulse_freq
(divisor, address)[source]¶ Set the testpulse frequency, computed by dividing the CLK2X frequency by
divisor
.Parameters: - divisor – test pulse frequency divisor
- address – daq board addresses to change test pulse freq
-
get_packet_count
(io_channel, address)[source]¶ Get the number of packets received, as determined by the number of UART “start” bits processed.
Parameters: - io_channel – IO channel to check
- address – address of daq board
-
FakeIO IO Interface¶
A module for the FakeIO class.
-
class
larpix.io.fakeio.
FakeIO
[source]¶ An IO stand-in that sends output to stdout (i.e. print) and reads input from a data member that can be set in advance.
The queue is implemented as a
collections.deque
object. Data can be queued up in advance through repeated calls toqueue.append()
. The first element of the queue will be passed on to theController.read
method each time it is called. This is a true queue, i.e. first-in, first-out.The format for an element of the queue is a tuple:
([list_of_Packets], b'corresponding bytes')
.Although meaningless in terms of the internal implementation,
FakeIO
objects contain an internal state determining whether the object is currently “listening,” and will raise aRuntimeError
ifempty_queue
is called when the object is not listening.-
classmethod
parse_chip_key
(key)[source]¶ Placeholder function for parsing chip keys
chip_key
Parameters: key – chip key to be returned in dict
Returns: dict
with keys('chip_key')
-
classmethod
generate_chip_key
(**kwargs)[source]¶ Placeholder function for generating a chip key
Parameters: chip_key – chip key to return Returns: chip_key
that was passed into the function
-
static
add_timestamps
(packets, positions, timestamps=0)[source]¶ Insert timestamp packets into a list of packets in the given positions.
Convenience method for modifying lists of packets to add to the FakeIO queue. Modifies the list in-place.
The positions are with respect to the indexes of the original list, so that the inserted element is just before the element that originally had that index. e.g.
>>> add_timestamps([a, b, c, d], [1, 3]) [a, TimestampPacket(...), b, c, TimestampPacket(...), d]
If timestamps is a list, those timestamps will be used for the TimestampPackets. If it is an int, it will be taken as the starting time, and each subsequent packet will be incremented by 1. A default starting time of 0 is assumed.
-
classmethod
LArPix Configuration Files¶
Here is the documentation for the configuration files.
Chip configuration files¶
This module contains chip configuration files. The format is a standard JSON file structured as follows:
{
"pixel_trim_thresholds": [<list of 32 5-bit integers>],
"global_threshold": <8-bit integer>,
"csa_gain": <1-bit integer>,
"csa_bypass": <1-bit integer>,
"internal_bypass": <1-bit integer>,
"csa_bypass_select": [<list of 32 1-bit integers>],
"csa_monitor_select": [<list of 32 1-bit integers>],
"csa_testpulse_enable": [<list of 32 1-bit integers>],
"csa_testpulse_dac_amplitude": <8-bit integer>,
"test_mode": <1-bit integer>,
"cross_trigger_mode": <1-bit integer>,
"periodic_reset": <1-bit integer>,
"fifo_diagnostic": <1-bit integer>,
"sample_cycles": <8-bit integer>,
"test_burst_length": <16-bit integer>,
"adc_burst_length": <8-bit integer>,
"channel_mask": [<list of 32 1-bit integers>],
"external_trigger_mask": [<list of 32 1-bit integers>],
"reset_cycles": <24-bit integer>
}
All fields are necessary.
Controller configuration files¶
This module contains daisy chain configuration files. The format is a standard JSON file structured as follows:
{
"name": <string identifier for system (typically pcb-<int> for a single pixel tile)>,
"chip_list": [<A list of chip keys, one for each chip>]
}
All fields are necessary.
IO configuration files¶
This module contains io configuration files used by io classes to look up
detector components based on the io_group
and io_channel
contained within
chip keys. See the larpix core documentation for more details on larpix.Key
objects.
JSON formatting¶
The format is a standard JSON file structured as follows:
{
"_config_type": "io",
"io_class": "<name of io class config should be used with>",
"io_group": [
[<io group number>, <assoc. value to be used by io class>],
...
]
}
Field description¶
The "_config_type": "io"
field is used in loading for validation (so that
you don’t accidentally try to load a chip
config into your io class. This
will always be “io” for io confiugration files.
The "io_class": "<name>"
field is used to specify the io class that the
configuration is compatible with. Examples are provided for each built-in io
class.
The "io_group": [[<group #>, <io class spec.>], ...]
list is a list of pairs
used to create a map between the io_group
number and the internal
representation used by the io class. E.g. the MultiZMQ_IO uses the IP address to
identify the io_group
.
LArPix Logger¶
-
class
larpix.logger.
Logger
(enabled=False, *args, **kwargs)[source]¶ Base class for larpix logger objects that explicity describes the necessary functions for a Logger implementation. Additional functions are not built into the larpix core.
-
WRITE
= 0¶ Flag to indicate packets were sent to ASICs
-
READ
= 1¶ Flag to indicate packets were received from ASICs
-
record
(data, direction=0, *args, **kwargs)[source]¶ Log specified data.
Parameters: - data –
list
of data to be written to log. Valid data types are specified by logger implementation. Raises aValueError
if datatype is invalid. - direction –
Logger.WRITE
if packets were sent to ASICs,Logger.READ
if packets were received from ASICs. (default:Logger.WRITE
)
- data –
-
is_enabled
()[source]¶ Check if logger is enabled, i.e. actively recording data. All data passed into
record()
between anenable()
anddisable()
command should be reflected in the log.
-
is_open
()[source]¶ Returns the value of the internal state “open/closed” (
True
if open).Deprecated since version 2.4.0:
open
,close
, andis_open
are deprecated and will be removed in the next major release of larpix-control.
-
open
(enable=True)[source]¶ Change internal state to “open” (meaningless), and if
enable
, enable this logger (meaningful).Parameters: enable – whether to enable this logger Deprecated since version 2.4.0:
open
,close
, andis_open
are deprecated and will be removed in the next major release of larpix-control.
-
Implementations¶
Here is the documentation for the various LArPix loggers.
Stdout Logger Interface¶
-
class
larpix.logger.stdout_logger.
StdoutLogger
(filename=None, buffer_length=0, mode='wa', enabled=False)[source]¶ The StdoutLogger is logger class that acts as a test logger class. All objects are displayed according to their string representation and routed to stdout.
Parameters: - buffer_length – how many data messages to hang on to before flushing buffer to stdout
- mode – how logger file should be opened (not implemented in
StdoutLogger
)
HDF5 Logger Interface¶
-
class
larpix.logger.h5_logger.
HDF5Logger
(filename=None, buffer_length=10000, directory='', version='1.0', enabled=False)[source]¶ The HDF5Logger is a logger class for logging packets to the LArPix+HDF5 format.
The file format is implemented in
larpix.format.hdf5format
, which also contains a function to convert back from LArPix+HDF5 to LArPix packets.Variables: data_desc_map – specifies the mapping between objects sent to the logger and the specific logger buffer to store them in. As of LArPix+HDF5 version 1.0 and larpix-control version 2.3.0 there is only one buffer called
'packets'
which stores all of the data to send to LArPix+HDF5.Parameters: - filename – filename to store data (appended to
directory
) (optional, default:None
) - buffer_length – how many data messages to hang on to before flushing
buffer to the file (optional, default:
10000
) - directory – the directory to save the data in (optional, default: ‘’)
- version – the format version of LArPix+HDF5 to use (optional,
default:
larpix.format.hdf5format.latest_version
)
-
record
(data, direction=0)[source]¶ Send the specified data to log file
Note
buffer is flushed after all
data
is placed in buffer, this means that the buffer size will exceed the set value temporarilyParameters: - data – list of data to be written to log
- direction –
Logger.WRITE
if packets were sent to ASICs,Logger.READ
if packets were received from ASICs. (default:Logger.WRITE
)
- filename – filename to store data (appended to
LArPix Formats¶
The data formats used for LArPix are:
LArPix+HDF5 Format¶
This module gives access to the LArPix+HDF5 file format.
File format description¶
All LArPix+HDF5 files use the HDF5 format so that they can be read and written using any language that has an HDF5 binding. The documentation for the Python h5py binding is at <http://docs.h5py.org>.
The to_file
and from_file
methods translate between a list of
Packet-like objects and an HDF5 data file. from_file
can be used to
load up the full file all at once or just a subset of rows (supposing
the full file was too big to fit in memory). To access the data most
efficiently, do not rely on from_file
and instead perform analysis
directly on the HDF5 data file.
File Header¶
The file header can be found in the /_header
HDF5 group. At a
minimum, the header will contain the following HDF5 attributes:
version
: a string containing the LArPix+HDF5 versioncreated
: a Unix timestamp of the file’s creation timemodified
: a Unix timestamp of the file’s last-modified time
Versions¶
The LArPix+HDF5 format is self-describing and versioned. This means as
the format evolves, the files themselves will identify which version
of the format should be used to interpret them. When writing a file
with to_file
, the format version can be specified, or by default,
the latest version is used. When reading a file with from_file
, by
default, the format version of the actual file is used. If a specific
format version is expected or required, that version can be specified,
and a RuntimeError
will be raised if a different format version is
encountered.
The versions are always in the format major.minor
and are stored as
strings (e.g. '1.0'
, '1.5'
).
The minor format will increase if a non-breaking change is made, so that a script compatible with a lower minor version will also work with files that have a higher minor version. E.g. a script designed to work with v1.0 will also work with v1.5. The reverse is not necessarily true: a script designed to work with v1.5 may not work with v1.0 files.
The major format will increase if a breaking change is made. This means that a script designed to work with v1.5 will likely not work with v2.0 files, and vice versa.
File Data¶
The file data is saved in HDF5 datasets, and the specific data format depends on the LArPix+HDF5 version.
For version 1.0, there are two dataset: packets
and messages
.
The packets
dataset
contains a list of all of the packets sent and received during a
particular time interval.
Shape:
(N,)
,N >= 0
Datatype: a compound datatype (called “structured type” in h5py/numpy). Not all fields are relevant for each packet. Unused fields are set to a default value of 0 or the empty string. Keys/fields:
chip_key
(S32
/32-character string): the chip key identifying the ASIC associated with this packettype
(u1
/unsigned byte): the packet type code, which can be interpreted according to the map stored in the raw_packet attribute ‘packet_types’chipid
(u1
/unsigned byte): the LArPix chipidparity
(u1
/unsigned byte): the packet parity bit (0 or 1)valid_parity
(u1
/unsigned byte): 1 if the packet parity is valid (odd), 0 if it is invalidchannel
(u1
/unsigned byte): the ASIC channeltimestamp
(u8
/unsigned 8-byte long int): the timestamp associated with the packet. Caution: this field does “triple duty” as both the ASIC timestamp in data packets (type
== 0), as the global timestamp in timestamp packets (type
== 4), and as the message timestamp in message packets (type
== 5).adc_counts
(u1
/unsigned byte): the ADC data wordfifo_half
(u1
/unsigned byte): 1 if the FIFO half full flag is present, 0 otherwise.fifo_full
(u1
/unsigned byte): 1 if the FIFO full flag is present, 0 otherwise.register
(u1
/unsigned byte): the configuration register indexvalue
(u1
/unsigned byte): the configuration register valuecounter
(u4
/unsigned 4-byte int): the test counter value, or the message index. Caution: this field does “double duty” as the counter for test packets (type
== 1) and as the message index for message packets (type
== 5).direction
(u1
/unsigned byte): 0 if packet was sent to ASICs, 1 if packet was received from ASICs.Packet types lookup: the
packets
dataset has an attribute'packet_types'
which contains the following lookup table for packets:0: 'data', 1: 'test', 2: 'config write', 3: 'config read', 4: 'timestamp', 5: 'message',
The messages
dataset has the full messages referred to by message
packets in the packets
dataset.
Shape:
(N,)
,N >= 0
Datatype: a compound datatype with fields:
message
(S64
/64-character string): the messagetimestamp
(u8
/unsigned 8-byte long int): the timestamp associated with the messageindex
(u4
/unsigned 4-byte int): the message index, which should be equal to the row index in themessages
dataset
Examples¶
Plot a histogram of ADC counts (selecting packet type to be data packets only)
>>> import matplotlib.pyplot as plt
>>> import h5py
>>> f = h5py.File('output.h5', 'r')
>>> packets = f['packets']
>>> plt.hist(packets['adc_counts'][packets['type'] == 0])
>>> plt.show()
Load the first 10 packets in a file into Packet objects and print any MessagePacket packets to the console
>>> from larpix.format.hdf5format import from_file
>>> from larpix.larpix import MessagePacket
>>> result = from_file('output.h5', end=10)
>>> for packet in result['packets']:
... if isinstance(packet, MessagePacket):
... print(packet)
-
larpix.format.hdf5format.
latest_version
= '1.0'¶ The most recent / up-to-date LArPix+HDF5 format version
-
larpix.format.hdf5format.
dtypes
¶ The dtype specification used in the HDF5 files.
Structure:
{version: {dset_name: [structured dtype fields]}}
-
larpix.format.hdf5format.
dtype_property_index_lookup
¶ A map between attribute name and “column index” in the structured dtypes.
Structure:
{version: {dset_name: {field_name: index}}}
-
larpix.format.hdf5format.
to_file
(filename, packet_list, mode='a', version=None)[source]¶ Save the given packets to the given file.
This method can be used to update an existing file.
Parameters: - filename – the name of the file to save to
- packet_list – any iterable of objects of type
Packet
orTimestampPacket
. - mode – optional, the “file mode” to open the data file
(default:
'a'
) - version – optional, the LArPix+HDF5 format version to use. If
writing a new file and version is unspecified or
None
, the latest version will be used. If writing an existing file and version is unspecified orNone
, the existing file’s version will be used. If writing an existing file and version is specified and does not exactly match the existing file’s version, aRuntimeError
will be raised. (default:None
)
-
larpix.format.hdf5format.
from_file
(filename, version=None, start=None, end=None)[source]¶ Read the data from the given file into LArPix Packet objects.
Parameters: - filename – the name of the file to read
- version – the format version. Specify this parameter to
enforce a version check. When a specific version such as
'1.5'
is specified, aRuntimeError
will be raised if the stored format version number is not an exact match. If a version is prefixed with'~'
such as'~1.5'
, aRuntimeError
will be raised if the stored format version is incompatible with the specified version. Compatible versions are those with the same major version and at least the same minor version. E.g. for'~1.5'
, versions between v1.5 and v2.0 are compatible. If unspecified orNone
, will use the stored format version. - start – the index of the first row to read
- end – the index after the last row to read (same semantics as
Python
range
)
Returns packet_dict: a dict with keys
'packets'
containing a list of packet objects; and'created'
,'modified'
, and'version'
, containing the file metadata.
LArPix interface message formats¶
The module contains all the message formats used by systems that interface with larpix-control:
- dataserver_message_encode: convert from packets to the data server messaging format
- dataserver_message_decode: convert from data server messaging format to packets
-
larpix.format.message_format.
dataserver_message_encode
(packets, key_parser=None, version=(1, 0))[source]¶ Convert a list of packets to larpix dataserver messages. DAQ board messages are formatted using 8-byte words with the first word being a header word describing the interpretation of other words in the message. These messages are formatted as follows
- All messages:
byte[0] = major version
byte[1] = minor version
byte[2] = message type
b'D'
: LArPix datab'T'
: Timestamp datab'H'
: Heartbeat
- LArPix heartbeat messages:
- byte[3] =
b'H'
- byte[4] =
b'B'
- byte[5:7] are unused
- byte[3] =
- LArPix data messages:
- byte[3] = io channel
- bytes[4:7] are unused
- bytes[8:] = raw LArPix 7-byte UART words ending in a single null byte
- Timestamp data messages:
- byte[3:7] are unused
- byte[8:14] = 7-byte Unix timestamp
- byte[15] is unused
A key parser should be provided to extract the
'io_chain'
from the packet chip key. If none is provided, io_chain will be 0 for all packets. E.g.:from larpix.larpix import Packet, Key def ex_key_parser(key): return dict(io_chain=key.io_channel) packet = Packet() packet.chip_key = Key('1-1-1') msgs = datserver_message_encode([packet], key_parser=ex_key_parser) msgs[0] # b'\x01\x00D\x01\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00' msgs[0][:8] # header msgs[0][8:] # data words
Parameters: - packets – list of
larpix.Packet
objects - key_parser – optional, a method that takes a
larpix.Key
object and returns a dict with'io_chain'
- version – optional, encode a message in specified version format,
tuple
of major, minor numbers
Returns: list of bytestream messages, 1 for each packet
-
larpix.format.message_format.
dataserver_message_decode
(msgs, key_generator=None, version=(1, 0), **kwargs)[source]¶ Convert a list of larpix data server messages into packets. A key generator should be provided if packets are to be used with an
larpix.io.IO
object. The data server messages provide achip_id
andio_chain
for keys. Additional keyword arguments can be passed along to the key generator. E.g.:from larpix.larpix import Key def ex_key_gen(chip_id, io_chain, io_group): return Key(Key.key_format.format( chip_id=chip_id, io_channel=io_chain, io_group=io_group )) msg = b'\x01\x00D\x01\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00' packets = dataserver_message_decode([msg], key_generator=ex_key_gen, io_group=1) packets[0] # Packet(b'\x04\x00\x00\x00\x00\x00\x00'), key of '1-1-1'
Parameters: - msgs – list of bytestream messages each starting with a single 8-byte header word, followed by N 8-byte data words
- key_generator – optional, a method that takes
chip_id
andio_chain
as arguments and returns alarpix.Key
object - version – optional, message version to validate against,
tuple
of major, minor version numbers
Returns: list of
larpix.Packet
andlarpix.TimestampPacket
objects