mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2025-12-13 05:53:06 +01:00
intermediate: NMEA0183A AIS to N2K
This commit is contained in:
278
lib/nmea0183ton2k/NMEA0183AIStoNMEA2000.h
Normal file
278
lib/nmea0183ton2k/NMEA0183AIStoNMEA2000.h
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
This code is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This code is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//imported from https://github.com/AK-Homberger/NMEA2000-AIS-Gateway/tree/main/MyAISToN2k
|
||||
#include <Arduino.h>
|
||||
#include "ais_decoder.h"
|
||||
#include "default_sentence_parser.h"
|
||||
#include "NMEA0183DataToN2K.h"
|
||||
#include "NMEA0183.h"
|
||||
|
||||
const double pi = 3.1415926535897932384626433832795;
|
||||
const double knToms = 1852.0 / 3600.0;
|
||||
const double degToRad = pi / 180.0;
|
||||
const double nmTom = 1.852 * 1000;
|
||||
|
||||
uint16_t DaysSince1970 = 0;
|
||||
|
||||
class MyAisDecoder : public AIS::AisDecoder
|
||||
{
|
||||
private:
|
||||
NMEA0183DataToN2K::N2kSender sender;
|
||||
void send(const tN2kMsg &msg){
|
||||
(*sender)(msg);
|
||||
}
|
||||
AIS::DefaultSentenceParser parser;
|
||||
public:
|
||||
MyAisDecoder(NMEA0183DataToN2K::N2kSender sender)
|
||||
{
|
||||
this->sender=sender;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void onType123(unsigned int _uMsgType, unsigned int _uMmsi, unsigned int _uNavstatus,
|
||||
int _iRot, unsigned int _uSog, bool _bPosAccuracy,
|
||||
long _iPosLon, long _iPosLat, int _iCog, int _iHeading, int _Repeat, bool _Raim,
|
||||
unsigned int _timestamp, unsigned int _maneuver_i) override {
|
||||
|
||||
// Serial.println("123");
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
// PGN129038
|
||||
SetN2kAISClassAPosition(N2kMsg, _uMsgType, (tN2kAISRepeat)_Repeat, _uMmsi,
|
||||
_iPosLat / 600000.0, _iPosLon / 600000.0,
|
||||
_bPosAccuracy, _Raim, _timestamp,
|
||||
_iCog * degToRad, _uSog * knToms / 10.0,
|
||||
_iHeading * degToRad, _iRot, (tN2kAISNavStatus)_uNavstatus);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType411(unsigned int , unsigned int , unsigned int , unsigned int , unsigned int , unsigned int , unsigned int , unsigned int , bool , int , int ) override {
|
||||
//Serial.println("411");
|
||||
}
|
||||
|
||||
virtual void onType5(unsigned int _uMsgType, unsigned int _uMmsi, unsigned int _uImo, const std::string &_strCallsign,
|
||||
const std::string &_strName,
|
||||
unsigned int _uType, unsigned int _uToBow, unsigned int _uToStern,
|
||||
unsigned int _uToPort, unsigned int _uToStarboard, unsigned int _uFixType,
|
||||
unsigned int _uEtaMonth, unsigned int _uEtaDay, unsigned int _uEtaHour,
|
||||
unsigned int _uEtaMinute, unsigned int _uDraught,
|
||||
const std::string &_strDestination, unsigned int _ais_version,
|
||||
unsigned int _repeat, bool _dte) override {
|
||||
|
||||
// Serial.println("5");
|
||||
|
||||
// Necessary due to conflict with TimeLib.h (redefinition of tmElements_t)
|
||||
|
||||
time_t t = DaysSince1970 * (24UL * 3600UL);
|
||||
tmElements_t tm;
|
||||
|
||||
tNMEA0183Msg::breakTime(t, tm);
|
||||
|
||||
//tNMEA0183Msg::SetYear(tm, 2020);
|
||||
tNMEA0183Msg::SetMonth(tm, _uEtaMonth);
|
||||
tNMEA0183Msg::SetDay(tm, _uEtaDay);
|
||||
tNMEA0183Msg::SetHour(tm, 0);
|
||||
tNMEA0183Msg::SetMin(tm, 0);
|
||||
tNMEA0183Msg::SetSec(tm, 0);
|
||||
|
||||
uint16_t eta_days = tNMEA0183Msg::makeTime(tm) / (24UL * 3600UL);
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
char CS[30];
|
||||
char Name[30];
|
||||
char Dest[30];
|
||||
|
||||
strncpy(CS, _strCallsign.c_str(), sizeof(CS));
|
||||
strncpy(Name, _strName.c_str(), sizeof(Name));
|
||||
strncpy(Dest, _strDestination.c_str(), sizeof(Dest));
|
||||
|
||||
// PGN129794
|
||||
SetN2kAISClassAStatic(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi,
|
||||
_uImo, CS, Name, _uType, _uToBow + _uToStern,
|
||||
_uToPort + _uToStarboard, _uToStarboard, _uToBow, eta_days,
|
||||
(_uEtaHour * 3600) + (_uEtaMinute * 60), _uDraught / 10.0, Dest,
|
||||
(tN2kAISVersion) _ais_version, (tN2kGNSStype) _uFixType,
|
||||
(tN2kAISDTE) _dte, (tN2kAISTranceiverInfo) _ais_version);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType9(unsigned int , unsigned int , bool , int , int , int , unsigned int ) override {
|
||||
//Serial.println("9");
|
||||
}
|
||||
|
||||
virtual void onType14(unsigned int _repeat, unsigned int _uMmsi,
|
||||
const std::string &_strText, int _iPayloadSizeBits) override {
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
char Text[162];
|
||||
strncpy(Text, _strText.c_str(), sizeof(Text));
|
||||
|
||||
N2kMsg.SetPGN(129802UL);
|
||||
N2kMsg.Priority = 4;
|
||||
N2kMsg.Destination = 255; // Redundant, PGN129802 is broadcast by default.
|
||||
N2kMsg.AddByte((_repeat & 0x03) << 6 | (14 & 0x3f));
|
||||
N2kMsg.Add4ByteUInt(_uMmsi);
|
||||
N2kMsg.AddByte(0);
|
||||
|
||||
if (strlen(Text) == 0) {
|
||||
N2kMsg.AddByte(0x03); N2kMsg.AddByte(0x01); N2kMsg.AddByte(0x00);
|
||||
} else {
|
||||
N2kMsg.AddByte(strlen(Text) + 2); N2kMsg.AddByte(0x01);
|
||||
for (int i = 0; i < strlen(Text); i++)
|
||||
N2kMsg.AddByte(Text[i]);
|
||||
}
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType18(unsigned int _uMsgType, unsigned int _uMmsi, unsigned int _uSog, bool _bPosAccuracy,
|
||||
long _iPosLon, long _iPosLat, int _iCog, int _iHeading, bool _raim, unsigned int _repeat,
|
||||
bool _unit, bool _diplay, bool _dsc, bool _band, bool _msg22, bool _assigned,
|
||||
unsigned int _timestamp, bool _state ) override {
|
||||
//Serial.println("18");
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
// PGN129039
|
||||
SetN2kAISClassBPosition(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi,
|
||||
_iPosLat / 600000.0, _iPosLon / 600000.0, _bPosAccuracy, _raim,
|
||||
_timestamp, _iCog * degToRad, _uSog * knToms / 10.0,
|
||||
_iHeading * degToRad, (tN2kAISUnit) _unit,
|
||||
_diplay, _dsc, _band, _msg22, (tN2kAISMode) _assigned, _state);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType19(unsigned int _uMmsi, unsigned int _uSog, bool _bPosAccuracy, int _iPosLon, int _iPosLat,
|
||||
int _iCog, int _iHeading, const std::string &_strName, unsigned int _uType,
|
||||
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort,
|
||||
unsigned int _uToStarboard, unsigned int _timestamp, unsigned int _fixtype,
|
||||
bool _dte, bool _assigned, unsigned int _repeat, bool _raim) override {
|
||||
|
||||
//Serial.println("19");
|
||||
tN2kMsg N2kMsg;
|
||||
|
||||
// PGN129040
|
||||
|
||||
char Name[21] = "";
|
||||
strncpy(Name, _strName.c_str(), sizeof(Name));
|
||||
|
||||
N2kMsg.SetPGN(129040UL);
|
||||
N2kMsg.Priority = 4;
|
||||
N2kMsg.AddByte((_repeat & 0x03) << 6 | (19 & 0x3f));
|
||||
N2kMsg.Add4ByteUInt(_uMmsi);
|
||||
N2kMsg.Add4ByteDouble(_iPosLon / 600000.0, 1e-07);
|
||||
N2kMsg.Add4ByteDouble(_iPosLat / 600000.0, 1e-07);
|
||||
N2kMsg.AddByte((_timestamp & 0x3f) << 2 | (_raim & 0x01) << 1 | (_bPosAccuracy & 0x01));
|
||||
N2kMsg.Add2ByteUDouble(_iCog * degToRad, 1e-04);
|
||||
N2kMsg.Add2ByteUDouble(_uSog * knToms / 10.0, 0.01);
|
||||
N2kMsg.AddByte(0xff); // Regional Application
|
||||
N2kMsg.AddByte(0xff); // Regional Application
|
||||
N2kMsg.AddByte(_uType );
|
||||
N2kMsg.Add2ByteUDouble(_iHeading * degToRad, 1e-04);
|
||||
N2kMsg.AddByte(_fixtype << 4);
|
||||
N2kMsg.Add2ByteDouble(_uToBow + _uToStern, 0.1);
|
||||
N2kMsg.Add2ByteDouble(_uToPort + _uToStarboard, 0.1);
|
||||
N2kMsg.Add2ByteDouble(_uToStarboard, 0.1);
|
||||
N2kMsg.Add2ByteDouble(_uToBow, 0.1);
|
||||
N2kMsg.AddStr(Name, 20);
|
||||
N2kMsg.AddByte((_dte & 0x01) | (_assigned & 0x01) << 1) ;
|
||||
N2kMsg.AddByte(0);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
|
||||
virtual void onType21(unsigned int , unsigned int , const std::string &, bool , int , int , unsigned int , unsigned int , unsigned int , unsigned int ) override {
|
||||
//Serial.println("21");
|
||||
}
|
||||
|
||||
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi,
|
||||
const std::string &_strName) override {
|
||||
//Serial.println("24A");
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
char Name[30];
|
||||
strncpy(Name, _strName.c_str(), sizeof(Name));
|
||||
|
||||
// PGN129809
|
||||
SetN2kAISClassBStaticPartA(N2kMsg, _uMsgType, (tN2kAISRepeat) _repeat, _uMmsi, Name);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType24B(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi,
|
||||
const std::string &_strCallsign, unsigned int _uType,
|
||||
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort,
|
||||
unsigned int _uToStarboard, const std::string &_strVendor) override {
|
||||
|
||||
// Serial.println("24B");
|
||||
|
||||
|
||||
tN2kMsg N2kMsg;
|
||||
char CS[30];
|
||||
char Vendor[30];
|
||||
|
||||
strncpy(CS, _strCallsign.c_str(), sizeof(CS));
|
||||
strncpy(Vendor, _strVendor.c_str(), sizeof(Vendor));
|
||||
|
||||
// PGN129810
|
||||
SetN2kAISClassBStaticPartB(N2kMsg, _uMsgType, (tN2kAISRepeat)_repeat, _uMmsi,
|
||||
_uType, Vendor, CS, _uToBow + _uToStern, _uToPort + _uToStarboard,
|
||||
_uToStarboard, _uToBow, _uMmsi);
|
||||
|
||||
send(N2kMsg);
|
||||
}
|
||||
|
||||
virtual void onType27(unsigned int , unsigned int , unsigned int , bool , int , int , int ) override {
|
||||
//Serial.println("27");
|
||||
}
|
||||
|
||||
virtual void onSentence(const AIS::StringRef &_Stc) override {
|
||||
//Serial.printf("Sentence: %s\n", _Stc);
|
||||
}
|
||||
|
||||
virtual void onMessage(const AIS::StringRef &, const AIS::StringRef &, const AIS::StringRef &) override {}
|
||||
|
||||
virtual void onNotDecoded(const AIS::StringRef &, int ) override {}
|
||||
|
||||
virtual void onDecodeError(const AIS::StringRef &_strMessage, const std::string &_strError) override {
|
||||
std::string msg(_strMessage.data(), _strMessage.size());
|
||||
AIS::stripTrailingWhitespace(msg);
|
||||
|
||||
Serial.printf("%s [%s]\n", _strError.c_str(), msg.c_str());
|
||||
}
|
||||
|
||||
virtual void onParseError(const AIS::StringRef &_strMessage, const std::string &_strError) override {
|
||||
std::string msg(_strMessage.data(), _strMessage.size());
|
||||
AIS::stripTrailingWhitespace(msg);
|
||||
|
||||
Serial.printf("%s [%s]\n", _strError.c_str(), msg.c_str());
|
||||
}
|
||||
public:
|
||||
void handleMessage(const char * msg){
|
||||
int len=strlen(msg);
|
||||
char buffer[len+1];
|
||||
memcpy(buffer,msg,len);
|
||||
strcat(buffer,"\n");
|
||||
size_t i=0;
|
||||
do {
|
||||
i=decodeMsg(buffer,len+1,i,parser);
|
||||
} while (i != 0) ;
|
||||
}
|
||||
};
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "ConverterList.h"
|
||||
#include <map>
|
||||
#include <strings.h>
|
||||
#include "NMEA0183AIStoNMEA2000.h"
|
||||
NMEA0183DataToN2K::NMEA0183DataToN2K(GwLog *logger, GwBoatData *boatData,N2kSender callback)
|
||||
{
|
||||
this->sender = callback;
|
||||
@@ -44,7 +45,7 @@ class SNMEA0183Msg : public tNMEA0183Msg{
|
||||
class NMEA0183DataToN2KFunctions : public NMEA0183DataToN2K
|
||||
{
|
||||
private:
|
||||
double dummy = 0;
|
||||
MyAisDecoder *aisDecoder=NULL;
|
||||
ConverterList<NMEA0183DataToN2KFunctions, SNMEA0183Msg> converters;
|
||||
std::map<unsigned long,unsigned long> lastSends;
|
||||
class WaypointNumber{
|
||||
@@ -220,7 +221,9 @@ private:
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void convertAIVDX(const SNMEA0183Msg &msg){
|
||||
aisDecoder->handleMessage(msg.line);
|
||||
}
|
||||
//shortcut for lambda converters
|
||||
#define CVL [](const SNMEA0183Msg &msg, NMEA0183DataToN2KFunctions *p) -> void
|
||||
void registerConverters()
|
||||
@@ -230,6 +233,11 @@ private:
|
||||
converters.registerConverter(
|
||||
126992UL,129025UL,129026UL,127258UL,
|
||||
String(F("RMC")), &NMEA0183DataToN2KFunctions::convertRMC);
|
||||
unsigned long aispgns[7]{129810UL,129809UL,129040UL,129039UL,129802UL,129794UL,129038UL};
|
||||
converters.registerConverter(7,&aispgns[0],
|
||||
String(F("AIVDM")),&NMEA0183DataToN2KFunctions::convertAIVDX);
|
||||
converters.registerConverter(7,&aispgns[0],
|
||||
String(F("AIVDO")),&NMEA0183DataToN2KFunctions::convertAIVDX);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -268,6 +276,7 @@ public:
|
||||
NMEA0183DataToN2KFunctions(GwLog *logger, GwBoatData *boatData, N2kSender callback)
|
||||
: NMEA0183DataToN2K(logger, boatData, callback)
|
||||
{
|
||||
aisDecoder= new MyAisDecoder(this->sender);
|
||||
registerConverters();
|
||||
LOG_DEBUG(GwLog::LOG, "NMEA0183DataToN2KFunctions: registered %d converters", converters.numConverters());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user