Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion six/modules/c++/cphd/include/cphd/PVPBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -513,12 +513,14 @@ struct SIX_CPHD_API PVPBlock
SIX_CPHD_API friend std::ostream& operator<< (std::ostream& os, const PVPSet& p);

private:
//! The PVP Block [Num Channles][Num Parameters]
//! The PVP Block [Num Channels][Num Parameters]
std::vector<std::vector<PVPSet> > mData;
//! Number of bytes per PVP vector
size_t mNumBytesPerVector = 0;
//! PVP block metadata
Pvp mPvp;
//! Offset into global PVP array [NumChannels]
std::vector<size_t> mPvpByteOffset;

/*
* Optional parameter flags
Expand Down
19 changes: 10 additions & 9 deletions six/modules/c++/cphd/source/PVPBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,11 @@ PVPBlock::PVPBlock(const Pvp& p, const Data& d) :
mPvp = p;
mNumBytesPerVector = d.getNumBytesPVPSet();
mData.resize(d.getNumChannels());
mPvpByteOffset.resize(d.getNumChannels());
for (size_t ii = 0; ii < d.getNumChannels(); ++ii)
{
mData[ii].resize(d.getNumVectors(ii));
mPvpByteOffset[ii] = d.channels[ii].pvpArrayByteOffset;
}
size_t calculateBytesPerVector = mPvp.getReqSetSize()*sizeof(double);
if (six::Init::isUndefined<size_t>(mNumBytesPerVector) ||
Expand Down Expand Up @@ -643,29 +645,27 @@ int64_t PVPBlock::load(io::SeekableInputStream& inStream,
int64_t sizePVP,
size_t numThreads)
{
// Allocate the buffers
size_t numBytesIn(0);
size_t lastByte(0);

// Compute the PVPBlock size per channel
// Compute the last byte of the PVPBlock across all channels
// (channels aren't necessarily the same size)
for (size_t ii = 0; ii < mData.size(); ++ii)
{
numBytesIn += getPVPsize(ii);
lastByte = std::max(lastByte, mPvpByteOffset[ii] + getPVPsize(ii));
}

if (numBytesIn != static_cast<size_t>(sizePVP))
if (lastByte > static_cast<size_t>(sizePVP))
{
std::ostringstream oss;
oss << "PVPBlock::load: calculated PVP size(" << numBytesIn
<< ") != header PVP_DATA_SIZE(" << sizePVP << ")";
oss << "PVPBlock::load: last PVP byte(" << lastByte
<< ") is past the end of the PVP_DATA_SIZE(" << sizePVP << ")";
throw except::Exception(Ctxt(oss));
}

const bool swapToLittleEndian = std::endian::native == std::endian::little;

// Seek to start of PVPBlock
size_t totalBytesRead(0);
inStream.seek(startPVP, io::Seekable::START);
std::vector<std::byte> readBuf;
const size_t numBytesPerVector = getNumBytesPVPSet();

Expand All @@ -676,8 +676,9 @@ int64_t PVPBlock::load(io::SeekableInputStream& inStream,
if (!readBuf.empty())
{
auto const buf = readBuf.data();
inStream.seek(startPVP + mPvpByteOffset[ii], io::Seekable::START);
ptrdiff_t bytesThisRead = inStream.read(buf, readBuf.size());
if (bytesThisRead == io::InputStream::IS_EOF)
if (bytesThisRead != (ptrdiff_t)readBuf.size())
{
std::ostringstream oss;
oss << "EOF reached during PVP read for channel " << (ii);
Expand Down
62 changes: 59 additions & 3 deletions six/modules/c++/cphd/unittests/test_pvp_block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,17 @@ TEST_CASE(testPvpOptional)
pvpBlock.setFxN1(fxN1, channel, vector);
const double fxN2 = cphd::getRandom();
pvpBlock.setFxN2(fxN2, channel, vector);

const cphd::PvpAntenna txAnt(
cphd::getRandomVector3(),
cphd::getRandomVector3(),
cphd::getRandomVector2());
pvpBlock.setTxAntenna(txAnt, channel, vector);

const cphd::PvpAntenna rcvAnt(
cphd::getRandomVector3(),
cphd::getRandomVector3(),
cphd::getRandomVector2());
cphd::getRandomVector2());
pvpBlock.setRcvAntenna(rcvAnt, channel, vector);

const double addedParam1 = cphd::getRandom();
Expand Down Expand Up @@ -368,10 +368,66 @@ TEST_CASE(testLoadPVPBlockFromMemory)
TEST_ASSERT_EQ(pvpBlock.getTxPos(0, 0)[2], 9);
}

TEST_CASE(testPvpArrayByteOffset)
{
// For ease of testing, we make the somewhat specious assumption
// that an item of PVP data is equivalent to a double.
static_assert(sizeof(double) == cphd::PVPType::WORD_BYTE_SIZE,
"This test is not valid for compilers with "
"sizeof(double) != 8");

cphd::Pvp pvp;
cphd::setPVPXML(pvp);
const size_t setSize = pvp.getReqSetSize();
const size_t elementsPerChannel = setSize * NUM_VECTORS;

io::ByteStream file;
std::vector<size_t> pvpArrayByteOffsets;
for (size_t channel = 0; channel < NUM_CHANNELS; channel++)
{
pvpArrayByteOffsets.push_back(file.tell());
for (size_t ii = 0; ii < elementsPerChannel; ++ii)
{
double value = channel + ii * NUM_CHANNELS;
cphd::byteSwap(&value, sizeof(double), 1, 1);
file.write(&value, sizeof(double));
}
}

cphd::Data data;
data.numBytesPVP = setSize * sizeof(double);
for (size_t channel = 0; channel < NUM_CHANNELS; channel++)
{
// Assign PVP blocks in reverse order (the last PVP block is assigned to
// the first channel, etc.)
cphd::Data::Channel chan(NUM_VECTORS, 100, 0,
pvpArrayByteOffsets[NUM_CHANNELS - channel - 1]);
data.channels.push_back(chan);
}

cphd::PVPBlock pvpBlock(pvp, data);

file.seek(0, io::Seekable::START);
pvpBlock.load(file, 0, file.size(), 1);

TEST_ASSERT_EQ(pvpBlock.getTxTime(0, 0), 2);
TEST_ASSERT_EQ(pvpBlock.getTxTime(1, 0), 1);
TEST_ASSERT_EQ(pvpBlock.getTxTime(2, 0), 0);

TEST_ASSERT_EQ(pvpBlock.getTxTime(0, 1), 2 + setSize * NUM_CHANNELS);
TEST_ASSERT_EQ(pvpBlock.getTxTime(1, 1), 1 + setSize * NUM_CHANNELS);
TEST_ASSERT_EQ(pvpBlock.getTxTime(2, 1), 0 + setSize * NUM_CHANNELS);

TEST_ASSERT_EQ(pvpBlock.getTxPos(2, 0)[0], 3);
TEST_ASSERT_EQ(pvpBlock.getTxPos(2, 0)[1], 6);
TEST_ASSERT_EQ(pvpBlock.getTxPos(2, 0)[2], 9);
}

TEST_MAIN(
TEST_CHECK(testPvpRequired);
TEST_CHECK(testPvpOptional);
TEST_CHECK(testPvpThrow);
TEST_CHECK(testPvpEquality);
TEST_CHECK(testLoadPVPBlockFromMemory);
TEST_CHECK(testPvpArrayByteOffset);
)
Loading