A simplified API for passing messages between DAQModules
- Main point-of-contact for Unified API
- Methods to retrieve
Sender
/Receiver
instances usingConnectionRef
s oruid
(defined below) - Configures
Queue
s andNetworkManager
automatically inconfigure
dunedaq::get_iomanager()
will return a pointer to the IOManager singletonIOManager::get_sender<DataType>(std::string uid)
andIOManager::get_receiver<DataType>(std::string uid)
should be used to get Sender and Receiver objects connected to the appropriate connections. Note thatConnectionId
objects are not required, as they will be constructed from the provided DataType and uid arguments.- Subscribers interested in multiple connections for a single DataType should use a Regular Expression to match the desired connections; this can be anywhere from a full wildcard (
".*"
) to a specific connection UID, depending on the desired scope of the subscription. Topics are now automatically assigned by IOManager as the string representation of DataType. - The
topic
argument has been removed fromSenderConcept<T>::send
appfwk
will give DAQModules a list ofappfwk::app::ConnectionReference
objects, which associate a "name" to connection UIDs. Methods inDAQModuleHelper.hpp
take DAQModule configuration objects and extract specific UIDs for given names.
auto mandatory_connections =
appfwk::connection_index(init_data, { "token_connection", "td_connection", "busy_connection" });
m_token_connection = mandatory_connections["token_connection"];
m_td_connection = mandatory_connections["td_connection"];
auto busy_connection = mandatory_connections["busy_connection"];
m_busy_sender = iom->get_sender<dfmessages::TriggerInhibit>(busy_connection);
- Upon agreement from both endpoints, a connection can use a generated UID string (e.g. from SourceID::to_string()).
- The
serialization
library provides a new macroDUNE_DAQ_TYPESTRING(Type, string)
which is included in the standardDUNE_DAQ_SERIALIZABLE
andDUNE_DAQ_SERIALIZE_NON_INTRUSIVE
macros (called from thedunedaq
namespace only). These macros define the functiondatatype_to_string<T>
which is used by IOManager to translate a datatype to the appropriate string. This template function must be visible in every compilation unit sending or receiving a given type!- If it is not available, an error message will be produced at runtime that IOManager was unable to find connection "uid" of type Unknown
- In
daqconf
, all connections and queues must have a declared data type that matches a call toDUNE_DAQ_TYPESTRING
.add_endpoint
andconnect_modules
have changed their API to accomodate this.
ConnectionId
uniquely identifies a network connection or queueuid
: String identifier for connectiondata_type
: String representation of data type
Connection
defines a network connection, with required initializationid
:ConnectionId
connection_type
: Describes what kind of connection (kSendReceive, kPubSub)uri
: Field is used by lower-level code to configure the connection- Standard ZMQ URI should be used, e.g.
tcp://localhost:1234
(name translation is provided by IPM)
- Standard ZMQ URI should be used, e.g.
QueueConfig
represents an app-internal queueid
:ConectionId
queue_type
: Type of the queue implementation (e.g. kStdDeQueue, kFollySPSCQueue, kFollyMPMCQueue)capacity
: Capacity of the queue
Receiver
is base type without template (for use inIOManager::m_receiver
s)ReceiverConcept
introduces template and serves as class given byIOManager::get_receiver
QueueReceiverModel
andNetworkReceiverModel
implement receives and callback loop for queues and networkNetworkReceiverModel::read_network
determines if type is serializable using template metaprogramming
- Similar design as for
Receiver
s QueueSenderModel
andNetworkSenderModel
implement sends for queues and networkNetworkReceiverModel::write_network
determines if type is serializable using template metaprogramming
// Int sender
std::string uid = "bar";
int msg = 5;
std::chrono::milliseconds timeout(100);
auto isender = IOManager::get()->get_sender<int>(uid);
isender->send(msg, timeout);
isender->send(msg, timeout);
// One line send
IOManager::get()->get_sender<int>(uid)->send(msg, timeout);
// Send when timeouts may occur
bool sent = isender->try_send(msg, timeout);
// String receiver
std::string uid = "bar";
auto receiver = IOManager::get()->get_receiver<std::string>(uid);
std::string got;
try {
got = receiver->receive(timeout);
} catch (dunedaq::appfwk::QueueTimeoutExpired&) {
// Deal with exception
}
// Alternate API for when timeouts may be allowed
std::optional<std::string> ret = receiver->try_receive(timeout);
if(ret) TLOG() << "Received " << *ret;
// Callback receiver
std::string uid = "zyx";
// CB function
std::function<void(std::string)> str_receiver_cb = [&](std::string data) {
std::cout << "Str receiver callback called with data: " << data << '\n';
};
auto cbrec = IOManager::get()->get_receiver<std::string>(uid);
cbrec->add_callback(str_receiver_cb);
try {
got = cbrec->receive(timeout);
} catch (dunedaq::iomanager::ReceiveCallbackConflict&) {
// This is expected
}
IOManager::get()->remove_callback(uid);
The standard send()
and receive()
methods will throw an ERS exception if they time out. This is ideal for cases where timeouts are an exceptional condition (this applies to most, if not all send calls, for example). In cases where the timeout condition can be safely ignored (such as the callback-driving methods which are retrying the receive in a tight loop), the try_send
and try_receive
methods may be used. Note that these methods are not noexcept
, any non-timeout issues will result in an ERS exception.
Please see this page for information about updating your code to use IOManager. Also, if you are interested in using dynamic connection names, look at this page
The API used for queues is documented here. Network connections use IPM and NetworkManager