diff --git a/src/ActisenseReader.cpp b/src/ActisenseReader.cpp index 53afaa3..998f07a 100644 --- a/src/ActisenseReader.cpp +++ b/src/ActisenseReader.cpp @@ -158,7 +158,7 @@ bool tActisenseReader::GetMessageFromStream(tN2kMsg &N2kMsg, bool ReadOut) { ReadStream->read(); // Read ch out ClearBuffer(); StartOfTextReceived=true; - } + } else if ( ReadOut ) ReadStream->read(); // Read character to ensure the same character is not handled again in the loop break; default: EscapeReceived=(NewByte==Escape); @@ -185,6 +185,7 @@ void tActisenseReader::ParseMessages() { while (GetMessageFromStream(N2kMsg)) { if (MsgHandler!=0) MsgHandler(N2kMsg); + if (CallbackHandlerInterface!=0) CallbackHandlerInterface->OnMessage(N2kMsg); } } diff --git a/src/ActisenseReader.h b/src/ActisenseReader.h index 2708d5e..ca0f2e6 100644 --- a/src/ActisenseReader.h +++ b/src/ActisenseReader.h @@ -40,6 +40,25 @@ #include "N2kMsg.h" #include "N2kStream.h" +/************************************************************************//** + * \class tActisenseReaderCallbackInterface + * \brief Interface for handling 'OnMessage' callbacks from tActisenseReader + * \ingroup group_helperClass + * + * This is an interface that might be implemented and passed as an instance + * using method 'SetCallbackHandlerInterface'. It's an alternative to use + * instead of 'SetMsgHandler', when there is a need to use C++ instances + * instead of C-like function pointers. + * + */ +class tActisenseReaderCallbackInterface +{ +public: + virtual ~tActisenseReaderCallbackInterface() { } + + virtual void OnMessage(const tN2kMsg &N2kMsg) = 0; +}; + /************************************************************************//** * \class tActisenseReader * \brief Class for reading Actisense format messages @@ -79,6 +98,8 @@ class tActisenseReader N2kStream* ReadStream; // Handler callback void (*MsgHandler)(const tN2kMsg &N2kMsg); + /** \brief C++ variant of handling callbacks as an alternative to C-like 'MsgHandler' */ + tActisenseReaderCallbackInterface* CallbackHandlerInterface; protected: /********************************************************************//** @@ -122,6 +143,17 @@ class tActisenseReader void SetReadStream(N2kStream* _stream) { ReadStream=_stream; } + /********************************************************************//** + * \brief Set callback handler interface instance + * + * Set a pointer to an instance of a callback handler to be executed when + * new messages arrive from Actisense protocol. + * + * \param _callbackHandlerInterface The callback handler instance + */ + + void SetCallbackHandlerInterface(tActisenseReaderCallbackInterface* _callbackHandlerInterface) { CallbackHandlerInterface=_callbackHandlerInterface; } + /********************************************************************//** * \brief Set the default source address for the messages * diff --git a/src/NMEA2000.cpp b/src/NMEA2000.cpp index 0424b88..983c0c2 100644 --- a/src/NMEA2000.cpp +++ b/src/NMEA2000.cpp @@ -684,6 +684,7 @@ tNMEA2000::tNMEA2000() { MsgHandler=0; MsgHandlers=0; ISORqstHandler=0; + CallbackHandlerInterface=0; OpenScheduler.FromNow(0); OpenState=os_None; @@ -1252,6 +1253,7 @@ bool tNMEA2000::Open() { SetHeartbeatIntervalAndOffset(DefaultHeartbeatInterval,10000); // Init default hearbeat interval and offset. #endif if ( OnOpen!=0 ) OnOpen(); + if ( CallbackHandlerInterface!=0 ) CallbackHandlerInterface->OnOpen(); } else { // Read rubbish out from CAN controller unsigned long canId; @@ -2323,6 +2325,13 @@ void tNMEA2000::RespondISORequest(const tN2kMsg &N2kMsg, unsigned long Requested return; } } + /* If user has established a callback handler interface */ + if (CallbackHandlerInterface!=0) { + /* and if it handled the request, we are done */ + if (CallbackHandlerInterface->OnIsoRequest(RequestedPGN,N2kMsg.Source,iDev)) { + return; + } + } tN2kMsg N2kMsgR; // No user handler, or there was one and it returned FALSE. Send NAK @@ -2623,6 +2632,7 @@ void tNMEA2000::ParseMessages() { //***************************************************************************** void tNMEA2000::RunMessageHandlers(const tN2kMsg &N2kMsg) { if ( MsgHandler!=0 ) MsgHandler(N2kMsg); + if ( CallbackHandlerInterface!=0 ) CallbackHandlerInterface->OnMessage(N2kMsg); tMsgHandler *MsgHandler=MsgHandlers; // Loop through all PGN handlers @@ -2689,6 +2699,11 @@ void tNMEA2000::SetISORqstHandler(bool(*ISORequestHandler)(unsigned long Request ISORqstHandler=ISORequestHandler; } +//***************************************************************************** +void tNMEA2000::SetCallbackHandlerInterface(tNMEA2000CallbackInterface *_CallbackHandlerInterface) { + CallbackHandlerInterface=_CallbackHandlerInterface; +} + #if !defined(N2K_NO_GROUP_FUNCTION_SUPPORT) //***************************************************************************** void tNMEA2000::RemoveGroupFunctionHandler(tN2kGroupFunctionHandler *pGroupFunctionHandler) { diff --git a/src/NMEA2000.h b/src/NMEA2000.h index 84e59bc..e4c1052 100644 --- a/src/NMEA2000.h +++ b/src/NMEA2000.h @@ -107,6 +107,27 @@ /** \brief Null Address (???)*/ #define N2kNullCanBusAddress 254 +/************************************************************************//** + * \class tNMEA2000CallbackInterface + * \brief Interface for handling various NMEA2000 callbacks using C++ objects + * \ingroup group_helperClass + * + * This is an interface that might be implemented and passed as an instance + * using method 'SetCallbackHandlerInterface'. It's an alternative to use + * instead of 'OnOpen', 'MsgHandler', and 'ISORqstHandler', when there is a + * need to use C++ instances instead of C-like function pointers. + * + */ +class tNMEA2000CallbackInterface +{ +public: + virtual ~tNMEA2000CallbackInterface() { } + + virtual void OnOpen() = 0; + virtual void OnMessage(const tN2kMsg &N2kMsg) = 0; + virtual bool OnIsoRequest(unsigned long RequestedPGN, unsigned char Requester, int DeviceIndex) = 0; +}; + /************************************************************************//** * \class tNMEA2000 * \brief tNMEA2000 device class definition. @@ -1078,6 +1099,9 @@ class tNMEA2000 /** \brief Handler callbacks for 'ISORequest' messages */ bool (*ISORqstHandler)(unsigned long RequestedPGN, unsigned char Requester, int DeviceIndex); + /** \brief C++ variant of handling callbacks as an alternative to C-like function pointers */ + tNMEA2000CallbackInterface *CallbackHandlerInterface; + #if !defined(N2K_NO_GROUP_FUNCTION_SUPPORT) /** \brief Pointer to Buffer for GRoup Function Handlers*/ tN2kGroupFunctionHandler *pGroupFunctionHandlers; @@ -2792,6 +2816,18 @@ class tNMEA2000 */ void SetISORqstHandler(bool(*ISORequestHandler)(unsigned long RequestedPGN, unsigned char Requester, int DeviceIndex)); + /********************************************************************//** + * \brief Set callback handler interface instance + * + * Set a pointer to an instance of a callback handler to be executed as + * an alternative to using C-like function pointer callbacks for 'OnOpen', + * 'MsgHandler', and 'ISORqstHandler'. The callback handler must implement + * all virtual methods of the interface. + * + * \param _CallbackHandlerInterface The callback handler instance + */ + void SetCallbackHandlerInterface(tNMEA2000CallbackInterface *_CallbackHandlerInterface); + #if !defined(N2K_NO_GROUP_FUNCTION_SUPPORT) /**********************************************************************//**