//
// Copyright 2013-2014 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#include
#include
// "push" and "pop" introduced in GCC 4.6; works with all clang
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 5)
#pragma GCC diagnostic push
#endif
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
namespace uhd { namespace niusrprio
{
//-------------------------------------------------------
// niriok_proxy_impl_v2
//-------------------------------------------------------
niriok_proxy_impl_v2::niriok_proxy_impl_v2()
{
}
niriok_proxy_impl_v2::~niriok_proxy_impl_v2()
{
close();
}
nirio_status niriok_proxy_impl_v2::open(const std::string& interface_path)
{
WRITER_LOCK
if (interface_path.empty()) return NiRio_Status_ResourceNotFound;
//close if already open.
// use non-locking _close since we already have the lock
_close();
in_transport_post_open_t in = {};
out_transport_post_open_t out = {};
in.status = NiRio_Status_Success;
nirio_status status = NiRio_Status_Success;
nirio_status_chain(nirio_driver_iface::rio_open(
interface_path, _device_handle), status);
if (nirio_status_not_fatal(status))
{
nirio_status_chain(nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_POST_OPEN,
&in, sizeof(in), &out, sizeof(out)), status);
if (nirio_status_fatal(status)) _close();
}
return status;
}
void niriok_proxy_impl_v2::close(void)
{
WRITER_LOCK
_close();
}
// this protected _close doesn't acquire the lock, so it can be used in methods
// that already have the lock
void niriok_proxy_impl_v2::_close()
{
if(nirio_driver_iface::rio_isopen(_device_handle))
{
in_transport_pre_close_t in = {};
out_transport_pre_close_t out = {};
in.status = NiRio_Status_Success;
nirio_driver_iface::rio_ioctl(
_device_handle, IOCTL_TRANSPORT_PRE_CLOSE, &in, sizeof(in), &out, sizeof(out));
nirio_driver_iface::rio_close(_device_handle);
}
}
nirio_status niriok_proxy_impl_v2::reset()
{
READER_LOCK
in_transport_reset_t in = {};
out_transport_reset_t out = {};
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_RESET,
&in, sizeof(in), &out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::get_cached_session(
uint32_t& session)
{
READER_LOCK
nirio_ioctl_packet_t out(&session, sizeof(session), 0);
return nirio_driver_iface::rio_ioctl(_device_handle,
nirio_driver_iface::NIRIO_IOCTL_GET_SESSION,
NULL, 0,
&out, sizeof(out));
}
nirio_status niriok_proxy_impl_v2::get_version(
nirio_version_t type,
uint32_t& major,
uint32_t& upgrade,
uint32_t& maintenance,
char& phase,
uint32_t& build)
{
nirio_device_attribute32_t version_attr = (type==CURRENT)?RIO_CURRENT_VERSION:RIO_OLDEST_COMPATIBLE_VERSION;
uint32_t raw_version = 0;
nirio_status status = get_attribute(version_attr, raw_version);
major = (raw_version & VERSION_MAJOR_MASK) >> VERSION_MAJOR_SHIFT;
upgrade = (raw_version & VERSION_UPGRD_MASK) >> VERSION_UPGRD_SHIFT;
maintenance = (raw_version & VERSION_MAINT_MASK) >> VERSION_MAINT_SHIFT;
build = (raw_version & VERSION_BUILD_MASK) >> VERSION_BUILD_SHIFT;
uint32_t phase_num = (raw_version & VERSION_PHASE_MASK) >> VERSION_PHASE_SHIFT;
switch (phase_num) {
case 0: phase = 'd'; break;
case 1: phase = 'a'; break;
case 2: phase = 'b'; break;
case 3: phase = 'f'; break;
}
return status;
}
nirio_status niriok_proxy_impl_v2::get_attribute(
const nirio_device_attribute32_t attribute,
uint32_t& attrValue)
{
READER_LOCK
in_transport_get32_t in = {};
out_transport_get32_t out = {};
in.attribute = attribute;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_GET32,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
attrValue = out.retVal__;
return out.status;
}
nirio_status niriok_proxy_impl_v2::set_attribute(
const nirio_device_attribute32_t attribute,
const uint32_t value)
{
READER_LOCK
in_transport_set32_t in = {};
out_transport_set32_t out = {};
in.attribute = attribute;
in.value = value;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_SET32,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::peek(uint32_t offset, uint32_t& value)
{
READER_LOCK
if (offset % 4 != 0) return NiRio_Status_MisalignedAccess;
in_transport_peek32_t in = {};
out_transport_peek32_t out = {};
in.offset = offset;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_PEEK32,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
value = out.retVal__;
return out.status;
}
nirio_status niriok_proxy_impl_v2::peek(uint32_t offset, uint64_t& value)
{
READER_LOCK
if (offset % 8 != 0) return NiRio_Status_MisalignedAccess;
in_transport_peek64_t in = {};
out_transport_peek64_t out = {};
in.offset = offset;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_PEEK64,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
value = out.retVal__;
return out.status;
}
nirio_status niriok_proxy_impl_v2::poke(uint32_t offset, const uint32_t& value)
{
READER_LOCK
if (offset % 4 != 0) return NiRio_Status_MisalignedAccess;
in_transport_poke32_t in = {};
out_transport_poke32_t out = {};
in.offset = offset;
in.value = value;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_POKE32,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::poke(uint32_t offset, const uint64_t& value)
{
READER_LOCK
if (offset % 8 != 0) return NiRio_Status_MisalignedAccess;
in_transport_poke64_t in = {};
out_transport_poke64_t out = {};
in.offset = offset;
in.value = value;
in.status = NiRio_Status_Success;
nirio_status ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_POKE64,
&in, sizeof(in),
&out, sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::map_fifo_memory(
uint32_t fifo_instance,
size_t size,
nirio_driver_iface::rio_mmap_t& map)
{
READER_LOCK
return nirio_driver_iface::rio_mmap(_device_handle,
GET_FIFO_MEMORY_TYPE(fifo_instance),
size, true, map);
}
nirio_status niriok_proxy_impl_v2::unmap_fifo_memory(
nirio_driver_iface::rio_mmap_t& map)
{
READER_LOCK
return nirio_driver_iface::rio_munmap(map);
}
nirio_status niriok_proxy_impl_v2::stop_all_fifos()
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_stop_all_t in = {};
out_transport_fifo_stop_all_t out = {};
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_STOP_ALL,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::add_fifo_resource(const nirio_fifo_info_t& fifo_info)
{
READER_LOCK
nirio_status status = NiRio_Status_Success;
nirio_status ioctl_status = NiRio_Status_Success;
switch(fifo_info.direction)
{
case INPUT_FIFO:
{
in_transport_add_input_fifo_resource_t in = {};
out_transport_add_input_fifo_resource_t out = {};
in.channel = fifo_info.channel;
in.baseAddress = fifo_info.base_addr;
in.depthInSamples = fifo_info.depth;
in.dataType.scalarType = fifo_info.scalar_type;
in.dataType.bitWidth = fifo_info.bitWidth;
in.dataType.integerWordLength = fifo_info.integerWordLength;
in.version = fifo_info.version;
in.status = NiRio_Status_Success;
ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_ADD_INPUT_FIFO_RESOURCE,
&in, sizeof(in),
&out, sizeof(out));
status = nirio_status_fatal(ioctl_status) ? ioctl_status : out.status;
break;
}
case OUTPUT_FIFO:
{
in_transport_add_output_fifo_resource_t in = {};
out_transport_add_output_fifo_resource_t out = {};
in.channel = fifo_info.channel;
in.baseAddress = fifo_info.base_addr;
in.depthInSamples = fifo_info.depth;
in.dataType.scalarType = fifo_info.scalar_type;
in.dataType.bitWidth = fifo_info.bitWidth;
in.dataType.integerWordLength = fifo_info.integerWordLength;
in.version = fifo_info.version;
in.status = NiRio_Status_Success;
ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_ADD_OUTPUT_FIFO_RESOURCE,
&in, sizeof(in),
&out, sizeof(out));
status = nirio_status_fatal(ioctl_status) ? ioctl_status : out.status;
break;
}
default:
status = NiRio_Status_SoftwareFault;
}
return status;
}
nirio_status niriok_proxy_impl_v2::set_device_config()
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_set_device_config_t in = {};
out_transport_set_device_config_t out = {};
in.attribute = 0; //this is unused in the kernel
in.status = NiRio_Status_Success;
ioctl_status = nirio_driver_iface::rio_ioctl(_device_handle,
IOCTL_TRANSPORT_SET_DEVICE_CONFIG,
&in, sizeof(in),
&out, sizeof(out));
return nirio_status_fatal(ioctl_status) ? ioctl_status : out.status;
}
nirio_status niriok_proxy_impl_v2::start_fifo(
uint32_t channel)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_start_t in = {};
out_transport_fifo_start_t out = {};
in.channel = channel;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_START,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::stop_fifo(
uint32_t channel)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_stop_t in = {};
out_transport_fifo_stop_t out = {};
in.channel = channel;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_STOP,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::configure_fifo(
uint32_t channel,
uint32_t requested_depth,
uint8_t /*requires_actuals*/, //Unused
uint32_t& actual_depth,
uint32_t& actual_size)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_config_t in = {};
out_transport_fifo_config_t out = {};
in.channel = channel;
in.requestedDepth = requested_depth;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_CONFIG,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
UHD_ASSERT_THROW(out.actualDepth <= std::numeric_limits::max());
actual_depth = static_cast(out.actualDepth);
UHD_ASSERT_THROW(out.actualSize <= std::numeric_limits::max());
actual_size = static_cast(out.actualSize);
return out.status;
}
nirio_status niriok_proxy_impl_v2::wait_on_fifo(
uint32_t channel,
uint32_t elements_requested,
uint32_t scalar_type,
uint32_t bit_width,
uint32_t timeout,
uint8_t output,
void*& data_pointer,
uint32_t& elements_acquired,
uint32_t& elements_remaining)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_wait_t in = {};
out_transport_fifo_wait_t out = {};
in.channel = channel;
in.elementsRequested = elements_requested;
in.dataType.scalarType = map_int_to_scalar_type(scalar_type);
in.dataType.bitWidth = bit_width;
in.dataType.integerWordLength = bit_width; // same as bit_width for all types except fixed point, which is not supported
in.output = (output != 0);
in.timeout = timeout;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_WAIT,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
data_pointer = reinterpret_cast(out.elements);
UHD_ASSERT_THROW(out.elementsAcquired <= std::numeric_limits::max());
elements_acquired = static_cast(out.elementsAcquired);
UHD_ASSERT_THROW(out.elementsRemaining <= std::numeric_limits::max());
elements_remaining = static_cast(out.elementsRemaining);
return out.status;
}
nirio_status niriok_proxy_impl_v2::grant_fifo(
uint32_t channel,
uint32_t elements_to_grant)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_grant_t in = {};
out_transport_fifo_grant_t out = {};
in.channel = channel;
in.elements = elements_to_grant;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_GRANT,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
return out.status;
}
nirio_status niriok_proxy_impl_v2::read_fifo(
uint32_t channel,
uint32_t elements_to_read,
void* buffer,
uint32_t /*buffer_datatype_width*/, //Unused
uint32_t scalar_type,
uint32_t bit_width,
uint32_t timeout,
uint32_t& number_read,
uint32_t& number_remaining)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_read_t in = {};
out_transport_fifo_read_t out = {};
in.channel = channel;
in.buf = reinterpret_cast(buffer);
in.numberElements = elements_to_read;
in.dataType.scalarType = map_int_to_scalar_type(scalar_type);
in.dataType.bitWidth = bit_width;
in.dataType.integerWordLength = bit_width; // same as bit_width for all types except fixed point, which is not supported
in.timeout = timeout;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_READ,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
number_read = out.read;
number_remaining = out.remaining;
return out.status;
}
nirio_status niriok_proxy_impl_v2::write_fifo(
uint32_t channel,
uint32_t elements_to_write,
void* buffer,
uint32_t /*buffer_datatype_width*/, //Unused
uint32_t scalar_type,
uint32_t bit_width,
uint32_t timeout,
uint32_t& number_remaining)
{
READER_LOCK
nirio_status ioctl_status = NiRio_Status_Success;
in_transport_fifo_write_t in = {};
out_transport_fifo_write_t out = {};
in.channel = channel;
in.buf = reinterpret_cast(buffer);
in.numberElements = elements_to_write;
in.dataType.scalarType = map_int_to_scalar_type(scalar_type);
in.dataType.bitWidth = bit_width;
in.dataType.integerWordLength = bit_width; // same as bit_width for all types except fixed point, which is not supported
in.timeout = timeout;
in.status = NiRio_Status_Success;
ioctl_status =
nirio_driver_iface::rio_ioctl(
_device_handle,
IOCTL_TRANSPORT_FIFO_WRITE,
&in,
sizeof(in),
&out,
sizeof(out));
if (nirio_status_fatal(ioctl_status)) return ioctl_status;
number_remaining = out.remaining;
return out.status;
}
}}
#if defined(__clang__) || defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 5)
#pragma GCC diagnostic pop
#endif