intermediate: add nmea0183 to n2k
This commit is contained in:
		
							parent
							
								
									0b4aa58d71
								
							
						
					
					
						commit
						c8778e4ceb
					
				|  | @ -0,0 +1,132 @@ | |||
| #include "NMEA0183DataToN2K.h" | ||||
| #include "NMEA0183Messages.h" | ||||
| NMEA0183DataToN2K::NMEA0183DataToN2K(GwLog *logger, GwBoatData *boatData,N2kSender callback) | ||||
| { | ||||
|     this->sender = callback; | ||||
|     this->logger = logger; | ||||
|     this->boatData=boatData; | ||||
|     LOG_DEBUG(GwLog::LOG,"NMEA0183DataToN2K created %p",this); | ||||
| } | ||||
| 
 | ||||
| bool NMEA0183DataToN2K::parseAndSend(const char *buffer, int sourceId) { | ||||
|     LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] parsing %s",sourceId,buffer) | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K{ | ||||
|     public: | ||||
|         typedef void (NMEA0183DataToN2KFunctions::*Converter)(const tNMEA0183Msg  &msg); | ||||
|     private:     | ||||
|         class ConverterEntry | ||||
|         { | ||||
|             public: | ||||
|                 unsigned long count = 0; | ||||
|                 unsigned long *pgn; | ||||
|                 unsigned int numPgn=0; | ||||
|                 Converter converter; | ||||
|                 ConverterEntry(){ | ||||
|                     pgn=NULL; | ||||
|                     converter=NULL; | ||||
|                 } | ||||
|                 ConverterEntry(unsigned long pgn,Converter cv = NULL) { | ||||
|                      converter = cv;  | ||||
|                      numPgn=1; | ||||
|                      this->pgn=new unsigned long[1]; | ||||
|                      this->pgn[0]=pgn; | ||||
|                      } | ||||
|                 ConverterEntry(unsigned long pgn1,unsigned long pgn2,Converter cv = NULL) { | ||||
|                      converter = cv;  | ||||
|                      numPgn=2; | ||||
|                      this->pgn=new unsigned long[2]; | ||||
|                      this->pgn[0]=pgn1; | ||||
|                      this->pgn[1]=pgn2; | ||||
|                      } | ||||
|                 ConverterEntry(unsigned long pgn1,unsigned long pgn2,unsigned long pgn3,Converter cv = NULL) { | ||||
|                      converter = cv;  | ||||
|                      numPgn=3; | ||||
|                      this->pgn=new unsigned long[3]; | ||||
|                      this->pgn[0]=pgn1; | ||||
|                      this->pgn[1]=pgn2; | ||||
|                      this->pgn[2]=pgn3; | ||||
|                      }           | ||||
|         }; | ||||
|         typedef std::map<String, ConverterEntry> ConverterMap; | ||||
|         ConverterMap converters; | ||||
| 
 | ||||
|         /**
 | ||||
|         *  register a converter | ||||
|         *  each of the converter functions must be registered in the constructor  | ||||
|         **/ | ||||
|         void registerConverter(unsigned long pgn, String sentence,Converter converter) | ||||
|         { | ||||
|             ConverterEntry e(pgn,converter); | ||||
|             converters[sentence] = e; | ||||
|         } | ||||
|         void registerConverter(unsigned long pgn,unsigned long pgn2, String sentence,Converter converter) | ||||
|         { | ||||
|             ConverterEntry e(pgn,pgn2,converter); | ||||
|             converters[sentence] = e; | ||||
|         } | ||||
| 
 | ||||
