/* * Copyright (c) 2025 Real-Time Innovations, Inc. All rights reserved. * No duplications, whole or partial, manual or electronic, may be made * without express written permission. Any such copies, or revisions thereof, * must display this notice unaltered. * This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef commend_readerService_h #define commend_readerService_h #ifndef reda_table_h #include "reda/reda_table.h" #endif #ifndef property_propertyNames_h #include "property/property_propertyNames.h" #endif #ifndef mig_rtps_h #include "mig/mig_rtps.h" #endif #ifndef commend_dll_h #include "commend/commend_dll.h" #endif #ifndef commend_common_h #include "commend/commend_common.h" #endif #ifndef commend_readerStatistics_h #include "commend/commend_readerStatistics.h" #endif #ifndef mig_generator_h #include "mig/mig_generator.h" #endif #ifdef __cplusplus extern "C" { #endif /* Doxygen file-level documentation =====================================*/ /*e \file \brief COMMENDReaderService *interface*--as in no implementation. */ /*e \defgroup COMMENDReaderServiceModule COMMENDReaderService * \ingroup COMMENDModule * @brief This COMMEND layer submodule defines reader services. * * COMMEND reader services enable the user to create, destroy and * configure reader endpoints in an application. * * At the COMMEND level, all distributed communication takes place * between reader and writer endpoints. Each reader endpoint receives * data from one or more remote writer endpoints and each writer * endpoint sends data to one or more remote reader endpoints, * effectively enabling many-to-many communication. * * Reader and writer endpoints are identified across the network * by a global unique identifier (GUID). * * COMMEND offers reader services with different QoS: * \li \c COMMENDBeReaderService: for best effort reader endpoints * \li \c COMMENDReaderService: for strict reliable reader endpoints * * The COMMEND layer message meta-traffic will be different for each type * of QoS. * * All reader services implement the abstract interface defined * by \c COMMENDReaderService. * * For information on how to receive data once a reader endpoint * has been created, refer to \c COMMENDReaderServiceReaderSampleListener. * * @see COMMENDBeReaderServiceModule * @see COMMENDReaderServiceModule */ /*e \defgroup COMMENDReaderServiceReaderActivityListenerModule * COMMENDReaderServiceReaderActivityListener * \ingroup COMMENDReaderServiceModule * @brief Reader activity listeners enable the user to receive information * via callbacks on communication endpoint activity, such as a remote writer * timing out. * * Detailed description of the base reader activity listeners. */ /*e \defgroup COMMENDReaderServiceReaderSampleListenerModule * COMMENDReaderServiceReaderSampleListener * \ingroup COMMENDReaderServiceModule * * @brief Reader sample listeners enable the user to receive data from a * reader endpoint via callback routines. * * Upon creation, each * reader endpoint is associated with a specific reader sample listener. * This listener contains the * callbacks that will be used for the associated reader. * * For example, as specified by the abstract interface * \c COMMENDReaderServiceReaderSampleListener, all reader * sample listeners contain an \e onNewData callback. Each time * a reader endpoint receives new data, the onNewData callback of * the associated listener will be called. * * This is illustrated in the code fragment below. * * \code * //define the callback routine * RTIBool COMMENDBeReaderServiceTester_onNewData( * const struct COMMENDReaderServiceReaderSampleListener *listener, * const struct REDASequenceNumber *firstRelevantSequenceNumber, * const struct COMMENDReaderServiceData *data, int reservedCount, * const struct COMMENDReaderServiceReaderListenerStorage *storage, * struct REDAWorker *worker) * { * //code to be executed when a new issue arrives * } * * //main function * void main() * { * * //create a reader sample listener that contains the callback routine * const struct COMMENDReaderServiceReaderSampleListener listener = { * COMMENDBeReaderServiceTester_onNewData}; * * //create a best effort reader service * service = (struct COMMENDReaderService *) * COMMENDBeReaderService_new(db, facade, NULL, ea, worker); * * //create a new reader endpoint that uses the reader sample listener * service->createReader(service, READER_OID, &listener, NULL, * &readerProperty, ea, worker) * * ... * * } * \endcode * * In the code fragment above, the \c COMMENDBeReaderServiceTester_onNewData * callback will be called each time the reader endpoint receives a new issue. * * @see COMMENDReaderServiceReaderSampleListener */ #define COMMEND_READER_SERVICE_OK (0) #define COMMEND_READER_SERVICE_ERROR (1) #define COMMEND_READER_SERVICE_PRECONDITION_NOT_MET (3) #define COMMEND_READER_SERVICE_ILLEGAL_OPERATION (4) struct COMMENDReaderService; struct COMMENDReaderServiceReaderSampleListener; struct COMMENDReaderServiceReaderStatisticsListener; struct COMMENDReaderServiceReaderActivityListener; struct COMMENDReaderServiceData { struct MIGGeneratorSample sample; /*e writer of the data */ struct MIGRtpsGuid writer; /*e intended reader */ struct MIGRtpsGuid reader; /*e context */ const struct MIGInterpreterContext *context; }; #define COMMEND_READER_SERVICE_DATA_DEFAULT \ { \ MIG_GENERATOR_SAMPLE_DEFAULT, /* sample */ \ MIG_RTPS_GUID_UNKNOWN, /* writer */ \ MIG_RTPS_GUID_UNKNOWN, /* reader */ \ NULL /* context */ \ } #define COMMEND_READER_SERVICE_LISTENER_STORAGE_LENGTH (4) struct COMMENDReaderServiceReaderListenerStorage { void *field[COMMEND_READER_SERVICE_LISTENER_STORAGE_LENGTH]; }; #define COMMENDReaderServiceReaderListenerStorage_INITIALIZER \ { \ { \ NULL, NULL, NULL, NULL \ } \ } /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * Function prototype for onNewData callback. * * Each time a reader receives a new ISSUE or VAR message, * the onNewData callback of the reader's sample * listener is called. * * * @param listener \b In. The sample listener that contains the callback. * @param firstRelevantSequenceNumber \b In. The lowest sequence number that * the reader should wait for from a specific remote writer. * @param nextRelevantRangeStartSequenceNumber \b In. The sequence number * immediately after the highest sequence number of * the current committable range. Indicates the lowest sequence number that * the reader should wait for once firstRelevantSequenceNumber has been * accepted. * @param data \b Inout. The new data that was received. Internal state may be * modified. * @param reservedCount \b In. The number of slots to be reserved for future * in order to accept currect data. If -1, do not need to check the available * space. For BE, it's always -1. For SR, any data with sn lower than the * highest sn we've accepted will use -1. * @param timestamp \b In. The arrival timestamp of the data. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return RTI_TRUE if successfully receive the new data. * * @see COMMENDReaderServiceReaderSampleListener */ typedef RTIBool (*COMMENDReaderServiceReaderSampleListenerOnNewDataCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct REDASequenceNumber *firstRelevantSequenceNumber, const struct REDASequenceNumber *nextRelevantRangeStartSequenceNumber, RTIBool *droppedSampleOutsideReaderResourceLimits, struct COMMENDReaderServiceData *data, int reservedCount, const struct RTINtpTime *timestamp, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnGetFreeCount callback for strict reliable reader sample listener. * * COMMEND uses this callback to ask the user how many slots are available * to store future incoming ISSUE or VAR messages. In the context of NDDS, * user refers to the PRESENTATION layer. * * Based on this information, COMMEND can avoid NACK'ing for more * ISSUEs/VARs than the higher level can store. * * The user need not reserve the number of slots returned by this * callback. As these slots are typically shared as a resource, * it is still possible the user will fail to accept issues * because there are no more slots available. This function * simply helps making COMMEND more efficient by minimizing * occurrence of the latter. * * @pre none * @post none * * &&& These params still need work &&& * * @param listener \b In. Object interested in the callback. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return Number of spaces available, >= 0. * * @see COMMENDReaderServiceReaderSampleListener */ typedef int (*COMMENDReaderServiceReaderSampleListenerOnGetFreeCountCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnLostData callback for strict reliable reader sample listener. * * This callback is called when the reader endpoint detects that the * \e firstAvailableSequenceNumber at the remote writer endpoint is greater * than the lowest sequence number that is missing at the reader endpoint. * * The callback therefore indicates to the user that some data was lost * and will not be recoverable as it is no longer available at the writer. * * COMMEND keeps track of the "committed sequence number" of each * reader-remote writer pair. The committedSequenceNumber is one less * than the first sequence number whose corresponding sample is in the * UNKNOWN state. * * Figure illustrates the possible states for a sample. * The initial state is UNKNOWN and eventually will become either * RECEIVED, IRRELEVANT or LOST. * * &&& Need to finish this &&& * * @pre The reader has detected that the remote writer no * longer has some data that the reader was expecting. * * @post The listener has got the info. The committed sn should be moved to * (firstRelevantSequenceNumber - 1) * * @param listener \b In. Object interested in the callback. * @param firstRelevantSequenceNumber \b In. The lowest sequence number * the reader should wait for from a specific remote writer. * @param reservedCount \b In. An updated number of slots to be reserved for * future. If -1, do not need to update the available space. For BE, it's always * -1. * @param timestamp \b In. The arrival timestamp of the lost data. * @param sampleLostCount \b In. The difference between the first uncommitted * sequence number and first relevant sequence number. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return void * * @see COMMENDReaderServiceReaderSampleListener */ typedef void (*COMMENDReaderServiceReaderSampleListenerOnLostDataCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct REDASequenceNumber *firstRelevantSequenceNumber, int reservedCount, const struct RTINtpTime *timestamp, unsigned int sampleLostCount, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnCommitData callback for strict reliable reader sample listener. * * This callback is called when the reader endpoint determines that the * "committed sequence number" can be moved forward (in response to a GAP). * * The callback therefore indicates to the user that some data is deemed * irrelevant at the writer and may be ignored possibly allowing the * committal of other previously received data. * * &&& Need to finish this &&& * * @pre The reader has determined that data may be committed as some data * the reader was expecting has been deemed irrelvant by the remote writer. * * @post The listener has got the info. The committed sn should be moved to * (firstRelevantSequenceNumber - 1) * * @param listener \b In. Object interested in the callback. * @param firstRelevantSequenceNumber \b In. The lowest sequence number * the reader should wait for from a specific remote writer. * @param reservedCount \b In. An updated number of slots to be reserved for * future. If -1, do not need to update the available space. For BE, it's always * -1. * @param timestamp \b In. The arrival timestamp of the commit data. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return void * * @see COMMENDReaderServiceReaderSampleListener */ typedef void (*COMMENDReaderServiceReaderSampleListenerOnCommitDataCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct REDASequenceNumber *firstRelevantSequenceNumber, int reservedCount, const struct RTINtpTime *timestamp, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnGetAppAck callback for strict reliable reader sample listener * with application-level acknowledgement * * COMMEND uses this callback to ask the user what its * application-level acknowledgment state is. In particular, * a PRES reader will be asked for the app-ack state for a given * PRES remote writer. * * @param listener \b In. Object interested in the callback. * @param appAckOut \b Out. An iterator that allows the COMMEND * reader to access the app-ack state provided by the user. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return void * * @see COMMENDReaderServiceReaderSampleListener */ typedef RTIBool (*COMMENDReaderServiceReaderSampleListenerOnGetAppAckCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct MIGRtpsAppAck *appAckOut, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * * OnAppConfAck callback for strict reliable reader sample listener * with application-level acknowledgement * * This callback is called when an application-level * acknowledgement confirmation message (APP_ACK_CONF) has been received. * * @param listener \b In. Object interested in the callback. * @param appAckConfIn \b In. An iterator that allows the user to access * the contents of the APP_ACK_CONF message. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return void * * @see COMMENDReaderServiceReaderSampleListener */ typedef RTIBool (*COMMENDReaderServiceReaderSampleListenerOnAppAckConfCallback)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct MIGRtpsAppAck *appAckConfIn, const struct RTINtpTime *now, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnHbVirtual callback for strict reliable reader sample listener. * Used when collaborative reliability applies * * This callback is called when an heartbeat containing virtual writer info * (HEARTBEAT_VIRTUAL) has been received. * * @param listener \b In. Object interested in the callback. * @param writerInfoList \b In. List of Writer Info * @param timestamp \b In. The arrival timestamp of the virtual HB. * @param storage \b In. The listener storage cached. * @param worker \b In. * * @return void * * @see COMMENDReaderServiceReaderSampleListener */ typedef void (*COMMENDReaderServiceReaderSampleListenerOnHeartbeatVirtual)( const struct COMMENDReaderServiceReaderSampleListener *listener, const struct MIGRtpsWriterInfoList *writerInfoList, const struct RTINtpTime *timestamp, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderSampleListenerModule * OnRemoteWriterFirstHeartbeat callback for strict reliable reader * activity listener. * * @param listener \b In. Listener that contains the callback. * @param storage \b In. The listener storage cached.&&& more info &&& * @param worker \b In.&&& more info &&& * * @return RTI_TRUE if the response must be delayed. RTI_FALSE otherwise. * * @see COMMENDReaderServiceReaderSampleListener * @see RTIEventGeneratorOnEventCallback */ typedef RTIBool ( *COMMENDReaderServiceReaderActivityListenerOnFirstHeartbeatCallback)( const struct COMMENDReaderServiceReaderActivityListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDASequenceNumber *lastSn, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * New defination: * Deprecated. Will never be called. * * Old defination: * OnRemoteWriterInactive callback for strict reliable reader * activity listener. * * A strict reliable reader keeps track of the activity state * of each of its remote writers. A remote writer is considered * active when it responds to ACK messages. * All remote writers start in the active state by default. * When a remote writer no longer replies to periodic ACK messages * (if any), the state of the remote writer switches to inactive * and this callback is called to notify the user. * * @pre The reader is sending periodic ACK messages (\c ackRate > 0 ) * and there is no response from the remote writer after \c ackRetriesMax * messages. * * @post The remote writer is in the inactive state. * * Afterwards, COMMEND keeps sending periodic * ACK messages (if \c ackRate > 0) to the remote writer. That way, the * reader can be notified when the remote writer comes back up. * * &&& when do you use ackRate == 0?? &&& * &&& would be nice to have state diagram? &&& * * @param listener \b In. Listener that contains the callback. * @param storage \b In. The listener storage cached. &&& more info &&& * @param worker \b In. &&& more info &&& * * @return void * * @see COMMENDReaderServiceReaderActivityListener * @see COMMENDReaderServiceReaderProperty for setting \c ackRate * @see COMMENDReaderServiceRemoteWriterProperty for setting \c ackRetriesMax */ typedef void ( *COMMENDReaderServiceReaderActivityListenerOnRemoteWriterInactiveCallback)( const struct COMMENDReaderServiceReaderActivityListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * New defination: * OnRemoteWriterActive callback for best effort and strict reliable reader * activity listner. * * The callback is called to notify a user a remote writer has sent some message * besides new data to indicate its liveliness. The remote writer will always be * in an active state unless it is removed. * * Old defination: * OnRemoteWriterActive callback for strict reliable reader * activity listener. * * This callback is called to notify a user a remote writer * has switched back to the active state from the inactive state. * * @pre The remote writer is in the inactive state and the reader * receives a message from the remote writer which does NOT * trigger the \c onNewData, \c onIrrelevantData or \c onLostData * callbacks. * * @post The remote writer is in the active state. * * &&& again, would be nice to have a statechart here &&& * * @param listener \b In. Listener that contains the callback. * @param storage \b In. The listener storage cached. &&& more info &&& * @param worker \b In. &&& more info &&& * * @return void * * @see COMMENDReaderServiceReaderActivityListener */ typedef void ( *COMMENDReaderServiceReaderActivityListenerOnRemoteWriterActiveCallback)( const struct COMMENDReaderServiceReaderActivityListener *listener, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * OnStateRequest callback for strict reliable reader * activity listener. * * This callback allows the user of the COMMEND layer * to choose the response time of a reader to a HEARTBEAT * message. The response can either be immediate * or within a specified time period. * * @pre The reader has received a HEARTBEAT message for which * the RTPS protocol specifies it must return an ACK message * (either the final bit in the HEARTBEAT message is zero, * or the reader is missing data). * In this case, this callback is called so the reader can * find out when to send the ACK. * * @post \li If the callback returns RTI_FALSE, it indicates an immediate ACK * response is required. All \b Out parameters are ignored in this case. * \li If the callback returns RTI_TRUE, it indicates the ACK response * must be delayed. When to send the ACK is specified by \c nextResponseTime * and \c snooze. * * @param listener \b In. Listener that contains the callback. * @param nextResponseTime \b Out. The desired absolute time the ACK is sent. * @param snooze \b Out. The maximum delay that can be tolerated for * actually sending the ACK. That is, the ACK must be sent within * \c snooze seconds after \c nextResponseTime. By allowing some * freedom in sending the ACK, the alarm task could * possibly handle multiple events at the same time, * thereby increasing overall efficiency. * The value for \c snooze can be zero. * @param storage \b In. The listener storage cached.&&& more info &&& * @param worker \b In.&&& more info &&& * * @return RTI_TRUE if the response must be delayed. RTI_FALSE otherwise. * * @see COMMENDReaderServiceReaderActivityListener * @see RTIEventGeneratorOnEventCallback */ typedef RTIBool ( *COMMENDReaderServiceReaderActivityListenerOnStateRequestCallback)( const struct COMMENDReaderServiceReaderActivityListener *listener, struct RTINtpTime *nextResponseTime, struct RTINtpTime *snooze, const struct RTINtpTime *now, const struct COMMENDReaderServiceReaderListenerStorage *storage, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Derive from this class to handle one of the three callbacks * for sample listeners. * * Usage example: * \code * //define onNewData callback * RTIBool COMMENDReaderServiceTester_onNewData( * const struct COMMENDReaderServiceReaderSampleListener *listener, * const struct REDASequenceNumber *firstRelevantSequenceNumber, * const struct COMMENDReaderServiceData *data, int reservedCount, * const struct COMMENDReaderServiceReaderListenerStorage *storage, * struct REDAWorker *worker) * { * //code to be executed when a new ISSUE or VAR message is received * } * * ... // define other callback functions * * void main() { * * //declare a strict reliable sample listener * //initialize using the callbacks defined above * struct COMMENDReaderServiceReaderSampleListener readerSampleListener = {{ * COMMENDReaderServiceTester_onNewData}, COMMENDReaderServiceTester_onLostData, COMMENDReaderServiceTester_onGetFreeCount}; * * service = (struct COMMENDReaderService *) * COMMENDReaderService_new(db, facade, NULL, ea, worker); * * //Specify the sample listener when creating a new reader. * //The callbacks in readerSampleListener will be called for this reader. * service->createReader( * service, READER_OID, * (const struct COMMENDReaderServiceReaderSampleListener *) * &readerSampleListener, * (const struct COMMENDReaderServiceReaderActivityListener *) * &readerActivityListener, * (const struct COMMENDReaderServiceReaderProperty *)&readerProperty, * ea, worker); * ... * * } * \endcode */ struct COMMENDReaderServiceReaderSampleListener { COMMENDReaderServiceReaderSampleListenerOnNewDataCallback onNewData; COMMENDReaderServiceReaderSampleListenerOnLostDataCallback onLostData; COMMENDReaderServiceReaderSampleListenerOnCommitDataCallback onCommitData; COMMENDReaderServiceReaderSampleListenerOnGetFreeCountCallback onGetFreeCount; COMMENDReaderServiceReaderSampleListenerOnGetAppAckCallback onGetAppAck; COMMENDReaderServiceReaderSampleListenerOnAppAckConfCallback onAppAckConf; COMMENDReaderServiceReaderSampleListenerOnHeartbeatVirtual onHbVirtual; }; /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Derive from this class to handle one of the three callbacks. */ #define COMMENDReaderServiceReaderSampleListener_INITIALIZER \ { \ NULL, /* onNewData */ \ NULL, /* onLostData */ \ NULL, /* onCommitData */ \ NULL, /* onGetFreeCount */ \ NULL, /* onGetAppAck */ \ NULL, /* onAppAckConf */ \ NULL /* onHbVirtual */ \ } struct COMMENDReaderServiceReaderActivityListener { COMMENDReaderServiceReaderActivityListenerOnRemoteWriterInactiveCallback onRemoteWriterInactive; COMMENDReaderServiceReaderActivityListenerOnRemoteWriterActiveCallback onRemoteWriterActive; COMMENDReaderServiceReaderActivityListenerOnStateRequestCallback onStateRequest; COMMENDReaderServiceReaderActivityListenerOnFirstHeartbeatCallback onFirstHeartbeat; }; struct COMMENDReaderServiceReaderFragmentResourceProperty { /*e The initial number of samples for which a Reader may store fragments. */ int initial_fragmented_samples; /*e The maximum number of samples for which a Reader may store fragments. */ int max_fragmented_samples; /*e The maximum number of samples per remote writer for which a Reader may store fragments. */ int max_fragmented_samples_per_remote_writer; /*e Maximum number of fragments the reader can store per sample. */ int max_fragments_per_sample; /*e Maximum size of any (fragmented) sample this reader will receive.*/ int max_sample_size; int max_sample_params_size; /* * when true, the service will not pre-allocate memory, but instead will * allocate memory from the heap upon receiving the first fragment of a new * sample. * The amount of memory allocated equals the amount of * memory needed to store all fragments in the sample. Once all fragments * of a sample have been received, the sample is deserialized and stored * in the regular receive queue. At that time, the dynamically allocated * memory is freed again if the SampleDataPool is not loaned. If it is * loaned from pres reader, then the memory is freed from pres when the * samples are returned. */ RTIBool useDynamicSampleDataPool; }; #define COMMEND_READER_SERVICE_READER_FRAGMENT_RESOURCE_PROPERTY_DEFAULT \ { \ 4, /* initial_fragmented_samples */ \ 1024, /* max_fragmented_samples */ \ 2, /* max_fragmented_samples_per_remote_writer */ \ 256, /* max_fragments_per_sample */ \ 1024 * 1024, /* max_sample_size */ \ -1, /* max_sample_params_size */ \ RTI_TRUE /* useDynamicSampleDataPool */ \ } /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * This one only applies to participant's stateless reader (the one used for * authentication). See COMMEND_READER_LOSS_PERCENTAGE_EXTENDED and * COMMEND_READER_LOSS_PERCENTAGE. */ #define COMMEND_STATELESS_READER_LOSS_PERCENTAGE \ PROPERTY_NAME_DDS_PARTICIPANT_STATELESS_DATA_READER_LOSS_PERCENTAGE /* Format: \ , \ */ /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Configures the loss percentage of samples for a reader. See also * COMMEND_READER_LOSS_PERCENTAGE_EXTENDED and * COMMEND_STATELESS_READER_LOSS_PERCENTAGE. If several of those properties are * set, only one of them is applied following the order of precedence: * COMMEND_READER_LOSS_PERCENTAGE_EXTENDED > COMMEND_READER_LOSS_PERCENTAGE > * COMMEND_STATELESS_READER_LOSS_PERCENTAGE * * Format: * R|D,percentage,lastLostSeqNum,lossDuration * * - R: In case of Random, random samples will be dropped and accrued towards * the overall percentage of samples lost. * - D: In the case of Deterministic loss, (seqnum % 100/percentage) will be * dropped. * * - percentage is the percentage of samples that will be dropped. * * - lastLostSeqNum is the last sequence number that was dropped. * After this sequence number the sample will not be dropped. * If it is 0xffff or -1, this parameter will be ignored. * if ((lastLostSN > 0xffff) || (lastLostSN < 0)) { * lastLostSN = 0xffff; * } * * - lossDuration is the time in seconds that the samples will be lost. * Min value = 0, max value = 254. * If lossDuration is 0xff or -1, that value will be ignored. * if ((lossDuration > 0xff) || (lossDuration < 0)) { * lossDuration = 0xff; * } * * Example usage: * "D,100,-1,-1" drop all the samples. * "R,20,-1,5" drop random samples (overall 20%) but not after 5 seconds. * "D,50,100,-1" drop every other sample until their seqNum is more than * 100. */ #define COMMEND_READER_LOSS_PERCENTAGE \ PROPERTY_NAME_DDS_DATA_READER_LOSS_PERCENTAGE /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Configures the loss percentage of samples for a reader. See also * COMMEND_READER_LOSS_PERCENTAGE and COMMEND_STATELESS_READER_LOSS_PERCENTAGE. * If several of those properties are set, only one of them is applied following * the order of precedence: * COMMEND_READER_LOSS_PERCENTAGE_EXTENDED > COMMEND_READER_LOSS_PERCENTAGE > * COMMEND_STATELESS_READER_LOSS_PERCENTAGE * * Format: * R|D|,S|F,percentage,firstLostSeqNum,lastLostSeqNum,firstLostFragment,lastLostFragment,lossDuration * * - Drop policy: * - R: In case of Random, random samples or fragments will be dropped and * accrued towards the overall percentage of samples lost. * - D: In the case of Deterministic, loss is based on the sample sequence * number or first fragment number, (num % 100/percentage) will be dropped. * * - Sample/Fragment: * - S: The drop policy is applied to samples. firstLostSeqNum and * lastLostSeqNum are applied if configured. * - F: The drop policy is applied to fragments. firstLostFragment and * lastLostFragment are applied if configured. Remember that we use the first * fragment in the DATA_FRAG to do the comparisons, therefore if there are * more than one fragments per DATA_FRAGE there could be fragments in the lost * interval that will not be dropped. * firstLostSeqNum and lastLostSeqNum are also applied if configured. * * - percentage: the percentage of samples or fragments that will be dropped * when using the random policy. When using the deterministic policy, this value * is used to compute the module as described above. Range [0, 100], values * outside this range will be mapped to the maximum value. Min value = 0, max * value = 100. * * - firstLostSeqNum is the first sample sequence number that will be dropped. * Before this sequence number the sample will not be dropped. Range [0, 65534] * and -1, values outside this range will be mapped to 0xFFFF ignoring this * setting. * - lastLostSeqNum is the last sample sequence number that will be dropped. * After this sequence number the sample will not be dropped. Range [0, 65534] * and -1, values outside this range will be mapped to 0xFFFF ignoring this * setting. * * - firstLostFragment is the first fragment number that will be dropped. Before * this fragment number the fragment will not be dropped. Range [0, 254] and -1, * values outside this range will be mapped to 0xFF ignoring this setting. * - lastLostFragment is the last fragment number that was dropped. After this * fragment number the fragment will not be dropped. Range [0, 254] and -1, * values outside this range will be mapped to 0xFF ignoring this setting. * * - lossDuration is the time in seconds that the samples will be lost. * Range [0, 254] and -1, values outside this range will be mapped to the * maximum value. When set to -1 the duration is ignored. * * Example usage: * - "D,S,100,-1,-1,-1,-1,-1" drop all the samples. * - "R,S,20,-1,-1,-1,-1,5" drop random samples (overall 20%) but not after * 5 seconds. * - "D,S,50,1,100,-1,-1,-1" drop every other sample until their seqNum * is more than 100. * - "D,F,50,-1,-1,20,30,-1" drop every other fragment between 20 and 30 * for all samples. * - "R,F,20,5,10,1,5,-1" drop random samples and fragments (overall 20%) * between SN 5 and 10 and fragments between 1 and 5. */ #define COMMEND_READER_LOSS_PERCENTAGE_EXTENDED \ PROPERTY_NAME_DDS_DATA_READER_LOSS_PERCENTAGE_EXTENDED #define COMMEND_READER_TIMESTAMP_FIRST_FRAG_ONLY \ PROPERTY_NAME_DDS_DATA_READER_TIMESTAMP_FIRST_FRAG_ONLY /* boolean */ typedef enum { COMMEND_READER_LOSS_KIND_RANDOM_SAMPLE, COMMEND_READER_LOSS_KIND_RANDOM_FRAGMENT, COMMEND_READER_LOSS_KIND_DETERMINISTIC_SAMPLE, COMMEND_READER_LOSS_KIND_DETERMINISTIC_FRAGMENT } COMMENDReaderLossKind; struct COMMENDReaderServiceReaderProperty { /*e specified for any destination a reader may create */ int transportPriority; /*e specified for local reader */ struct RTINetioAliasList transportAliasList; /*e multicast entryport. Can be INVALID */ struct RTINetioLocator multicastEntryport; int multicastEntryportCount; /*e Description for unicast entryports. Can be 0 to * COMMEND_COMMON_APP_IPADDRESS_COUNT_MAX. */ struct RTINetioLocator unicastEntryport[COMMEND_COMMON_APP_IPADDRESS_COUNT_MAX]; int unicastEntryportCount; /*e Whether this reader supports fragmented samples. */ RTIBool supportsFragments; /*e Resource properties for storing fragments. Only relevant if supportsFragments == RTI_TRUE. */ struct COMMENDReaderServiceReaderFragmentResourceProperty fragmentResources; /* * Indicates if dataFrag messages should be compatible with RTI DDS 43 * In 43 the format of the DataFrag message was not compliante with the RTPS * spec */ RTIBool use43DataFragFormat; /* * \brief Percentage of sample or fragment losses * * The following field is only used for testing. * * This value is initialized from the property * COMMEND_READER_LOSS_PERCENTAGE or COMMEND_READER_LOSS_PERCENTAGE_EXTENDED */ RTI_UINT64 lossPercentage; /* * \brief Indicates if the losses are random or deterministic and if they * affect to fragments or samples. * * The following field is only used for testing. * * If the losses are deterministic they a sample or fragment is lost if * num%(100/lossPercentage) == 0 where num is the SN (sn) for samples or the * first fragment number (fn) for fragments. */ COMMENDReaderLossKind lossKind; /* \brief Indicates whether INFO_TS prepended only to sample with first * fragment of sample * * The following field is only used for testing. * * If RTI_TRUE, INFO_TS is allowed only from sample containing first * fragment of sample. All other samples with fragments have context's * timestamp reset, nullifying effect of prepended INFO_TS. */ RTIBool timestampOnlyFirstFrag; /*e Indicates if UDPv4 loopback destinations should be ignored when the * associated writer is reachable through shared memory. */ RTIBool ignoreRedundantUdpv4LoopbackDestinations; /*e Indicates if UDPv6 loopback destinations should be ignored when the * associated writer is reachable through shared memory. */ RTIBool ignoreRedundantUdpv6LoopbackDestinations; /* e Indicates if the reader should ignore all the entry ports, and * therefore not to create/share any receive resource. */ RTIBool ignoreEntryPorts; /* Topic name for the Commend reader */ char *topicName; /*i \brief maximum length of a sample for unprotected channels */ RTI_UINT32 channelsMaxSampleLength; /* Security behavior of the reader */ struct MIGGeneratorSecurityProperty security; }; /* clang-format off */ #define COMMEND_READER_SERVICE_READER_PROPERTY_DEFAULT \ { \ NDDS_TRANSPORT_PRIORITY_DEFAULT, /* transportPriority */ \ RTI_NETIO_ALIAS_LIST_DEFAULT, /* aliasList */ \ RTI_NETIO_LOCATOR_INVALID, /* multicastEntryport */ \ 0, /* multicastEntryportCount */ \ RTI_NETIO_RTPS_LOCATOR_LIST_DEFAULT, /* unicastEntryport */ \ 0, /* unicastEntryportCount */ \ RTI_FALSE, \ COMMEND_READER_SERVICE_READER_FRAGMENT_RESOURCE_PROPERTY_DEFAULT, \ RTI_FALSE, /* use43DataFragFormat */ \ 0, /* lossPercentage */ \ RTI_TRUE, /* randomLoss */ \ RTI_FALSE, /* timestampOnlyFirstFrag */ \ RTI_FALSE, /* ignoreRedundantUdpv4LoopbackDestinations */ \ RTI_FALSE, /* ignoreRedundantUdpv6LoopbackDestinations */ \ RTI_FALSE, /* ignoreEntryPorts */ \ NULL, /* topicName */ \ MIG_UNPROTECTED_CHANNELS_MAX_LENGTH_DEFAULT, /* channelsMaxSampleLength */ \ MIG_GENERATOR_SECURITY_PROPERTY_DEFAULT /* security */ \ } /* clang-format on */ struct COMMENDReaderServiceRemoteWriterProperty; /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * @brief The reader service properties determine the amount of memory * allocated when creating the reader service. * * The allocation block sizes should be set to the expected number of * readers/remote writers that will be created/asserted using the reader * service. If more readers/remote writers end up being created/asserted, the * reader service will automatically allocate more memory. * * @see COMMEND_READER_SERVICE_PROPERTY_DEFAULT */ struct COMMENDReaderServiceProperty { /*e Allocation block size for reader table.*/ struct REDATableProperty localTable; /* remote reader table property */ struct REDATableProperty remoteTable; }; /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Function prototype for adding a new reader endpoint to a reader service. * * COMMEND reader endpoints implement the receiver end of the RTPS * protocol. They hold no data, but handle the communication state, such * as keep track of last received sequence number, respond to heartbeats, * etc. The exact protocol a reader end-point implements is determined * by the QoS type of its reader service. * * New data arrivals or communication state changes are * communicated to the user using sample and activity listeners respectively. * * @pre All pointer parameters are valid and not NULL. * @pre No reader with identical ObjectId \e oid has been added before. * @post A new reader entry is added to the reader service. * * @param me \b In. Pointer to the reader service instance the function is * called upon. * * @param recordWR \b Out. * * @param oid \b In. The new reader's ObjectId. * @param loanedFstSampleDataPool \b In. Loaned sample data pool for * reassembling serialized sample from fragments. * @param sampleListener \b In. Pointer to the sample listener you want to * install for this reader. * @param activityListener \b In. Pointer to the activity listener you want to * install for this reader. * @param property \b In. Pointer to the new reader's desired properties. * @param ea \b In. Pointer to an exclusive area you want this reader to use * (can be shared among readers). * @param worker \b In. Pointer to a worker that will be used to create this * reader. * * @return RTI_TRUE if success, RTI_FALSE otherwise. * * @see COMMENDReaderService */ typedef RTIBool (*COMMENDReaderServiceReaderCreateFunction)( struct COMMENDReaderService *me, struct REDAWeakReference *recordWR, MIGRtpsObjectId oid, struct REDAFastBufferPool *loanedFstSampleDataPool, const struct COMMENDReaderServiceReaderSampleListener *sampleListener, const struct COMMENDReaderServiceReaderActivityListener *activityListener, const struct COMMENDReaderServiceReaderListenerStorage *storage, const struct COMMENDReaderServiceReaderProperty *property, struct REDAExclusiveArea *ea, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Function prototype for removing a reader endpoint from a reader service. * * This call frees up all resources within the reader service * associated with the reader endpoint and its remote writer end-points. * * @pre All pointer parameters are valid and not NULL. * @pre The reader service contains a reader entry with ObjectId \e oid. * @post The reader entry is removed from the reader service. * * @param me \b In. Pointer to the reader service instance the function is * called upon. * @param oid \b In. The reader's ObjectId. * @param worker \b In. Pointer to a worker that will be used to remove this * reader. * * @return RTI_TRUE if success, RTI_FALSE otherwise. * * @see COMMENDReaderService */ typedef RTIBool (*COMMENDReaderServiceReaderDestroyFunction)( struct COMMENDReaderService *me, MIGRtpsObjectId oid, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Function prototype for asserting a remote writer or modifying an existing * remote writer. * * Each reader endpoint must keep track of the state of its remote * writer endpoints in order to be able to implement the RTPS protocol. * In order to respond to a heartbeat for example, a reader endpoint * must keep track of the latest sequence number it received from that * remote writer endpoint. * * When asserting a remote writer, the necessary * data structures are initialized to keep track of all information * related to that writer. * * When modifying an existing remote writer, all immutable parameters will * be ignored (i.e., use NULL in this case is fine). It's caller's * reponsibility to make sure those parameters are the same as the ones * used when first assert the remote writer. Here, only certain fields in * property are mutable. Refer to specific property for what fields are * mutable. * * @pre All pointer parameters are valid and not NULL. * @pre The reader service contains a reader entry with ObjectId \e oid. * @pre &&& TODO: define precondition of the GUID &&& * @post An entry is added for the remote writer. * * @param me \b In. Pointer to the reader service instance the function is * called upon. * @param oid \b In. The ObjectId (see RTPS specification) of the reader for * which you assert this remote writer. * @param guid \b In. Pointer to the remote writer's GUID (see RTPS * specification). * @param storage \b In. &&& TODO &&& * @param property \b In. Pointer to the remote writer's properties. If a remote * writer with the guid has been asserted before, the immutable parts in the * property will be ignored, and so those parts can be set to any value. * @param worker \b In. Pointer to a worker that will be used to assert this * remote writer. * * @return RTI_TRUE if success, RTI_FALSE otherwise. * * @see COMMENDReaderService */ typedef RTIBool (*COMMENDReaderServiceRemoteWriterAssertFunction)( struct COMMENDReaderService *me, MIGRtpsObjectId oid, const struct MIGRtpsGuid *guid, const struct COMMENDReaderServiceReaderListenerStorage *sampleStorage, const struct COMMENDReaderServiceReaderListenerStorage *activityStorage, const struct COMMENDReaderServiceRemoteWriterProperty *property, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Function prototype for removing a remote writer. * * This call frees up all resources within the reader service * associated with the specified remote writer. * * @pre All pointer parameters are valid and not NULL. * @pre The reader service contains a reader entry with ObjectId \e oid. * pre &&& TODO: define precondition on the GUID &&& * @post The entry for the remote writer has been removed. * * @param me \b In. Pointer to the reader service instance the function is * called upon. * @param readerOid \b In. The ObjectId (see RTPS specification) of the reader * whose remote writer will be removed. * @param remoteWriterGuid \b In. Pointer to the remote writer's GUID (see RTPS * specification). * @param worker \b In. Pointer to a worker that will be used to remove this * remote writer. * * @return RTI_TRUE if success, RTI_FALSE otherwise. * * @see COMMENDReaderService */ typedef RTIBool (*COMMENDReaderServiceRemoteWriterRemoveFunction)( struct COMMENDReaderService *me, MIGRtpsObjectId readerOid, const struct MIGRtpsGuid *remoteWriterGuid, struct REDAWorker *worker); typedef RTIBool (*COMMENDReaderServiceReaderPropertySetFunction)( struct COMMENDReaderService *me, MIGRtpsObjectId oid, const struct COMMENDReaderServiceReaderProperty *p, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Shutdown the reader service. It should be done before the active facade * shutdown. * * @param w \b In. * @param worker \b In. * * @return */ typedef void (*COMMENDReaderServiceShutdownFunction)( struct COMMENDReaderService *w, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Delete a reader service. * * When deleting a reader service, all its reader endpoints * are automatically destroyed too. * * @pre Parameters are valid, non-NULL pointers. * @post The reader service is deleted. * * @param me \b In. Pointer to the service to be deleted. * @param worker \b In. Pointer to a worker that will perform the deletion. * * @return void * * @see COMMENDBeReaderService_new */ typedef void (*COMMENDReaderServiceDeletionFunction)( struct COMMENDReaderService *me, struct REDAWorker *worker); typedef RTIBool (*COMMENDReaderServiceGetLocalReaderStatisticsFunction)( struct COMMENDReaderService *me, struct COMMENDReaderServiceLocalReaderStatistics *stats, const struct REDAWeakReference *reader, RTIBool clearChange, struct REDAWorker *worker); typedef RTIBool (*COMMENDReaderServiceGetMatchedPublicationStatisticsFunction)( struct COMMENDReaderService *me, struct COMMENDReaderServiceMatchedWriterStatistics *status, const struct MIGRtpsGuid *guid, const struct REDAWeakReference *reader, RTIBool clearChange, struct REDAWorker *worker); typedef RTIBool (*COMMENDReaderServiceSetLocalReaderStatisticsFunction)( struct COMMENDReaderService *me, const struct COMMENDReaderServiceLocalReaderStatistics *stats, const struct REDAWeakReference *reader, struct REDAWorker *worker); typedef RTIBool (*COMMENDReaderServiceSetMatchedPublicationStatisticsFunction)( struct COMMENDReaderService *me, const struct COMMENDReaderServiceMatchedWriterStatistics *status, const struct MIGRtpsGuid *guid, const struct REDAWeakReference *reader, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Sets the last received sn for the input remote writer. * * After the function call: * * If offsetMode is 0, all the sequence numbers less or equal to sn * will be considered as received. * * If offsetMode is < 0, all the sequence numbers less or equal to * remoteWriterLastSn - sn will be considered as received. * * If offsetMode is > 0 all the sequence numbers greater or equal to * remoteWriterLastSn + sn will be considered as received. * * remoteWriterLastSn represents the last sequence available * in the writer. * * This function can be called only for COMMENDSrReaderService objects. * * @pre Parameters are valid, non-NULL pointers. * @pre remoteWriterGuid must correspond to a publication currently * associated with the reader identified by readerOid. * @pre The function must be called before the reader receives any sample * from the remote writer. * * @param me \b In. Pointer to the reader service instance the function is * called upon. * @param failReason \b Out. Fail reason. * @param remoteWriterGuid \b In. remote Writer Guid. * @param sn \b In. New sequence number. Depending on the value * of offsetMode, that sequence number will be interpreted as an offset * or as an absolute value. * @param worker \b In. Pointer to the worker calling this function. * * @return RTI_TRUE if success. Otherwise, RTI_FALSE. * If there is a failure *failReason will be initialized with the failure * reason. */ typedef RTIBool (*COMMENDReaderServiceSetReaderLastReceivedSnFunction)( struct COMMENDReaderService *me, int *failReason, MIGRtpsObjectId readerOid, const struct MIGRtpsGuid *remoteWriterGuid, int offsetMode, const struct REDASequenceNumber *sn, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Sends an APP_ACK message to a remote writer * * @param me \b In. Reader service instance * @param failReason \b Out. Fail reason. * @param reader Weak \b In. reference to the reader that will send the message * @param remoteWriterGuid \b In. Remote writer guid, destination of the message * @param appAck \b In. The application-level acknowledgment state * for this remote writer's virtual writers. * @param worker \b In. Pointer to the worker calling this function. * * @return RTI_TRUE if success. Otherwise, RTI_FALSE. * If there is a failure *failReason will be initialized with the failure * reason. */ typedef RTIBool (*COMMENDSrReaderServiceSendAppAckFunction)( struct COMMENDReaderService *me, int *failReason, const struct REDAWeakReference *reader, const struct MIGRtpsGuid *remoteWriterGuid, struct MIGRtpsAppAck *appAck, struct REDAWorker *worker); /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * @brief Abstract interface (no implementation). * Defines the reader service interface. * * COMMEND offers multiple types of reader services * for different QoS settings. All reader services * implement the abstract \c COMMENDReaderService interface * such that they all share a common API. * * This common reader service interface consists of: * \li \c createReader: create a reader endpoint. * \li \c destroyReader: destroy a reader endpoint. * \li \c assertRemoteWriter: assert a remote writer endpoint for a given reader * endpoint. * \li \c removeRemoteWriter: remove a remote writer endpoint for a given reader * endpoint. * * For a detailed description of each function, refer to the * function prototype definitions. * * For actual implementations of the interface, refer to * \li \c COMMENDBeReaderService * \li \c COMMENDReaderService * * The code sample below illustrates how to use the reader service * interface in the case of a strict reliable reader service. * \code * struct COMMENDReaderService *readerService = NULL; * * //Create a new strict reliable reader service and type-cast it * readerService = (struct COMMENDReaderService *) * COMMENDReaderService_new(db, facade, NULL, ea, worker); * * //Create a new Reader using this reader service * readerService->createReader(readerService, READER_OID, ...); * * //Assert a remote writer for this reader * readerService->assertRemoteWriter(readerService, READER_OID, ...); * \endcode * * In this case, the function pointers in *readerService are initialized by * \c COMMENDReaderService_new so that they point to the functions * that implement the reader service API for strict reliable readers. * * @see COMMENDBeReaderServiceModule * @see COMMENDReaderServiceModule */ struct COMMENDReaderService { COMMENDReaderServiceReaderCreateFunction createReader; COMMENDReaderServiceReaderDestroyFunction destroyReader; COMMENDReaderServiceRemoteWriterAssertFunction assertRemoteWriter; COMMENDReaderServiceRemoteWriterRemoveFunction removeRemoteWriter; COMMENDReaderServiceReaderPropertySetFunction setReaderProperty; COMMENDReaderServiceSetReaderLastReceivedSnFunction setReaderLastReceivedSn; COMMENDReaderServiceShutdownFunction shutdown; COMMENDReaderServiceDeletionFunction deleteService; COMMENDReaderServiceGetLocalReaderStatisticsFunction getLocalReaderStatistics; COMMENDReaderServiceGetMatchedPublicationStatisticsFunction getMatchedPublicationStatistics; COMMENDReaderServiceSetLocalReaderStatisticsFunction setLocalReaderStatistics; COMMENDReaderServiceSetMatchedPublicationStatisticsFunction setMatchedPublicationStatistics; COMMENDSrReaderServiceSendAppAckFunction sendAppAck; }; /*e \ingroup COMMENDReaderServiceReaderActivityListenerModule * Default reader service property values. * * Defines the default values for \c COMMENDReaderServiceProperty. * * Reader service property values are set using the \e property parameter in * \c COMMENDReaderService_new or \c COMMENDBeReaderService_new. * Passing NULL sets the properties to the values specified by * \c COMMEND_READER_SERVICE_PROPERTY_DEFAULT. * * Example usage: * \code * struct COMMENDReaderService *service = NULL; * * //create a reader service with default properties * service = (struct COMMENDReaderService *) * COMMENDBeReaderService_new(db, facade, NULL, ea, worker); * \endcode */ #define COMMEND_READER_SERVICE_PROPERTY_DEFAULT \ { \ /* localTable */ \ { { 16, \ REDA_FAST_BUFFER_POOL_UNLIMITED, \ REDA_FAST_BUFFER_POOL_UNLIMITED }, \ 1 }, \ /* remoteTable */ \ { \ { 16, \ REDA_FAST_BUFFER_POOL_UNLIMITED, \ REDA_FAST_BUFFER_POOL_UNLIMITED }, \ 1 \ } \ } #ifdef __cplusplus } /* extern "C" */ #endif #include "commend/commend_readerService_impl.h" #endif /* commend_readerService_h */