Skip to content

Commit

Permalink
Add low-level register based tests for VISA. (#1013)
Browse files Browse the repository at this point in the history
* Add peek/poke tests
* Optionally include additional information in error message. Add test for viOpen resource string.
* Clean up echo thread interactions. This fixes the Ubuntu test crash.
  • Loading branch information
dmondrik authored Oct 16, 2023
1 parent ced0872 commit 1e69024
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 67 deletions.
23 changes: 16 additions & 7 deletions source/custom/visa_service.custom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,27 @@ static ViStatus GetAttributeValue(ViObject vi, ViAttr attributeID, VisaService::
return status;
}

::grpc::Status VisaService::ConvertApiErrorStatusForViSession(::grpc::ServerContextBase* context, int32_t status, ViSession vi)
::grpc::Status ConvertVisaApiErrorStatus(::grpc::ServerContextBase* context, ViStatus status, ViObject vi, VisaService::LibrarySharedPtr library, const char* extraInfo = nullptr)
{
std::string description(nidevice_grpc::kMaxGrpcErrorDescriptionSize, '\0');
library_->StatusDesc(vi, status, &description[0]);
library->StatusDesc(vi, status, &description[0]);
// Although NI-VISA messages don't currently include context, we shouldn't assume it.
if (extraInfo != nullptr && description.find(extraInfo) == description.npos) {
nidevice_grpc::converters::trim_trailing_nulls(description);
description.append("\n");
description.append(extraInfo);
}
return nidevice_grpc::ApiErrorAndDescriptionToStatus(context, status, description);
}

::grpc::Status VisaService::ConvertApiErrorStatusForViSession(::grpc::ServerContextBase* context, int32_t status, ViSession vi)
{
return ConvertVisaApiErrorStatus(context, status, vi, library_);
}

::grpc::Status VisaService::ConvertApiErrorStatusForViObject(::grpc::ServerContextBase* context, int32_t status, ViObject vi)
{
std::string description(nidevice_grpc::kMaxGrpcErrorDescriptionSize, '\0');
library_->StatusDesc(vi, status, &description[0]);
return nidevice_grpc::ApiErrorAndDescriptionToStatus(context, status, description);
return ConvertVisaApiErrorStatus(context, status, vi, library_);
}


Expand Down Expand Up @@ -335,7 +344,7 @@ ::grpc::Status VisaService::Open(::grpc::ServerContext* context, const OpenReque
auto cleanup_lambda = [library](ViSession id) { library->Close(id); };
int status = session_repository_->add_session(grpc_device_session_name, init_lambda, cleanup_lambda, initialization_behavior, &new_session_initialized);
if (!status_ok(status)) {
return ConvertApiErrorStatusForViSession(context, status, rsrc_manager_handle);
return ConvertVisaApiErrorStatus(context, status, rsrc_manager_handle, library_, instrument_descriptor);
}

ViUInt16 numEvents = 0;
Expand Down Expand Up @@ -431,7 +440,7 @@ ::grpc::Status VisaService::ParseRsrc(::grpc::ServerContext* context, const Pars
std::string alias_if_exists(256 - 1, '\0');
auto status = library_->ParseRsrc(rsrc_manager_handle, resource_name, &interface_type, &interface_number, (ViChar*)resource_class.data(), (ViChar*)expanded_unaliased_name.data(), (ViChar*)alias_if_exists.data());
if (!status_ok(status)) {
return ConvertApiErrorStatusForViSession(context, status, rsrc_manager_handle);
return ConvertVisaApiErrorStatus(context, status, rsrc_manager_handle, library_, resource_name);
}
response->set_status(status);
response->set_interface_type(interface_type);
Expand Down
209 changes: 195 additions & 14 deletions source/tests/system/visa_driver_api_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class VisaDriverApiTest : public ::testing::Test {
client::raise_if_error(status, context);
driver_session_ = std::make_unique<nidevice_grpc::Session>(response.vi());

EXPECT_TRUE(status.ok());
EXPECT_EQ(VI_SUCCESS, response.status());
ASSERT_TRUE(status.ok());
ASSERT_EQ(VI_SUCCESS, response.status());
}

void close_driver_session()
Expand Down Expand Up @@ -164,7 +164,7 @@ class VisaMessageBasedLoopbackTest : public VisaDriverApiTest {

void SetUp() override
{
EXPECT_EQ(0, echoserver_.start());
ASSERT_EQ(0, echoserver_.start());

std::string portNumber(std::to_string(echoserver_.get_server_port()));
std::string instrument_descriptor("TCPIP0::localhost::" + portNumber + "::SOCKET");
Expand All @@ -175,6 +175,10 @@ class VisaMessageBasedLoopbackTest : public VisaDriverApiTest {

void TearDown() override
{
echoserver_.prepare_stop();
// Sending any single byte at this point will stop the server loop.
client::write(GetStub(), GetNamedSession(), " ");

close_driver_session();
echoserver_.stop();
}
Expand Down Expand Up @@ -207,15 +211,15 @@ class VisaMessageBasedLoopbackTest : public VisaDriverApiTest {

void read(size_t count, const std::string& expectedData, ViStatus expectedStatus)
{
auto response = client::read(GetStub(), GetNamedSession(), count);
auto response = client::read(GetStub(), GetNamedSession(), static_cast<uint32_t>(count));
EXPECT_EQ(expectedStatus, response.status());
EXPECT_EQ(expectedData.size(), response.return_count());
EXPECT_EQ(expectedData, response.buffer());
}

void read_async(size_t count, const std::string& expectedData, ViStatus expectedStatus, bool requiresTerminate = false)
{
auto asyncResponse = client::read_async(GetStub(), GetNamedSession(), count);
auto asyncResponse = client::read_async(GetStub(), GetNamedSession(), static_cast<uint32_t>(count));
EXPECT_THAT((std::array<ViStatus, 2>{ VI_SUCCESS, VI_SUCCESS_SYNC }), testing::Contains(asyncResponse.status()));
if (requiresTerminate) {
std::this_thread::sleep_for(std::chrono::milliseconds(kFastTimeoutMsec));
Expand Down Expand Up @@ -374,7 +378,7 @@ TEST_F(VisaMessageBasedLoopbackTest, Flush_ClearsBuffer)

class VisaRegisterBasedLoopbackTest : public VisaDriverApiTest {
public:
VisaRegisterBasedLoopbackTest() : allocatedBase_(0)
VisaRegisterBasedLoopbackTest() : allocatedBase_(0), mappedBase_(0)
{
}
virtual ~VisaRegisterBasedLoopbackTest()
Expand All @@ -384,7 +388,9 @@ class VisaRegisterBasedLoopbackTest : public VisaDriverApiTest {
void SetUp() override
{
initialize_driver_session("PXI::MEMACC");
allocatedBase_ = allocate(1024);
auto response = client::mem_alloc_ex(GetStub(), GetNamedSession(), 4096);
ASSERT_EQ(VI_SUCCESS, response.status());
allocatedBase_ = response.offset();
}

void TearDown() override
Expand All @@ -393,13 +399,6 @@ class VisaRegisterBasedLoopbackTest : public VisaDriverApiTest {
close_driver_session();
}

uint64_t allocate(uint64_t size)
{
auto response = client::mem_alloc_ex(GetStub(), GetNamedSession(), size);
EXPECT_EQ(VI_SUCCESS, response.status());
return response.offset();
}

void free(uint64_t offset)
{
auto response = client::mem_free(GetStub(), GetNamedSession(), offset);
Expand Down Expand Up @@ -528,8 +527,74 @@ class VisaRegisterBasedLoopbackTest : public VisaDriverApiTest {
EXPECT_EQ(VI_SUCCESS, response.status());
}

void map()
{
auto response = client::map_address(GetStub(), GetNamedSession(), visa::ADDRESS_SPACE_PXI_ALLOC_SPACE, allocatedBase_, 4096, false, 0);
EXPECT_EQ(VI_SUCCESS, response.status());
mappedBase_ = response.address();
}

void unmap()
{
auto response = client::unmap_address(GetStub(), GetNamedSession());
EXPECT_EQ(VI_SUCCESS, response.status());
}

ViUInt8 peek8(uint64_t offset)
{
auto response = client::peek8(GetStub(), GetNamedSession(), mappedBase_ + offset);
EXPECT_EQ(VI_SUCCESS, response.status());
return response.value();
}

ViUInt16 peek16(uint64_t offset)
{
auto response = client::peek16(GetStub(), GetNamedSession(), mappedBase_ + offset);
EXPECT_EQ(VI_SUCCESS, response.status());
return response.value();
}

ViUInt32 peek32(uint64_t offset)
{
auto response = client::peek32(GetStub(), GetNamedSession(), mappedBase_ + offset);
EXPECT_EQ(VI_SUCCESS, response.status());
return response.value();
}

ViUInt64 peek64(uint64_t offset)
{
auto response = client::peek64(GetStub(), GetNamedSession(), mappedBase_ + offset);
EXPECT_EQ(VI_SUCCESS, response.status());
return response.value();
}

void poke8(uint64_t offset, ViUInt8 value)
{
auto response = client::poke8(GetStub(), GetNamedSession(), mappedBase_ + offset, value);
EXPECT_EQ(VI_SUCCESS, response.status());
}

void poke16(uint64_t offset, ViUInt16 value)
{
auto response = client::poke16(GetStub(), GetNamedSession(), mappedBase_ + offset, value);
EXPECT_EQ(VI_SUCCESS, response.status());
}

void poke32(uint64_t offset, ViUInt32 value)
{
auto response = client::poke32(GetStub(), GetNamedSession(), mappedBase_ + offset, value);
EXPECT_EQ(VI_SUCCESS, response.status());
}

void poke64(uint64_t offset, ViUInt64 value)
{
auto response = client::poke64(GetStub(), GetNamedSession(), mappedBase_ + offset, value);
EXPECT_EQ(VI_SUCCESS, response.status());
}

private:
uint64_t allocatedBase_;
uint64_t mappedBase_;
};

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithMoveOut8_In8_ReadsData)
Expand Down Expand Up @@ -632,6 +697,122 @@ TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithOut64_MoveIn64_ReadsData)
}
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithMoveOut8_Peek8_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 11;
ViUInt8 buffer[testLength] = { 0x01, 0x02, 0x00, 0x03, 0xFE };
moveOut8(startingOffset, buffer, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(buffer[i], peek8(startingOffset + i));
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithMoveOut16_Peek16_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 14;
ViUInt16 buffer[testLength] = { 0x0123, 0x0234, 0x00, 0x8675, 0xFEDC };
moveOut16(startingOffset, buffer, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(buffer[i], peek16(startingOffset + i * 2));
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithMoveOut32_Peek32_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 16;
ViUInt32 buffer[testLength] = { 0x01234567, 0x02340234, 0x00, 0x86754321, 0xC0FFEE };
moveOut32(startingOffset, buffer, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(buffer[i], peek32(startingOffset + i * 4));
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithMoveOut64_Peek64_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 16;
ViUInt64 buffer[testLength] = { 0x01234567DEADBEEF, 0x02340234, 0x00, 0x867543210ABCDEF, 0xC0FFEE };
moveOut64(startingOffset, buffer, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(buffer[i], peek64(startingOffset + i * 8));
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithPoke8_MoveIn8_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 11;
ViUInt8 buffer[testLength] = { 0x01, 0x02, 0x00, 0x03, 0xFE };
for (int i = 0; i < testLength; ++i) {
poke8(startingOffset + i, buffer[i]);
}
auto readBuffer = moveIn8(startingOffset, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(readBuffer[i], buffer[i]);
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithPoke16_MoveIn16_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 14;
ViUInt16 buffer[testLength] = { 0x0123, 0x0234, 0x00, 0x8675, 0xFEDC };
for (int i = 0; i < testLength; ++i) {
poke16(startingOffset + i * 2, buffer[i]);
}
auto readBuffer = moveIn16(startingOffset, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(readBuffer[i], buffer[i]);
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithPoke32_MoveIn32_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 16;
ViUInt32 buffer[testLength] = { 0x01234567, 0x02340234, 0x00, 0x86754321, 0xC0FFEE };
for (int i = 0; i < testLength; ++i) {
poke32(startingOffset + i * 4, buffer[i]);
}
auto readBuffer = moveIn32(startingOffset, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(readBuffer[i], buffer[i]);
}
unmap();
}

TEST_F(VisaRegisterBasedLoopbackTest, DataWrittenWithPoke64_MoveIn64_ReadsData)
{
map();
const int testLength = 5;
const int startingOffset = 16;
ViUInt64 buffer[testLength] = { 0x01234567DEADBEEF, 0x02340234, 0x00, 0x867543210ABCDEF, 0xC0FFEE };
for (int i = 0; i < testLength; ++i) {
poke64(startingOffset + i * 8, buffer[i]);
}
auto readBuffer = moveIn64(startingOffset, testLength);
for (int i = 0; i < testLength; ++i) {
EXPECT_EQ(readBuffer[i], buffer[i]);
}
unmap();
}

} // namespace system
} // namespace tests
} // namespace ni
23 changes: 18 additions & 5 deletions source/tests/system/visa_session_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,24 @@ TEST_F(VisaSessionTest, OpenSession_CloseSession_ClosesDriverSession)

TEST_F(VisaSessionTest, OpenWithErrorFromDriver_ReturnsDriverErrorWithUserErrorMessage)
{
EXPECT_THROW_DRIVER_ERROR_WITH_SUBSTR({
visa::OpenResponse init_response;
call_open(kVisaTestInvalidInstrumentDescriptor, visa::LOCK_STATE_NO_LOCK, "", 0, &init_response);
},
kInvalidRsrc, kVisaErrorInstrumentDescriptorNotFoundMessage);
EXPECT_THROW_DRIVER_ERROR_WITH_SUBSTR(
{
visa::OpenResponse init_response;
call_open(kVisaTestInvalidInstrumentDescriptor, visa::LOCK_STATE_NO_LOCK, "", 0, &init_response);
},
kInvalidRsrc,
kVisaErrorInstrumentDescriptorNotFoundMessage);
}

TEST_F(VisaSessionTest, OpenWithErrorFromDriver_ReturnsDriverErrorWithResourceDescriptor)
{
EXPECT_THROW_DRIVER_ERROR_WITH_SUBSTR(
{
visa::OpenResponse init_response;
call_open(kVisaTestInvalidInstrumentDescriptor, visa::LOCK_STATE_NO_LOCK, "", 0, &init_response);
},
kInvalidRsrc,
kVisaTestInvalidInstrumentDescriptor);
}

TEST_F(VisaSessionTest, InvalidSession_CloseSession_ReturnsWarning)
Expand Down
Loading

0 comments on commit 1e69024

Please sign in to comment.