Accessing FELIX card registers

felix-io allows to interface with the regular and i2c registers of the FELIX card. It replaces felix-register. We can interface to felix-io from felix-client using the translate, read_register, write_register functions.

The translate function takes a vector of fids and returns a map of device_ids. This translation is required as there is one felix-io endpoint per device. If the device ID is well known, it may also be used directly, in all other cases this function can transform any standard FIDs to a unique list of device IDs, mapped to the provided FIDs. In case of an invalid or unknown FID a felix::BusException is thrown.

The read_register and write_register functions are used to actually read or write data from the FELIX device. Both functions take the device ID as the first argument to address the given device. The read_register functions takes the register name to be read as an argument and returns a map of name to vector of class BitFieldRecord. In case the value read is a single register, this map has one entry and the key is the provided name. In case a group of registers was queried, it contains one key per member of that register group. The BitFieldRecord struct contains contains the raw value, the unit, and the decoded value (for example, a temperature in Celsius).

write_register takes the value as to be set as well and returns nothing.

In case of failures a felix::FelixIoException is thrown containing the underlying error.

For more information see _felix-io: https://gitlab.cern.ch/atlas-tdaq-felix/felix-io-api

virtual std::map<felix::DeviceId, std::vector<std::uint64_t>> FelixClientThreadExtension520::translate(const std::vector<std::uint64_t> &fids) = 0
virtual std::map<std::string, std::vector<felix::BitFieldRecord>> FelixClientThreadExtension520::read_register(const felix::DeviceId &dev_id, const std::string &name) const = 0
virtual void FelixClientThreadExtension520::write_register(const felix::DeviceId &dev_id, const std::string &name, std::uint64_t value) const = 0

Example

 1const auto fids = std::vector<std::uint64_t>{0x1000000000080000};
 2
 3std::map<felix::DeviceId, std::vector<std::uint64_t>> device_id_to_fid = client.translate(fids);
 4
 5for (const auto& device : device_id_to_fid | std::views::keys()) {
 6  std::map<std::string, std::vector<BitFieldRecord>> results = client.read_register(device_id_to_fid.begin()->first, "REG_MAP_VERSION");
 7
 8  for (auto const& result: results) {
 9    std::println("Reply for felix-io deivce: {}, Name: {}", device, result.first);
10    for (auto const& value: result.second) {
11      std::println("  Value: {}", value);
12    }
13  }
14}

Deprecated API

Before felix-io we provided similar functionality through felix-register. We can interface felix-register from felix-client using the send_cmd function. This function sends a message to felix-register and waits for a response. The function takes a vector of fids, a command and a list of arguments. The command is a string and the arguments are a list of strings. It also takes an out parameter to store the replies received by felix-register. Success or failure is reported by the returned status code.

virtual Status FelixClientThreadExtension42::send_cmd(const std::vector<uint64_t> &fids, Cmd cmd, const std::vector<std::string> &cmd_args, std::vector<Reply> &replies) = 0

A command can be sent to multiple felixes by providing multiple FIDs in the fids parameter. It will only send one command once per FELIX instance.

Commands

  • UNKOWN: do not use it.

  • NOOP: do not use it.

  • GET: read a register. Pass exactly one register name as cmd_args (1 argument in total).

  • SET: write a register. Pass exactly one register name as cmd_args plus the value you want to set it to (2 arguments in total).

  • TRIGGER: do not use it.

  • ECR_RESET: Set the ECR counter. Pass the counter as cmd_args (1 argument in total).

Return codes

  • OK: Success, or you did not pass any FIDs.

  • ERROR: General error.

  • ERROR_NO_SUBSCRIPTION: If the bus information is missing or we cannot subscribe.

  • ERROR_NO_CONNECTION: If we cannot send the request.

  • ERROR_NO_REPLY: If no reply arrived within the timeout.

  • ERROR_INVALID_CMD: Command is not one of NOOP, GET, SET, ECR_RESET.

  • ERROR_INVALID_ARGS: Number of command arguments not correct for given command.

  • ERROR_INVALID_REGISTER: If a register cannot be read.

  • ERROR_NOT_AUTHORIZED: If a register cannot be written.

Replies

The replies parameter contains a list of replies either containing the response from the server or information about errors. The reply contains the following fields:

  • ctrl_fid: The FID to which the command is sent

  • status: The status code of the reply (see below)

  • value: Value returned by the server (set in case of GET command)

  • message: Error message (set in case of status code not equal to OK)

enum FelixClientThreadExtension::Status

Values:

enumerator OK
enumerator ERROR
enumerator ERROR_NO_SUBSCRIPTION
enumerator ERROR_NO_CONNECTION
enumerator ERROR_NO_REPLY
enumerator ERROR_INVALID_CMD
enumerator ERROR_INVALID_ARGS
enumerator ERROR_INVALID_REGISTER
enumerator ERROR_NOT_AUTHORIZED

Example

1const auto fids = std::vector<std::uint64_t>{0x1000000000080000, 0x1010000000080000};
2
3auto replies = std::vector<FelixClientThread::Reply>{};
4const auto status = fct.send_cmd(fids, FelixClientThread::Cmd::GET, {"REG_MAP_VERSION"}, replies);
5
6std::println("Status: {}", std::to_underlying(status));
7for (const auto& reply : replies) {
8  std::println("Reply for felix-register FID: {:#x}, Status: {}, Value: {:#x}, Message: {}", reply.ctrl_fid, std::to_underlying(reply.status), reply.value, reply.message);
9}