276 lines
9.2 KiB
C++
276 lines
9.2 KiB
C++
// Copyright (2019-2024) Paul Scherrer Institute
|
|
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include "../pcie_driver/jfjoch_fpga.h"
|
|
#include "JungfraujochDevice.h"
|
|
|
|
#include "../../common/JFJochException.h"
|
|
#include "../pcie_driver/jfjoch_ioctl.h"
|
|
|
|
JungfraujochDevice::JungfraujochDevice(const std::string &device_name, bool write_access) {
|
|
fd = open(device_name.c_str(), write_access ? O_RDWR : O_RDONLY);
|
|
if (fd == -1) {
|
|
if (errno == EBUSY)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Device already opened");
|
|
else if (errno == EACCES)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Permission denied");
|
|
else
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Cannot open device");
|
|
}
|
|
|
|
auto action_release = GetRevision();
|
|
if (action_release != JFJOCH_FPGA_RELEASE)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Mismatch of FPGA revision between driver and library");
|
|
}
|
|
|
|
JungfraujochDevice::~JungfraujochDevice() {
|
|
close(fd);
|
|
}
|
|
|
|
void JungfraujochDevice::Start() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_START) != 0)
|
|
throw PCIeDeviceException("Failed starting action");
|
|
}
|
|
|
|
void JungfraujochDevice::Cancel() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_CANCEL) != 0)
|
|
throw PCIeDeviceException("Failed setting cancel bit");
|
|
}
|
|
|
|
void JungfraujochDevice::End() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_END) != 0)
|
|
throw PCIeDeviceException("Failed ending action");
|
|
}
|
|
|
|
bool JungfraujochDevice::IsIdle() const {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_ISIDLE, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed checking if idle");
|
|
return tmp;
|
|
}
|
|
|
|
DataCollectionStatus JungfraujochDevice::GetDataCollectionStatus() const {
|
|
DataCollectionStatus ret{};
|
|
if (ioctl(fd, IOCTL_JFJOCH_STATUS, &ret) != 0)
|
|
throw PCIeDeviceException("Failed reading status");
|
|
return ret;
|
|
}
|
|
|
|
DataCollectionConfig JungfraujochDevice::GetConfig() const {
|
|
DataCollectionConfig ret{};
|
|
if (ioctl(fd, IOCTL_JFJOCH_READ_CONFIG, &ret) != 0)
|
|
throw PCIeDeviceException("Failed reading config");
|
|
return ret;
|
|
}
|
|
|
|
DeviceStatus JungfraujochDevice::GetDeviceStatus() const {
|
|
DeviceStatus ret{};
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_DEV_STATUS, &ret) != 0)
|
|
throw PCIeDeviceException("Failed reading env. data");
|
|
return ret;
|
|
}
|
|
|
|
void JungfraujochDevice::ClearNetworkCounters() {
|
|
if (ioctl(fd, IOCTL_JFJOCH_CLR_CNTRS) != 0)
|
|
throw PCIeDeviceException("Failed clearing network counters");
|
|
}
|
|
|
|
void JungfraujochDevice::Reset() {
|
|
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::GetNumaNode() const {
|
|
int32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_NUMA, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed reading NUMA node");
|
|
return tmp;
|
|
}
|
|
|
|
void JungfraujochDevice::SetConfig(const DataCollectionConfig &config) {
|
|
if (config.nframes > MAX_FRAMES)
|
|
throw PCIeDeviceException("Cannot handle this many frames");
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_CONFIG, &config) != 0)
|
|
throw PCIeDeviceException("Failed writing config");
|
|
}
|
|
|
|
bool JungfraujochDevice::ReadWorkCompletion(uint32_t *output) {
|
|
int tmp = ioctl(fd, IOCTL_JFJOCH_READ_WC_MBOX, output);
|
|
if (tmp != 0) {
|
|
if ((errno == EAGAIN) || (errno == EINTR))
|
|
return false;
|
|
throw PCIeDeviceException("Failed receiving work completion");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool JungfraujochDevice::SendWorkRequest(uint32_t id) {
|
|
int tmp = ioctl(fd, IOCTL_JFJOCH_SEND_WR, &id);
|
|
if (tmp != 0) {
|
|
if (errno == EAGAIN)
|
|
return false;
|
|
throw PCIeDeviceException("Failed sending work request");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::GetBufferCount() const {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_BUF_COUNT, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed getting buffer count");
|
|
return tmp;
|
|
}
|
|
|
|
uint64_t JungfraujochDevice::GetMACAddress(uint32_t interface) const {
|
|
struct FPGAMacAddress tmp{.addr = UINT64_MAX, .if_number = interface};
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_MAC, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed getting MAC address");
|
|
return tmp.addr;
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::GetIPv4Address(uint32_t interface) const {
|
|
struct FPGAIPAddress tmp{.addr = UINT32_MAX, .if_number = interface};
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_IPV4, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed getting IPv4 address");
|
|
return tmp.addr;
|
|
}
|
|
|
|
void JungfraujochDevice::SetIPv4Address(uint32_t input, uint32_t interface) {
|
|
struct FPGAIPAddress tmp{.addr = input, .if_number = interface};
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_IPV4, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed setting IPv4 address");
|
|
}
|
|
|
|
void JungfraujochDevice::RunFrameGenerator(const FrameGeneratorConfig &config) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_RUN_FRAME_GEN, &config) != 0)
|
|
throw PCIeDeviceException("Failed starting frame generator");
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::ReadRegister(uint32_t addr) const {
|
|
RegisterConfig config;
|
|
config.addr = addr;
|
|
if (ioctl(fd, IOCTL_JFJOCH_READ_REGISTER, &config) != 0)
|
|
throw PCIeDeviceException("Failed reading register");
|
|
return config.val;
|
|
}
|
|
|
|
void JungfraujochDevice::LoadCalibration(const LoadCalibrationConfig &config) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_LOAD_CALIB, &config) != 0)
|
|
throw PCIeDeviceException("Failed uploading calibration");
|
|
}
|
|
|
|
DeviceOutput *JungfraujochDevice::MapKernelBuffer(uint32_t id) {
|
|
auto tmp = (DeviceOutput *) mmap(nullptr, FPGA_BUFFER_LOCATION_SIZE,
|
|
PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
fd, FPGA_BUFFER_LOCATION_SIZE * id);
|
|
|
|
if (tmp == MAP_FAILED)
|
|
throw PCIeDeviceException("Mmap of kernel buffer error");
|
|
|
|
return tmp;
|
|
}
|
|
|
|
void JungfraujochDevice::UnmapKernelBuffer(DeviceOutput *val) {
|
|
munmap(val, FPGA_BUFFER_LOCATION_SIZE);
|
|
}
|
|
|
|
void JungfraujochDevice::SetSpotFinderParameters(const SpotFinderParameters& params) {
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_SPOTFIN_PAR, ¶ms) != 0)
|
|
throw PCIeDeviceException("Failed settings spot finder parameters");
|
|
}
|
|
|
|
SpotFinderParameters JungfraujochDevice::GetSpotFinderParameters() {
|
|
SpotFinderParameters ret{};
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_SPOTFIN_PAR, &ret) != 0)
|
|
throw PCIeDeviceException("Failed fetching spot finder parameters");
|
|
return ret;
|
|
}
|
|
uint32_t JungfraujochDevice::GetDataSource() {
|
|
uint32_t tmp;
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_DATA_SOURCE, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed getting data source");
|
|
return tmp;
|
|
}
|
|
|
|
void JungfraujochDevice::SetDataSource(uint32_t id) {
|
|
if (id >= 4)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Data source is 2-bit variable");
|
|
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_DATA_SOURCE, &id) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed setting data source");
|
|
}
|
|
|
|
bool JungfraujochDevice::ReadWorkCompletion(JungfraujochDeviceCompletion &completion) {
|
|
uint32_t tmp = 0;
|
|
bool ret = ReadWorkCompletion(&tmp);
|
|
completion.buffer_id = tmp & 0xFFFF;
|
|
completion.data_collection_id = (tmp >> 16) & 0xFFFF;
|
|
return ret;
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::GetRevision() {
|
|
uint32_t tmp = 0;
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_REVISION, &tmp) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed getting data source");
|
|
return tmp;
|
|
}
|
|
|
|
NetworkStatus JungfraujochDevice::GetNetworkStatus(uint32_t interface) {
|
|
NetworkStatus status{};
|
|
status.jfjoch_net_magic = interface;
|
|
if (ioctl(fd, IOCTL_JFJOCH_NET_STATUS, &status) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed getting network status");
|
|
return status;
|
|
}
|
|
|
|
uint32_t JungfraujochDevice::GetNetworkMode(uint32_t interface) {
|
|
struct FPGANetworkMode tmp{.mode = UINT32_MAX, .if_number = interface};
|
|
if (ioctl(fd, IOCTL_JFJOCH_GET_NET_MODE, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed getting network mode");
|
|
return tmp.mode;
|
|
}
|
|
|
|
void JungfraujochDevice::SetNetworkMode(uint32_t mode, uint32_t interface) {
|
|
struct FPGANetworkMode tmp{.mode = mode, .if_number = interface};
|
|
if (ioctl(fd, IOCTL_JFJOCH_SET_NET_MODE, &tmp) != 0)
|
|
throw PCIeDeviceException("Failed setting network mode");
|
|
}
|
|
|
|
std::string JungfraujochDevice::GetDataSourceStr() {
|
|
switch (GetDataSource()) {
|
|
case STREAM_MERGE_SRC_NONE:
|
|
return "None";
|
|
case STREAM_MERGE_SRC_NETWORK:
|
|
return "Network";
|
|
case STREAM_MERGE_SRC_FRAME_GEN:
|
|
return "Frame generator";
|
|
default:
|
|
return "Unknown";
|
|
}
|
|
}
|
|
|
|
uint8_t JungfraujochDevice::ReadClockConfig(uint8_t addr) {
|
|
I2COperation operation{
|
|
.dev_addr = 0xD0,
|
|
.reg_addr = addr
|
|
};
|
|
|
|
if (ioctl(fd, IOCTL_JFJOCH_I2C_CLK_READ, &operation) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed reading I2C config");
|
|
|
|
return operation.content;
|
|
}
|
|
|
|
void JungfraujochDevice::WriteClockConfig(uint8_t addr, uint8_t val) {
|
|
I2COperation operation{
|
|
.dev_addr = 0xD0,
|
|
.reg_addr = addr,
|
|
.content = val
|
|
};
|
|
|
|
if (ioctl(fd, IOCTL_JFJOCH_I2C_CLK_WRITE, &operation) != 0)
|
|
throw JFJochException(JFJochExceptionCategory::PCIeError, "Failed writing I2C config");
|
|
}
|