57 #include <boost/chrono/duration.hpp>
58 #include <boost/chrono/time_point.hpp>
59 #include <boost/lexical_cast.hpp>
60 #include <boost/thread/thread.hpp>
61 #include <boost/date_time/posix_time/posix_time_types.hpp>
76 mData(1, std::pair<const uint8_t*, size_t>(aPtr, aNrBytes))
92 std::ios::fmtflags lOrigFlags( aStream.flags() );
94 size_t lNrBytesWritten = 0;
95 for (
size_t i = 0; i < aPacket.
mData.size(); i++) {
96 for (
const uint8_t* lPtr = aPacket.
mData.at(i).first; lPtr != (aPacket.
mData.at(i).first + aPacket.
mData.at(i).second); lPtr++, lNrBytesWritten++) {
97 if ((lNrBytesWritten & 3) == 0)
98 aStream << std::endl <<
" @ " << std::setw(3) <<
std::dec << (lNrBytesWritten >> 2) <<
" : x";
99 aStream << std::setw(2) <<
std::hex << uint16_t(*lPtr) <<
" ";
103 aStream.flags( lOrigFlags );
145 #define MAP_SIZE (32*1024UL)
146 #define MAP_MASK (MAP_SIZE - 1)
154 mFd = ::open(mPath.c_str(), mFlags);
156 exception::MmapInitialisationError lExc;
157 log(lExc,
"Failed to open device file ",
Quote(mPath),
"; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
161 const off_t lPageSize = sysconf(_SC_PAGESIZE);
162 const off_t lPageBaseAddr = (mOffset & ~(lPageSize-1));
164 mMmapPtr = mmap(0,
MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, lPageBaseAddr);
165 mMmapIOPtr =
static_cast<uint8_t*
>(mMmapPtr) + (mOffset - lPageBaseAddr);
167 if (mMmapPtr == (
void *)-1) {
168 exception::MmapInitialisationError lExc;
169 log(lExc,
"Error occurred when mapping device file '" + mPath +
"' to memory; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
177 if (mMmapPtr != NULL) {
178 if (munmap(mMmapPtr,
MAP_SIZE) == -1)
179 log (
Error() ,
"mmap client for ",
Quote(mPath),
" encountered error when unmapping memory" );
187 int rc = ::close(mFd);
195 void Mmap::File::read(
const uint32_t aAddr,
const uint32_t aNrWords, std::vector<uint32_t>& aValues)
200 uint8_t* lVirtAddr =
static_cast<uint8_t*
>(mMmapIOPtr) + off_t(4*aAddr);
202 for (
size_t i=0; i<aNrWords; i++) {
203 aValues.push_back(*((uint32_t*) (lVirtAddr + 4 * i)));
208 void Mmap::File::write(
const uint32_t aAddr,
const std::vector<std::pair<const uint8_t*, size_t> >& aData)
214 for (
size_t i = 0; i < aData.size(); i++)
215 lNrBytes += aData.at(i).second;
217 assert((lNrBytes % 4) == 0);
219 char *allocated = NULL;
220 posix_memalign((
void **)&allocated, 4096, lNrBytes + 4096);
221 if (allocated == NULL) {
222 exception::MmapCommunicationError lExc;
223 log(lExc,
"Failed to allocate ",
Integer(lNrBytes + 4096),
" bytes in File::write/2 function");
228 char* buffer = allocated;
229 size_t lNrBytesCopied = 0;
230 for (
size_t i = 0; i < aData.size(); i++) {
231 memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
232 lNrBytesCopied += aData.at(i).second;
237 while (lNrBytesCopied < lNrBytes) {
238 char* lSrcPtr = buffer + lNrBytesCopied;
239 char* lVirtAddr =
static_cast<char*
>(mMmapIOPtr) + aAddr + lNrBytesCopied;
240 if ((lNrBytes - lNrBytesCopied) >= 8) {
241 *((uint64_t*) lVirtAddr) = *(uint64_t*) lSrcPtr;
244 else if ((lNrBytes - lNrBytesCopied) >= 4) {
245 *((uint64_t*) lVirtAddr) = uint64_t(*(uint32_t*) lSrcPtr);
257 IPbus< 2 , 0 > ( aId , aUri ),
267 if ( getenv(
"UHAL_ENABLE_IPBUS_MMAP") == NULL ) {
268 exception::ProtocolDoesNotExist lExc;
269 log(lExc,
"The IPbus 2.0 mmap client is still an experimental feature, since the software-driver interface could change in the future.");
270 log(lExc,
"In order to enable the IPbus 2.0 mmap client, you need to define the environment variable 'UHAL_ENABLE_IPBUS_MMAP'");
276 for (NameValuePairVectorType::const_iterator lIt = aUri.
mArguments.begin(); lIt != aUri.
mArguments.end(); lIt++) {
277 if (lIt->first ==
"sleep") {
278 mSleepDuration = boost::chrono::microseconds(boost::lexical_cast<size_t>(lIt->second));
279 log (
Notice() ,
"mmap client with URI ",
Quote (
uri()),
" : Inter-poll-/-interrupt sleep duration set to ", boost::lexical_cast<size_t>(lIt->second),
" us by URI 'sleep' attribute");
281 else if (lIt->first ==
"offset") {
282 const bool lIsHex = (lIt->second.find(
"0x") == 0) or (lIt->second.find(
"0X") == 0);
283 const size_t lOffset = (lIsHex ? boost::lexical_cast<HexTo<size_t> >(lIt->second) : boost::lexical_cast<size_t>(lIt->second));
302 log(
Debug(),
"mmap client (URI: ",
Quote(
uri()),
") : implementDispatch method called");
315 log(
Debug(),
"mmap client (URI: ",
Quote(
uri()),
") : Flush method called");
325 log(
Notice(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : closing device files since exception detected");
330 InnerProtocol::dispatchExceptionHandler();
355 std::vector<uint32_t> lValues;
357 log (
Info(),
"Read status info from addr 0 (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
365 if (lValues.at(1) > 0xFFFF) {
366 exception::MmapInitialisationError lExc;
372 exception::MmapInitialisationError lExc;
378 log (
Info() ,
"mmap client connected to device at ",
Quote(
mDeviceFile.
getPath()),
"; FPGA has ",
Integer(
mNumberOfPages),
" pages, each of size ",
Integer(
mPageSize),
" words, index ",
Integer(
mIndexNextPage),
" should be filled next" );
391 log (
Info(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : writing ",
Integer(aBuffers->sendCounter() / 4),
"-word packet to page ",
Integer(
mIndexNextPage),
" in ",
Quote(
mDeviceFile.
getPath()));
393 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
394 std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
395 lDataToWrite.push_back( std::make_pair(
reinterpret_cast<const uint8_t*
>(&lHeaderWord),
sizeof lHeaderWord) );
396 lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
409 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
413 uint32_t lHwPublishedPageCount = 0x0;
416 std::vector<uint32_t> lValues;
419 lHwPublishedPageCount = lValues.at(3);
420 log (
Info(),
"Read status info from addr 0 (",
Integer(lValues.at(0)),
", ",
Integer(lValues.at(1)),
", ",
Integer(lValues.at(2)),
", ",
Integer(lValues.at(3)),
"): ",
PacketFmt((
const uint8_t*)lValues.data(), 4 * lValues.size()));
428 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
429 exception::MmapTimeout lExc;
434 log(
Debug(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Trying to read page index ",
Integer(lPageIndexToRead),
" = count ",
Integer(
mReadReplyPageCount+1),
"; published page count is ",
Integer(lHwPublishedPageCount),
"; sleeping for ",
mSleepDuration.count(),
"us");
439 log(
Info(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (published count ",
Integer(lHwPublishedPageCount),
", surpasses required, ",
Integer(
mReadReplyPageCount + 1),
")");
447 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
450 std::vector<uint32_t> lPageContents;
452 log (
Debug(),
"Read " ,
Integer(lNrWordsToRead),
" 32-bit words from address " ,
Integer(4 + lPageIndexToRead * 4 *
mPageSize),
" ... ",
PacketFmt((
const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
455 const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
456 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
457 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
458 log (
Warning(),
"Expected reply packet to contain ",
Integer(lBuffers->replyCounter() >> 2),
" words, but it actually contains ",
Integer(lNrWordsInPacket),
" words");
460 size_t lNrBytesCopied = 0;
461 for ( std::deque< std::pair< uint8_t* , uint32_t > >::const_iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
464 if ( lNrBytesCopied >= 4*lNrWordsInPacket)
467 size_t lNrBytesToCopy =
std::min( lIt->second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
468 memcpy ( lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
469 lNrBytesCopied += lNrBytesToCopy;