|         void convertRMB(const tNMEA0183Msg &msg){ | ||||
|             LOG_DEBUG(GwLog::DEBUG+1,"convert RMB"); | ||||
|         } | ||||
|     public: | ||||
|         virtual bool parseAndSend(const char *buffer, int sourceId) { | ||||
|             LOG_DEBUG(GwLog::DEBUG+1,"NMEA0183DataToN2K[%d] parsing %s",sourceId,buffer) | ||||
|             tNMEA0183Msg msg; | ||||
|             if (! msg.SetMessage(buffer)){ | ||||
|                 LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] invalid message %s",sourceId,buffer) | ||||
|                 return false; | ||||
|             } | ||||
|             String code=String(msg.MessageCode()); | ||||
|             ConverterMap::iterator it=converters.find(code); | ||||
|             if (it != converters.end()){ | ||||
|                 (it->second).count++; | ||||
|                 //call to member function - see e.g. https://isocpp.org/wiki/faq/pointers-to-members
 | ||||
|                 ((*this).*((it->second).converter))(msg);    | ||||
|             } | ||||
|             else{ | ||||
|                 LOG_DEBUG(GwLog::DEBUG,"NMEA0183DataToN2K[%d] no handler for  %s",sourceId,code.c_str()); | ||||
|                 return false; | ||||
|             } | ||||
|             return true; | ||||
|         }     | ||||
|         virtual unsigned long *handledPgns() | ||||
|         { | ||||
|             logger->logString("CONV: # %d handled PGNS", (int)converters.size()); | ||||
|             //for now max 3 pgns per converter
 | ||||
|             unsigned long *rt = new unsigned long[converters.size() *3 + 1]; | ||||
|             int idx = 0; | ||||
|             for (ConverterMap::iterator it = converters.begin(); | ||||
|                 it != converters.end(); it++) | ||||
|             {    | ||||
|                 for (int i=0;i<it->second.numPgn && i < 3;i++){ | ||||
|                     bool found=false; | ||||
|                     for (int e=0;e<idx;e++){ | ||||
|                         if (rt[e] == it->second.pgn[i]){ | ||||
|                             found=true; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                     if (! found){ | ||||
|                         rt[idx] = it->second.pgn[i]; | ||||
|                         idx++; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             rt[idx] = 0; | ||||
|             return rt; | ||||
|         } | ||||
|         NMEA0183DataToN2KFunctions(GwLog *logger,GwBoatData *boatData,N2kSender callback) | ||||
|             :NMEA0183DataToN2K(logger,boatData,callback){ | ||||
|                 registerConverter(129283UL,String(F("RMB")),&NMEA0183DataToN2KFunctions::convertRMB); | ||||
|             } | ||||
|    | ||||
| }; | ||||
| 
 | ||||
| NMEA0183DataToN2K* NMEA0183DataToN2K::create(GwLog *logger,GwBoatData *boatData,N2kSender callback){ | ||||
|     return new NMEA0183DataToN2KFunctions(logger, boatData,callback); | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,20 @@ | |||
| #ifndef _NMEA0183DATATON2K_H | ||||
| #define _NMEA0183DATATON2K_H | ||||
| #include "GwLog.h" | ||||
| #include "GwBoatData.h" | ||||
| #include "N2kMessages.h" | ||||
| 
 | ||||
| class NMEA0183DataToN2K{ | ||||
|     public: | ||||
|         typedef bool (*N2kSender)(const tN2kMsg &msg); | ||||
|     protected: | ||||
|         GwLog * logger; | ||||
|         GwBoatData *boatData; | ||||
|         N2kSender sender; | ||||
|     public: | ||||
|         NMEA0183DataToN2K(GwLog *logger,GwBoatData *boatData,N2kSender callback); | ||||
|         virtual bool parseAndSend(const char *buffer, int sourceId); | ||||
|         virtual unsigned long *handledPgns()=0; | ||||
|         static NMEA0183DataToN2K* create(GwLog *logger,GwBoatData *boatData,N2kSender callback); | ||||
| }; | ||||
| #endif | ||||
							
								
								
									
										25
									
								
								src/main.cpp
								
								
								
								
							
							
						
						
									
										25
									
								
								src/main.cpp
								
								
								
								
							|  | @ -41,6 +41,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting | |||
| #include "GwMessage.h" | ||||
| #include "GwSerial.h" | ||||
| #include "GwWebServer.h" | ||||
| #include "NMEA0183DataToN2K.h" | ||||
| 
 | ||||
| 
 | ||||
| //NMEA message channels
 | ||||
|  | @ -70,11 +71,8 @@ int NodeAddress;  // To store last Node Address | |||
| 
 | ||||
| Preferences preferences;             // Nonvolatile storage on ESP32 - To store LastDeviceAddress
 | ||||
| N2kDataToNMEA0183 *nmea0183Converter=NULL; | ||||
| NMEA0183DataToN2K *toN2KConverter=NULL; | ||||
| 
 | ||||
| // Set the information for other bus devices, which messages we support
 | ||||
| const unsigned long TransmitMessages[] PROGMEM = {127489L, // Engine dynamic
 | ||||
|                                                   0 | ||||
| }; | ||||
| 
 | ||||
| void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg,int id); | ||||
| 
 | ||||
|  | @ -86,6 +84,8 @@ GwConfigInterface *sendUsb=NULL; | |||
| GwConfigInterface *sendTCP=NULL; | ||||
| GwConfigInterface *sendSeasmart=NULL; | ||||
| GwConfigInterface *systemName=NULL; | ||||
| GwConfigInterface *n2kFromUSB=NULL; | ||||
| GwConfigInterface *n2kFromTCP=NULL; | ||||
| 
 | ||||
| GwSerial usbSerial(NULL, UART_NUM_0, USB_CHANNEL_ID); | ||||
| class GwSerialLog : public GwLogWriter{ | ||||
|  | @ -254,6 +254,8 @@ void setup() { | |||
|   sendTCP=config.getConfigItem(config.sendTCP,true); | ||||
|   sendSeasmart=config.getConfigItem(config.sendSeasmart,true); | ||||
|   systemName=config.getConfigItem(config.systemName,true); | ||||
|   n2kFromTCP=config.getConfigItem(config.tcpToN2k,true); | ||||
|   n2kFromUSB=config.getConfigItem(config.usbToN2k,true); | ||||
|   MDNS.begin(config.getConfigItem(config.systemName)->asCString()); | ||||
|   gwWifi.setup(); | ||||
| 
 | ||||
|  | @ -288,6 +290,11 @@ void setup() { | |||
|    | ||||
|   nmea0183Converter= N2kDataToNMEA0183::create(&logger, &boatData,&NMEA2000,  | ||||
|     SendNMEA0183Message, N2K_CHANNEL_ID); | ||||
| 
 | ||||
|   toN2KConverter= NMEA0183DataToN2K::create(&logger,&boatData,[](const tN2kMsg &msg)->bool{ | ||||
|     logger.logDebug(GwLog::DEBUG+1,"send N2K"); | ||||
|     return true; | ||||
|   });   | ||||
|    | ||||
|   NMEA2000.SetN2kCANMsgBufSize(8); | ||||
|   NMEA2000.SetN2kCANReceiveFrameBufSize(250); | ||||
|  | @ -321,8 +328,8 @@ void setup() { | |||
|   logger.logDebug(GwLog::LOG,"NodeAddress=%d\n", NodeAddress); | ||||
| 
 | ||||
|   NMEA2000.SetMode(tNMEA2000::N2km_ListenAndNode, NodeAddress); | ||||
| 
 | ||||
|   NMEA2000.ExtendTransmitMessages(TransmitMessages); | ||||
|   // Set the information for other bus devices, which messages we support
 | ||||
|   NMEA2000.ExtendTransmitMessages(toN2KConverter->handledPgns()); | ||||
|   NMEA2000.ExtendReceiveMessages(nmea0183Converter->handledPgns()); | ||||
|   NMEA2000.SetMsgHandler([](const tN2kMsg &n2kMsg){ | ||||
|     numCan++; | ||||
|  | @ -367,8 +374,10 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId) { | |||
| } | ||||
| 
 | ||||
| void handleReceivedNmeaMessage(const char *buf, int sourceId){ | ||||
|   //TODO - for now only send out again
 | ||||
|   //add the conversion to N2K here
 | ||||
|   if ((sourceId == USB_CHANNEL_ID && n2kFromUSB->asBoolean())|| | ||||
|       (sourceId >= MIN_TCP_CHANNEL_ID && n2kFromTCP->asBoolean()) | ||||
|     ) | ||||
|     toN2KConverter->parseAndSend(buf,sourceId); | ||||
|   sendBufferToChannels(buf,sourceId); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,13 @@ | |||
|         "default": "true", | ||||
|         "description": "receive NMEA data on the USB port" | ||||
|     }, | ||||
|     { | ||||
|         "name": "usbToN2k", | ||||
|         "label": "USB to NMEA2000", | ||||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "convert NMEA0183 from the USB port to NMEA2000" | ||||
|     }, | ||||
|     { | ||||
|         "name": "serverPort", | ||||
|         "label": "TCP port", | ||||
|  | @ -53,11 +60,18 @@ | |||
|     }, | ||||
|     { | ||||
|         "name": "readTCP", | ||||
|         "label": "NMEA from TCP", | ||||
|         "label": "TCP to NMEA2000", | ||||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "receive NMEA data from connected TCP clients" | ||||
|     }, | ||||
|     { | ||||
|         "name": "tcpToN2k", | ||||
|         "label": "NMEA from TCP", | ||||
|         "type": "boolean", | ||||
|         "default": "true", | ||||
|         "description": "convert NMEA0183 from TCP clients to NMEA2000" | ||||
|     }, | ||||
|     { | ||||
|         "name": "sendSeasmart", | ||||
|         "label": "Seasmart to TCP", | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 andreas
						andreas