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> 67 #include "uhal/log/log.hpp" 76 mData(1,
std::pair<const uint8_t*, size_t>(aPtr, aNrBytes))
89 std::ios::fmtflags lOrigFlags( aStream.flags() );
91 size_t lNrBytesWritten = 0;
92 for (
size_t i = 0; i < aPacket.
mData.size(); i++) {
93 for (
const uint8_t* lPtr = aPacket.
mData.at(i).first; lPtr != (aPacket.
mData.at(i).first + aPacket.
mData.at(i).second); lPtr++, lNrBytesWritten++) {
94 if ((lNrBytesWritten & 3) == 0)
95 aStream << std::endl <<
" @ " << std::setw(3) << std::dec << (lNrBytesWritten >> 2) <<
" : x";
96 aStream << std::setw(2) <<
std::hex << uint16_t(*lPtr) <<
" ";
100 aStream.flags( lOrigFlags );
111 mMmapBaseAddress(NULL)
130 #define MAP_SIZE (32*1024UL) 131 #define MAP_MASK (MAP_SIZE - 1) 140 exception::MmapInitialisationError lExc;
141 log(lExc,
"Failed to open device file ",
Quote(
mPath),
"; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
147 exception::MmapInitialisationError lExc;
148 log(lExc,
"Error occurred when mapping device file '" +
mPath +
"' to memory; errno=",
Integer(errno),
", meaning ",
Quote (strerror(errno)));
157 log (
Error() ,
"mmap client for ",
Quote(
mPath),
" encountered error when unmapping memory" );
169 void Mmap::File::read(
const uint32_t aAddr,
const uint32_t aNrWords, std::vector<uint32_t>& aValues)
174 uint8_t* lVirtAddr =
static_cast<uint8_t*
>(
mMmapBaseAddress) + off_t(4*aAddr);
176 for (
size_t i=0; i<aNrWords; i++) {
177 aValues.push_back(*((uint32_t*) (lVirtAddr + 4 * i)));
184 void Mmap::File::write(
const uint32_t aAddr,
const std::vector<std::pair<const uint8_t*, size_t> >& aData)
190 for (
size_t i = 0; i < aData.size(); i++)
191 lNrBytes += aData.at(i).second;
193 assert((lNrBytes % 4) == 0);
195 char *allocated = NULL;
196 posix_memalign((
void **)&allocated, 4096, lNrBytes + 4096);
197 if (allocated == NULL) {
198 exception::MmapCommunicationError lExc;
199 log(lExc,
"Failed to allocate ",
Integer(lNrBytes + 4096),
" bytes in File::write/2 function");
204 char* buffer = allocated;
205 size_t lNrBytesCopied = 0;
206 for (
size_t i = 0; i < aData.size(); i++) {
207 memcpy(buffer + lNrBytesCopied, aData.at(i).first, aData.at(i).second);
208 lNrBytesCopied += aData.at(i).second;
213 while (lNrBytesCopied < lNrBytes) {
214 char* lSrcPtr = buffer + lNrBytesCopied;
215 char* lVirtAddr =
static_cast<char*
>(
mMmapBaseAddress) + aAddr + lNrBytesCopied;
216 if ((lNrBytes - lNrBytesCopied) >= 8) {
217 *((uint64_t*) lVirtAddr) = *(uint64_t*) lSrcPtr;
220 else if ((lNrBytes - lNrBytesCopied) >= 4) {
221 *((uint64_t*) lVirtAddr) = uint64_t(*(uint32_t*) lSrcPtr);
233 IPbus< 2 , 0 > ( aId , aUri ),
243 if ( getenv(
"UHAL_ENABLE_IPBUS_MMAP") == NULL ) {
244 exception::ProtocolDoesNotExist lExc;
245 log(lExc,
"The IPbus 2.0 mmap client is still an experimental feature, since the software-driver interface could change in the future.");
246 log(lExc,
"In order to enable the IPbus 2.0 mmap client, you need to define the environment variable 'UHAL_ENABLE_IPBUS_MMAP'");
252 for (NameValuePairVectorType::const_iterator lIt = aUri.
mArguments.begin(); lIt != aUri.
mArguments.end(); lIt++) {
253 if (lIt->first ==
"sleep") {
254 mSleepDuration = boost::chrono::microseconds(boost::lexical_cast<size_t>(lIt->second));
255 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");
271 log(
Debug(),
"mmap client (URI: ",
Quote(
uri()),
") : implementDispatch method called");
284 log(
Debug(),
"mmap client (URI: ",
Quote(
uri()),
") : Flush method called");
294 log(
Notice(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : closing device files since exception detected");
299 InnerProtocol::dispatchExceptionHandler();
324 std::vector<uint32_t> lValues;
326 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()));
334 if (lValues.at(1) > 0xFFFF) {
335 exception::MmapInitialisationError lExc;
341 exception::MmapInitialisationError lExc;
347 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" );
360 log (
Info(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : writing ",
Integer(aBuffers->sendCounter() / 4),
"-word packet to page ",
Integer(
mIndexNextPage),
" in ",
Quote(
mDeviceFile.
getPath()));
362 const uint32_t lHeaderWord = (0x10000 | (((aBuffers->sendCounter() / 4) - 1) & 0xFFFF));
363 std::vector<std::pair<const uint8_t*, size_t> > lDataToWrite;
364 lDataToWrite.push_back( std::make_pair(reinterpret_cast<const uint8_t*>(&lHeaderWord),
sizeof lHeaderWord) );
365 lDataToWrite.push_back( std::make_pair(aBuffers->getSendBuffer(), aBuffers->sendCounter()) );
380 SteadyClock_t::time_point lStartTime = SteadyClock_t::now();
384 uint32_t lHwPublishedPageCount = 0x0;
387 std::vector<uint32_t> lValues;
390 lHwPublishedPageCount = lValues.at(3);
391 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()));
399 if (SteadyClock_t::now() - lStartTime > boost::chrono::microseconds(getBoostTimeoutPeriod().total_microseconds())) {
400 exception::MmapTimeout lExc;
405 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");
410 log(
Info(),
"mmap client ",
Quote(
id()),
" (URI: ",
Quote(
uri()),
") : Reading page ",
Integer(lPageIndexToRead),
" (published count ",
Integer(lHwPublishedPageCount),
", surpasses required, ",
Integer(
mReadReplyPageCount + 1),
")");
418 uint32_t lNrWordsToRead(lBuffers->replyCounter() >> 2);
421 std::vector<uint32_t> lPageContents;
423 log (
Debug(),
"Read " ,
Integer(lNrWordsToRead),
" 32-bit words from address " ,
Integer(4 + lPageIndexToRead * 4 * mPageSize),
" ... ",
PacketFmt((
const uint8_t*)lPageContents.data(), 4 * lPageContents.size()));
426 const std::deque< std::pair< uint8_t* , uint32_t > >& lReplyBuffers ( lBuffers->getReplyBuffer() );
427 size_t lNrWordsInPacket = (lPageContents.at(0) >> 16) + (lPageContents.at(0) & 0xFFFF);
428 if (lNrWordsInPacket != (lBuffers->replyCounter() >> 2))
429 log (
Warning(),
"Expected reply packet to contain ",
Integer(lBuffers->replyCounter() >> 2),
" words, but it actually contains ",
Integer(lNrWordsInPacket),
" words");
431 size_t lNrBytesCopied = 0;
432 for ( std::deque< std::pair< uint8_t* , uint32_t > >::const_iterator lIt = lReplyBuffers.begin() ; lIt != lReplyBuffers.end() ; ++lIt )
435 if ( lNrBytesCopied >= 4*lNrWordsInPacket)
438 size_t lNrBytesToCopy =
std::min( lIt->second , uint32_t(4*lNrWordsInPacket - lNrBytesCopied) );
439 memcpy ( lIt->first, &lPageContents.at(1 + (lNrBytesCopied / 4)), lNrBytesToCopy );
440 lNrBytesCopied += lNrBytesToCopy;
void disconnect()
Close the connection to the device.
uint32_t getMaxSendSize()
Return the maximum size to be sent based on the buffer size in the target.
void returnBufferToPool(boost::shared_ptr< Buffers > &aBuffers)
Function to return a buffer to the buffer pool.
virtual void Flush()
Concrete implementation of the synchronization function to block until all buffers have been sent...
void setPath(const std::string &aPath)
A class which provides the version-specific functionality for IPbus.
minutes past the hour formatted as two digits e.g.
void write(const boost::shared_ptr< Buffers > &aBuffers)
Write request packet to next page in host-to-FPGA device file.
void implementDispatch(boost::shared_ptr< Buffers > aBuffers)
Send the IPbus buffer to the target, read back the response and call the packing-protocol's validate ...
uint32_t mPublishedReplyPageCount
uint32_t getMaxReplySize()
Return the maximum size of reply packet based on the buffer size in the target.
An abstract base exception class providing an interface to a throw/ThrowAsDerivedType mechanism which...
virtual ~Mmap()
Destructor.
const std::string & getPath() const
NameValuePairVectorType mArguments
The "key1=val1&key2=val2&key3=val3" part of a URI of the form "protocol://host:port/patha/pathb/blah...
void read()
Read next pending reply packet from appropriate page of FPGA-to-host device file, and validate conten...
_Quote< T > Quote(const T &aT)
void connect()
Set up the connection to the device.
std::deque< boost::shared_ptr< Buffers > > mReplyQueue
The list of buffers still awaiting a reply.
void read(const uint32_t aAddr, const uint32_t aNrWords, std::vector< uint32_t > &aValues)
virtual const char * what() const
Function which returns the error message associated with an exception If no error message has previou...
void write(const uint32_t aAddr, const std::vector< std::pair< const uint8_t *, size_t > > &aData)
uhal::exception::exception * mAsynchronousException
A pointer to an exception object for passing exceptions from the worker thread to the main thread...
boost::chrono::microseconds mSleepDuration
const std::vector< std::pair< const uint8_t *, size_t > > mData
File(const std::string &aPath, int aFlags)
virtual exception::exception * validate(boost::shared_ptr< Buffers > aBuffers)
Function which dispatch calls when the reply is received to check that the headers are as expected...
uint32_t mReadReplyPageCount
std::ostream & operator<<(std::ostream &aStr, const uhal::HttpResponseType &aHttpResponse)
virtual void dispatchExceptionHandler()
Function which tidies up this protocol layer in the event of an exception.
PacketFmt(const uint8_t *const, const size_t)
_Integer< T, IntFmt<> > Integer(const T &aT)
Forward declare a function which creates an instance of the ultra-lightweight wrapper from an integer...
Struct to store a URI when parsed by boost spirit.