mirror of
https://github.com/thooge/esp32-nmea2000-obp60.git
synced 2026-02-11 07:03:07 +01:00
Merge branch 'wellenvogel:master' into master
This commit is contained in:
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -62,5 +62,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag: ${{ steps.version.outputs.version}}
|
tag: ${{ steps.version.outputs.version}}
|
||||||
file: ./.pio/build/*/*-{all,update}.bin
|
file: ./.pio/build/*/*${{ steps.version.outputs.version }}*-{all,update}.bin
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|||||||
23
Readme.md
23
Readme.md
@@ -43,6 +43,10 @@ What is included
|
|||||||
|
|
||||||
For the details of the mapped PGNs and NMEA sentences refer to [Conversions](doc/Conversions.pdf).
|
For the details of the mapped PGNs and NMEA sentences refer to [Conversions](doc/Conversions.pdf).
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either [version 2 of the License](LICENSE), or (at your option) any later version.
|
||||||
|
|
||||||
Hardware
|
Hardware
|
||||||
--------
|
--------
|
||||||
The software is prepared to run on different kinds of ESP32 based modules and accessoirs. For some of them prebuild binaries are available that only need to be flashed, others would require to add some definitions of the used PINs and features and to build the binary.
|
The software is prepared to run on different kinds of ESP32 based modules and accessoirs. For some of them prebuild binaries are available that only need to be flashed, others would require to add some definitions of the used PINs and features and to build the binary.
|
||||||
@@ -170,6 +174,25 @@ For details refer to the [example description](lib/exampletask/Readme.md).
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
---------
|
---------
|
||||||
|
[20251126](../../releases/tag/20251126)
|
||||||
|
* fix a bug in the Actisense reader that could lead to an endless loop (making the device completely non responsive)
|
||||||
|
* upgrade to 4.24.1 of the NMEA2000 library (2025/11/01) - refer to the [changes](https://github.com/ttlappalainen/NMEA2000/blob/master/Documents/src/changes.md) - Especially UTF8 support
|
||||||
|
*********
|
||||||
|
[20251007](../../releases/tag/20251007)
|
||||||
|
*********
|
||||||
|
* add AIS Aton translations (PGN 129041 <-> Ais class 21)
|
||||||
|
* improved mapping of AIS transducer information (NMEA2000) to AIS channel and Talker on NMEA0183
|
||||||
|
* use a forked version of the NMEA2000 library (as an intermediate workaround)
|
||||||
|
* [#114](../../issues/114) correctly translate AIS type 1/3 from PGN 129038
|
||||||
|
* add support for a generic S3 build in the build UI
|
||||||
|
* [#117](../../issues/117) add support for a transmit enable pin for RS 485 conections (also in the build UI)
|
||||||
|
* [#116](../../issues/116) SDA and SCL are swapped in the build UI
|
||||||
|
* [#112](../../issues/112) clearify licenses
|
||||||
|
* [#110](../../issues/110) / [#115](../../pull/115) support for the M5 GPS unit v1.1
|
||||||
|
* [#102](../../issues/102) optimize Wifi reconnect handling
|
||||||
|
* [#111](../../pull/111) allow for a custom python build script
|
||||||
|
* [#113](../../issues/113) support for M5 stack Env4
|
||||||
|
|
||||||
[20250305](../../releases/tag/20250305)
|
[20250305](../../releases/tag/20250305)
|
||||||
*********
|
*********
|
||||||
* better handling for reconnect to a raspberry pi after reset [#102](../../issues/102)
|
* better handling for reconnect to a raspberry pi after reset [#102](../../issues/102)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -516,3 +516,16 @@ env.Append(
|
|||||||
)
|
)
|
||||||
#script does not run on clean yet - maybe in the future
|
#script does not run on clean yet - maybe in the future
|
||||||
env.AddPostAction("clean",cleangenerated)
|
env.AddPostAction("clean",cleangenerated)
|
||||||
|
extraScripts=getFileList(getOption(env,'custom_script',toArray=True))
|
||||||
|
for script in extraScripts:
|
||||||
|
if os.path.isfile(script):
|
||||||
|
print(f"#extra {script}")
|
||||||
|
with open(script) as fh:
|
||||||
|
try:
|
||||||
|
code = compile(fh.read(), script, 'exec')
|
||||||
|
except SyntaxError as e:
|
||||||
|
print(f"#ERROR: script {script} does not compile: {e}")
|
||||||
|
continue
|
||||||
|
exec(code)
|
||||||
|
else:
|
||||||
|
print(f"#ERROR: script {script} not found")
|
||||||
|
|||||||
@@ -627,7 +627,7 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
|||||||
}
|
}
|
||||||
|
|
||||||
// decode message fields (binary buffer has to go through all fields, but some fields are not used)
|
// decode message fields (binary buffer has to go through all fields, but some fields are not used)
|
||||||
_buffer.getUnsignedValue(2); // repeatIndicator
|
auto repeat=_buffer.getUnsignedValue(2); // repeatIndicator
|
||||||
auto mmsi = _buffer.getUnsignedValue(30);
|
auto mmsi = _buffer.getUnsignedValue(30);
|
||||||
auto aidType = _buffer.getUnsignedValue(5);
|
auto aidType = _buffer.getUnsignedValue(5);
|
||||||
auto name = _buffer.getString(120);
|
auto name = _buffer.getString(120);
|
||||||
@@ -640,11 +640,11 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
|||||||
auto toStarboard = _buffer.getUnsignedValue(6);
|
auto toStarboard = _buffer.getUnsignedValue(6);
|
||||||
|
|
||||||
_buffer.getUnsignedValue(4); // epfd type
|
_buffer.getUnsignedValue(4); // epfd type
|
||||||
_buffer.getUnsignedValue(6); // timestamp
|
auto timestamp=_buffer.getUnsignedValue(6); // timestamp
|
||||||
_buffer.getBoolValue(); // off position
|
auto offPosition=_buffer.getBoolValue(); // off position
|
||||||
_buffer.getUnsignedValue(8); // reserved
|
_buffer.getUnsignedValue(8); // reserved
|
||||||
_buffer.getBoolValue(); // RAIM
|
auto raim=_buffer.getBoolValue(); // RAIM
|
||||||
_buffer.getBoolValue(); // virtual aid
|
auto virtualAton=_buffer.getBoolValue(); // virtual aid
|
||||||
_buffer.getBoolValue(); // assigned mode
|
_buffer.getBoolValue(); // assigned mode
|
||||||
_buffer.getUnsignedValue(1); // spare
|
_buffer.getUnsignedValue(1); // spare
|
||||||
|
|
||||||
@@ -654,7 +654,9 @@ void AisDecoder::decodeType21(PayloadBuffer &_buffer, unsigned int _uMsgType, in
|
|||||||
nameExt = _buffer.getString(88);
|
nameExt = _buffer.getString(88);
|
||||||
}
|
}
|
||||||
|
|
||||||
onType21(mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat, toBow, toStern, toPort, toStarboard);
|
onType21(mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat,
|
||||||
|
toBow, toStern, toPort, toStarboard,
|
||||||
|
repeat,timestamp, raim, virtualAton, offPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decode Voyage Report and Static Data (type nibble already pulled from buffer) */
|
/* decode Voyage Report and Static Data (type nibble already pulled from buffer) */
|
||||||
|
|||||||
@@ -297,7 +297,8 @@ namespace AIS
|
|||||||
bool assigned, unsigned int repeat, bool raim) = 0;
|
bool assigned, unsigned int repeat, bool raim) = 0;
|
||||||
|
|
||||||
virtual void onType21(unsigned int _uMmsi, unsigned int _uAidType, const std::string &_strName, bool _bPosAccuracy, int _iPosLon, int _iPosLat,
|
virtual void onType21(unsigned int _uMmsi, unsigned int _uAidType, const std::string &_strName, bool _bPosAccuracy, int _iPosLon, int _iPosLat,
|
||||||
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort, unsigned int _uToStarboard) = 0;
|
unsigned int _uToBow, unsigned int _uToStern, unsigned int _uToPort, unsigned int _uToStarboard,
|
||||||
|
unsigned int repeat,unsigned int timestamp, bool raim, bool virtualAton, bool offPosition) = 0;
|
||||||
|
|
||||||
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi, const std::string &_strName) = 0;
|
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi, const std::string &_strName) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#define LOGLEVEL GwLog::DEBUG
|
#define LOGLEVEL GwLog::DEBUG
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef GWBUILD_NAME
|
||||||
|
#define FIRMWARE_TYPE GWSTRINGIFY(GWBUILD_NAME)
|
||||||
|
#else
|
||||||
#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
|
#define FIRMWARE_TYPE GWSTRINGIFY(PIO_ENV_BUILD)
|
||||||
|
#endif
|
||||||
#define IDF_VERSION GWSTRINGIFY(ESP_IDF_VERSION_MAJOR) "." GWSTRINGIFY(ESP_IDF_VERSION_MINOR) "." GWSTRINGIFY(ESP_IDF_VERSION_PATCH)
|
#define IDF_VERSION GWSTRINGIFY(ESP_IDF_VERSION_MAJOR) "." GWSTRINGIFY(ESP_IDF_VERSION_MINOR) "." GWSTRINGIFY(ESP_IDF_VERSION_PATCH)
|
||||||
@@ -249,3 +249,16 @@ unsigned long GwChannel::countTx(){
|
|||||||
if (! countOut) return 0UL;
|
if (! countOut) return 0UL;
|
||||||
return countOut->getGlobal();
|
return countOut->getGlobal();
|
||||||
}
|
}
|
||||||
|
String GwChannel::typeString(int type){
|
||||||
|
switch (type){
|
||||||
|
case GWSERIAL_TYPE_UNI:
|
||||||
|
return "UNI";
|
||||||
|
case GWSERIAL_TYPE_BI:
|
||||||
|
return "BI";
|
||||||
|
case GWSERIAL_TYPE_RX:
|
||||||
|
return "RX";
|
||||||
|
case GWSERIAL_TYPE_TX:
|
||||||
|
return "TX";
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
@@ -77,7 +77,8 @@ class GwChannel{
|
|||||||
if (maxSourceId < 0) return source == sourceId;
|
if (maxSourceId < 0) return source == sourceId;
|
||||||
return (source >= sourceId && source <= maxSourceId);
|
return (source >= sourceId && source <= maxSourceId);
|
||||||
}
|
}
|
||||||
String getMode(){return impl->getMode();}
|
static String typeString(int type);
|
||||||
|
String getMode(){return typeString(impl->getType());}
|
||||||
int getMinId(){return sourceId;};
|
int getMinId(){return sourceId;};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "GwBuffer.h"
|
#include "GwBuffer.h"
|
||||||
|
#include "GwChannelModes.h"
|
||||||
class GwChannelInterface{
|
class GwChannelInterface{
|
||||||
public:
|
public:
|
||||||
virtual void loop(bool handleRead,bool handleWrite)=0;
|
virtual void loop(bool handleRead,bool handleWrite)=0;
|
||||||
virtual void readMessages(GwMessageFetcher *writer)=0;
|
virtual void readMessages(GwMessageFetcher *writer)=0;
|
||||||
virtual size_t sendToClients(const char *buffer, int sourceId, bool partial=false)=0;
|
virtual size_t sendToClients(const char *buffer, int sourceId, bool partial=false)=0;
|
||||||
virtual Stream * getStream(bool partialWrites){ return NULL;}
|
virtual Stream * getStream(bool partialWrites){ return NULL;}
|
||||||
virtual String getMode(){return "UNKNOWN";}
|
virtual int getType(){ return GWSERIAL_TYPE_BI;} //return the numeric type
|
||||||
};
|
};
|
||||||
@@ -15,8 +15,10 @@ class SerInit{
|
|||||||
int tx=-1;
|
int tx=-1;
|
||||||
int mode=-1;
|
int mode=-1;
|
||||||
int fixedBaud=-1;
|
int fixedBaud=-1;
|
||||||
SerInit(int s,int r,int t, int m, int b=-1):
|
int ena=-1;
|
||||||
serial(s),rx(r),tx(t),mode(m),fixedBaud(b){}
|
int elow=1;
|
||||||
|
SerInit(int s,int r,int t, int m, int b=-1,int en=-1,int el=-1):
|
||||||
|
serial(s),rx(r),tx(t),mode(m),fixedBaud(b),ena(en),elow(el){}
|
||||||
};
|
};
|
||||||
std::vector<SerInit> serialInits;
|
std::vector<SerInit> serialInits;
|
||||||
|
|
||||||
@@ -47,11 +49,20 @@ static int typeFromMode(const char *mode){
|
|||||||
#ifndef GWSERIAL_RX
|
#ifndef GWSERIAL_RX
|
||||||
#define GWSERIAL_RX -1
|
#define GWSERIAL_RX -1
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GWSERIAL_ENA
|
||||||
|
#define GWSERIAL_ENA -1
|
||||||
|
#endif
|
||||||
|
#ifndef GWSERIAL_ELO
|
||||||
|
#define GWSERIAL_ELO 0
|
||||||
|
#endif
|
||||||
|
#ifndef GWSERIAL_BAUD
|
||||||
|
#define GWSERIAL_BAUD -1
|
||||||
|
#endif
|
||||||
#ifdef GWSERIAL_TYPE
|
#ifdef GWSERIAL_TYPE
|
||||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, GWSERIAL_TYPE)
|
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, GWSERIAL_TYPE,GWSERIAL_BAUD,GWSERIAL_ENA,GWSERIAL_ELO)
|
||||||
#else
|
#else
|
||||||
#ifdef GWSERIAL_MODE
|
#ifdef GWSERIAL_MODE
|
||||||
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_MODE))
|
CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_MODE),GWSERIAL_BAUD,GWSERIAL_ENA,GWSERIAL_ELO)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
// serial 2
|
// serial 2
|
||||||
@@ -61,11 +72,20 @@ CFG_SERIAL(SERIAL1_CHANNEL_ID, GWSERIAL_RX, GWSERIAL_TX, typeFromMode(GWSERIAL_M
|
|||||||
#ifndef GWSERIAL2_RX
|
#ifndef GWSERIAL2_RX
|
||||||
#define GWSERIAL2_RX -1
|
#define GWSERIAL2_RX -1
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GWSERIAL2_ENA
|
||||||
|
#define GWSERIAL2_ENA -1
|
||||||
|
#endif
|
||||||
|
#ifndef GWSERIAL2_ELO
|
||||||
|
#define GWSERIAL2_ELO 0
|
||||||
|
#endif
|
||||||
|
#ifndef GWSERIAL2_BAUD
|
||||||
|
#define GWSERIAL2_BAUD -1
|
||||||
|
#endif
|
||||||
#ifdef GWSERIAL2_TYPE
|
#ifdef GWSERIAL2_TYPE
|
||||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, GWSERIAL2_TYPE)
|
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, GWSERIAL2_TYPE,GWSERIAL2_BAUD,GWSERIAL2_ENA,GWSERIAL2_ELO)
|
||||||
#else
|
#else
|
||||||
#ifdef GWSERIAL2_MODE
|
#ifdef GWSERIAL2_MODE
|
||||||
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, typeFromMode(GWSERIAL2_MODE))
|
CFG_SERIAL(SERIAL2_CHANNEL_ID, GWSERIAL2_RX, GWSERIAL2_TX, typeFromMode(GWSERIAL2_MODE),GWSERIAL2_BAUD,GWSERIAL2_ENA,GWSERIAL2_ELO)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
class GwSerialLog : public GwLogWriter
|
class GwSerialLog : public GwLogWriter
|
||||||
@@ -285,8 +305,8 @@ static ChannelParam channelParameters[]={
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
GwSerial* createSerial(GwLog *logger, T* s,int id, bool canRead=true){
|
GwSerial* createSerial(GwLog *logger, T* s,int id, int type, bool canRead=true){
|
||||||
return new GwSerialImpl<T>(logger,s,id,canRead);
|
return new GwSerialImpl<T>(logger,s,id,type,canRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ChannelParam * findChannelParam(int id){
|
static ChannelParam * findChannelParam(int id){
|
||||||
@@ -300,7 +320,7 @@ static ChannelParam * findChannelParam(int id){
|
|||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int idx,int rx,int tx, bool setLog=false){
|
static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int idx,int type,int rx,int tx, bool setLog,int ena=-1,int elow=1){
|
||||||
LOG_DEBUG(GwLog::DEBUG,"create serial: channel=%d, rx=%d,tx=%d",
|
LOG_DEBUG(GwLog::DEBUG,"create serial: channel=%d, rx=%d,tx=%d",
|
||||||
idx,rx,tx);
|
idx,rx,tx);
|
||||||
ChannelParam *param=findChannelParam(idx);
|
ChannelParam *param=findChannelParam(idx);
|
||||||
@@ -312,19 +332,45 @@ static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int id
|
|||||||
GwLog *streamLog=setLog?nullptr:logger;
|
GwLog *streamLog=setLog?nullptr:logger;
|
||||||
switch(param->id){
|
switch(param->id){
|
||||||
case USB_CHANNEL_ID:
|
case USB_CHANNEL_ID:
|
||||||
serialStream=createSerial(streamLog,&USBSerial,param->id);
|
serialStream=createSerial(streamLog,&USBSerial,param->id,type);
|
||||||
break;
|
break;
|
||||||
case SERIAL1_CHANNEL_ID:
|
case SERIAL1_CHANNEL_ID:
|
||||||
serialStream=createSerial(streamLog,&Serial1,param->id);
|
serialStream=createSerial(streamLog,&Serial1,param->id,type);
|
||||||
break;
|
break;
|
||||||
case SERIAL2_CHANNEL_ID:
|
case SERIAL2_CHANNEL_ID:
|
||||||
serialStream=createSerial(streamLog,&Serial2,param->id);
|
serialStream=createSerial(streamLog,&Serial2,param->id,type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (serialStream == nullptr){
|
if (serialStream == nullptr){
|
||||||
LOG_DEBUG(GwLog::ERROR,"invalid serial config with id %d",param->id);
|
LOG_DEBUG(GwLog::ERROR,"invalid serial config with id %d",param->id);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (ena >= 0){
|
||||||
|
int value=-1;
|
||||||
|
if (type == GWSERIAL_TYPE_UNI){
|
||||||
|
String cfgMode=config->getString(param->direction);
|
||||||
|
if (cfgMode == "send"){
|
||||||
|
value=elow?0:1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
value=elow?1:0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == GWSERIAL_TYPE_RX){
|
||||||
|
value=elow?1:0;
|
||||||
|
}
|
||||||
|
if (type == GWSERIAL_TYPE_TX){
|
||||||
|
value=elow?0:1;
|
||||||
|
}
|
||||||
|
if (value >= 0){
|
||||||
|
LOG_DEBUG(GwLog::LOG,"serial %d: setting output enable %d to %d",param->id,ena,value);
|
||||||
|
pinMode(ena,OUTPUT);
|
||||||
|
digitalWrite(ena,value);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_DEBUG(GwLog::ERROR,"serial %d: output enable ignored for mode %d",param->id, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
serialStream->begin(config->getInt(param->baud,115200),SERIAL_8N1,rx,tx);
|
serialStream->begin(config->getInt(param->baud,115200),SERIAL_8N1,rx,tx);
|
||||||
if (setLog){
|
if (setLog){
|
||||||
logger->setWriter(new GwSerialLog(serialStream,config->getBool(param->preventLog,false)));
|
logger->setWriter(new GwSerialLog(serialStream,config->getBool(param->preventLog,false)));
|
||||||
@@ -332,12 +378,13 @@ static GwSerial * createSerialImpl(GwConfigHandler *config,GwLog *logger, int id
|
|||||||
}
|
}
|
||||||
return serialStream;
|
return serialStream;
|
||||||
}
|
}
|
||||||
static GwChannel * createChannel(GwLog *logger, GwConfigHandler *config, int id,GwChannelInterface *impl, int type=GWSERIAL_TYPE_BI){
|
static GwChannel * createChannel(GwLog *logger, GwConfigHandler *config, int id,GwChannelInterface *impl){
|
||||||
ChannelParam *param=findChannelParam(id);
|
ChannelParam *param=findChannelParam(id);
|
||||||
if (param == nullptr){
|
if (param == nullptr){
|
||||||
LOG_DEBUG(GwLog::ERROR,"invalid channel id %d",id);
|
LOG_DEBUG(GwLog::ERROR,"invalid channel id %d",id);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
int type=impl->getType();
|
||||||
bool canRead=false;
|
bool canRead=false;
|
||||||
bool canWrite=false;
|
bool canWrite=false;
|
||||||
bool validType=false;
|
bool validType=false;
|
||||||
@@ -425,10 +472,10 @@ void GwChannelList::begin(bool fallbackSerial){
|
|||||||
GwChannel *channel=NULL;
|
GwChannel *channel=NULL;
|
||||||
//usb
|
//usb
|
||||||
if (! fallbackSerial){
|
if (! fallbackSerial){
|
||||||
GwSerial *usbSerial=createSerialImpl(config, logger,USB_CHANNEL_ID,GWUSB_RX,GWUSB_TX,true);
|
GwSerial *usbSerial=createSerialImpl(config, logger,USB_CHANNEL_ID,GWSERIAL_TYPE_BI,GWUSB_RX,GWUSB_TX,true);
|
||||||
if (usbSerial != nullptr){
|
if (usbSerial != nullptr){
|
||||||
usbSerial->enableWriteLock(); //as it is used for logging we need this additionally
|
usbSerial->enableWriteLock(); //as it is used for logging we need this additionally
|
||||||
GwChannel *usbChannel=createChannel(logger,config,USB_CHANNEL_ID,usbSerial,GWSERIAL_TYPE_BI);
|
GwChannel *usbChannel=createChannel(logger,config,USB_CHANNEL_ID,usbSerial);
|
||||||
if (usbChannel != nullptr){
|
if (usbChannel != nullptr){
|
||||||
addChannel(usbChannel);
|
addChannel(usbChannel);
|
||||||
}
|
}
|
||||||
@@ -444,10 +491,11 @@ void GwChannelList::begin(bool fallbackSerial){
|
|||||||
|
|
||||||
//new serial config handling
|
//new serial config handling
|
||||||
for (auto &&init:serialInits){
|
for (auto &&init:serialInits){
|
||||||
LOG_INFO("creating serial channel %d, rx=%d,tx=%d,type=%d",init.serial,init.rx,init.tx,init.mode);
|
LOG_INFO("creating serial channel %d, rx=%d,tx=%d,type=%d fixedBaud=%d ena=%d elow=%d",
|
||||||
GwSerial *ser=createSerialImpl(config,logger,init.serial,init.rx,init.tx);
|
init.serial,init.rx,init.tx,init.mode,init.fixedBaud,init.ena,init.elow);
|
||||||
|
GwSerial *ser=createSerialImpl(config,logger,init.serial,init.mode,init.rx,init.tx,false,init.ena,init.elow);
|
||||||
if (ser != nullptr){
|
if (ser != nullptr){
|
||||||
channel=createChannel(logger,config,init.serial,ser,init.mode);
|
channel=createChannel(logger,config,init.serial,ser);
|
||||||
if (channel != nullptr){
|
if (channel != nullptr){
|
||||||
addChannel(channel);
|
addChannel(channel);
|
||||||
}
|
}
|
||||||
@@ -466,8 +514,8 @@ void GwChannelList::begin(bool fallbackSerial){
|
|||||||
config->getInt(config->remotePort),
|
config->getInt(config->remotePort),
|
||||||
config->getBool(config->readTCL)
|
config->getBool(config->readTCL)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
addChannel(createChannel(logger,config,TCP_CLIENT_CHANNEL_ID,client));
|
addChannel(createChannel(logger,config,TCP_CLIENT_CHANNEL_ID,client));
|
||||||
|
}
|
||||||
|
|
||||||
//udp writer
|
//udp writer
|
||||||
if (config->getBool(GwConfigDefinitions::udpwEnabled)){
|
if (config->getBool(GwConfigDefinitions::udpwEnabled)){
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -57,6 +57,44 @@ Files
|
|||||||
|
|
||||||
Starting from Version 20250305 you should normally not use this file name any more as those styles would be added for all build environments. Instead define a parameter _custom_css_ in your [platformio.ini](platformio.ini) for the environments you would like to add some styles for. This parameter accepts a list of file names (relative to the project root, separated by , or as multi line entry)
|
Starting from Version 20250305 you should normally not use this file name any more as those styles would be added for all build environments. Instead define a parameter _custom_css_ in your [platformio.ini](platformio.ini) for the environments you would like to add some styles for. This parameter accepts a list of file names (relative to the project root, separated by , or as multi line entry)
|
||||||
|
|
||||||
|
* [script.py](script.py)<br>
|
||||||
|
Starting from version 20251007 you can define a parameter "custom_script" in your [platformio.ini](platformio.ini).
|
||||||
|
This parameter can contain a list of file names (relative to the project root) that will be added as a [platformio extra script](https://docs.platformio.org/en/latest/scripting/index.html#scripting). The scripts will be loaded at the end of the main [extra_script](../../extra_script.py).
|
||||||
|
You can add code there that is specific for your build.
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
# PlatformIO extra script for obp60task
|
||||||
|
epdtype = "unknown"
|
||||||
|
pcbvers = "unknown"
|
||||||
|
for x in env["BUILD_FLAGS"]:
|
||||||
|
if x.startswith("-D HARDWARE_"):
|
||||||
|
pcbvers = x.split('_')[1]
|
||||||
|
if x.startswith("-D DISPLAY_"):
|
||||||
|
epdtype = x.split('_')[1]
|
||||||
|
|
||||||
|
propfilename = os.path.join(env["PROJECT_LIBDEPS_DIR"], env ["PIOENV"], "GxEPD2/library.properties")
|
||||||
|
properties = {}
|
||||||
|
with open(propfilename, 'r') as file:
|
||||||
|
for line in file:
|
||||||
|
match = re.match(r'^([^=]+)=(.*)$', line)
|
||||||
|
if match:
|
||||||
|
key = match.group(1).strip()
|
||||||
|
value = match.group(2).strip()
|
||||||
|
properties[key] = value
|
||||||
|
|
||||||
|
gxepd2vers = "unknown"
|
||||||
|
try:
|
||||||
|
if properties["name"] == "GxEPD2":
|
||||||
|
gxepd2vers = properties["version"]
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
env["CPPDEFINES"].extend([("BOARD", env["BOARD"]), ("EPDTYPE", epdtype), ("PCBVERS", pcbvers), ("GXEPD2VERS", gxepd2vers)])
|
||||||
|
|
||||||
|
print("added hardware info to CPPDEFINES")
|
||||||
|
print("friendly board name is '{}'".format(env.GetProjectOption ("board_name")))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Interfaces
|
Interfaces
|
||||||
----------
|
----------
|
||||||
|
|||||||
@@ -14,5 +14,6 @@ custom_config=
|
|||||||
lib/exampletask/exampleConfig.json
|
lib/exampletask/exampleConfig.json
|
||||||
custom_js=lib/exampletask/example.js
|
custom_js=lib/exampletask/example.js
|
||||||
custom_css=lib/exampletask/example.css
|
custom_css=lib/exampletask/example.css
|
||||||
|
custom_script=lib/exampletask/script.py
|
||||||
upload_port = /dev/esp32
|
upload_port = /dev/esp32
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
4
lib/exampletask/script.py
Normal file
4
lib/exampletask/script.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Import("env")
|
||||||
|
|
||||||
|
print("exampletask extra script running")
|
||||||
|
syntax error here
|
||||||
23
lib/hardware/GwChannelModes.h
Normal file
23
lib/hardware/GwChannelModes.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
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 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
|
||||||
|
|
||||||
|
defines for the channel modes(types)
|
||||||
|
*/
|
||||||
|
#ifndef _GWCHANNELMODES_H
|
||||||
|
#define _GWCHANNELMODES_H
|
||||||
|
#define GWSERIAL_TYPE_UNI 1
|
||||||
|
#define GWSERIAL_TYPE_BI 2
|
||||||
|
#define GWSERIAL_TYPE_RX 3
|
||||||
|
#define GWSERIAL_TYPE_TX 4
|
||||||
|
#define GWSERIAL_TYPE_UNK 0
|
||||||
|
#endif
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -20,11 +20,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifndef _GWHARDWARE_H
|
#ifndef _GWHARDWARE_H
|
||||||
#define _GWHARDWARE_H
|
#define _GWHARDWARE_H
|
||||||
#define GWSERIAL_TYPE_UNI 1
|
#include "GwChannelModes.h"
|
||||||
#define GWSERIAL_TYPE_BI 2
|
|
||||||
#define GWSERIAL_TYPE_RX 3
|
|
||||||
#define GWSERIAL_TYPE_TX 4
|
|
||||||
#define GWSERIAL_TYPE_UNK 0
|
|
||||||
#include <GwConfigItem.h>
|
#include <GwConfigItem.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include "GwAppInfo.h"
|
#include "GwAppInfo.h"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -35,7 +35,12 @@
|
|||||||
#ifdef M5_GPS_KIT
|
#ifdef M5_GPS_KIT
|
||||||
GWRESOURCE_USE(BASE,M5_GPS_KIT)
|
GWRESOURCE_USE(BASE,M5_GPS_KIT)
|
||||||
GWRESOURCE_USE(SERIAL1,M5_GPS_KIT)
|
GWRESOURCE_USE(SERIAL1,M5_GPS_KIT)
|
||||||
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_UNI,9600
|
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_RX,9600
|
||||||
|
#endif
|
||||||
|
#ifdef M5_GPSV2_KIT
|
||||||
|
GWRESOURCE_USE(BASE,M5_GPSV2_KIT)
|
||||||
|
GWRESOURCE_USE(SERIAL1,M5_GPSV2_KIT)
|
||||||
|
#define _GWI_SERIAL1 BOARD_LEFT1,-1,GWSERIAL_TYPE_RX,115200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//M5 ProtoHub
|
//M5 ProtoHub
|
||||||
@@ -61,7 +66,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
//can kit for M5 Atom
|
//can kit for M5 Atom
|
||||||
#ifdef M5_CAN_KIT
|
#if defined (M5_CAN_KIT)
|
||||||
GWRESOURCE_USE(BASE,M5_CAN_KIT)
|
GWRESOURCE_USE(BASE,M5_CAN_KIT)
|
||||||
GWRESOURCE_USE(CAN,M5_CANKIT)
|
GWRESOURCE_USE(CAN,M5_CANKIT)
|
||||||
#define ESP32_CAN_TX_PIN BOARD_LEFT1
|
#define ESP32_CAN_TX_PIN BOARD_LEFT1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -43,6 +43,13 @@
|
|||||||
#define _GWI_SERIAL_GROOVE$GS$ GWSERIAL_TYPE_RX,9600
|
#define _GWI_SERIAL_GROOVE$GS$ GWSERIAL_TYPE_RX,9600
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#GROVE
|
||||||
|
//https://docs.m5stack.com/en/unit/Unit-GPS%20v1.1
|
||||||
|
#ifdef M5_GPSV11_UNIT$GS$
|
||||||
|
GWRESOURCE_USE(GROOVE$G$,M5_GPSV11_UNIT$GS$)
|
||||||
|
#define _GWI_SERIAL_GROOVE$GS$ GWSERIAL_TYPE_RX,115200
|
||||||
|
#endif
|
||||||
|
|
||||||
#GROVE
|
#GROVE
|
||||||
//CAN via groove
|
//CAN via groove
|
||||||
#ifdef M5_CANUNIT$GS$
|
#ifdef M5_CANUNIT$GS$
|
||||||
@@ -64,15 +71,15 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#GROVE
|
#GROVE
|
||||||
//#ifdef M5_ENV4$GS$
|
#ifdef M5_ENV4$GS$
|
||||||
// #ifndef M5_GROOVEIIC$GS$
|
#ifndef M5_GROOVEIIC$GS$
|
||||||
// #define M5_GROOVEIIC$GS$
|
#define M5_GROOVEIIC$GS$
|
||||||
// #endif
|
#endif
|
||||||
// GROOVE_IIC(SHT3X,$Z$,1)
|
GROOVE_IIC(SHT4X,$Z$,1)
|
||||||
// GROOVE_IIC(BMP280,$Z$,1)
|
GROOVE_IIC(BMP280,$Z$,1)
|
||||||
// #define _GWSHT3X
|
#define _GWSHT4X
|
||||||
// #define _GWBMP280
|
#define _GWBMP280
|
||||||
//#endif
|
#endif
|
||||||
|
|
||||||
#GROVE
|
#GROVE
|
||||||
//example: -DSHT3XG1_A : defines STH3Xn1 on grove A - x depends on the other devices
|
//example: -DSHT3XG1_A : defines STH3Xn1 on grove A - x depends on the other devices
|
||||||
@@ -93,6 +100,25 @@
|
|||||||
#define _GWSHT3X
|
#define _GWSHT3X
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#GROVE
|
||||||
|
//example: -DSHT4XG1_A : defines STH4Xn1 on grove A - x depends on the other devices
|
||||||
|
#ifdef GWSHT4XG1$GS$
|
||||||
|
#ifndef M5_GROOVEIIC$GS$
|
||||||
|
#define M5_GROOVEIIC$GS$
|
||||||
|
#endif
|
||||||
|
GROOVE_IIC(SHT4X,$Z$,1)
|
||||||
|
#define _GWSHT4X
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#GROVE
|
||||||
|
#ifdef GWSHT4XG2$GS$
|
||||||
|
#ifndef M5_GROOVEIIC$GS$
|
||||||
|
#define M5_GROOVEIIC$GS$
|
||||||
|
#endif
|
||||||
|
GROOVE_IIC(SHT4X,$Z$,2)
|
||||||
|
#define _GWSHT4X
|
||||||
|
#endif
|
||||||
|
|
||||||
#GROVE
|
#GROVE
|
||||||
#ifdef GWQMP6988G1$GS$
|
#ifdef GWQMP6988G1$GS$
|
||||||
#ifndef M5_GROOVEIIC$GS$
|
#ifndef M5_GROOVEIIC$GS$
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class BME280Config : public IICSensorBase{
|
|||||||
bool prAct=true;
|
bool prAct=true;
|
||||||
bool tmAct=true;
|
bool tmAct=true;
|
||||||
bool huAct=true;
|
bool huAct=true;
|
||||||
|
bool sEnv=true;
|
||||||
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||||
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_InsideHumidity;
|
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_InsideHumidity;
|
||||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||||
@@ -152,6 +153,7 @@ SensorBase::Creator registerBME280(GwApi *api){
|
|||||||
CFG_SGET(s, prNam, prefix); \
|
CFG_SGET(s, prNam, prefix); \
|
||||||
CFG_SGET(s, tmOff, prefix); \
|
CFG_SGET(s, tmOff, prefix); \
|
||||||
CFG_SGET(s, prOff, prefix); \
|
CFG_SGET(s, prOff, prefix); \
|
||||||
|
CFG_SGET(s, sEnv, prefix); \
|
||||||
s->busId = bus; \
|
s->busId = bus; \
|
||||||
s->addr = baddr; \
|
s->addr = baddr; \
|
||||||
s->ok = true; \
|
s->ok = true; \
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class BMP280Config : public IICSensorBase{
|
|||||||
public:
|
public:
|
||||||
bool prAct=true;
|
bool prAct=true;
|
||||||
bool tmAct=true;
|
bool tmAct=true;
|
||||||
|
bool sEnv=true;
|
||||||
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||||
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_Undef;
|
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_Undef;
|
||||||
@@ -150,6 +151,7 @@ SensorBase::Creator registerBMP280(GwApi *api){
|
|||||||
CFG_SGET(s, prNam, prefix); \
|
CFG_SGET(s, prNam, prefix); \
|
||||||
CFG_SGET(s, tmOff, prefix); \
|
CFG_SGET(s, tmOff, prefix); \
|
||||||
CFG_SGET(s, prOff, prefix); \
|
CFG_SGET(s, prOff, prefix); \
|
||||||
|
CFG_SGET(s, sEnv,prefix); \
|
||||||
s->busId = bus; \
|
s->busId = bus; \
|
||||||
s->addr = baddr; \
|
s->addr = baddr; \
|
||||||
s->ok = true; \
|
s->ok = true; \
|
||||||
|
|||||||
@@ -104,12 +104,19 @@ void sendN2kTemperature(GwApi *api,CFG &cfg,double value, int counterId){
|
|||||||
|
|
||||||
template <class CFG>
|
template <class CFG>
|
||||||
void sendN2kEnvironmentalParameters(GwApi *api,CFG &cfg,double tmValue, double huValue, double prValue, int counterId){
|
void sendN2kEnvironmentalParameters(GwApi *api,CFG &cfg,double tmValue, double huValue, double prValue, int counterId){
|
||||||
|
if (! cfg.sEnv) return;
|
||||||
tN2kMsg msg;
|
tN2kMsg msg;
|
||||||
SetN2kEnvironmentalParameters(msg,1,cfg.tmSrc,tmValue,cfg.huSrc,huValue,prValue);
|
SetN2kEnvironmentalParameters(msg,1,cfg.tmSrc,tmValue,cfg.huSrc,huValue,prValue);
|
||||||
api->sendN2kMessage(msg);
|
api->sendN2kMessage(msg);
|
||||||
api->increment(counterId,cfg.prefix+String("hum"));
|
if (huValue != N2kDoubleNA){
|
||||||
api->increment(counterId,cfg.prefix+String("press"));
|
api->increment(counterId,cfg.prefix+String("ehum"));
|
||||||
api->increment(counterId,cfg.prefix+String("temp"));
|
}
|
||||||
|
if (prValue != N2kDoubleNA){
|
||||||
|
api->increment(counterId,cfg.prefix+String("epress"));
|
||||||
|
}
|
||||||
|
if (tmValue != N2kDoubleNA){
|
||||||
|
api->increment(counterId,cfg.prefix+String("etemp"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _GWI_IIC1
|
#ifndef _GWI_IIC1
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ static std::vector<IICGrove> iicGroveList;
|
|||||||
#include "GwBME280.h"
|
#include "GwBME280.h"
|
||||||
#include "GwBMP280.h"
|
#include "GwBMP280.h"
|
||||||
#include "GwQMP6988.h"
|
#include "GwQMP6988.h"
|
||||||
#include "GwSHT3X.h"
|
#include "GwSHTXX.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "GwTimer.h"
|
#include "GwTimer.h"
|
||||||
@@ -91,6 +91,7 @@ void initIicTask(GwApi *api){
|
|||||||
GwConfigHandler *config=api->getConfig();
|
GwConfigHandler *config=api->getConfig();
|
||||||
std::vector<SensorBase::Creator> creators;
|
std::vector<SensorBase::Creator> creators;
|
||||||
creators.push_back(registerSHT3X(api));
|
creators.push_back(registerSHT3X(api));
|
||||||
|
creators.push_back(registerSHT4X(api));
|
||||||
creators.push_back(registerQMP6988(api));
|
creators.push_back(registerQMP6988(api));
|
||||||
creators.push_back(registerBME280(api));
|
creators.push_back(registerBME280(api));
|
||||||
creators.push_back(registerBMP280(api));
|
creators.push_back(registerBMP280(api));
|
||||||
@@ -147,13 +148,13 @@ bool initWire(GwLog *logger, TwoWire &wire, int num){
|
|||||||
#ifdef _GWI_IIC1
|
#ifdef _GWI_IIC1
|
||||||
return initWireDo(logger,wire,num,_GWI_IIC1);
|
return initWireDo(logger,wire,num,_GWI_IIC1);
|
||||||
#endif
|
#endif
|
||||||
return initWireDo(logger,wire,num,"",GWIIC_SDA,GWIIC_SCL);
|
return initWireDo(logger,wire,num,"",GWIIC_SCL,GWIIC_SDA);
|
||||||
}
|
}
|
||||||
if (num == 2){
|
if (num == 2){
|
||||||
#ifdef _GWI_IIC2
|
#ifdef _GWI_IIC2
|
||||||
return initWireDo(logger,wire,num,_GWI_IIC2);
|
return initWireDo(logger,wire,num,_GWI_IIC2);
|
||||||
#endif
|
#endif
|
||||||
return initWireDo(logger,wire,num,"",GWIIC_SDA2,GWIIC_SCL2);
|
return initWireDo(logger,wire,num,"",GWIIC_SCL2,GWIIC_SDA2);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ class QMP6988Config : public IICSensorBase{
|
|||||||
public:
|
public:
|
||||||
String prNam="Pressure";
|
String prNam="Pressure";
|
||||||
bool prAct=true;
|
bool prAct=true;
|
||||||
|
bool sEnv=true;
|
||||||
|
tN2kTempSource tmSrc=tN2kTempSource::N2kts_InsideTemperature;
|
||||||
|
tN2kHumiditySource huSrc=tN2kHumiditySource::N2khs_Undef;
|
||||||
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
tN2kPressureSource prSrc=tN2kPressureSource::N2kps_Atmospheric;
|
||||||
float prOff=0;
|
float prOff=0;
|
||||||
QMP6988 *device=nullptr;
|
QMP6988 *device=nullptr;
|
||||||
@@ -39,6 +42,7 @@ class QMP6988Config : public IICSensorBase{
|
|||||||
float computed=pressure+prOff;
|
float computed=pressure+prOff;
|
||||||
LOG_DEBUG(GwLog::DEBUG,"%s measure %2.0fPa, computed %2.0fPa",prefix.c_str(), pressure,computed);
|
LOG_DEBUG(GwLog::DEBUG,"%s measure %2.0fPa, computed %2.0fPa",prefix.c_str(), pressure,computed);
|
||||||
sendN2kPressure(api,*this,computed,counterId);
|
sendN2kPressure(api,*this,computed,counterId);
|
||||||
|
sendN2kEnvironmentalParameters(api,*this,N2kDoubleNA,N2kDoubleNA,computed,counterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -90,6 +94,7 @@ SensorBase::Creator registerQMP6988(GwApi *api){
|
|||||||
CFG_SGET(s,prAct,prefix); \
|
CFG_SGET(s,prAct,prefix); \
|
||||||
CFG_SGET(s,intv,prefix); \
|
CFG_SGET(s,intv,prefix); \
|
||||||
CFG_SGET(s,prOff,prefix); \
|
CFG_SGET(s,prOff,prefix); \
|
||||||
|
CFG_SGET(s,sEnv,prefix); \
|
||||||
s->busId = bus; \
|
s->busId = bus; \
|
||||||
s->addr = baddr; \
|
s->addr = baddr; \
|
||||||
s->ok = true; \
|
s->ok = true; \
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
#include "GwSHT3X.h"
|
|
||||||
#ifdef _GWSHT3X
|
|
||||||
class SHT3XConfig;
|
|
||||||
static GwSensorConfigInitializerList<SHT3XConfig> configs;
|
|
||||||
class SHT3XConfig : public IICSensorBase{
|
|
||||||
public:
|
|
||||||
String tmNam;
|
|
||||||
String huNam;
|
|
||||||
bool tmAct=false;
|
|
||||||
bool huAct=false;
|
|
||||||
tN2kHumiditySource huSrc;
|
|
||||||
tN2kTempSource tmSrc;
|
|
||||||
SHT3X *device=nullptr;
|
|
||||||
using IICSensorBase::IICSensorBase;
|
|
||||||
virtual bool isActive(){
|
|
||||||
return tmAct || huAct;
|
|
||||||
}
|
|
||||||
virtual bool initDevice(GwApi * api,TwoWire *wire){
|
|
||||||
if (! isActive()) return false;
|
|
||||||
device=new SHT3X();
|
|
||||||
device->init(addr,wire);
|
|
||||||
GwLog *logger=api->getLogger();
|
|
||||||
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
virtual bool preinit(GwApi * api){
|
|
||||||
GwLog *logger=api->getLogger();
|
|
||||||
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
|
|
||||||
addHumidXdr(api,*this);
|
|
||||||
addTempXdr(api,*this);
|
|
||||||
return isActive();
|
|
||||||
}
|
|
||||||
virtual void measure(GwApi * api,TwoWire *wire, int counterId)
|
|
||||||
{
|
|
||||||
if (!device)
|
|
||||||
return;
|
|
||||||
GwLog *logger=api->getLogger();
|
|
||||||
int rt = 0;
|
|
||||||
if ((rt = device->get()) == 0)
|
|
||||||
{
|
|
||||||
double temp = device->cTemp;
|
|
||||||
temp = CToKelvin(temp);
|
|
||||||
double humid = device->humidity;
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "%s measure temp=%2.1f, humid=%2.0f",prefix.c_str(), (float)temp, (float)humid);
|
|
||||||
if (huAct)
|
|
||||||
{
|
|
||||||
sendN2kHumidity(api, *this, humid, counterId);
|
|
||||||
}
|
|
||||||
if (tmAct)
|
|
||||||
{
|
|
||||||
sendN2kTemperature(api, *this, temp, counterId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOG_DEBUG(GwLog::DEBUG, "unable to query %s: %d",prefix.c_str(), rt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void readConfig(GwConfigHandler *cfg){
|
|
||||||
if (ok) return;
|
|
||||||
configs.readConfig(this,cfg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
SensorBase::Creator creator=[](GwApi *api,const String &prfx)-> SensorBase*{
|
|
||||||
if (! configs.knowsPrefix(prfx)) return nullptr;
|
|
||||||
return new SHT3XConfig(api,prfx);
|
|
||||||
};
|
|
||||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
|
||||||
GwLog *logger=api->getLogger();
|
|
||||||
#if defined(GWSHT3X) || defined (GWSHT3X11)
|
|
||||||
{
|
|
||||||
api->addSensor(creator(api,"SHT3X11"));
|
|
||||||
CHECK_IIC1();
|
|
||||||
#pragma message "GWSHT3X11 defined"
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(GWSHT3X12)
|
|
||||||
{
|
|
||||||
api->addSensor(creator(api,"SHT3X12"));
|
|
||||||
CHECK_IIC1();
|
|
||||||
#pragma message "GWSHT3X12 defined"
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(GWSHT3X21)
|
|
||||||
{
|
|
||||||
api->addSensor(creator(api,"SHT3X21"));
|
|
||||||
CHECK_IIC2();
|
|
||||||
#pragma message "GWSHT3X21 defined"
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(GWSHT3X22)
|
|
||||||
{
|
|
||||||
api->addSensor(creator(api,"SHT3X22"));
|
|
||||||
CHECK_IIC2();
|
|
||||||
#pragma message "GWSHT3X22 defined"
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return creator;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* we do not dynamically compute the config names
|
|
||||||
* just to get compile time errors if something does not fit
|
|
||||||
* correctly
|
|
||||||
*/
|
|
||||||
#define CFGSHT3X(s, prefix, bus, baddr) \
|
|
||||||
CFG_SGET(s, tmNam, prefix); \
|
|
||||||
CFG_SGET(s, huNam, prefix); \
|
|
||||||
CFG_SGET(s, iid, prefix); \
|
|
||||||
CFG_SGET(s, tmAct, prefix); \
|
|
||||||
CFG_SGET(s, huAct, prefix); \
|
|
||||||
CFG_SGET(s, intv, prefix); \
|
|
||||||
CFG_SGET(s, huSrc, prefix); \
|
|
||||||
CFG_SGET(s, tmSrc, prefix); \
|
|
||||||
s->busId = bus; \
|
|
||||||
s->addr = baddr; \
|
|
||||||
s->ok = true; \
|
|
||||||
s->intv *= 1000;
|
|
||||||
|
|
||||||
#define SCSHT3X(prefix, bus, addr) \
|
|
||||||
GWSENSORDEF(configs, SHT3XConfig, CFGSHT3X, prefix, bus, addr)
|
|
||||||
|
|
||||||
SCSHT3X(SHT3X11, 1, 0x44);
|
|
||||||
SCSHT3X(SHT3X12, 1, 0x45);
|
|
||||||
SCSHT3X(SHT3X21, 2, 0x44);
|
|
||||||
SCSHT3X(SHT3X22, 2, 0x45);
|
|
||||||
|
|
||||||
#else
|
|
||||||
SensorBase::Creator registerSHT3X(GwApi *api){
|
|
||||||
return SensorBase::Creator();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
254
lib/iictask/GwSHTXX.cpp
Normal file
254
lib/iictask/GwSHTXX.cpp
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
#include "GwSHTXX.h"
|
||||||
|
#if defined(_GWSHT3X) || defined(_GWSHT4X)
|
||||||
|
class SHTXXConfig : public IICSensorBase{
|
||||||
|
public:
|
||||||
|
String tmNam;
|
||||||
|
String huNam;
|
||||||
|
bool tmAct=false;
|
||||||
|
bool huAct=false;
|
||||||
|
bool sEnv=true;
|
||||||
|
tN2kHumiditySource huSrc;
|
||||||
|
tN2kTempSource tmSrc;
|
||||||
|
using IICSensorBase::IICSensorBase;
|
||||||
|
virtual bool isActive(){
|
||||||
|
return tmAct || huAct;
|
||||||
|
}
|
||||||
|
virtual bool preinit(GwApi * api){
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
LOG_DEBUG(GwLog::LOG,"%s configured",prefix.c_str());
|
||||||
|
addHumidXdr(api,*this);
|
||||||
|
addTempXdr(api,*this);
|
||||||
|
return isActive();
|
||||||
|
}
|
||||||
|
virtual bool doMeasure(GwApi * api,double &temp, double &humid){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void measure(GwApi * api,TwoWire *wire, int counterId) override
|
||||||
|
{
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
double temp = N2kDoubleNA;
|
||||||
|
double humid = N2kDoubleNA;
|
||||||
|
if (doMeasure(api,temp,humid)){
|
||||||
|
temp = CToKelvin(temp);
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "%s measure temp=%2.1f, humid=%2.0f",prefix.c_str(), (float)temp, (float)humid);
|
||||||
|
if (huAct)
|
||||||
|
{
|
||||||
|
sendN2kHumidity(api, *this, humid, counterId);
|
||||||
|
}
|
||||||
|
if (tmAct)
|
||||||
|
{
|
||||||
|
sendN2kTemperature(api, *this, temp, counterId);
|
||||||
|
}
|
||||||
|
if (huAct || tmAct){
|
||||||
|
sendN2kEnvironmentalParameters(api,*this,temp,humid,N2kDoubleNA,counterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* we do not dynamically compute the config names
|
||||||
|
* just to get compile time errors if something does not fit
|
||||||
|
* correctly
|
||||||
|
*/
|
||||||
|
#define INITSHTXX(type,prefix,bus,baddr) \
|
||||||
|
[] (type *s ,GwConfigHandler *cfg) { \
|
||||||
|
CFG_SGET(s, tmNam, prefix); \
|
||||||
|
CFG_SGET(s, huNam, prefix); \
|
||||||
|
CFG_SGET(s, iid, prefix); \
|
||||||
|
CFG_SGET(s, tmAct, prefix); \
|
||||||
|
CFG_SGET(s, huAct, prefix); \
|
||||||
|
CFG_SGET(s, intv, prefix); \
|
||||||
|
CFG_SGET(s, huSrc, prefix); \
|
||||||
|
CFG_SGET(s, tmSrc, prefix); \
|
||||||
|
CFG_SGET(s, sEnv,prefix); \
|
||||||
|
s->busId = bus; \
|
||||||
|
s->addr = baddr; \
|
||||||
|
s->ok = true; \
|
||||||
|
s->intv *= 1000; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_GWSHT3X)
|
||||||
|
class SHT3XConfig;
|
||||||
|
static GwSensorConfigInitializerList<SHT3XConfig> configs3;
|
||||||
|
class SHT3XConfig : public SHTXXConfig{
|
||||||
|
SHT3X *device=nullptr;
|
||||||
|
public:
|
||||||
|
using SHTXXConfig::SHTXXConfig;
|
||||||
|
virtual bool initDevice(GwApi * api,TwoWire *wire)override{
|
||||||
|
if (! isActive()) return false;
|
||||||
|
device=new SHT3X();
|
||||||
|
device->init(addr,wire);
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool doMeasure(GwApi *api,double &temp, double &humid) override{
|
||||||
|
if (!device)
|
||||||
|
return false;
|
||||||
|
int rt=0;
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
if ((rt = device->get()) == 0)
|
||||||
|
{
|
||||||
|
temp = device->cTemp;
|
||||||
|
humid = device->humidity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "unable to query %s: %d",prefix.c_str(), rt);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void readConfig(GwConfigHandler *cfg) override{
|
||||||
|
if (ok) return;
|
||||||
|
configs3.readConfig(this,cfg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SensorBase::Creator creator3=[](GwApi *api,const String &prfx)-> SensorBase*{
|
||||||
|
if (! configs3.knowsPrefix(prfx)) return nullptr;
|
||||||
|
return new SHT3XConfig(api,prfx);
|
||||||
|
};
|
||||||
|
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
#if defined(GWSHT3X) || defined (GWSHT3X11)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT3X11"));
|
||||||
|
CHECK_IIC1();
|
||||||
|
#pragma message "GWSHT3X11 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT3X12)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT3X12"));
|
||||||
|
CHECK_IIC1();
|
||||||
|
#pragma message "GWSHT3X12 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT3X21)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT3X21"));
|
||||||
|
CHECK_IIC2();
|
||||||
|
#pragma message "GWSHT3X21 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT3X22)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT3X22"));
|
||||||
|
CHECK_IIC2();
|
||||||
|
#pragma message "GWSHT3X22 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return creator3;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define SCSHT3X(prefix, bus, addr) \
|
||||||
|
GwSensorConfigInitializer<SHT3XConfig> __initCFGSHT3X ## prefix \
|
||||||
|
(configs3,GwSensorConfig<SHT3XConfig>(#prefix,INITSHTXX(SHT3XConfig,prefix,bus,addr)));
|
||||||
|
|
||||||
|
SCSHT3X(SHT3X11, 1, 0x44);
|
||||||
|
SCSHT3X(SHT3X12, 1, 0x45);
|
||||||
|
SCSHT3X(SHT3X21, 2, 0x44);
|
||||||
|
SCSHT3X(SHT3X22, 2, 0x45);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if defined(_GWSHT4X)
|
||||||
|
class SHT4XConfig;
|
||||||
|
static GwSensorConfigInitializerList<SHT4XConfig> configs4;
|
||||||
|
class SHT4XConfig : public SHTXXConfig{
|
||||||
|
SHT4X *device=nullptr;
|
||||||
|
public:
|
||||||
|
using SHTXXConfig::SHTXXConfig;
|
||||||
|
virtual bool initDevice(GwApi * api,TwoWire *wire)override{
|
||||||
|
if (! isActive()) return false;
|
||||||
|
device=new SHT4X();
|
||||||
|
device->begin(wire,addr);
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
LOG_DEBUG(GwLog::LOG,"initialized %s at address %d, intv %ld",prefix.c_str(),(int)addr,intv);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool doMeasure(GwApi *api,double &temp, double &humid) override{
|
||||||
|
if (!device)
|
||||||
|
return false;
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
if (device->update())
|
||||||
|
{
|
||||||
|
temp = device->cTemp;
|
||||||
|
humid = device->humidity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
LOG_DEBUG(GwLog::DEBUG, "unable to query %s",prefix.c_str());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void readConfig(GwConfigHandler *cfg) override{
|
||||||
|
if (ok) return;
|
||||||
|
configs4.readConfig(this,cfg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
SensorBase::Creator creator4=[](GwApi *api,const String &prfx)-> SensorBase*{
|
||||||
|
if (! configs4.knowsPrefix(prfx)) return nullptr;
|
||||||
|
return new SHT4XConfig(api,prfx);
|
||||||
|
};
|
||||||
|
SensorBase::Creator registerSHT4X(GwApi *api){
|
||||||
|
GwLog *logger=api->getLogger();
|
||||||
|
#if defined(GWSHT4X) || defined (GWSHT4X11)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT4X11"));
|
||||||
|
CHECK_IIC1();
|
||||||
|
#pragma message "GWSHT4X11 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT4X12)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT4X12"));
|
||||||
|
CHECK_IIC1();
|
||||||
|
#pragma message "GWSHT4X12 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT4X21)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT4X21"));
|
||||||
|
CHECK_IIC2();
|
||||||
|
#pragma message "GWSHT4X21 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(GWSHT4X22)
|
||||||
|
{
|
||||||
|
api->addSensor(creator3(api,"SHT4X22"));
|
||||||
|
CHECK_IIC2();
|
||||||
|
#pragma message "GWSHT4X22 defined"
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return creator4;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define SCSHT4X(prefix, bus, addr) \
|
||||||
|
GwSensorConfigInitializer<SHT4XConfig> __initCFGSHT4X ## prefix \
|
||||||
|
(configs4,GwSensorConfig<SHT4XConfig>(#prefix,INITSHTXX(SHT4XConfig,prefix,bus,addr)));
|
||||||
|
|
||||||
|
SCSHT4X(SHT4X11, 1, 0x44);
|
||||||
|
SCSHT4X(SHT4X12, 1, 0x45);
|
||||||
|
SCSHT4X(SHT4X21, 2, 0x44);
|
||||||
|
SCSHT4X(SHT4X22, 2, 0x45);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#ifndef _GWSHT3X
|
||||||
|
SensorBase::Creator registerSHT3X(GwApi *api){
|
||||||
|
return SensorBase::Creator();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef _GWSHT4X
|
||||||
|
SensorBase::Creator registerSHT4X(GwApi *api){
|
||||||
|
return SensorBase::Creator();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
#ifndef _GWSHT3X_H
|
#ifndef _GWSHTXX_H
|
||||||
#define _GWSHT3X_H
|
#define _GWSHTXX_H
|
||||||
#include "GwIicSensors.h"
|
#include "GwIicSensors.h"
|
||||||
#ifdef _GWIIC
|
#ifdef _GWIIC
|
||||||
#if defined(GWSHT3X) || defined(GWSHT3X11) || defined(GWSHT3X12) || defined(GWSHT3X21) || defined(GWSHT3X22)
|
#if defined(GWSHT3X) || defined(GWSHT3X11) || defined(GWSHT3X12) || defined(GWSHT3X21) || defined(GWSHT3X22)
|
||||||
#define _GWSHT3X
|
#define _GWSHT3X
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(GWSHT4X) || defined(GWSHT4X11) || defined(GWSHT4X12) || defined(GWSHT4X21) || defined(GWSHT4X22)
|
||||||
|
#define _GWSHT4X
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#undef _GWSHT3X
|
#undef _GWSHT3X
|
||||||
#undef GWSHT3X
|
#undef GWSHT3X
|
||||||
@@ -12,9 +15,19 @@
|
|||||||
#undef GWSHT3X12
|
#undef GWSHT3X12
|
||||||
#undef GWSHT3X21
|
#undef GWSHT3X21
|
||||||
#undef GWSHT3X22
|
#undef GWSHT3X22
|
||||||
|
#undef _GWSHT4X
|
||||||
|
#undef GWSHT4X
|
||||||
|
#undef GWSHT4X11
|
||||||
|
#undef GWSHT4X12
|
||||||
|
#undef GWSHT4X21
|
||||||
|
#undef GWSHT4X22
|
||||||
#endif
|
#endif
|
||||||
#ifdef _GWSHT3X
|
#ifdef _GWSHT3X
|
||||||
#include "SHT3X.h"
|
#include "SHT3X.h"
|
||||||
#endif
|
#endif
|
||||||
SensorBase::Creator registerSHT3X(GwApi *api);
|
#ifdef _GWSHT4X
|
||||||
|
#include "SHT4X.h"
|
||||||
|
#endif
|
||||||
|
SensorBase::Creator registerSHT3X(GwApi *api);
|
||||||
|
SensorBase::Creator registerSHT4X(GwApi *api);
|
||||||
#endif
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "GwSHT3X.h"
|
#include "GwSHTXX.h"
|
||||||
#ifdef _GWSHT3X
|
#ifdef _GWSHT3X
|
||||||
|
|
||||||
bool SHT3X::init(uint8_t slave_addr_in, TwoWire* wire_in)
|
bool SHT3X::init(uint8_t slave_addr_in, TwoWire* wire_in)
|
||||||
|
|||||||
131
lib/iictask/SHT4X.cpp
Normal file
131
lib/iictask/SHT4X.cpp
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#include "GwSHTXX.h"
|
||||||
|
#ifdef _GWSHT4X
|
||||||
|
|
||||||
|
uint8_t crc8(const uint8_t *data, int len) {
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* CRC-8 formula from page 14 of SHT spec pdf
|
||||||
|
*
|
||||||
|
* Test data 0xBE, 0xEF should yield 0x92
|
||||||
|
*
|
||||||
|
* Initialization data 0xFF
|
||||||
|
* Polynomial 0x31 (x8 + x5 +x4 +1)
|
||||||
|
* Final XOR 0x00
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t POLYNOMIAL(0x31);
|
||||||
|
uint8_t crc(0xFF);
|
||||||
|
|
||||||
|
for (int j = len; j; --j) {
|
||||||
|
crc ^= *data++;
|
||||||
|
|
||||||
|
for (int i = 8; i; --i) {
|
||||||
|
crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHT4X::begin(TwoWire* wire, uint8_t addr) {
|
||||||
|
_addr = addr;
|
||||||
|
_wire = wire;
|
||||||
|
int error;
|
||||||
|
_wire->beginTransmission(addr);
|
||||||
|
error = _wire->endTransmission();
|
||||||
|
if (error == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHT4X::update() {
|
||||||
|
uint8_t readbuffer[6];
|
||||||
|
uint8_t cmd = SHT4x_NOHEAT_HIGHPRECISION;
|
||||||
|
uint16_t duration = 10;
|
||||||
|
|
||||||
|
if (_heater == SHT4X_NO_HEATER) {
|
||||||
|
if (_precision == SHT4X_HIGH_PRECISION) {
|
||||||
|
cmd = SHT4x_NOHEAT_HIGHPRECISION;
|
||||||
|
duration = 10;
|
||||||
|
}
|
||||||
|
if (_precision == SHT4X_MED_PRECISION) {
|
||||||
|
cmd = SHT4x_NOHEAT_MEDPRECISION;
|
||||||
|
duration = 5;
|
||||||
|
}
|
||||||
|
if (_precision == SHT4X_LOW_PRECISION) {
|
||||||
|
cmd = SHT4x_NOHEAT_LOWPRECISION;
|
||||||
|
duration = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_heater == SHT4X_HIGH_HEATER_1S) {
|
||||||
|
cmd = SHT4x_HIGHHEAT_1S;
|
||||||
|
duration = 1100;
|
||||||
|
}
|
||||||
|
if (_heater == SHT4X_HIGH_HEATER_100MS) {
|
||||||
|
cmd = SHT4x_HIGHHEAT_100MS;
|
||||||
|
duration = 110;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_heater == SHT4X_MED_HEATER_1S) {
|
||||||
|
cmd = SHT4x_MEDHEAT_1S;
|
||||||
|
duration = 1100;
|
||||||
|
}
|
||||||
|
if (_heater == SHT4X_MED_HEATER_100MS) {
|
||||||
|
cmd = SHT4x_MEDHEAT_100MS;
|
||||||
|
duration = 110;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_heater == SHT4X_LOW_HEATER_1S) {
|
||||||
|
cmd = SHT4x_LOWHEAT_1S;
|
||||||
|
duration = 1100;
|
||||||
|
}
|
||||||
|
if (_heater == SHT4X_LOW_HEATER_100MS) {
|
||||||
|
cmd = SHT4x_LOWHEAT_100MS;
|
||||||
|
duration = 110;
|
||||||
|
}
|
||||||
|
// _i2c.writeByte(_addr, cmd, 1);
|
||||||
|
_wire->beginTransmission(_addr);
|
||||||
|
_wire->write(cmd);
|
||||||
|
_wire->write(1);
|
||||||
|
_wire->endTransmission();
|
||||||
|
|
||||||
|
|
||||||
|
delay(duration);
|
||||||
|
|
||||||
|
_wire->requestFrom(_addr, (uint8_t)6);
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < 6; i++) {
|
||||||
|
readbuffer[i] = _wire->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readbuffer[2] != crc8(readbuffer, 2) ||
|
||||||
|
readbuffer[5] != crc8(readbuffer + 3, 2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float t_ticks = (uint16_t)readbuffer[0] * 256 + (uint16_t)readbuffer[1];
|
||||||
|
float rh_ticks = (uint16_t)readbuffer[3] * 256 + (uint16_t)readbuffer[4];
|
||||||
|
|
||||||
|
cTemp = -45 + 175 * t_ticks / 65535;
|
||||||
|
humidity = -6 + 125 * rh_ticks / 65535;
|
||||||
|
humidity = min(max(humidity, (float)0.0), (float)100.0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHT4X::setPrecision(sht4x_precision_t prec) {
|
||||||
|
_precision = prec;
|
||||||
|
}
|
||||||
|
|
||||||
|
sht4x_precision_t SHT4X::getPrecision(void) {
|
||||||
|
return _precision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHT4X::setHeater(sht4x_heater_t heat) {
|
||||||
|
_heater = heat;
|
||||||
|
}
|
||||||
|
|
||||||
|
sht4x_heater_t SHT4X::getHeater(void) {
|
||||||
|
return _heater;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
76
lib/iictask/SHT4X.h
Normal file
76
lib/iictask/SHT4X.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#ifndef __SHT4X_H_
|
||||||
|
#define __SHT4X_H_
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "Wire.h"
|
||||||
|
|
||||||
|
#define SHT40_I2C_ADDR_44 0x44
|
||||||
|
#define SHT40_I2C_ADDR_45 0x45
|
||||||
|
#define SHT41_I2C_ADDR_44 0x44
|
||||||
|
#define SHT41_I2C_ADDR_45 0x45
|
||||||
|
#define SHT45_I2C_ADDR_44 0x44
|
||||||
|
#define SHT45_I2C_ADDR_45 0x45
|
||||||
|
|
||||||
|
#define SHT4x_DEFAULT_ADDR 0x44 /**< SHT4x I2C Address */
|
||||||
|
#define SHT4x_NOHEAT_HIGHPRECISION \
|
||||||
|
0xFD /**< High precision measurement, no heater */
|
||||||
|
#define SHT4x_NOHEAT_MEDPRECISION \
|
||||||
|
0xF6 /**< Medium precision measurement, no heater */
|
||||||
|
#define SHT4x_NOHEAT_LOWPRECISION \
|
||||||
|
0xE0 /**< Low precision measurement, no heater */
|
||||||
|
|
||||||
|
#define SHT4x_HIGHHEAT_1S \
|
||||||
|
0x39 /**< High precision measurement, high heat for 1 sec */
|
||||||
|
#define SHT4x_HIGHHEAT_100MS \
|
||||||
|
0x32 /**< High precision measurement, high heat for 0.1 sec */
|
||||||
|
#define SHT4x_MEDHEAT_1S \
|
||||||
|
0x2F /**< High precision measurement, med heat for 1 sec */
|
||||||
|
#define SHT4x_MEDHEAT_100MS \
|
||||||
|
0x24 /**< High precision measurement, med heat for 0.1 sec */
|
||||||
|
#define SHT4x_LOWHEAT_1S \
|
||||||
|
0x1E /**< High precision measurement, low heat for 1 sec */
|
||||||
|
#define SHT4x_LOWHEAT_100MS \
|
||||||
|
0x15 /**< High precision measurement, low heat for 0.1 sec */
|
||||||
|
|
||||||
|
#define SHT4x_READSERIAL 0x89 /**< Read Out of Serial Register */
|
||||||
|
#define SHT4x_SOFTRESET 0x94 /**< Soft Reset */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SHT4X_HIGH_PRECISION,
|
||||||
|
SHT4X_MED_PRECISION,
|
||||||
|
SHT4X_LOW_PRECISION,
|
||||||
|
} sht4x_precision_t;
|
||||||
|
|
||||||
|
/** Optional pre-heater configuration setting */
|
||||||
|
typedef enum {
|
||||||
|
SHT4X_NO_HEATER,
|
||||||
|
SHT4X_HIGH_HEATER_1S,
|
||||||
|
SHT4X_HIGH_HEATER_100MS,
|
||||||
|
SHT4X_MED_HEATER_1S,
|
||||||
|
SHT4X_MED_HEATER_100MS,
|
||||||
|
SHT4X_LOW_HEATER_1S,
|
||||||
|
SHT4X_LOW_HEATER_100MS,
|
||||||
|
} sht4x_heater_t;
|
||||||
|
|
||||||
|
class SHT4X {
|
||||||
|
public:
|
||||||
|
bool begin(TwoWire* wire = &Wire, uint8_t addr = SHT40_I2C_ADDR_44);
|
||||||
|
bool update(void);
|
||||||
|
|
||||||
|
float cTemp = 0;
|
||||||
|
float humidity = 0;
|
||||||
|
|
||||||
|
void setPrecision(sht4x_precision_t prec);
|
||||||
|
sht4x_precision_t getPrecision(void);
|
||||||
|
void setHeater(sht4x_heater_t heat);
|
||||||
|
sht4x_heater_t getHeater(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TwoWire* _wire;
|
||||||
|
uint8_t _addr;
|
||||||
|
|
||||||
|
sht4x_precision_t _precision = SHT4X_HIGH_PRECISION;
|
||||||
|
sht4x_heater_t _heater = SHT4X_NO_HEATER;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,49 +1,77 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"name": "SHT3X",
|
"name": "SHTXX",
|
||||||
"replace": [
|
"replace": [
|
||||||
{
|
{
|
||||||
"b": "1",
|
"b": "1",
|
||||||
"i": "11",
|
"i": "11",
|
||||||
"n": "99"
|
"n": "99",
|
||||||
|
"x": "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b": "1",
|
"b": "1",
|
||||||
"i": "12",
|
"i": "12",
|
||||||
"n": "98"
|
"n": "98",
|
||||||
|
"x": "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b": "2",
|
"b": "2",
|
||||||
"i": "21",
|
"i": "21",
|
||||||
"n": "109"
|
"n": "109",
|
||||||
|
"x": "3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"b": "2",
|
"b": "2",
|
||||||
"i": "22",
|
"i": "22",
|
||||||
"n": "108"
|
"n": "108",
|
||||||
|
"x": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b": "1",
|
||||||
|
"i": "11",
|
||||||
|
"n": "119",
|
||||||
|
"x": "4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b": "1",
|
||||||
|
"i": "12",
|
||||||
|
"n": "118",
|
||||||
|
"x": "4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b": "2",
|
||||||
|
"i": "21",
|
||||||
|
"n": "129",
|
||||||
|
"x": "4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"b": "2",
|
||||||
|
"i": "22",
|
||||||
|
"n": "128",
|
||||||
|
"x": "4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
],
|
],
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"name": "SHT3X$itmAct",
|
"name": "SHT$xX$itmAct",
|
||||||
"label": "SHT3X$i Temp",
|
"label": "SHT$xX$i Temp",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "Enable the $i. I2C SHT3x temp sensor (bus $b)",
|
"description": "Enable the $i. I2C SHT$xX temp sensor (bus $b)",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$itmSrc",
|
"name": "SHT$xX$itmSrc",
|
||||||
"label": "SHT3X$i Temp Type",
|
"label": "SHT$xX$i Temp Type",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"default": "2",
|
"default": "2",
|
||||||
"description": "the NMEA2000 source type for the temperature",
|
"description": "the NMEA2000 source type for the temperature (PGN 130312,130311)",
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"l": "SeaTemperature",
|
"l": "SeaTemperature",
|
||||||
@@ -112,23 +140,23 @@
|
|||||||
],
|
],
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$ihuAct",
|
"name": "SHT$xX$ihuAct",
|
||||||
"label": "SHT3X$i Humidity",
|
"label": "SHT$xX$i Humidity",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "true",
|
"default": "true",
|
||||||
"description": "Enable the $i. I2C SHT3x humidity sensor (bus $b)",
|
"description": "Enable the $i. I2C SHT$xX humidity sensor (bus $b)",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$ihuSrc",
|
"name": "SHT$xX$ihuSrc",
|
||||||
"label": "SHT3X$i Humid Type",
|
"label": "SHT$xX$i Humid Type",
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"l": "OutsideHumidity",
|
"l": "OutsideHumidity",
|
||||||
@@ -141,57 +169,68 @@
|
|||||||
],
|
],
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X": "true"
|
"SHT$xX": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$iiid",
|
"name": "SHT$xX$iiid",
|
||||||
"label": "SHT3X$i N2K iid",
|
"label": "SHT$xX$i N2K iid",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "$n",
|
"default": "$n",
|
||||||
"description": "the N2K instance id for the $i. SHT3X Temperature and Humidity ",
|
"description": "the N2K instance id for the $i. SHT$xX Temperature and Humidity (PGN 130312,130311) ",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 253,
|
"max": 253,
|
||||||
"check": "checkMinMax",
|
"check": "checkMinMax",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$iintv",
|
"name": "SHT$xX$isEnv",
|
||||||
"label": "SHT3X$i Interval",
|
"label": "SHT$xX$i send Env",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "also send PGN 130311",
|
||||||
|
"category": "iicsensors$b",
|
||||||
|
"capabilities": {
|
||||||
|
"SHT$xX$i": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SHT$xX$iintv",
|
||||||
|
"label": "SHT$xX$i Interval",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2,
|
"default": 2,
|
||||||
"description": "Interval(s) to query SHT3X Temperature and Humidity (1...300)",
|
"description": "Interval(s) to query SHT$xX Temperature and Humidity (1...300)",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"min": 1,
|
"min": 1,
|
||||||
"max": 300,
|
"max": 300,
|
||||||
"check": "checkMinMax",
|
"check": "checkMinMax",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$itmNam",
|
"name": "SHT$xX$itmNam",
|
||||||
"label": "SHT3X$i Temp XDR",
|
"label": "SHT$xX$i Temp XDR",
|
||||||
"type": "String",
|
"type": "String",
|
||||||
"default": "Temp$i",
|
"default": "Temp$i",
|
||||||
"description": "set the XDR transducer name for the $i. SHT3X Temperature, leave empty to disable NMEA0183 XDR ",
|
"description": "set the XDR transducer name for the $i. SHT$xX Temperature, leave empty to disable NMEA0183 XDR ",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SHT3X$ihuNam",
|
"name": "SHT$xX$ihuNam",
|
||||||
"label": "SHT3X$i Humid XDR",
|
"label": "SHT$xX$i Humid XDR",
|
||||||
"type": "String",
|
"type": "String",
|
||||||
"default": "Humidity$i",
|
"default": "Humidity$i",
|
||||||
"description": "set the XDR transducer name for the $i. SHT3X Humidity, leave empty to disable NMEA0183 XDR",
|
"description": "set the XDR transducer name for the $i. SHT$xX Humidity, leave empty to disable NMEA0183 XDR",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"SHT3X$i": "true"
|
"SHT$xX$i": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -247,6 +286,17 @@
|
|||||||
"QMP6988$i": "true"
|
"QMP6988$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "QMP6988$isEnv",
|
||||||
|
"label": "QMP6988$i send Env",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "also send PGN 130311",
|
||||||
|
"category": "iicsensors$b",
|
||||||
|
"capabilities": {
|
||||||
|
"QMP6988$i": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "QMP6988$iintv",
|
"name": "QMP6988$iintv",
|
||||||
"label": "QMP6988-$i Interval",
|
"label": "QMP6988-$i Interval",
|
||||||
@@ -473,7 +523,7 @@
|
|||||||
"label": "BME280-$i N2K iid",
|
"label": "BME280-$i N2K iid",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "$n",
|
"default": "$n",
|
||||||
"description": "the N2K instance id for the BME280 Temperature and Humidity ",
|
"description": "the N2K instance id for the BME280 Temperature, Humidity, Pressure (PGN 130312,130313, 130314) ",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 253,
|
"max": 253,
|
||||||
@@ -482,6 +532,17 @@
|
|||||||
"BME280$i": "true"
|
"BME280$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "BME280$isEnv",
|
||||||
|
"label": "BME280$i send Env",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "also send PGN 130311",
|
||||||
|
"category": "iicsensors$b",
|
||||||
|
"capabilities": {
|
||||||
|
"BME280$i": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "BME280$iintv",
|
"name": "BME280$iintv",
|
||||||
"label": "BME280-$i Interval",
|
"label": "BME280-$i Interval",
|
||||||
@@ -683,7 +744,7 @@
|
|||||||
"label": "BMP280-$i N2K iid",
|
"label": "BMP280-$i N2K iid",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": "$n",
|
"default": "$n",
|
||||||
"description": "the N2K instance id for the BMP280 Temperature",
|
"description": "the N2K instance id for the BMP280 Temperature/Pressure (PGN 130312,130314)",
|
||||||
"category": "iicsensors$b",
|
"category": "iicsensors$b",
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 253,
|
"max": 253,
|
||||||
@@ -692,6 +753,17 @@
|
|||||||
"BMP280$i": "true"
|
"BMP280$i": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "BMP280$isEnv",
|
||||||
|
"label": "BMP280$i send Env",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "also send PGN 130311",
|
||||||
|
"category": "iicsensors$b",
|
||||||
|
"capabilities": {
|
||||||
|
"BMP280$i": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "BMP280$iintv",
|
"name": "BMP280$iintv",
|
||||||
"label": "BMP280-$i Interval",
|
"label": "BMP280-$i Interval",
|
||||||
|
|||||||
@@ -11,6 +11,17 @@ build_flags=
|
|||||||
-D M5_CAN_KIT
|
-D M5_CAN_KIT
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
|
|
||||||
|
[env:m5stack-atom-env4]
|
||||||
|
extends = sensors
|
||||||
|
board = m5stack-atom
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
${sensors.lib_deps}
|
||||||
|
build_flags=
|
||||||
|
-D M5_ENV4
|
||||||
|
-D M5_CAN_KIT
|
||||||
|
${env.build_flags}
|
||||||
|
|
||||||
|
|
||||||
[env:m5stack-atom-bme280]
|
[env:m5stack-atom-bme280]
|
||||||
extends = sensors
|
extends = sensors
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -27,6 +27,8 @@ const double nmTom = 1.852 * 1000;
|
|||||||
|
|
||||||
uint16_t DaysSince1970 = 0;
|
uint16_t DaysSince1970 = 0;
|
||||||
|
|
||||||
|
#define boolbit(b) (b?1:0)
|
||||||
|
|
||||||
class MyAisDecoder : public AIS::AisDecoder
|
class MyAisDecoder : public AIS::AisDecoder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -82,25 +84,24 @@ class MyAisDecoder : public AIS::AisDecoder
|
|||||||
|
|
||||||
tN2kMsg N2kMsg;
|
tN2kMsg N2kMsg;
|
||||||
|
|
||||||
// PGN129038
|
SetN2kPGN129038(
|
||||||
|
N2kMsg,
|
||||||
N2kMsg.SetPGN(129038L);
|
_uMsgType,
|
||||||
N2kMsg.Priority = 4;
|
(tN2kAISRepeat)_Repeat,
|
||||||
N2kMsg.AddByte((_Repeat & 0x03) << 6 | (_uMsgType & 0x3f));
|
_uMmsi,
|
||||||
N2kMsg.Add4ByteUInt(_uMmsi);
|
_iPosLon/ 600000.0,
|
||||||
N2kMsg.Add4ByteDouble(_iPosLon / 600000.0, 1e-07);
|
_iPosLat / 600000.0,
|
||||||
N2kMsg.Add4ByteDouble(_iPosLat / 600000.0, 1e-07);
|
_bPosAccuracy,
|
||||||
N2kMsg.AddByte((_timestamp & 0x3f) << 2 | (_Raim & 0x01) << 1 | (_bPosAccuracy & 0x01));
|
_Raim,
|
||||||
N2kMsg.Add2ByteUDouble(decodeCog(_iCog), 1e-04);
|
_timestamp,
|
||||||
N2kMsg.Add2ByteUDouble(_uSog * knToms/10.0, 0.01);
|
decodeCog(_iCog),
|
||||||
N2kMsg.AddByte(0x00); // Communication State (19 bits)
|
_uSog * knToms/10.0,
|
||||||
N2kMsg.AddByte(0x00);
|
tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception,
|
||||||
N2kMsg.AddByte(0x00); // AIS transceiver information (5 bits)
|
decodeHeading(_iHeading),
|
||||||
N2kMsg.Add2ByteUDouble(decodeHeading(_iHeading), 1e-04);
|
decodeRot(_iRot),
|
||||||
N2kMsg.Add2ByteDouble(decodeRot(_iRot), 3.125E-05); // 1e-3/32.0
|
(tN2kAISNavStatus)_uNavstatus,
|
||||||
N2kMsg.AddByte(0xF0 | (_uNavstatus & 0x0f));
|
0xff
|
||||||
N2kMsg.AddByte(0xff); // Reserved
|
);
|
||||||
N2kMsg.AddByte(0xff); // SID (NA)
|
|
||||||
|
|
||||||
send(N2kMsg);
|
send(N2kMsg);
|
||||||
}
|
}
|
||||||
@@ -255,9 +256,40 @@ class MyAisDecoder : public AIS::AisDecoder
|
|||||||
send(N2kMsg);
|
send(N2kMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//mmsi, aidType, name + nameExt, posAccuracy, posLon, posLat, toBow, toStern, toPort, toStarboard
|
||||||
virtual void onType21(unsigned int , unsigned int , const std::string &, bool , int , int , unsigned int , unsigned int , unsigned int , unsigned int ) override {
|
virtual void onType21(unsigned int mmsi , unsigned int aidType , const std::string & name, bool accuracy, int posLon, int posLat, unsigned int toBow,
|
||||||
|
unsigned int toStern, unsigned int toPort, unsigned int toStarboard,
|
||||||
|
unsigned int repeat,unsigned int timestamp, bool raim, bool virtualAton, bool offPosition) override {
|
||||||
//Serial.println("21");
|
//Serial.println("21");
|
||||||
|
//the name can be at most 120bit+88bit (35 byte) + termination -> 36 Byte
|
||||||
|
//in principle we should use tN2kAISAtoNReportData to directly call the library
|
||||||
|
//function for 129041. But this makes the conversion really complex.
|
||||||
|
bool assignedMode=false;
|
||||||
|
tN2kGNSStype gnssType=tN2kGNSStype::N2kGNSSt_GPS; //canboat considers 0 as undefined...
|
||||||
|
tN2kAISTransceiverInformation transceiverInfo=tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception;
|
||||||
|
tN2kMsg N2kMsg;
|
||||||
|
N2kMsg.SetPGN(129041);
|
||||||
|
N2kMsg.Priority=4;
|
||||||
|
N2kMsg.AddByte((repeat & 0x03) << 6 | (21 & 0x3f));
|
||||||
|
N2kMsg.Add4ByteUInt(mmsi); //N2kData.UserID
|
||||||
|
N2kMsg.Add4ByteDouble(posLon / 600000.0, 1e-07);
|
||||||
|
N2kMsg.Add4ByteDouble(posLat / 600000.0, 1e-07);
|
||||||
|
N2kMsg.AddByte((timestamp & 0x3f)<<2 | boolbit(raim)<<1 | boolbit(accuracy));
|
||||||
|
N2kMsg.Add2ByteUDouble(toBow+toStern, 0.1);
|
||||||
|
N2kMsg.Add2ByteUDouble(toPort+toStarboard, 0.1);
|
||||||
|
N2kMsg.Add2ByteUDouble(toStarboard, 0.1);
|
||||||
|
N2kMsg.Add2ByteUDouble(toBow, 0.1);
|
||||||
|
N2kMsg.AddByte(boolbit(assignedMode) << 7
|
||||||
|
| boolbit(virtualAton) << 6
|
||||||
|
| boolbit(offPosition) << 5
|
||||||
|
| (aidType & 0x1f));
|
||||||
|
N2kMsg.AddByte((gnssType & 0x0F) << 1 | 0xe0);
|
||||||
|
N2kMsg.AddByte(N2kUInt8NA); //status
|
||||||
|
N2kMsg.AddByte((transceiverInfo & 0x1f) | 0xe0);
|
||||||
|
//bit offset 208 (see canboat/pgns.xml) -> 26 bytes from start
|
||||||
|
//as MaxDataLen is 223 and the string can be at most 36 bytes + 2 byte heading - no further check here
|
||||||
|
N2kMsg.AddVarStr(name.c_str());
|
||||||
|
send(N2kMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi,
|
virtual void onType24A(unsigned int _uMsgType, unsigned int _repeat, unsigned int _uMmsi,
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
GwXDRFoundMapping getOtherFieldMapping(GwXDRFoundMapping &found, int field){
|
GwXDRFoundMapping getOtherFieldMapping(GwXDRFoundMapping &found, int field){
|
||||||
if (found.empty) return GwXDRFoundMapping();
|
if (found.empty) return GwXDRFoundMapping();
|
||||||
return xdrMappings->getMapping(found.definition->category,
|
return xdrMappings->getMapping(0,found.definition->category,
|
||||||
found.definition->selector,
|
found.definition->selector,
|
||||||
field,
|
field,
|
||||||
found.instanceId);
|
found.instanceId);
|
||||||
|
|||||||
@@ -708,12 +708,37 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//helper for converting the AIS transceiver info to talker/channel
|
||||||
|
|
||||||
|
void setTalkerChannel(tNMEA0183AISMsg &msg, tN2kAISTransceiverInformation &transceiver){
|
||||||
|
bool channelA=true;
|
||||||
|
bool own=false;
|
||||||
|
switch (transceiver){
|
||||||
|
case tN2kAISTransceiverInformation::N2kaischannel_A_VDL_reception:
|
||||||
|
channelA=true;
|
||||||
|
own=false;
|
||||||
|
break;
|
||||||
|
case tN2kAISTransceiverInformation::N2kaischannel_B_VDL_reception:
|
||||||
|
channelA=false;
|
||||||
|
own=false;
|
||||||
|
break;
|
||||||
|
case tN2kAISTransceiverInformation::N2kaischannel_A_VDL_transmission:
|
||||||
|
channelA=true;
|
||||||
|
own=true;
|
||||||
|
break;
|
||||||
|
case tN2kAISTransceiverInformation::N2kaischannel_B_VDL_transmission:
|
||||||
|
channelA=false;
|
||||||
|
own=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
msg.SetChannelAndTalker(channelA,own);
|
||||||
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// 129038 AIS Class A Position Report (Message 1, 2, 3)
|
// 129038 AIS Class A Position Report (Message 1, 2, 3)
|
||||||
void HandleAISClassAPosReport(const tN2kMsg &N2kMsg)
|
void HandleAISClassAPosReport(const tN2kMsg &N2kMsg)
|
||||||
{
|
{
|
||||||
|
|
||||||
unsigned char SID;
|
|
||||||
tN2kAISRepeat _Repeat;
|
tN2kAISRepeat _Repeat;
|
||||||
uint32_t _UserID; // MMSI
|
uint32_t _UserID; // MMSI
|
||||||
double _Latitude =N2kDoubleNA;
|
double _Latitude =N2kDoubleNA;
|
||||||
@@ -732,64 +757,19 @@ private:
|
|||||||
uint8_t _MessageType = 1;
|
uint8_t _MessageType = 1;
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
|
||||||
if (ParseN2kPGN129038(N2kMsg, SID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
if (ParseN2kPGN129038(N2kMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM, _Seconds,
|
||||||
_COG, _SOG, _Heading, _ROT, _NavStatus,_AISTransceiverInformation,_SID))
|
_COG, _SOG, _Heading, _ROT, _NavStatus,_AISTransceiverInformation,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
// Debug
|
|
||||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
|
||||||
Serial.println("–––––––––––––––––––––––– Msg 1 ––––––––––––––––––––––––––––––––");
|
|
||||||
|
|
||||||
const double pi = 3.1415926535897932384626433832795;
|
|
||||||
const double radToDeg = 180.0 / pi;
|
|
||||||
const double msTokn = 3600.0 / 1852.0;
|
|
||||||
const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute]
|
|
||||||
Serial.print("Repeat: ");
|
|
||||||
Serial.println(_Repeat);
|
|
||||||
Serial.print("UserID: ");
|
|
||||||
Serial.println(_UserID);
|
|
||||||
Serial.print("Latitude: ");
|
|
||||||
Serial.println(_Latitude);
|
|
||||||
Serial.print("Longitude: ");
|
|
||||||
Serial.println(_Longitude);
|
|
||||||
Serial.print("Accuracy: ");
|
|
||||||
Serial.println(_Accuracy);
|
|
||||||
Serial.print("RAIM: ");
|
|
||||||
Serial.println(_RAIM);
|
|
||||||
Serial.print("Seconds: ");
|
|
||||||
Serial.println(_Seconds);
|
|
||||||
Serial.print("COG: ");
|
|
||||||
Serial.println(_COG * radToDeg);
|
|
||||||
Serial.print("SOG: ");
|
|
||||||
Serial.println(_SOG * msTokn);
|
|
||||||
Serial.print("Heading: ");
|
|
||||||
Serial.println(_Heading * radToDeg);
|
|
||||||
Serial.print("ROT: ");
|
|
||||||
Serial.println(_ROT * radsToDegMin);
|
|
||||||
Serial.print("NavStatus: ");
|
|
||||||
Serial.println(_NavStatus);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
setTalkerChannel(NMEA0183AISMsg,_AISTransceiverInformation);
|
||||||
|
if (_MessageType < 1 || _MessageType > 3) _MessageType=1; //only allow type 1...3 for 129038
|
||||||
if (SetAISClassABMessage1(NMEA0183AISMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy,
|
if (SetAISClassABMessage1(NMEA0183AISMsg, _MessageType, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy,
|
||||||
_RAIM, _Seconds, _COG, _SOG, _Heading, _ROT, _NavStatus))
|
_RAIM, _Seconds, _COG, _SOG, _Heading, _ROT, _NavStatus))
|
||||||
{
|
{
|
||||||
|
|
||||||
SendMessage(NMEA0183AISMsg);
|
SendMessage(NMEA0183AISMsg);
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
// Debug Print AIS-NMEA
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
|
||||||
char buf[7];
|
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
|
||||||
Serial.print(buf);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end 129038 AIS Class A Position Report Message 1/3
|
} // end 129038 AIS Class A Position Report Message 1/3
|
||||||
@@ -825,84 +805,18 @@ private:
|
|||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,21,
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,21,
|
||||||
_AISversion, _GNSStype, _DTE, _AISinfo,_SID))
|
_AISversion, _GNSStype, _DTE, _AISinfo,_SID))
|
||||||
{
|
{
|
||||||
|
setTalkerChannel(NMEA0183AISMsg,_AISinfo);
|
||||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
|
||||||
// Debug Print N2k Values
|
|
||||||
Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––");
|
|
||||||
Serial.print("MessageID: ");
|
|
||||||
Serial.println(_MessageID);
|
|
||||||
Serial.print("Repeat: ");
|
|
||||||
Serial.println(_Repeat);
|
|
||||||
Serial.print("UserID: ");
|
|
||||||
Serial.println(_UserID);
|
|
||||||
Serial.print("IMONumber: ");
|
|
||||||
Serial.println(_IMONumber);
|
|
||||||
Serial.print("Callsign: ");
|
|
||||||
Serial.println(_Callsign);
|
|
||||||
Serial.print("VesselType: ");
|
|
||||||
Serial.println(_VesselType);
|
|
||||||
Serial.print("Name: ");
|
|
||||||
Serial.println(_Name);
|
|
||||||
Serial.print("Length: ");
|
|
||||||
Serial.println(_Length);
|
|
||||||
Serial.print("Beam: ");
|
|
||||||
Serial.println(_Beam);
|
|
||||||
Serial.print("PosRefStbd: ");
|
|
||||||
Serial.println(_PosRefStbd);
|
|
||||||
Serial.print("PosRefBow: ");
|
|
||||||
Serial.println(_PosRefBow);
|
|
||||||
Serial.print("ETAdate: ");
|
|
||||||
Serial.println(_ETAdate);
|
|
||||||
Serial.print("ETAtime: ");
|
|
||||||
Serial.println(_ETAtime);
|
|
||||||
Serial.print("Draught: ");
|
|
||||||
Serial.println(_Draught);
|
|
||||||
Serial.print("Destination: ");
|
|
||||||
Serial.println(_Destination);
|
|
||||||
Serial.print("GNSStype: ");
|
|
||||||
Serial.println(_GNSStype);
|
|
||||||
Serial.print("DTE: ");
|
|
||||||
Serial.println(_DTE);
|
|
||||||
Serial.println("––––––––––––––––––––––– Msg 5 –––––––––––––––––––––––––––––––––");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (SetAISClassAMessage5(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType,
|
if (SetAISClassAMessage5(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _IMONumber, _Callsign, _Name, _VesselType,
|
||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _ETAdate, _ETAtime, _Draught, _Destination,
|
||||||
_GNSStype, _DTE))
|
_GNSStype, _DTE,_AISversion))
|
||||||
{
|
{
|
||||||
|
if (NMEA0183AISMsg.BuildMsg5Part1()){
|
||||||
SendMessage(NMEA0183AISMsg.BuildMsg5Part1(NMEA0183AISMsg));
|
SendMessage(NMEA0183AISMsg);
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
// Debug Print AIS-NMEA Message Type 5, Part 1
|
|
||||||
char buf[7];
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
}
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
if (NMEA0183AISMsg.BuildMsg5Part2()){
|
||||||
Serial.print(buf);
|
SendMessage(NMEA0183AISMsg);
|
||||||
#endif
|
|
||||||
|
|
||||||
SendMessage(NMEA0183AISMsg.BuildMsg5Part2(NMEA0183AISMsg));
|
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
// Print AIS-NMEA Message Type 5, Part 2
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
}
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
|
||||||
Serial.print(buf);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -926,35 +840,21 @@ private:
|
|||||||
tN2kAISUnit _Unit;
|
tN2kAISUnit _Unit;
|
||||||
bool _Display, _DSC, _Band, _Msg22, _State;
|
bool _Display, _DSC, _Band, _Msg22, _State;
|
||||||
tN2kAISMode _Mode;
|
tN2kAISMode _Mode;
|
||||||
tN2kAISTransceiverInformation _AISTranceiverInformation;
|
tN2kAISTransceiverInformation _AISTransceiverInformation;
|
||||||
uint8_t _SID;
|
uint8_t _SID;
|
||||||
|
|
||||||
if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
if (ParseN2kPGN129039(N2kMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
||||||
_Seconds, _COG, _SOG, _AISTranceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State,_SID))
|
_Seconds, _COG, _SOG, _AISTransceiverInformation, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
setTalkerChannel(NMEA0183AISMsg,_AISTransceiverInformation);
|
||||||
if (SetAISClassBMessage18(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
if (SetAISClassBMessage18(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Latitude, _Longitude, _Accuracy, _RAIM,
|
||||||
_Seconds, _COG, _SOG, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State))
|
_Seconds, _COG, _SOG, _Heading, _Unit, _Display, _DSC, _Band, _Msg22, _Mode, _State))
|
||||||
{
|
{
|
||||||
|
|
||||||
SendMessage(NMEA0183AISMsg);
|
SendMessage(NMEA0183AISMsg);
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
// Debug Print AIS-NMEA
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
|
||||||
char buf[7];
|
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
|
||||||
Serial.print(buf);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -976,8 +876,10 @@ private:
|
|||||||
{
|
{
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
setTalkerChannel(NMEA0183AISMsg,_AISInfo);
|
||||||
if (SetAISClassBMessage24PartA(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Name))
|
if (SetAISClassBMessage24PartA(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _Name))
|
||||||
{
|
{
|
||||||
|
SendMessage(NMEA0183AISMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -1005,77 +907,51 @@ private:
|
|||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID,_AISInfo,_SID))
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID,_AISInfo,_SID))
|
||||||
{
|
{
|
||||||
|
|
||||||
//
|
|
||||||
#ifdef SERIAL_PRINT_AIS_FIELDS
|
|
||||||
// Debug Print N2k Values
|
|
||||||
Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––");
|
|
||||||
Serial.print("MessageID: ");
|
|
||||||
Serial.println(_MessageID);
|
|
||||||
Serial.print("Repeat: ");
|
|
||||||
Serial.println(_Repeat);
|
|
||||||
Serial.print("UserID: ");
|
|
||||||
Serial.println(_UserID);
|
|
||||||
Serial.print("VesselType: ");
|
|
||||||
Serial.println(_VesselType);
|
|
||||||
Serial.print("Vendor: ");
|
|
||||||
Serial.println(_Vendor);
|
|
||||||
Serial.print("Callsign: ");
|
|
||||||
Serial.println(_Callsign);
|
|
||||||
Serial.print("Length: ");
|
|
||||||
Serial.println(_Length);
|
|
||||||
Serial.print("Beam: ");
|
|
||||||
Serial.println(_Beam);
|
|
||||||
Serial.print("PosRefStbd: ");
|
|
||||||
Serial.println(_PosRefStbd);
|
|
||||||
Serial.print("PosRefBow: ");
|
|
||||||
Serial.println(_PosRefBow);
|
|
||||||
Serial.print("MothershipID: ");
|
|
||||||
Serial.println(_MothershipID);
|
|
||||||
Serial.println("––––––––––––––––––––––– Msg 24 ––––––––––––––––––––––––––––––––");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tNMEA0183AISMsg NMEA0183AISMsg;
|
tNMEA0183AISMsg NMEA0183AISMsg;
|
||||||
|
setTalkerChannel(NMEA0183AISMsg,_AISInfo);
|
||||||
if (SetAISClassBMessage24(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign,
|
if (SetAISClassBMessage24PartB(NMEA0183AISMsg, _MessageID, _Repeat, _UserID, _VesselType, _Vendor, _Callsign,
|
||||||
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID))
|
_Length, _Beam, _PosRefStbd, _PosRefBow, _MothershipID))
|
||||||
{
|
{
|
||||||
|
SendMessage(NMEA0183AISMsg);
|
||||||
SendMessage(NMEA0183AISMsg.BuildMsg24PartA(NMEA0183AISMsg));
|
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
// Debug Print AIS-NMEA
|
|
||||||
char buf[7];
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
|
||||||
Serial.print(buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SendMessage(NMEA0183AISMsg.BuildMsg24PartB(NMEA0183AISMsg));
|
|
||||||
|
|
||||||
#ifdef SERIAL_PRINT_AIS_NMEA
|
|
||||||
Serial.print(NMEA0183AISMsg.GetPrefix());
|
|
||||||
Serial.print(NMEA0183AISMsg.Sender());
|
|
||||||
Serial.print(NMEA0183AISMsg.MessageCode());
|
|
||||||
for (int i = 0; i < NMEA0183AISMsg.FieldCount(); i++)
|
|
||||||
{
|
|
||||||
Serial.print(",");
|
|
||||||
Serial.print(NMEA0183AISMsg.Field(i));
|
|
||||||
}
|
|
||||||
sprintf(buf, "*%02X\r\n", NMEA0183AISMsg.GetCheckSum());
|
|
||||||
Serial.print(buf);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// PGN 129041 Aton
|
||||||
|
void HandleAISMessage21(const tN2kMsg &N2kMsg)
|
||||||
|
{
|
||||||
|
tN2kAISAtoNReportData data;
|
||||||
|
if (ParseN2kPGN129041(N2kMsg,data)){
|
||||||
|
tNMEA0183AISMsg nmea0183Msg;
|
||||||
|
setTalkerChannel(nmea0183Msg,data.AISTransceiverInformation);
|
||||||
|
if (SetAISMessage21(
|
||||||
|
nmea0183Msg,
|
||||||
|
data.Repeat,
|
||||||
|
data.UserID,
|
||||||
|
data.Latitude,
|
||||||
|
data.Longitude,
|
||||||
|
data.Accuracy,
|
||||||
|
data.RAIM,
|
||||||
|
data.Seconds,
|
||||||
|
data.Length,
|
||||||
|
data.Beam,
|
||||||
|
data.PositionReferenceStarboard,
|
||||||
|
data.PositionReferenceTrueNorth,
|
||||||
|
data.AtoNType,
|
||||||
|
data.OffPositionIndicator,
|
||||||
|
data.VirtualAtoNFlag,
|
||||||
|
data.AssignedModeFlag,
|
||||||
|
data.GNSSType,
|
||||||
|
data.AtoNStatus,
|
||||||
|
data.AtoNName
|
||||||
|
)){
|
||||||
|
SendMessage(nmea0183Msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HandleSystemTime(const tN2kMsg &msg){
|
void HandleSystemTime(const tN2kMsg &msg){
|
||||||
unsigned char sid=-1;
|
unsigned char sid=-1;
|
||||||
uint16_t DaysSince1970=N2kUInt16NA;
|
uint16_t DaysSince1970=N2kUInt16NA;
|
||||||
@@ -1271,12 +1147,12 @@ private:
|
|||||||
double Level=N2kDoubleNA;
|
double Level=N2kDoubleNA;
|
||||||
double Capacity=N2kDoubleNA;
|
double Capacity=N2kDoubleNA;
|
||||||
if (ParseN2kPGN127505(N2kMsg,Instance,FluidType,Level,Capacity)) {
|
if (ParseN2kPGN127505(N2kMsg,Instance,FluidType,Level,Capacity)) {
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRFLUID,FluidType,0,Instance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(Level,XDRFLUID,FluidType,0,Instance);
|
||||||
if (updateDouble(&mapping,Level)){
|
if (updateDouble(&mapping,Level)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found fluidlevel mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found fluidlevel mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Level));
|
addToXdr(mapping.buildXdrEntry(Level));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRFLUID,FluidType,1,Instance);
|
mapping=xdrMappings->getMapping(Capacity, XDRFLUID,FluidType,1,Instance);
|
||||||
if (updateDouble(&mapping,Capacity)){
|
if (updateDouble(&mapping,Capacity)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found fluid capacity mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found fluid capacity mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Capacity));
|
addToXdr(mapping.buildXdrEntry(Capacity));
|
||||||
@@ -1294,19 +1170,19 @@ private:
|
|||||||
double BatteryTemperature=N2kDoubleNA;
|
double BatteryTemperature=N2kDoubleNA;
|
||||||
if (ParseN2kPGN127508(N2kMsg,BatteryInstance,BatteryVoltage,BatteryCurrent,BatteryTemperature,SID)) {
|
if (ParseN2kPGN127508(N2kMsg,BatteryInstance,BatteryVoltage,BatteryCurrent,BatteryTemperature,SID)) {
|
||||||
int i=0;
|
int i=0;
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRBAT,0,0,BatteryInstance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(BatteryVoltage, XDRBAT,0,0,BatteryInstance);
|
||||||
if (updateDouble(&mapping,BatteryVoltage)){
|
if (updateDouble(&mapping,BatteryVoltage)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryVoltage mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryVoltage mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(BatteryVoltage));
|
addToXdr(mapping.buildXdrEntry(BatteryVoltage));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRBAT,0,1,BatteryInstance);
|
mapping=xdrMappings->getMapping(BatteryCurrent,XDRBAT,0,1,BatteryInstance);
|
||||||
if (updateDouble(&mapping,BatteryCurrent)){
|
if (updateDouble(&mapping,BatteryCurrent)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryCurrent mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryCurrent mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(BatteryCurrent));
|
addToXdr(mapping.buildXdrEntry(BatteryCurrent));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRBAT,0,2,BatteryInstance);
|
mapping=xdrMappings->getMapping(BatteryTemperature,XDRBAT,0,2,BatteryInstance);
|
||||||
if (updateDouble(&mapping,BatteryTemperature)){
|
if (updateDouble(&mapping,BatteryTemperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryTemperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found BatteryTemperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(BatteryTemperature));
|
addToXdr(mapping.buildXdrEntry(BatteryTemperature));
|
||||||
@@ -1338,13 +1214,13 @@ private:
|
|||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,N2kts_OutsideTemperature,0,0);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(OutsideAmbientAirTemperature, XDRTEMP,N2kts_OutsideTemperature,0,0);
|
||||||
if (updateDouble(&mapping,OutsideAmbientAirTemperature)){
|
if (updateDouble(&mapping,OutsideAmbientAirTemperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(OutsideAmbientAirTemperature));
|
addToXdr(mapping.buildXdrEntry(OutsideAmbientAirTemperature));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRPRESSURE,N2kps_Atmospheric,0,0);
|
mapping=xdrMappings->getMapping(AtmosphericPressure,XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||||
if (updateDouble(&mapping,AtmosphericPressure)){
|
if (updateDouble(&mapping,AtmosphericPressure)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
||||||
@@ -1379,19 +1255,19 @@ private:
|
|||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,TempSource,0,0);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,TempSource,0,0);
|
||||||
if (updateDouble(&mapping,Temperature)){
|
if (updateDouble(&mapping,Temperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRHUMIDITY,HumiditySource,0,0);
|
mapping=xdrMappings->getMapping(Humidity, XDRHUMIDITY,HumiditySource,0,0);
|
||||||
if (updateDouble(&mapping,Humidity)){
|
if (updateDouble(&mapping,Humidity)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Humidity));
|
addToXdr(mapping.buildXdrEntry(Humidity));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRPRESSURE,N2kps_Atmospheric,0,0);
|
mapping=xdrMappings->getMapping(AtmosphericPressure, XDRPRESSURE,N2kps_Atmospheric,0,0);
|
||||||
if (updateDouble(&mapping,AtmosphericPressure)){
|
if (updateDouble(&mapping,AtmosphericPressure)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
addToXdr(mapping.buildXdrEntry(AtmosphericPressure));
|
||||||
@@ -1426,12 +1302,12 @@ private:
|
|||||||
SendMessage(NMEA0183Msg);
|
SendMessage(NMEA0183Msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||||
if (updateDouble(&mapping,Temperature)){
|
if (updateDouble(&mapping,Temperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
mapping=xdrMappings->getMapping(setTemperature, XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||||
if (updateDouble(&mapping,setTemperature)){
|
if (updateDouble(&mapping,setTemperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(setTemperature));
|
addToXdr(mapping.buildXdrEntry(setTemperature));
|
||||||
@@ -1449,12 +1325,13 @@ private:
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRHUMIDITY,(int)HumiditySource,0,HumidityInstance);
|
GwXDRFoundMapping mapping;
|
||||||
|
mapping=xdrMappings->getMapping(ActualHumidity, XDRHUMIDITY,(int)HumiditySource,0,HumidityInstance);
|
||||||
if (updateDouble(&mapping,ActualHumidity)){
|
if (updateDouble(&mapping,ActualHumidity)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(ActualHumidity));
|
addToXdr(mapping.buildXdrEntry(ActualHumidity));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRHUMIDITY,(int)HumiditySource,1,HumidityInstance);
|
mapping=xdrMappings->getMapping(SetHumidity, XDRHUMIDITY,(int)HumiditySource,1,HumidityInstance);
|
||||||
if (updateDouble(&mapping,SetHumidity)){
|
if (updateDouble(&mapping,SetHumidity)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found humidity mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(SetHumidity));
|
addToXdr(mapping.buildXdrEntry(SetHumidity));
|
||||||
@@ -1472,7 +1349,7 @@ private:
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRPRESSURE,(int)PressureSource,0,PressureInstance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(ActualPressure, XDRPRESSURE,(int)PressureSource,0,PressureInstance);
|
||||||
if (! updateDouble(&mapping,ActualPressure)) return;
|
if (! updateDouble(&mapping,ActualPressure)) return;
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found pressure mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(ActualPressure));
|
addToXdr(mapping.buildXdrEntry(ActualPressure));
|
||||||
@@ -1490,12 +1367,12 @@ private:
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
}
|
}
|
||||||
for (int i=0;i<8;i++){
|
for (int i=0;i<8;i++){
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,i,instance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(values[i], XDRENGINE,0,i,instance);
|
||||||
if (! updateDouble(&mapping,values[i])) continue;
|
if (! updateDouble(&mapping,values[i])) continue;
|
||||||
addToXdr(mapping.buildXdrEntry(values[i]));
|
addToXdr(mapping.buildXdrEntry(values[i]));
|
||||||
}
|
}
|
||||||
for (int i=0;i< 2;i++){
|
for (int i=0;i< 2;i++){
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,i+8,instance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(ivalues[i],XDRENGINE,0,i+8,instance);
|
||||||
if (! updateDouble(&mapping,ivalues[i])) continue;
|
if (! updateDouble(&mapping,ivalues[i])) continue;
|
||||||
addToXdr(mapping.buildXdrEntry((double)ivalues[i]));
|
addToXdr(mapping.buildXdrEntry((double)ivalues[i]));
|
||||||
}
|
}
|
||||||
@@ -1511,7 +1388,7 @@ private:
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
}
|
}
|
||||||
for (int i=0;i<3;i++){
|
for (int i=0;i<3;i++){
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRATTITUDE,0,i,instance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(values[i], XDRATTITUDE,0,i,instance);
|
||||||
if (! updateDouble(&mapping,values[i])) continue;
|
if (! updateDouble(&mapping,values[i])) continue;
|
||||||
addToXdr(mapping.buildXdrEntry(values[i]));
|
addToXdr(mapping.buildXdrEntry(values[i]));
|
||||||
}
|
}
|
||||||
@@ -1525,15 +1402,15 @@ private:
|
|||||||
speed,pressure,tilt)){
|
speed,pressure,tilt)){
|
||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRENGINE,0,10,instance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(speed, XDRENGINE,0,10,instance);
|
||||||
if (updateDouble(&mapping,speed)){
|
if (updateDouble(&mapping,speed)){
|
||||||
addToXdr(mapping.buildXdrEntry(speed));
|
addToXdr(mapping.buildXdrEntry(speed));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRENGINE,0,11,instance);
|
mapping=xdrMappings->getMapping(pressure, XDRENGINE,0,11,instance);
|
||||||
if (updateDouble(&mapping,pressure)){
|
if (updateDouble(&mapping,pressure)){
|
||||||
addToXdr(mapping.buildXdrEntry(pressure));
|
addToXdr(mapping.buildXdrEntry(pressure));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRENGINE,0,12,instance);
|
mapping=xdrMappings->getMapping(tilt, XDRENGINE,0,12,instance);
|
||||||
if (updateDouble(&mapping,tilt)){
|
if (updateDouble(&mapping,tilt)){
|
||||||
addToXdr(mapping.buildXdrEntry((double)tilt));
|
addToXdr(mapping.buildXdrEntry((double)tilt));
|
||||||
}
|
}
|
||||||
@@ -1559,12 +1436,12 @@ private:
|
|||||||
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
LOG_DEBUG(GwLog::DEBUG,"unable to parse PGN %d",msg.PGN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
GwXDRFoundMapping mapping=xdrMappings->getMapping(Temperature, XDRTEMP,(int)TemperatureSource,0,TemperatureInstance);
|
||||||
if (updateDouble(&mapping,Temperature)){
|
if (updateDouble(&mapping,Temperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(Temperature));
|
addToXdr(mapping.buildXdrEntry(Temperature));
|
||||||
}
|
}
|
||||||
mapping=xdrMappings->getMapping(XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
mapping=xdrMappings->getMapping(setTemperature, XDRTEMP,(int)TemperatureSource,1,TemperatureInstance);
|
||||||
if (updateDouble(&mapping,setTemperature)){
|
if (updateDouble(&mapping,setTemperature)){
|
||||||
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
LOG_DEBUG(GwLog::DEBUG+1,"found temperature mapping %s",mapping.definition->toString().c_str());
|
||||||
addToXdr(mapping.buildXdrEntry(setTemperature));
|
addToXdr(mapping.buildXdrEntry(setTemperature));
|
||||||
@@ -1614,6 +1491,7 @@ private:
|
|||||||
converters.registerConverter(129794UL, &N2kToNMEA0183Functions::HandleAISClassAMessage5); // AIS Class A Ship Static and Voyage related data, Message Type 5
|
converters.registerConverter(129794UL, &N2kToNMEA0183Functions::HandleAISClassAMessage5); // AIS Class A Ship Static and Voyage related data, Message Type 5
|
||||||
converters.registerConverter(129809UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24A); // AIS Class B "CS" Static Data Report, Part A
|
converters.registerConverter(129809UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24A); // AIS Class B "CS" Static Data Report, Part A
|
||||||
converters.registerConverter(129810UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24B); // AIS Class B "CS" Static Data Report, Part B
|
converters.registerConverter(129810UL, &N2kToNMEA0183Functions::HandleAISClassBMessage24B); // AIS Class B "CS" Static Data Report, Part B
|
||||||
|
converters.registerConverter(129041UL, &N2kToNMEA0183Functions::HandleAISMessage21); // AIS Aton
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <NMEA0183AISMessages.h>
|
#include "NMEA0183AISMessages.h"
|
||||||
#include <N2kTypes.h>
|
#include <N2kTypes.h>
|
||||||
#include <N2kMsg.h>
|
#include <N2kMsg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -34,7 +34,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
//#include <unordered_map>
|
//#include <unordered_map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <NMEA0183AISMsg.h>
|
#include "NMEA0183AISMsg.h"
|
||||||
|
|
||||||
const double pi=3.1415926535897932384626433832795;
|
const double pi=3.1415926535897932384626433832795;
|
||||||
const double kmhToms=1000.0/3600.0;
|
const double kmhToms=1000.0/3600.0;
|
||||||
@@ -47,17 +47,15 @@ const double nmTom=1.852*1000;
|
|||||||
const double mToFathoms=0.546806649;
|
const double mToFathoms=0.546806649;
|
||||||
const double mToFeet=3.2808398950131;
|
const double mToFeet=3.2808398950131;
|
||||||
const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute]
|
const double radsToDegMin = 60 * 360.0 / (2 * pi); // [rad/s -> degree/minute]
|
||||||
const char Prefix='!';
|
|
||||||
|
|
||||||
std::vector<ship *> vships;
|
|
||||||
|
|
||||||
int numShips(){return vships.size();}
|
|
||||||
// ************************ Helper for AIS ***********************************
|
// ************************ Helper for AIS ***********************************
|
||||||
static bool AddMessageType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType);
|
static bool AddMessageType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType);
|
||||||
static bool AddRepeat(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat);
|
static bool AddRepeat(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat);
|
||||||
static bool AddUserID(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t UserID);
|
static bool AddUserID(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t UserID);
|
||||||
static bool AddIMONumber(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t &IMONumber);
|
static bool AddIMONumber(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t &IMONumber);
|
||||||
static bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length);
|
static bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length);
|
||||||
|
//static bool AddVesselType(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t VesselType);
|
||||||
static bool AddDimensions(tNMEA0183AISMsg &NMEA0183AISMsg, double Length, double Beam, double PosRefStbd, double PosRefBow);
|
static bool AddDimensions(tNMEA0183AISMsg &NMEA0183AISMsg, double Length, double Beam, double PosRefStbd, double PosRefBow);
|
||||||
static bool AddNavStatus(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t &NavStatus);
|
static bool AddNavStatus(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t &NavStatus);
|
||||||
static bool AddROT(tNMEA0183AISMsg &NMEA0183AISMsg, double &rot);
|
static bool AddROT(tNMEA0183AISMsg &NMEA0183AISMsg, double &rot);
|
||||||
@@ -91,7 +89,7 @@ bool SetAISClassABMessage1( tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType
|
|||||||
if ( !AddNavStatus(NMEA0183AISMsg, NavStatus) ) return false; // 38-41 | 4 Navigational Status e.g.: "Under way sailing"
|
if ( !AddNavStatus(NMEA0183AISMsg, NavStatus) ) return false; // 38-41 | 4 Navigational Status e.g.: "Under way sailing"
|
||||||
if ( !AddROT(NMEA0183AISMsg, ROT) ) return false; // 42-49 | 8 Rate of Turn (ROT)
|
if ( !AddROT(NMEA0183AISMsg, ROT) ) return false; // 42-49 | 8 Rate of Turn (ROT)
|
||||||
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 50-59 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 50-59 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy, 1) ) return false;// 60 | 1 GPS Accuracy 1 oder 0, Default 0
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy) ) return false;// 60 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||||
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 61-88 | 28 Longitude in Minutes / 10000
|
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 61-88 | 28 Longitude in Minutes / 10000
|
||||||
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 89-115 | 27 Latitude in Minutes / 10000
|
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 89-115 | 27 Latitude in Minutes / 10000
|
||||||
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 116-127 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 116-127 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
||||||
@@ -99,17 +97,12 @@ bool SetAISClassABMessage1( tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType
|
|||||||
if ( !AddSeconds(NMEA0183AISMsg, Seconds) ) return false; // 137-142 | 6 Seconds in UTC timestamp)
|
if ( !AddSeconds(NMEA0183AISMsg, Seconds) ) return false; // 137-142 | 6 Seconds in UTC timestamp)
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 143-144 | 2 Maneuver Indicator: 0 (default) 1, 2 (not delivered within this PGN)
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 143-144 | 2 Maneuver Indicator: 0 (default) 1, 2 (not delivered within this PGN)
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 3) ) return false; // 145-147 | 3 Spare
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 3) ) return false; // 145-147 | 3 Spare
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM, 1) ) return false; // 148-148 | 1 RAIM flag 0 = RAIM not in use (default), 1 = RAIM in use
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM) ) return false; // 148-148 | 1 RAIM flag 0 = RAIM not in use (default), 1 = RAIM in use
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 19) ) return false; // 149-167 | 19 Radio Status (-> 0 NOT SENT WITH THIS PGN!!!!!)
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 19) ) return false; // 149-167 | 19 Radio Status (-> 0 NOT SENT WITH THIS PGN!!!!!)
|
||||||
|
if ( !NMEA0183AISMsg.InitAis()) return false;
|
||||||
if ( !NMEA0183AISMsg.Init("VDM","AI", Prefix) ) return false;
|
int padBits=0;
|
||||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||||
if ( !NMEA0183AISMsg.AddEmptyField() ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField("A") ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload() ) ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField("0") ) return false; // Message 1,2,3 has always Zero Padding
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,14 +114,16 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
|||||||
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
||||||
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
||||||
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
||||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE ) {
|
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE,
|
||||||
|
tN2kAISVersion AISversion) {
|
||||||
|
|
||||||
// AIS Type 5 Message
|
// AIS Type 5 Message
|
||||||
NMEA0183AISMsg.ClearAIS();
|
NMEA0183AISMsg.ClearAIS();
|
||||||
if ( !AddMessageType(NMEA0183AISMsg, 5) ) return false; // 0 - 5 | 6 Message Type -> Constant: 5
|
if ( !AddMessageType(NMEA0183AISMsg, 5) ) return false; // 0 - 5 | 6 Message Type -> Constant: 5
|
||||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(1, 2) ) return false; // 38 - 39 | 2 AIS Version -> 0 oder 1 NOT DERIVED FROM N2k, Always 1!!!!
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin((uint32_t)AISversion, 2) )
|
||||||
|
return false; // 38 - 39 | 2 AIS Version -> 0 oder 1 NOT DERIVED FROM N2k, Always 1!!!!
|
||||||
if ( !AddIMONumber(NMEA0183AISMsg, IMONumber) ) return false; // 40 - 69 | 30 IMO Number unisgned
|
if ( !AddIMONumber(NMEA0183AISMsg, IMONumber) ) return false; // 40 - 69 | 30 IMO Number unisgned
|
||||||
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 70 - 111 | 42 Call Sign WDE4178 -> 7 6-bit characters -> Ascii lt. Table)
|
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 70 - 111 | 42 Call Sign WDE4178 -> 7 6-bit characters -> Ascii lt. Table)
|
||||||
if ( !AddText(NMEA0183AISMsg, Name, 120) ) return false; // 112-231 | 120 Vessel Name POINT FERMIN -> 20 6-bit characters -> Ascii lt. Table
|
if ( !AddText(NMEA0183AISMsg, Name, 120) ) return false; // 112-231 | 120 Vessel Name POINT FERMIN -> 20 6-bit characters -> Ascii lt. Table
|
||||||
@@ -146,10 +141,12 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
|||||||
|
|
||||||
// ****************************************************************************
|
// ****************************************************************************
|
||||||
// AIS position report (class B 129039) -> Type 18: Standard Class B CS Position Report
|
// AIS position report (class B 129039) -> Type 18: Standard Class B CS Position Report
|
||||||
// ParseN2kPGN129039(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
|
// PGN129039
|
||||||
|
// ParseN2kAISClassBPosition(const tN2kMsg &N2kMsg, uint8_t &MessageID, tN2kAISRepeat &Repeat, uint32_t &UserID,
|
||||||
// double &Latitude, double &Longitude, bool &Accuracy, bool &RAIM,
|
// double &Latitude, double &Longitude, bool &Accuracy, bool &RAIM,
|
||||||
// uint8_t &Seconds, double &COG, double &SOG, double &Heading, tN2kAISUnit &Unit,
|
// uint8_t &Seconds, double &COG, double &SOG, tN2kAISTransceiverInformation &AISTransceiverInformation,
|
||||||
// bool &Display, bool &DSC, bool &Band, bool &Msg22, tN2kAISMode &Mode, bool &State)
|
// double &Heading, tN2kAISUnit &Unit, bool &Display, bool &DSC, bool &Band, bool &Msg22, tN2kAISMode &Mode,
|
||||||
|
// bool &State)
|
||||||
// VDM, VDO (AIS VHF Data-link message 18)
|
// VDM, VDO (AIS VHF Data-link message 18)
|
||||||
bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID,
|
bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID,
|
||||||
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||||
@@ -162,7 +159,7 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
|||||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 38-45 | 8 Regional Reserved
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 38-45 | 8 Regional Reserved
|
||||||
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 46-55 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
if ( !AddSOG(NMEA0183AISMsg, SOG) ) return false; // 46-55 | 10 [m/s -> kts] SOG with one digit x10, 1023 = N/A
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy, 1)) return false; // 56 | 1 GPS Accuracy 1 oder 0, Default 0
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy)) return false; // 56 | 1 GPS Accuracy 1 oder 0, Default 0
|
||||||
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 57-84 | 28 Longitude in Minutes / 10000
|
if ( !AddLongitude(NMEA0183AISMsg, Longitude) ) return false; // 57-84 | 28 Longitude in Minutes / 10000
|
||||||
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 85-111 | 27 Latitude in Minutes / 10000
|
if ( !AddLatitude(NMEA0183AISMsg, Latitude) ) return false; // 85-111 | 27 Latitude in Minutes / 10000
|
||||||
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 112-123 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
if ( !AddCOG(NMEA0183AISMsg, COG) ) return false; // 112-123 | 12 Course over ground will be 3600 (0xE10) if that data is not available.
|
||||||
@@ -171,20 +168,16 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
|||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 139-140 | 2 Regional Reserved
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 139-140 | 2 Regional Reserved
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Unit, 1) ) return false; // 141 | 1 0=Class B SOTDMA unit 1=Class B CS (Carrier Sense) unit
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Unit, 1) ) return false; // 141 | 1 0=Class B SOTDMA unit 1=Class B CS (Carrier Sense) unit
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Display, 1) ) return false; // 142 | 1 0=No visual display, 1=Has display, (Probably not reliable).
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(Display, 1) ) return false; // 142 | 1 0=No visual display, 1=Has display, (Probably not reliable).
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(DSC, 1) ) return false; // 143 | 1 If 1, unit is attached to a VHF voice radio with DSC capability.
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(DSC) ) return false; // 143 | 1 If 1, unit is attached to a VHF voice radio with DSC capability.
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Band, 1) ) return false; // 144 | 1 If this flag is 1, the unit can use any part of the marine channel.
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Band) ) return false; // 144 | 1 If this flag is 1, the unit can use any part of the marine channel.
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Msg22, 1) ) return false; // 145 | 1 If 1, unit can accept a channel assignment via Message Type 22.
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Msg22)) return false; // 145 | 1 If 1, unit can accept a channel assignment via Message Type 22.
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Mode, 1) ) return false; // 146 | 1 Assigned-mode flag: 0 = autonomous mode (default), 1 = assigned mode
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Mode) ) return false; // 146 | 1 Assigned-mode flag: 0 = autonomous mode (default), 1 = assigned mode
|
||||||
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM, 1) ) return false; // 147 | 1 as for Message Type 1,2,3
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM) ) return false; // 147 | 1 as for Message Type 1,2,3
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 20) ) return false; // 148-167 | 20 Radio Status not in PGN 129039
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 20) ) return false; // 148-167 | 20 Radio Status not in PGN 129039
|
||||||
|
if ( !NMEA0183AISMsg.InitAis()) return false;
|
||||||
if ( !NMEA0183AISMsg.Init("VDM","AI", Prefix) ) return false;
|
int padBits=0;
|
||||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||||
if ( !NMEA0183AISMsg.AddStrField("1") ) return false;
|
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||||
if ( !NMEA0183AISMsg.AddEmptyField() ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField("B") ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload() ) ) return false;
|
|
||||||
if ( !NMEA0183AISMsg.AddStrField("0") ) return false; // Message 18, has always Zero Padding
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -217,41 +210,28 @@ bool SetAISClassBMessage18(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, u
|
|||||||
// Part A: MessageID, Repeat, UserID, ShipName -> store in vector to call on Part B arrivals!!!
|
// Part A: MessageID, Repeat, UserID, ShipName -> store in vector to call on Part B arrivals!!!
|
||||||
// Part B: MessageID, Repeat, UserID, VesselType (5), Callsign (5), Length & Beam, PosRefBow,.. (5)
|
// Part B: MessageID, Repeat, UserID, VesselType (5), Callsign (5), Length & Beam, PosRefBow,.. (5)
|
||||||
bool SetAISClassBMessage24PartA(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID, char *Name) {
|
bool SetAISClassBMessage24PartA(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat, uint32_t UserID, char *Name) {
|
||||||
|
// AIS Type 24 Message
|
||||||
bool found = false;
|
NMEA0183AISMsg.ClearAIS();
|
||||||
for (size_t i = 0; i < vships.size(); i++) {
|
// Common for PART A AND Part B Bit 0 - 39 / len 40
|
||||||
if ( vships[i]->_userID == UserID ) {
|
if ( !AddMessageType(NMEA0183AISMsg, 24) ) return false; // 0 - 5 | 6 Message Type -> Constant: 24
|
||||||
found = true;
|
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||||
break;
|
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||||
}
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
||||||
}
|
// Part A: 40 + 128 = len 168
|
||||||
if ( ! found ) {
|
if ( !AddText(NMEA0183AISMsg, Name, 120) ) return false; // 40-159 | 120 Vessel Name 20 6-bit characters -> Ascii Table
|
||||||
std::string nm;
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 160-167 | 8 Spare
|
||||||
nm+= Name;
|
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||||
vships.push_back(new ship(UserID, nm));
|
int padBits=0;
|
||||||
}
|
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||||
|
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***************************************************************************************************************
|
// ***************************************************************************************************************
|
||||||
bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||||
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
||||||
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID ) {
|
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID ) {
|
||||||
|
|
||||||
uint8_t PartNr = 0; // Identifier for the message part number; always 0 for Part A
|
|
||||||
char *ShipName = (char*)" "; // get from vector to look up for sent Messages Part A
|
|
||||||
|
|
||||||
uint8_t i;
|
|
||||||
for ( i = 0; i < vships.size(); i++) {
|
|
||||||
if ( vships[i]->_userID == UserID ) {
|
|
||||||
ShipName = const_cast<char*>( vships[i]->_shipName.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( i > MAX_SHIP_IN_VECTOR ) {
|
|
||||||
std::vector<ship *>::iterator it=vships.begin();
|
|
||||||
delete *it;
|
|
||||||
vships.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AIS Type 24 Message
|
// AIS Type 24 Message
|
||||||
NMEA0183AISMsg.ClearAIS();
|
NMEA0183AISMsg.ClearAIS();
|
||||||
@@ -259,11 +239,7 @@ bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID,
|
|||||||
if ( !AddMessageType(NMEA0183AISMsg, 24) ) return false; // 0 - 5 | 6 Message Type -> Constant: 24
|
if ( !AddMessageType(NMEA0183AISMsg, 24) ) return false; // 0 - 5 | 6 Message Type -> Constant: 24
|
||||||
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||||
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(PartNr, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(1, 2) ) return false; // 38-39 | 2 Part Number 0-1 ->
|
||||||
|
|
||||||
// Part A: 40 + 128 = len 168
|
|
||||||
if ( !AddText(NMEA0183AISMsg, ShipName, 120) ) return false; // 40-159 | 120 Vessel Name 20 6-bit characters -> Ascii Table
|
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 8) ) return false; // 160-167 | 8 Spare
|
|
||||||
|
|
||||||
// https://www.navcen.uscg.gov/?pageName=AISMessagesB
|
// https://www.navcen.uscg.gov/?pageName=AISMessagesB
|
||||||
// PART B: 40 + 128 = len 168
|
// PART B: 40 + 128 = len 168
|
||||||
@@ -272,6 +248,59 @@ bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID,
|
|||||||
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 218-259 | 90-131 | 42 Call Sign WDE4178 -> 7 6-bit characters, as in Msg Type 5
|
if ( !AddText(NMEA0183AISMsg, Callsign, 42) ) return false; // 218-259 | 90-131 | 42 Call Sign WDE4178 -> 7 6-bit characters, as in Msg Type 5
|
||||||
if ( !AddDimensions(NMEA0183AISMsg, Length, Beam, PosRefStbd, PosRefBow) ) return false; // 260-289 | 132-161 | 30 Dimensions
|
if ( !AddDimensions(NMEA0183AISMsg, Length, Beam, PosRefStbd, PosRefBow) ) return false; // 260-289 | 132-161 | 30 Dimensions
|
||||||
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 6) ) return false; // 290-295 | 162-167 | 6 Spare
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0, 6) ) return false; // 290-295 | 162-167 | 6 Spare
|
||||||
|
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||||
|
int padBits=0;
|
||||||
|
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayloadFix(padBits) ) ) return false;
|
||||||
|
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// AIS ATON report (129041) -> Type 21: Position and status report for aids-to-navigation
|
||||||
|
// PGN129041
|
||||||
|
|
||||||
|
bool SetAISMessage21(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat, uint32_t UserID,
|
||||||
|
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||||
|
uint8_t Seconds, double Length, double Beam, double PositionReferenceStarboard,
|
||||||
|
double PositionReferenceTrueNord, tN2kAISAtoNType Type, bool OffPositionIndicator,
|
||||||
|
bool VirtualAtoNFlag, bool AssignedModeFlag, tN2kGNSStype GNSSType, uint8_t AtoNStatus,
|
||||||
|
char * atonName ) {
|
||||||
|
//
|
||||||
|
NMEA0183AISMsg.ClearAIS();
|
||||||
|
if ( !AddMessageType(NMEA0183AISMsg, 21) ) return false; // 0 - 5 | 6 Message Type -> Constant: 18
|
||||||
|
if ( !AddRepeat(NMEA0183AISMsg, Repeat) ) return false; // 6 - 7 | 2 Repeat Indicator: 0 = default; 3 = do not repeat any more
|
||||||
|
if ( !AddUserID(NMEA0183AISMsg, UserID) ) return false; // 8 - 37 | 30 MMSI
|
||||||
|
if ( ! NMEA0183AISMsg.AddIntToPayloadBin(Type,5)) return false; // | 5 aid type
|
||||||
|
//the name must be split:
|
||||||
|
//if it's > 120 bits the rest goes to the last parameter
|
||||||
|
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(atonName,120))
|
||||||
|
return false; // | 120 name
|
||||||
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(Accuracy) ) return false; // | 1 accuracy
|
||||||
|
if ( !AddLongitude(NMEA0183AISMsg,Longitude)) return false; // | 28 lon
|
||||||
|
if ( !AddLatitude(NMEA0183AISMsg,Latitude)) return false; // | 27 lat
|
||||||
|
if ( !AddDimensions(NMEA0183AISMsg, Length, Beam,
|
||||||
|
PositionReferenceStarboard, PositionReferenceTrueNord)) return false; // | 30 dim
|
||||||
|
if ( !AddEPFDFixType(NMEA0183AISMsg,GNSSType)) return false; // | 4 fix type
|
||||||
|
if ( !AddSeconds(NMEA0183AISMsg,Seconds)) return false; // | 6 second
|
||||||
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(OffPositionIndicator))
|
||||||
|
return false; // | 1 off
|
||||||
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0,8)) return false; // | 8 reserverd
|
||||||
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(RAIM)) return false; // | 1 raim
|
||||||
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(VirtualAtoNFlag))
|
||||||
|
return false; // | 1 virt
|
||||||
|
if ( !NMEA0183AISMsg.AddBoolToPayloadBin(AssignedModeFlag))
|
||||||
|
return false; // | 1 assigned
|
||||||
|
if ( !NMEA0183AISMsg.AddIntToPayloadBin(0,1)) return false; // | 1 spare
|
||||||
|
size_t l=strlen(atonName);
|
||||||
|
if (l >=20){
|
||||||
|
uint8_t bitlen=(l-20)*6;
|
||||||
|
if (bitlen > 88) bitlen=88;
|
||||||
|
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(atonName+20,bitlen)) return false; // | name
|
||||||
|
}
|
||||||
|
if ( !NMEA0183AISMsg.InitAis() ) return false;
|
||||||
|
int padBits=0;
|
||||||
|
if ( !NMEA0183AISMsg.AddStrField( NMEA0183AISMsg.GetPayload(padBits) ) ) return false;
|
||||||
|
if ( !NMEA0183AISMsg.AddUInt32Field(padBits) ) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -325,7 +354,6 @@ bool AddIMONumber(tNMEA0183AISMsg &NMEA0183AISMsg, uint32_t &IMONumber) {
|
|||||||
// 120bit Name or Destination
|
// 120bit Name or Destination
|
||||||
bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length) {
|
bool AddText(tNMEA0183AISMsg &NMEA0183AISMsg, char *FieldVal, uint8_t length) {
|
||||||
uint8_t len = length/6;
|
uint8_t len = length/6;
|
||||||
|
|
||||||
if ( strlen(FieldVal) > len ) FieldVal[len] = 0;
|
if ( strlen(FieldVal) > len ) FieldVal[len] = 0;
|
||||||
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(FieldVal, length) ) return false;
|
if ( !NMEA0183AISMsg.AddEncodedCharToPayloadBin(FieldVal, length) ) return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -347,29 +375,26 @@ bool AddDimensions(tNMEA0183AISMsg &NMEA0183AISMsg, double Length, double Beam,
|
|||||||
uint16_t _PosRefStbd = 0;
|
uint16_t _PosRefStbd = 0;
|
||||||
uint16_t _PosRefPort = 0;
|
uint16_t _PosRefPort = 0;
|
||||||
|
|
||||||
if (PosRefBow < 0) PosRefBow=0; //could be N2kIsNA
|
if ( PosRefBow >= 0.0 && PosRefBow <= 511.0 ) {
|
||||||
if ( PosRefBow <= 511.0 ) {
|
_PosRefBow = ceil(PosRefBow);
|
||||||
_PosRefBow = round(PosRefBow);
|
|
||||||
} else {
|
} else {
|
||||||
_PosRefBow = 511;
|
_PosRefBow = 511;
|
||||||
}
|
}
|
||||||
if (PosRefStbd < 0 ) PosRefStbd=0; //could be N2kIsNA
|
|
||||||
if (PosRefStbd <= 63.0 ) {
|
if ( PosRefStbd >= 0.0 && PosRefStbd <= 63.0 ) {
|
||||||
_PosRefStbd = round(PosRefStbd);
|
_PosRefStbd = ceil(PosRefStbd);
|
||||||
} else {
|
} else {
|
||||||
_PosRefStbd = 63;
|
_PosRefStbd = 63;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !N2kIsNA(Length) ) {
|
if ( !N2kIsNA(Length) ) {
|
||||||
if (Length >= PosRefBow){
|
_PosRefStern = ceil( Length ) - _PosRefBow;
|
||||||
_PosRefStern=round(Length - PosRefBow);
|
if ( _PosRefStern < 0 ) _PosRefStern = 0;
|
||||||
}
|
|
||||||
if ( _PosRefStern > 511 ) _PosRefStern = 511;
|
if ( _PosRefStern > 511 ) _PosRefStern = 511;
|
||||||
}
|
}
|
||||||
if ( !N2kIsNA(Beam) ) {
|
if ( !N2kIsNA(Beam) ) {
|
||||||
if (Beam >= PosRefStbd){
|
_PosRefPort = ceil( Beam ) - _PosRefStbd;
|
||||||
_PosRefPort = round( Beam - PosRefStbd);
|
if ( _PosRefPort < 0 ) _PosRefPort = 0;
|
||||||
}
|
|
||||||
if ( _PosRefPort > 63 ) _PosRefPort = 63;
|
if ( _PosRefPort > 63 ) _PosRefPort = 63;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -572,3 +597,5 @@ bool AddETADateTime(tNMEA0183AISMsg &NMEA0183AISMsg, uint16_t &ETAdate, double &
|
|||||||
if ( ! NMEA0183AISMsg.AddIntToPayloadBin(minute, 6) ) return false;
|
if ( ! NMEA0183AISMsg.AddIntToPayloadBin(minute, 6) ) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,24 +27,16 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
#ifndef _tNMEA0183AISMessages_H_
|
#ifndef _tNMEA0183AISMessages_H_
|
||||||
#define _tNMEA0183AISMessages_H_
|
#define _tNMEA0183AISMessages_H_
|
||||||
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <N2kTypes.h>
|
#include <N2kTypes.h>
|
||||||
#include <NMEA0183AISMsg.h>
|
#include "NMEA0183AISMsg.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define MAX_SHIP_IN_VECTOR 200
|
|
||||||
class ship {
|
|
||||||
public:
|
|
||||||
uint32_t _userID;
|
|
||||||
std::string _shipName;
|
|
||||||
|
|
||||||
ship(uint32_t UserID, std::string ShipName) : _userID(UserID), _shipName(ShipName) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Types 1, 2 and 3: Position Report Class A or B
|
// Types 1, 2 and 3: Position Report Class A or B
|
||||||
bool SetAISClassABMessage1(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType, uint8_t Repeat,
|
bool SetAISClassABMessage1(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageType, uint8_t Repeat,
|
||||||
@@ -57,7 +49,8 @@ bool SetAISClassAMessage5(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, ui
|
|||||||
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
uint32_t UserID, uint32_t IMONumber, char *Callsign, char *Name,
|
||||||
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
uint8_t VesselType, double Length, double Beam, double PosRefStbd,
|
||||||
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
double PosRefBow, uint16_t ETAdate, double ETAtime, double Draught,
|
||||||
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE );
|
char *Destination, tN2kGNSStype GNSStype, uint8_t DTE,
|
||||||
|
tN2kAISVersion AISversion);
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// AIS position report (class B 129039) -> Standard Class B CS Position Report Message Type 18 Part B
|
// AIS position report (class B 129039) -> Standard Class B CS Position Report Message Type 18 Part B
|
||||||
@@ -73,11 +66,19 @@ bool SetAISClassBMessage24PartA(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Message
|
|||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
// Static Data Report Class B, Message Type 24
|
// Static Data Report Class B, Message Type 24
|
||||||
bool SetAISClassBMessage24(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
bool SetAISClassBMessage24PartB(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t MessageID, uint8_t Repeat,
|
||||||
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
uint32_t UserID, uint8_t VesselType, char *VendorID, char *Callsign,
|
||||||
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID );
|
double Length, double Beam, double PosRefStbd, double PosRefBow, uint32_t MothershipID );
|
||||||
|
|
||||||
int numShips();
|
//*****************************************************************************
|
||||||
|
// Aton class 21
|
||||||
|
bool SetAISMessage21(tNMEA0183AISMsg &NMEA0183AISMsg, uint8_t Repeat, uint32_t UserID,
|
||||||
|
double Latitude, double Longitude, bool Accuracy, bool RAIM,
|
||||||
|
uint8_t Seconds, double Length, double Beam, double PositionReferenceStarboard,
|
||||||
|
double PositionReferenceTrueNord, tN2kAISAtoNType Type, bool OffPositionIndicator,
|
||||||
|
bool VirtualAtoNFlag, bool AssignedModeFlag, tN2kGNSStype GNSSType, uint8_t AtoNStatus,
|
||||||
|
char * atonName );
|
||||||
|
|
||||||
inline int32_t aRoundToInt(double x) {
|
inline int32_t aRoundToInt(double x) {
|
||||||
return x >= 0
|
return x >= 0
|
||||||
? (int32_t) floor(x + 0.5)
|
? (int32_t) floor(x + 0.5)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
#include "NMEA0183AISMsg.h"
|
#include "NMEA0183AISMsg.h"
|
||||||
#include <NMEA0183Msg.h>
|
#include <NMEA0183Msg.h>
|
||||||
#include <Arduino.h>
|
//#include <Arduino.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -43,52 +43,37 @@ tNMEA0183AISMsg::tNMEA0183AISMsg() {
|
|||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
void tNMEA0183AISMsg::ClearAIS() {
|
void tNMEA0183AISMsg::ClearAIS() {
|
||||||
|
|
||||||
PayloadBin[0]=0;
|
|
||||||
Payload[0]=0;
|
Payload[0]=0;
|
||||||
|
PayloadBin.reset();
|
||||||
iAddPldBin=0;
|
iAddPldBin=0;
|
||||||
iAddPld=0;
|
iAddPld=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//*****************************************************************************
|
|
||||||
// Add 6bit with no data.
|
|
||||||
bool tNMEA0183AISMsg::AddEmptyFieldToPayloadBin(uint8_t iBits) {
|
|
||||||
|
|
||||||
if ( (iAddPldBin + iBits * 6) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
|
||||||
|
|
||||||
for (uint8_t i=0;i<iBits;i++) {
|
|
||||||
strncpy(PayloadBin+iAddPldBin, EmptyAISField, 6);
|
|
||||||
iAddPldBin+=6;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
bool tNMEA0183AISMsg::AddIntToPayloadBin(int32_t ival, uint16_t countBits) {
|
bool tNMEA0183AISMsg::AddIntToPayloadBin(int32_t ival, uint16_t countBits) {
|
||||||
|
|
||||||
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
||||||
|
|
||||||
AISBitSet bset(ival);
|
bset = ival;
|
||||||
|
|
||||||
PayloadBin[iAddPldBin]=0;
|
|
||||||
uint16_t iAdd=iAddPldBin;
|
uint16_t iAdd=iAddPldBin;
|
||||||
|
|
||||||
for(int i = countBits-1; i >= 0 ; i--) {
|
for(int i = countBits-1; i >= 0 ; i--) {
|
||||||
PayloadBin[iAdd] = bset[i]?'1':'0';
|
PayloadBin[iAdd]=bset [i];
|
||||||
iAdd++;
|
iAdd++;
|
||||||
}
|
}
|
||||||
|
|
||||||
iAddPldBin += countBits;
|
iAddPldBin += countBits;
|
||||||
PayloadBin[iAddPldBin]=0;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****************************************************************************
|
//****************************************************************************
|
||||||
bool tNMEA0183AISMsg::AddBoolToPayloadBin(bool &bval, uint8_t size) {
|
bool tNMEA0183AISMsg::AddBoolToPayloadBin(bool &bval) {
|
||||||
int8_t iTemp;
|
if ( (iAddPldBin + 1 ) >= AIS_BIN_MAX_LEN ) return false;
|
||||||
(bval == true)? iTemp = 1 : iTemp = 0;
|
PayloadBin[iAddPldBin]=bval;
|
||||||
if ( ! AddIntToPayloadBin(iTemp, size) ) return false;
|
iAddPldBin++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,13 +84,11 @@ bool tNMEA0183AISMsg::AddEncodedCharToPayloadBin(char *sval, size_t countBits) {
|
|||||||
|
|
||||||
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
if ( (iAddPldBin + countBits ) >= AIS_BIN_MAX_LEN ) return false; // Is there room for any data
|
||||||
|
|
||||||
PayloadBin[iAddPldBin]=0;
|
const char * ptr;
|
||||||
std::bitset<6> bs;
|
|
||||||
char * ptr;
|
|
||||||
size_t len = strlen(sval); // e.g.: should be 7 for Callsign
|
size_t len = strlen(sval); // e.g.: should be 7 for Callsign
|
||||||
if ( len * 6 > countBits ) len = countBits / 6;
|
if ( len * 6 > countBits ) len = countBits / 6;
|
||||||
|
|
||||||
for (int i = 0; i<len; i++) {
|
for (size_t i = 0; i<len; i++) {
|
||||||
|
|
||||||
ptr = strchr(AsciiChar, sval[i]);
|
ptr = strchr(AsciiChar, sval[i]);
|
||||||
if ( ptr ) {
|
if ( ptr ) {
|
||||||
@@ -117,37 +100,44 @@ bool tNMEA0183AISMsg::AddEncodedCharToPayloadBin(char *sval, size_t countBits) {
|
|||||||
AddIntToPayloadBin(0, 6);
|
AddIntToPayloadBin(0, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PayloadBin[iAddPldBin+1]=0;
|
|
||||||
|
|
||||||
// fill up with "@", also covers empty sval
|
// fill up with "@", also covers empty sval
|
||||||
if ( len * 6 < countBits ) {
|
if ( len * 6 < countBits ) {
|
||||||
for (int i=0;i<(countBits/6-len);i++) {
|
for (size_t i=0;i<(countBits/6-len);i++) {
|
||||||
AddIntToPayloadBin(0, 6);
|
AddIntToPayloadBin(0, 6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PayloadBin[iAddPldBin]=0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************
|
//*****************************************************************************
|
||||||
bool tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(const char *payloadbin) {
|
template <unsigned int S>
|
||||||
uint16_t len;
|
int tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(std::bitset<S> &src,uint16_t maxSize,uint16_t bitSize,uint16_t stoffset) {
|
||||||
|
Payload[0]='\0';
|
||||||
len = strlen( payloadbin ) / 6; // 28
|
uint16_t slen=maxSize;
|
||||||
|
if (stoffset >= slen) return 0;
|
||||||
|
slen-=stoffset;
|
||||||
|
uint16_t bitLen=bitSize > 0?bitSize:slen;
|
||||||
|
uint16_t len= bitLen / 6;
|
||||||
|
if ((len * 6) < bitLen) len+=1;
|
||||||
|
uint16_t padBits=0;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
char s[7];
|
std::bitset<6> s;
|
||||||
uint8_t dec;
|
uint8_t dec;
|
||||||
int i;
|
int i;
|
||||||
for ( i=0; i<len; i++ ) {
|
for ( i=0; i<len; i++ ) {
|
||||||
offset = i * 6;
|
offset = i * 6;
|
||||||
int k = 0;
|
int k = 5;
|
||||||
for (int j=offset; j<offset+6; j++ ) {
|
for (uint32_t j=offset; j<offset+6; j++ ) {
|
||||||
s[k] = payloadbin[j];
|
if (j < slen){
|
||||||
k++;
|
s[k] = src[stoffset+j];
|
||||||
}
|
}
|
||||||
s[k]=0;
|
else{
|
||||||
dec = strtoull (s, NULL, 2); //binToDec
|
s[k] = 0;
|
||||||
|
padBits++;
|
||||||
|
}
|
||||||
|
k--;
|
||||||
|
}
|
||||||
|
dec = s.to_ulong();
|
||||||
|
|
||||||
if (dec < 40 ) dec += 48;
|
if (dec < 40 ) dec += 48;
|
||||||
else dec += 56;
|
else dec += 56;
|
||||||
@@ -156,142 +146,56 @@ bool tNMEA0183AISMsg::ConvertBinaryAISPayloadBinToAscii(const char *payloadbin)
|
|||||||
}
|
}
|
||||||
Payload[i]=0;
|
Payload[i]=0;
|
||||||
|
|
||||||
return true;
|
return padBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tNMEA0183AISMsg::SetChannelAndTalker(bool channelA,bool own){
|
||||||
|
channel[0]=channelA?'A':'B';
|
||||||
|
strcpy(talker,own?"VDO":"VDM");
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************** BUILD 2-parted AIS Sentences ************************
|
//********************** BUILD 2-parted AIS Sentences ************************
|
||||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg5Part1(tNMEA0183AISMsg &AISMsg) {
|
bool tNMEA0183AISMsg::InitAis(int max,int number,int sequence){
|
||||||
|
if ( !Init(talker,"AI", '!') ) return false;
|
||||||
Init("VDM", "AI", '!');
|
if ( !AddUInt32Field(max) ) return false;
|
||||||
AddStrField("2");
|
if ( !AddUInt32Field(number) ) return false;
|
||||||
AddStrField("1");
|
if (sequence >= 0){
|
||||||
AddStrField("5");
|
if ( !AddUInt32Field(sequence) ) return false;
|
||||||
AddStrField("A");
|
}
|
||||||
AddStrField( GetPayloadType5_Part1() );
|
else{
|
||||||
AddStrField("0");
|
if ( !AddEmptyField() ) return false;
|
||||||
|
}
|
||||||
return AISMsg;
|
if ( !AddStrField(channel) ) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool tNMEA0183AISMsg::BuildMsg5Part1() {
|
||||||
|
if ( iAddPldBin != 424 ) return false;
|
||||||
|
InitAis(2,1,5);
|
||||||
|
int padBits=0;
|
||||||
|
AddStrField( GetPayload(padBits,0,336));
|
||||||
|
AddUInt32Field(padBits);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg5Part2(tNMEA0183AISMsg &AISMsg) {
|
bool tNMEA0183AISMsg::BuildMsg5Part2() {
|
||||||
|
if ( iAddPldBin != 424 ) return false;
|
||||||
Init("VDM", "AI", '!');
|
InitAis(2,2,5);
|
||||||
AddStrField("2");
|
int padBits=0;
|
||||||
AddStrField("2");
|
AddStrField( GetPayload(padBits,336,88) );
|
||||||
AddStrField("5");
|
AddUInt32Field(padBits);
|
||||||
AddStrField("A");
|
return true;
|
||||||
AddStrField( GetPayloadType5_Part2() );
|
|
||||||
AddStrField("2"); // Message 5, Part 2 has always 2 Padding Zeros
|
|
||||||
|
|
||||||
return AISMsg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg24PartA(tNMEA0183AISMsg &AISMsg) {
|
|
||||||
|
|
||||||
Init("VDM", "AI", '!');
|
|
||||||
AddStrField("1");
|
|
||||||
AddStrField("1");
|
|
||||||
AddEmptyField();
|
|
||||||
AddStrField("A");
|
|
||||||
AddStrField( GetPayloadType24_PartA() );
|
|
||||||
AddStrField("0");
|
|
||||||
|
|
||||||
return AISMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tNMEA0183AISMsg& tNMEA0183AISMsg::BuildMsg24PartB(tNMEA0183AISMsg &AISMsg) {
|
|
||||||
|
|
||||||
Init("VDM", "AI", '!');
|
|
||||||
AddStrField("1");
|
|
||||||
AddStrField("1");
|
|
||||||
AddEmptyField();
|
|
||||||
AddStrField("A");
|
|
||||||
AddStrField( GetPayloadType24_PartB() );
|
|
||||||
AddStrField("0"); // Message 24, both parts have always Zero Padding
|
|
||||||
|
|
||||||
return AISMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************* AIS PAYLOADS *********************************
|
//******************************* AIS PAYLOADS *********************************
|
||||||
//******************************************************************************
|
|
||||||
// get converted Payload for Message 1, 2, 3 & 18, always Length 168
|
// get converted Payload for Message 1, 2, 3 & 18, always Length 168
|
||||||
const char *tNMEA0183AISMsg::GetPayload() {
|
const char *tNMEA0183AISMsg::GetPayloadFix(int &padBits,uint16_t fixLen){
|
||||||
|
uint16_t lenbin = iAddPldBin;
|
||||||
uint16_t lenbin = strlen( PayloadBin);
|
if ( lenbin != fixLen ) return nullptr;
|
||||||
if ( lenbin != 168 ) return nullptr;
|
return GetPayload(padBits,0,0);
|
||||||
|
}
|
||||||
if ( !ConvertBinaryAISPayloadBinToAscii( PayloadBin ) ) return nullptr;
|
const char *tNMEA0183AISMsg::GetPayload(int &padBits,uint16_t offset,uint16_t bitLen) {
|
||||||
|
padBits=ConvertBinaryAISPayloadBinToAscii<AIS_BIN_MAX_LEN>(PayloadBin,iAddPldBin, bitLen,offset );
|
||||||
return Payload;
|
return Payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// get converted Part 1 of Payload for Message 5
|
|
||||||
const char *tNMEA0183AISMsg::GetPayloadType5_Part1() {
|
|
||||||
|
|
||||||
uint16_t lenbin = strlen( PayloadBin);
|
|
||||||
if ( lenbin != 424 ) return nullptr;
|
|
||||||
|
|
||||||
char to[337];
|
|
||||||
strncpy(to, PayloadBin, 336); // First Part is always 336 Length
|
|
||||||
to[336]=0;
|
|
||||||
|
|
||||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
|
||||||
|
|
||||||
return Payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// get converted Part 2 of Payload for Message 5
|
|
||||||
const char *tNMEA0183AISMsg::GetPayloadType5_Part2() {
|
|
||||||
|
|
||||||
uint16_t lenbin = strlen( PayloadBin);
|
|
||||||
if ( lenbin != 424 ) return nullptr;
|
|
||||||
|
|
||||||
lenbin = 88; // Second Part is always 424 - 336 + 2 padding Zeros in Length
|
|
||||||
char to[91];
|
|
||||||
strncpy(to, PayloadBin + 336, lenbin);
|
|
||||||
to[88]='0'; to[89]='0'; to[90]=0;
|
|
||||||
|
|
||||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
|
||||||
return Payload;
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// get converted Part A of Payload for Message 24
|
|
||||||
// Bit 0.....167, len 168
|
|
||||||
// In PayloadBin is Part A and Part B chained together with Length 296
|
|
||||||
const char *tNMEA0183AISMsg::GetPayloadType24_PartA() {
|
|
||||||
uint16_t lenbin = strlen( PayloadBin);
|
|
||||||
if ( lenbin != 296 ) return nullptr; // too short for Part A
|
|
||||||
|
|
||||||
char to[169]; // Part A has Length 168
|
|
||||||
*to = '\0';
|
|
||||||
for (int i=0; i<168; i++){
|
|
||||||
to[i] = PayloadBin[i];
|
|
||||||
}
|
|
||||||
to[168]=0;
|
|
||||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
|
||||||
return Payload;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// get converted Part B of Payload for Message 24
|
|
||||||
// Bit 0.....38 + bit39='1' (part number) + bit 168........295 296='\0' of total PayloadBin
|
|
||||||
// binary part B: len 40 + 128 = len 168
|
|
||||||
const char *tNMEA0183AISMsg::GetPayloadType24_PartB() {
|
|
||||||
uint16_t lenbin = strlen( PayloadBin);
|
|
||||||
if ( lenbin != 296 ) return nullptr; // too short for Part B
|
|
||||||
char to[169]; // Part B has Length 168
|
|
||||||
*to = '\0';
|
|
||||||
for (int i=0; i<39; i++){
|
|
||||||
to[i] = PayloadBin[i];
|
|
||||||
}
|
|
||||||
to[39] = 49; // part number 1
|
|
||||||
for (int i=40; i<168; i++) {
|
|
||||||
to[i] = PayloadBin[i+128];
|
|
||||||
}
|
|
||||||
to[168]=0;
|
|
||||||
if ( !ConvertBinaryAISPayloadBinToAscii( to ) ) return nullptr;
|
|
||||||
return Payload;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -45,43 +45,48 @@ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||||||
|
|
||||||
#define BITSET_LENGTH 120
|
#define BITSET_LENGTH 120
|
||||||
|
|
||||||
typedef std::bitset<BITSET_LENGTH> AISBitSet;
|
|
||||||
class tNMEA0183AISMsg : public tNMEA0183Msg {
|
class tNMEA0183AISMsg : public tNMEA0183Msg {
|
||||||
|
|
||||||
protected: // AIS-NMEA
|
protected: // AIS-NMEA
|
||||||
|
std::bitset<BITSET_LENGTH> bset;
|
||||||
static const char *EmptyAISField; // 6bits 0 not used yet.....
|
static const char *EmptyAISField; // 6bits 0 not used yet.....
|
||||||
static const char *AsciChar;
|
static const char *AsciChar;
|
||||||
|
|
||||||
uint16_t iAddPldBin;
|
uint16_t iAddPldBin;
|
||||||
char Payload[AIS_MSG_MAX_LEN];
|
char Payload[AIS_MSG_MAX_LEN];
|
||||||
uint8_t iAddPld;
|
uint8_t iAddPld;
|
||||||
|
char talker[4]="VDM";
|
||||||
|
char channel[2]="A";
|
||||||
|
std::bitset<AIS_BIN_MAX_LEN> PayloadBin;
|
||||||
public:
|
public:
|
||||||
char PayloadBin[AIS_BIN_MAX_LEN];
|
|
||||||
char PayloadBin2[AIS_BIN_MAX_LEN];
|
|
||||||
// Clear message
|
// Clear message
|
||||||
void ClearAIS();
|
void ClearAIS();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tNMEA0183AISMsg();
|
tNMEA0183AISMsg();
|
||||||
const char *GetPayload();
|
const char *GetPayloadFix(int &padBits,uint16_t fixLen=168);
|
||||||
const char *GetPayloadType5_Part1();
|
const char *GetPayload(int &padBits,uint16_t offset=0,uint16_t bitLen=0);
|
||||||
const char *GetPayloadType5_Part2();
|
|
||||||
const char *GetPayloadType24_PartA();
|
|
||||||
const char *GetPayloadType24_PartB();
|
|
||||||
const char *GetPayloadBin() const { return PayloadBin; }
|
|
||||||
|
|
||||||
const tNMEA0183AISMsg& BuildMsg5Part1(tNMEA0183AISMsg &AISMsg);
|
bool BuildMsg5Part1();
|
||||||
const tNMEA0183AISMsg& BuildMsg5Part2(tNMEA0183AISMsg &AISMsg);
|
bool BuildMsg5Part2();
|
||||||
const tNMEA0183AISMsg& BuildMsg24PartA(tNMEA0183AISMsg &AISMsg);
|
bool InitAis(int max=1,int number=1,int sequence=-1);
|
||||||
const tNMEA0183AISMsg& BuildMsg24PartB(tNMEA0183AISMsg &AISMsg);
|
|
||||||
|
|
||||||
// Generally Used
|
// Generally Used
|
||||||
bool AddIntToPayloadBin(int32_t ival, uint16_t countBits);
|
bool AddIntToPayloadBin(int32_t ival, uint16_t countBits);
|
||||||
bool AddBoolToPayloadBin(bool &bval, uint8_t size);
|
bool AddBoolToPayloadBin(bool &bval);
|
||||||
bool AddEncodedCharToPayloadBin(char *sval, size_t Length);
|
bool AddEncodedCharToPayloadBin(char *sval, size_t Length);
|
||||||
bool AddEmptyFieldToPayloadBin(uint8_t iBits);
|
/**
|
||||||
bool ConvertBinaryAISPayloadBinToAscii(const char *payloadbin);
|
* @param channelA - if set A, otherwise B
|
||||||
|
* @param own - if set VDO, else VDM
|
||||||
|
*/
|
||||||
|
void SetChannelAndTalker(bool channelA,bool own=false);
|
||||||
|
/**
|
||||||
|
* convert the payload to ascii
|
||||||
|
* return the number of padding bits
|
||||||
|
* @param bitSize the number of bits to be used, 0 - use all bits
|
||||||
|
*/
|
||||||
|
template <unsigned int SZ>
|
||||||
|
int ConvertBinaryAISPayloadBinToAscii(std::bitset<SZ> &src,uint16_t maxSize, uint16_t bitSize,uint16_t offset=0);
|
||||||
|
|
||||||
// AIS Helper functions
|
// AIS Helper functions
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# NMEA2000 -> NMEA0183 AIS converter v1.0.0
|
# NMEA2000 to NMEA0183 AIS Converter
|
||||||
|
|
||||||
Import from https://github.com/ronzeiller/NMEA0183-AIS
|
|
||||||
|
|
||||||
NMEA0183 AIS library © Ronnie Zeiller, www.zeiller.eu
|
NMEA0183 AIS library © Ronnie Zeiller, www.zeiller.eu
|
||||||
|
|
||||||
Addendum for NMEA2000 and NMEA0183 Library from Timo Lappalainen https://github.com/ttlappalainen
|
Addendum for NMEA2000 and NMEA0183 Library from Timo Lappalainen https://github.com/ttlappalainen
|
||||||
|
|
||||||
|
to get NMEA0183 AIS data from N2k-bus
|
||||||
|
|
||||||
## Conversions:
|
## Conversions:
|
||||||
|
|
||||||
@@ -15,6 +15,33 @@ Addendum for NMEA2000 and NMEA0183 Library from Timo Lappalainen https://github.
|
|||||||
- NMEA2000 PGN 129809 => AIS Class B "CS" Static Data Report, making a list of UserID (MMSI) and Ship Names used for Message 24 Part A
|
- NMEA2000 PGN 129809 => AIS Class B "CS" Static Data Report, making a list of UserID (MMSI) and Ship Names used for Message 24 Part A
|
||||||
- NMEA2000 PGN 129810 => AIS Class B "CS" Static Data Report, Message 24 Part A+B
|
- NMEA2000 PGN 129810 => AIS Class B "CS" Static Data Report, Message 24 Part A+B
|
||||||
|
|
||||||
|
### Versions
|
||||||
|
1.0.6 2024-03-25
|
||||||
|
- fixed to work with Timo´s NMEA2000 v4.21.3
|
||||||
|
|
||||||
|
1.0.5 2023-12-02
|
||||||
|
- removed VDO remote print statements
|
||||||
|
|
||||||
|
1.0.4 2023-12-02
|
||||||
|
- merged @Isoltero master with fixed memory over run, added VDO remote print statements Thanks to Luis Soltero
|
||||||
|
- fixed example, thanks to @arduinomnomnom
|
||||||
|
|
||||||
|
1.0.3 2022-05-01
|
||||||
|
- Update Examples: AISTransceiverInformation in ParseN2kPGN129039 for changes in NMEA2000 library: https://github.com/ttlappalainen/NMEA2000
|
||||||
|
|
||||||
|
|
||||||
|
1.0.2 2022-04-30
|
||||||
|
- bugfix: malloc without free. Thanks to Luis Soltero (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/3)
|
||||||
|
|
||||||
|
1.0.1 2022-03-15
|
||||||
|
- bugfix: buffer overrun missing space for termination. Thanks to Luis Soltero (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/2)
|
||||||
|
|
||||||
|
2020-12-25
|
||||||
|
- corrected Navigational Status 0. Thanks to Li-Ren (Issue https://github.com/ronzeiller/NMEA0183-AIS/issues/1)
|
||||||
|
|
||||||
|
1.0.0 2019-11-24
|
||||||
|
- initial upload
|
||||||
|
|
||||||
### Remarks
|
### Remarks
|
||||||
1. Message Type could be set to 1 or 3 (identical messages) on demand
|
1. Message Type could be set to 1 or 3 (identical messages) on demand
|
||||||
2. Maneuver Indicator (not part of NMEA2000 PGN 129038) => will be set to 0 (default)
|
2. Maneuver Indicator (not part of NMEA2000 PGN 129038) => will be set to 0 (default)
|
||||||
@@ -33,17 +60,14 @@ To use this library you need also:
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
MIT license
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to use,
|
Copyright (c) 2019-2022 Ronnie Zeiller, www.zeiller.eu
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
||||||
Software, and to permit persons to whom the Software is furnished to do so,
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
subject to the following conditions:
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
||||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
||||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -93,6 +93,7 @@ class GwSensorConfig{
|
|||||||
}
|
}
|
||||||
bool readConfig(T* s,GwConfigHandler *cfg){
|
bool readConfig(T* s,GwConfigHandler *cfg){
|
||||||
if (s == nullptr) return false;
|
if (s == nullptr) return false;
|
||||||
|
if (prefix != s->prefix) return false;
|
||||||
configReader(s,cfg);
|
configReader(s,cfg);
|
||||||
return s->ok;
|
return s->ok;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,18 +66,8 @@ GwSerial::~GwSerial()
|
|||||||
if (lock != nullptr) vSemaphoreDelete(lock);
|
if (lock != nullptr) vSemaphoreDelete(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
String GwSerial::getMode(){
|
int GwSerial::getType() {
|
||||||
switch (type){
|
return type;
|
||||||
case GWSERIAL_TYPE_UNI:
|
|
||||||
return "UNI";
|
|
||||||
case GWSERIAL_TYPE_BI:
|
|
||||||
return "BI";
|
|
||||||
case GWSERIAL_TYPE_RX:
|
|
||||||
return "RX";
|
|
||||||
case GWSERIAL_TYPE_TX:
|
|
||||||
return "TX";
|
|
||||||
}
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GwSerial::isInitialized() { return initialized; }
|
bool GwSerial::isInitialized() { return initialized; }
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class GwSerial : public GwChannelInterface{
|
|||||||
virtual Stream *getStream(bool partialWrites);
|
virtual Stream *getStream(bool partialWrites);
|
||||||
bool getAvailableWrite(){return availableWrite;}
|
bool getAvailableWrite(){return availableWrite;}
|
||||||
virtual void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1)=0;
|
virtual void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1)=0;
|
||||||
virtual String getMode() override;
|
virtual int getType() override;
|
||||||
friend GwSerialStream;
|
friend GwSerialStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@ template<typename T>
|
|||||||
setError(serial,logger);
|
setError(serial,logger);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "GwSocketHelper.h"
|
#include "GwSocketHelper.h"
|
||||||
#include "GWWifi.h"
|
#include "GWWifi.h"
|
||||||
|
|
||||||
|
|
||||||
GwUdpReader::GwUdpReader(const GwConfigHandler *config, GwLog *logger, int minId)
|
GwUdpReader::GwUdpReader(const GwConfigHandler *config, GwLog *logger, int minId)
|
||||||
{
|
{
|
||||||
this->config = config;
|
this->config = config;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
|||||||
@@ -431,7 +431,8 @@ GwXDRFoundMapping GwXDRMappings::getMapping(String xName,String xType,String xUn
|
|||||||
}
|
}
|
||||||
return selectMapping(&(it->second),instance,n183Key.c_str());
|
return selectMapping(&(it->second),instance,n183Key.c_str());
|
||||||
}
|
}
|
||||||
GwXDRFoundMapping GwXDRMappings::getMapping(GwXDRCategory category,int selector,int field,int instance){
|
GwXDRFoundMapping GwXDRMappings::getMapping(double value,GwXDRCategory category,int selector,int field,int instance){
|
||||||
|
if (value == N2kDoubleNA) return GwXDRFoundMapping(); //do not add to unknown mappings
|
||||||
unsigned long n2kKey=GwXDRMappingDef::n2kKey(category,selector,field);
|
unsigned long n2kKey=GwXDRMappingDef::n2kKey(category,selector,field);
|
||||||
auto it=n2kMap.find(n2kKey);
|
auto it=n2kMap.find(n2kKey);
|
||||||
if (it == n2kMap.end()){
|
if (it == n2kMap.end()){
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ class GwXDRMappings{
|
|||||||
//get the mappings
|
//get the mappings
|
||||||
//the returned mapping will exactly contain one mapping def
|
//the returned mapping will exactly contain one mapping def
|
||||||
GwXDRFoundMapping getMapping(String xName,String xType,String xUnit);
|
GwXDRFoundMapping getMapping(String xName,String xType,String xUnit);
|
||||||
GwXDRFoundMapping getMapping(GwXDRCategory category,int selector,int field=0,int instance=-1);
|
GwXDRFoundMapping getMapping(double value,GwXDRCategory category,int selector,int field=0,int instance=-1);
|
||||||
String getXdrEntry(String mapping, double value,int instance=0);
|
String getXdrEntry(String mapping, double value,int instance=0);
|
||||||
const char * getUnMapped();
|
const char * getUnMapped();
|
||||||
const GwXDRType * findType(const String &typeString, const String &unitString) const;
|
const GwXDRType * findType(const String &typeString, const String &unitString) const;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ extra_configs=
|
|||||||
|
|
||||||
[basedeps]
|
[basedeps]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
ttlappalainen/NMEA2000-library @ 4.22.0
|
ttlappalainen_NMEA2000=https://github.com/wellenvogel/NMEA2000.git#20251126
|
||||||
ttlappalainen/NMEA0183 @ 1.10.1
|
ttlappalainen/NMEA0183 @ 1.10.1
|
||||||
ArduinoJson @ 6.18.5
|
ArduinoJson @ 6.18.5
|
||||||
AsyncTCP-esphome @ 2.0.1
|
AsyncTCP-esphome @ 2.0.1
|
||||||
@@ -29,6 +29,18 @@ lib_deps =
|
|||||||
WiFi
|
WiFi
|
||||||
Update
|
Update
|
||||||
|
|
||||||
|
[devdeps]
|
||||||
|
lib_deps=
|
||||||
|
ttlappalainen_NMEA2000=symlink://../NMEA2000
|
||||||
|
ttlappalainen/NMEA0183 @ 1.10.1
|
||||||
|
ArduinoJson @ 6.18.5
|
||||||
|
AsyncTCP-esphome @ 2.0.1
|
||||||
|
ottowinter/ESPAsyncWebServer-esphome@2.0.1
|
||||||
|
FS
|
||||||
|
Preferences
|
||||||
|
ESPmDNS
|
||||||
|
WiFi
|
||||||
|
Update
|
||||||
[env]
|
[env]
|
||||||
platform = espressif32 @ 6.8.1
|
platform = espressif32 @ 6.8.1
|
||||||
framework = arduino
|
framework = arduino
|
||||||
@@ -67,6 +79,17 @@ lib_deps =
|
|||||||
adafruit/Adafruit BusIO @ 1.14.5
|
adafruit/Adafruit BusIO @ 1.14.5
|
||||||
adafruit/Adafruit Unified Sensor @ 1.1.13
|
adafruit/Adafruit Unified Sensor @ 1.1.13
|
||||||
|
|
||||||
|
[env:m5stack-atom-dev]
|
||||||
|
board = m5stack-atom
|
||||||
|
lib_deps =
|
||||||
|
${devdeps.lib_deps}
|
||||||
|
fastled/FastLED @ 3.6.0
|
||||||
|
|
||||||
|
build_flags =
|
||||||
|
-D BOARD_M5ATOM
|
||||||
|
${env.build_flags}
|
||||||
|
upload_port = /dev/esp32
|
||||||
|
upload_protocol = esptool
|
||||||
[env:m5stack-atom]
|
[env:m5stack-atom]
|
||||||
board = m5stack-atom
|
board = m5stack-atom
|
||||||
lib_deps = ${env.lib_deps}
|
lib_deps = ${env.lib_deps}
|
||||||
@@ -185,3 +208,14 @@ build_flags =
|
|||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
upload_port = /dev/esp32
|
upload_port = /dev/esp32
|
||||||
upload_protocol = esptool
|
upload_protocol = esptool
|
||||||
|
|
||||||
|
[env:s3devkitm-generic]
|
||||||
|
extends = sensors
|
||||||
|
board = esp32-s3-devkitm-1
|
||||||
|
lib_deps =
|
||||||
|
${env.lib_deps}
|
||||||
|
${sensors.lib_deps}
|
||||||
|
build_flags =
|
||||||
|
${env.build_flags}
|
||||||
|
upload_port = /dev/esp32
|
||||||
|
upload_protocol = esptool
|
||||||
|
|||||||
8
post.py
8
post.py
@@ -2,6 +2,7 @@ Import("env", "projenv")
|
|||||||
import os
|
import os
|
||||||
import glob
|
import glob
|
||||||
import shutil
|
import shutil
|
||||||
|
import re
|
||||||
|
|
||||||
print("##post script running")
|
print("##post script running")
|
||||||
HDROFFSET=288
|
HDROFFSET=288
|
||||||
@@ -39,6 +40,7 @@ def post(source,target,env):
|
|||||||
appoffset=env.subst("$ESP32_APP_OFFSET")
|
appoffset=env.subst("$ESP32_APP_OFFSET")
|
||||||
firmware=env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
firmware=env.subst("$BUILD_DIR/${PROGNAME}.bin")
|
||||||
(fwname,version)=getFirmwareInfo(firmware)
|
(fwname,version)=getFirmwareInfo(firmware)
|
||||||
|
fwname=re.sub(r"[^0-9A-Za-z_.-]*","",fwname)
|
||||||
print("found fwname=%s, fwversion=%s"%(fwname,version))
|
print("found fwname=%s, fwversion=%s"%(fwname,version))
|
||||||
python=env.subst("$PYTHONEXE")
|
python=env.subst("$PYTHONEXE")
|
||||||
print("base=%s,esptool=%s,appoffset=%s,uploaderflags=%s"%(base,esptool,appoffset,uploaderflags))
|
print("base=%s,esptool=%s,appoffset=%s,uploaderflags=%s"%(base,esptool,appoffset,uploaderflags))
|
||||||
@@ -70,10 +72,12 @@ def post(source,target,env):
|
|||||||
print("running %s"%" ".join(cmd))
|
print("running %s"%" ".join(cmd))
|
||||||
env.Execute(" ".join(cmd),"#testpost")
|
env.Execute(" ".join(cmd),"#testpost")
|
||||||
ofversion="-"+version
|
ofversion="-"+version
|
||||||
versionedFile=os.path.join(outdir,"%s%s-update.bin"%(base,ofversion))
|
versionedFile=os.path.join(outdir,"%s%s-update.bin"%(fwname,ofversion))
|
||||||
shutil.copyfile(firmware,versionedFile)
|
shutil.copyfile(firmware,versionedFile)
|
||||||
versioneOutFile=os.path.join(outdir,"%s%s-all.bin"%(base,ofversion))
|
print(f"wrote {versionedFile}")
|
||||||
|
versioneOutFile=os.path.join(outdir,"%s%s-all.bin"%(fwname,ofversion))
|
||||||
shutil.copyfile(outfile,versioneOutFile)
|
shutil.copyfile(outfile,versioneOutFile)
|
||||||
|
print(f"wrote {versioneOutFile}")
|
||||||
env.AddPostAction(
|
env.AddPostAction(
|
||||||
"$BUILD_DIR/${PROGNAME}.bin",
|
"$BUILD_DIR/${PROGNAME}.bin",
|
||||||
post
|
post
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
This code is free software; you can redistribute it and/or
|
This code is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2 of the License, or (at your option) any later version.
|
||||||
This code is distributed in the hope that it will be useful,
|
This code is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
@@ -72,9 +72,9 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
|
|||||||
#define MAX_NMEA2000_MESSAGE_SEASMART_SIZE 500
|
#define MAX_NMEA2000_MESSAGE_SEASMART_SIZE 500
|
||||||
#define MAX_NMEA0183_MESSAGE_SIZE MAX_NMEA2000_MESSAGE_SEASMART_SIZE
|
#define MAX_NMEA0183_MESSAGE_SIZE MAX_NMEA2000_MESSAGE_SEASMART_SIZE
|
||||||
//assert length of firmware name and version
|
//assert length of firmware name and version
|
||||||
CASSERT(strlen(FIRMWARE_TYPE) <= 32, "environment name (FIRMWARE_TYPE) must not exceed 32 chars");
|
CASSERT(strlen(FIRMWARE_TYPE) <= 31, "environment name (FIRMWARE_TYPE) must not exceed 32 chars");
|
||||||
CASSERT(strlen(VERSION) <= 32, "VERSION must not exceed 32 chars");
|
CASSERT(strlen(VERSION) <= 31, "VERSION must not exceed 32 chars");
|
||||||
CASSERT(strlen(IDF_VERSION) <= 32,"IDF_VERSION must not exceed 32 chars");
|
CASSERT(strlen(IDF_VERSION) <= 31,"IDF_VERSION must not exceed 32 chars");
|
||||||
//https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/app_image_format.html
|
//https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/app_image_format.html
|
||||||
//and removed the bugs in the doc...
|
//and removed the bugs in the doc...
|
||||||
__attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = {
|
__attribute__((section(".rodata_custom_desc"))) esp_app_desc_t custom_app_desc = {
|
||||||
|
|||||||
32
tools/gen3byte.py
Executable file
32
tools/gen3byte.py
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
#generate 3 byte codes for the RGB bytes
|
||||||
|
#refer to https://controllerstech.com/ws2812-leds-using-spi/
|
||||||
|
ONE_BIT='110'
|
||||||
|
ZERO_BIT='100'
|
||||||
|
|
||||||
|
currentStr=''
|
||||||
|
|
||||||
|
def checkAndPrint(curr):
|
||||||
|
if len(curr) >= 8:
|
||||||
|
print("0b%s,"%curr[0:8],end='')
|
||||||
|
return curr[8:]
|
||||||
|
return curr
|
||||||
|
first=True
|
||||||
|
|
||||||
|
print("uint8_t colorTo3Byte[256][3]=")
|
||||||
|
print("{")
|
||||||
|
for i in range(0,256):
|
||||||
|
if not first:
|
||||||
|
print("},")
|
||||||
|
first=False
|
||||||
|
print("{/*%02d*/"%i,end='')
|
||||||
|
mask=0x80
|
||||||
|
for b in range(0,8):
|
||||||
|
if (i & mask) != 0:
|
||||||
|
currentStr+=ONE_BIT
|
||||||
|
else:
|
||||||
|
currentStr+=ZERO_BIT
|
||||||
|
mask=mask >> 1
|
||||||
|
currentStr=checkAndPrint(currentStr)
|
||||||
|
print("}")
|
||||||
|
print("};")
|
||||||
29
tools/getPgnType.py
Executable file
29
tools/getPgnType.py
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
|
def err(txt):
|
||||||
|
print(txt,file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
HDR='''
|
||||||
|
PGNM_Fast=0
|
||||||
|
PGNM_Single=1
|
||||||
|
PGNM_ISO=2
|
||||||
|
PGN_MODES={
|
||||||
|
'''
|
||||||
|
FOOTER='''
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
with open(sys.argv[1],"r") as ih:
|
||||||
|
data=json.load(ih)
|
||||||
|
pgns=data.get('PGNs')
|
||||||
|
if pgns is None:
|
||||||
|
err("no pgns")
|
||||||
|
print(HDR)
|
||||||
|
for p in pgns:
|
||||||
|
t=p['Type']
|
||||||
|
pgn=p['PGN']
|
||||||
|
if t and pgn:
|
||||||
|
print(f" {pgn}: PGNM_{t},")
|
||||||
|
print(FOOTER)
|
||||||
19
tools/sendDelay.py
Executable file
19
tools/sendDelay.py
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print(f"usage: {sys.argv[0]} file delay")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
usage()
|
||||||
|
|
||||||
|
delay=float(sys.argv[2])
|
||||||
|
fn=sys.argv[1]
|
||||||
|
with open (fn,"r") as fh:
|
||||||
|
for line in fh:
|
||||||
|
print(line,end="",flush=True)
|
||||||
|
time.sleep(delay)
|
||||||
|
|
||||||
793
tools/sendN2K.py
Executable file
793
tools/sendN2K.py
Executable file
@@ -0,0 +1,793 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
import getopt
|
||||||
|
import time
|
||||||
|
|
||||||
|
###generated with getPgnType.py from canboat pgns.json
|
||||||
|
PGNM_Fast=0
|
||||||
|
PGNM_Single=1
|
||||||
|
PGNM_ISO=2
|
||||||
|
PGN_MODES={
|
||||||
|
|
||||||
|
59392: PGNM_Single,
|
||||||
|
59904: PGNM_Single,
|
||||||
|
60160: PGNM_Single,
|
||||||
|
60416: PGNM_Single,
|
||||||
|
60416: PGNM_Single,
|
||||||
|
60416: PGNM_Single,
|
||||||
|
60416: PGNM_Single,
|
||||||
|
60416: PGNM_Single,
|
||||||
|
60928: PGNM_Single,
|
||||||
|
61184: PGNM_Single,
|
||||||
|
61184: PGNM_Single,
|
||||||
|
61184: PGNM_Single,
|
||||||
|
65001: PGNM_Single,
|
||||||
|
65002: PGNM_Single,
|
||||||
|
65003: PGNM_Single,
|
||||||
|
65004: PGNM_Single,
|
||||||
|
65005: PGNM_Single,
|
||||||
|
65006: PGNM_Single,
|
||||||
|
65007: PGNM_Single,
|
||||||
|
65008: PGNM_Single,
|
||||||
|
65009: PGNM_Single,
|
||||||
|
65010: PGNM_Single,
|
||||||
|
65011: PGNM_Single,
|
||||||
|
65012: PGNM_Single,
|
||||||
|
65013: PGNM_Single,
|
||||||
|
65014: PGNM_Single,
|
||||||
|
65015: PGNM_Single,
|
||||||
|
65016: PGNM_Single,
|
||||||
|
65017: PGNM_Single,
|
||||||
|
65018: PGNM_Single,
|
||||||
|
65019: PGNM_Single,
|
||||||
|
65020: PGNM_Single,
|
||||||
|
65021: PGNM_Single,
|
||||||
|
65022: PGNM_Single,
|
||||||
|
65023: PGNM_Single,
|
||||||
|
65024: PGNM_Single,
|
||||||
|
65025: PGNM_Single,
|
||||||
|
65026: PGNM_Single,
|
||||||
|
65027: PGNM_Single,
|
||||||
|
65028: PGNM_Single,
|
||||||
|
65029: PGNM_Single,
|
||||||
|
65030: PGNM_Single,
|
||||||
|
65240: PGNM_ISO,
|
||||||
|
65280: PGNM_Single,
|
||||||
|
65284: PGNM_Single,
|
||||||
|
65285: PGNM_Single,
|
||||||
|
65285: PGNM_Single,
|
||||||
|
65286: PGNM_Single,
|
||||||
|
65286: PGNM_Single,
|
||||||
|
65287: PGNM_Single,
|
||||||
|
65287: PGNM_Single,
|
||||||
|
65288: PGNM_Single,
|
||||||
|
65289: PGNM_Single,
|
||||||
|
65290: PGNM_Single,
|
||||||
|
65292: PGNM_Single,
|
||||||
|
65293: PGNM_Single,
|
||||||
|
65293: PGNM_Single,
|
||||||
|
65302: PGNM_Single,
|
||||||
|
65305: PGNM_Single,
|
||||||
|
65305: PGNM_Single,
|
||||||
|
65305: PGNM_Single,
|
||||||
|
65305: PGNM_Single,
|
||||||
|
65305: PGNM_Single,
|
||||||
|
65309: PGNM_Single,
|
||||||
|
65312: PGNM_Single,
|
||||||
|
65340: PGNM_Single,
|
||||||
|
65341: PGNM_Single,
|
||||||
|
65345: PGNM_Single,
|
||||||
|
65350: PGNM_Single,
|
||||||
|
65359: PGNM_Single,
|
||||||
|
65360: PGNM_Single,
|
||||||
|
65361: PGNM_Single,
|
||||||
|
65371: PGNM_Single,
|
||||||
|
65374: PGNM_Single,
|
||||||
|
65379: PGNM_Single,
|
||||||
|
65408: PGNM_Single,
|
||||||
|
65409: PGNM_Single,
|
||||||
|
65410: PGNM_Single,
|
||||||
|
65420: PGNM_Single,
|
||||||
|
65480: PGNM_Single,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126208: PGNM_Fast,
|
||||||
|
126464: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126720: PGNM_Fast,
|
||||||
|
126983: PGNM_Fast,
|
||||||
|
126984: PGNM_Fast,
|
||||||
|
126985: PGNM_Fast,
|
||||||
|
126986: PGNM_Fast,
|
||||||
|
126987: PGNM_Fast,
|
||||||
|
126988: PGNM_Fast,
|
||||||
|
126992: PGNM_Single,
|
||||||
|
126993: PGNM_Single,
|
||||||
|
126996: PGNM_Fast,
|
||||||
|
126998: PGNM_Fast,
|
||||||
|
127233: PGNM_Fast,
|
||||||
|
127237: PGNM_Fast,
|
||||||
|
127245: PGNM_Single,
|
||||||
|
127250: PGNM_Single,
|
||||||
|
127251: PGNM_Single,
|
||||||
|
127252: PGNM_Single,
|
||||||
|
127257: PGNM_Single,
|
||||||
|
127258: PGNM_Single,
|
||||||
|
127488: PGNM_Single,
|
||||||
|
127489: PGNM_Fast,
|
||||||
|
127490: PGNM_Fast,
|
||||||
|
127491: PGNM_Fast,
|
||||||
|
127493: PGNM_Single,
|
||||||
|
127494: PGNM_Fast,
|
||||||
|
127495: PGNM_Fast,
|
||||||
|
127496: PGNM_Fast,
|
||||||
|
127497: PGNM_Fast,
|
||||||
|
127498: PGNM_Fast,
|
||||||
|
127500: PGNM_Single,
|
||||||
|
127501: PGNM_Single,
|
||||||
|
127502: PGNM_Single,
|
||||||
|
127503: PGNM_Fast,
|
||||||
|
127504: PGNM_Fast,
|
||||||
|
127505: PGNM_Single,
|
||||||
|
127506: PGNM_Fast,
|
||||||
|
127507: PGNM_Fast,
|
||||||
|
127508: PGNM_Single,
|
||||||
|
127509: PGNM_Fast,
|
||||||
|
127510: PGNM_Fast,
|
||||||
|
127511: PGNM_Single,
|
||||||
|
127512: PGNM_Single,
|
||||||
|
127513: PGNM_Fast,
|
||||||
|
127514: PGNM_Single,
|
||||||
|
127744: PGNM_Single,
|
||||||
|
127745: PGNM_Single,
|
||||||
|
127746: PGNM_Single,
|
||||||
|
127750: PGNM_Single,
|
||||||
|
127751: PGNM_Single,
|
||||||
|
128000: PGNM_Single,
|
||||||
|
128001: PGNM_Single,
|
||||||
|
128002: PGNM_Single,
|
||||||
|
128003: PGNM_Single,
|
||||||
|
128006: PGNM_Single,
|
||||||
|
128007: PGNM_Single,
|
||||||
|
128008: PGNM_Single,
|
||||||
|
128259: PGNM_Single,
|
||||||
|
128267: PGNM_Single,
|
||||||
|
128275: PGNM_Fast,
|
||||||
|
128520: PGNM_Fast,
|
||||||
|
128538: PGNM_Fast,
|
||||||
|
128768: PGNM_Single,
|
||||||
|
128769: PGNM_Single,
|
||||||
|
128776: PGNM_Single,
|
||||||
|
128777: PGNM_Single,
|
||||||
|
128778: PGNM_Single,
|
||||||
|
128780: PGNM_Single,
|
||||||
|
129025: PGNM_Single,
|
||||||
|
129026: PGNM_Single,
|
||||||
|
129027: PGNM_Single,
|
||||||
|
129028: PGNM_Single,
|
||||||
|
129029: PGNM_Fast,
|
||||||
|
129033: PGNM_Single,
|
||||||
|
129038: PGNM_Fast,
|
||||||
|
129039: PGNM_Fast,
|
||||||
|
129040: PGNM_Fast,
|
||||||
|
129041: PGNM_Fast,
|
||||||
|
129044: PGNM_Fast,
|
||||||
|
129045: PGNM_Fast,
|
||||||
|
129283: PGNM_Single,
|
||||||
|
129284: PGNM_Fast,
|
||||||
|
129285: PGNM_Fast,
|
||||||
|
129291: PGNM_Single,
|
||||||
|
129301: PGNM_Fast,
|
||||||
|
129302: PGNM_Fast,
|
||||||
|
129538: PGNM_Fast,
|
||||||
|
129539: PGNM_Single,
|
||||||
|
129540: PGNM_Fast,
|
||||||
|
129541: PGNM_Fast,
|
||||||
|
129542: PGNM_Fast,
|
||||||
|
129545: PGNM_Fast,
|
||||||
|
129546: PGNM_Single,
|
||||||
|
129547: PGNM_Fast,
|
||||||
|
129549: PGNM_Fast,
|
||||||
|
129550: PGNM_Fast,
|
||||||
|
129551: PGNM_Fast,
|
||||||
|
129556: PGNM_Fast,
|
||||||
|
129792: PGNM_Fast,
|
||||||
|
129793: PGNM_Fast,
|
||||||
|
129794: PGNM_Fast,
|
||||||
|
129795: PGNM_Fast,
|
||||||
|
129796: PGNM_Fast,
|
||||||
|
129797: PGNM_Fast,
|
||||||
|
129798: PGNM_Fast,
|
||||||
|
129799: PGNM_Fast,
|
||||||
|
129800: PGNM_Fast,
|
||||||
|
129801: PGNM_Fast,
|
||||||
|
129802: PGNM_Fast,
|
||||||
|
129803: PGNM_Fast,
|
||||||
|
129804: PGNM_Fast,
|
||||||
|
129805: PGNM_Fast,
|
||||||
|
129806: PGNM_Fast,
|
||||||
|
129807: PGNM_Fast,
|
||||||
|
129808: PGNM_Fast,
|
||||||
|
129808: PGNM_Fast,
|
||||||
|
129809: PGNM_Fast,
|
||||||
|
129810: PGNM_Fast,
|
||||||
|
130052: PGNM_Fast,
|
||||||
|
130053: PGNM_Fast,
|
||||||
|
130054: PGNM_Fast,
|
||||||
|
130060: PGNM_Fast,
|
||||||
|
130061: PGNM_Fast,
|
||||||
|
130064: PGNM_Fast,
|
||||||
|
130065: PGNM_Fast,
|
||||||
|
130066: PGNM_Fast,
|
||||||
|
130067: PGNM_Fast,
|
||||||
|
130068: PGNM_Fast,
|
||||||
|
130069: PGNM_Fast,
|
||||||
|
130070: PGNM_Fast,
|
||||||
|
130071: PGNM_Fast,
|
||||||
|
130072: PGNM_Fast,
|
||||||
|
130073: PGNM_Fast,
|
||||||
|
130074: PGNM_Fast,
|
||||||
|
130306: PGNM_Single,
|
||||||
|
130310: PGNM_Single,
|
||||||
|
130311: PGNM_Single,
|
||||||
|
130312: PGNM_Single,
|
||||||
|
130313: PGNM_Single,
|
||||||
|
130314: PGNM_Single,
|
||||||
|
130315: PGNM_Single,
|
||||||
|
130316: PGNM_Single,
|
||||||
|
130320: PGNM_Fast,
|
||||||
|
130321: PGNM_Fast,
|
||||||
|
130322: PGNM_Fast,
|
||||||
|
130323: PGNM_Fast,
|
||||||
|
130324: PGNM_Fast,
|
||||||
|
130330: PGNM_Fast,
|
||||||
|
130560: PGNM_Single,
|
||||||
|
130561: PGNM_Fast,
|
||||||
|
130562: PGNM_Fast,
|
||||||
|
130563: PGNM_Fast,
|
||||||
|
130564: PGNM_Fast,
|
||||||
|
130565: PGNM_Fast,
|
||||||
|
130566: PGNM_Fast,
|
||||||
|
130567: PGNM_Fast,
|
||||||
|
130569: PGNM_Fast,
|
||||||
|
130570: PGNM_Fast,
|
||||||
|
130571: PGNM_Fast,
|
||||||
|
130572: PGNM_Fast,
|
||||||
|
130573: PGNM_Fast,
|
||||||
|
130574: PGNM_Fast,
|
||||||
|
130576: PGNM_Single,
|
||||||
|
130577: PGNM_Fast,
|
||||||
|
130578: PGNM_Fast,
|
||||||
|
130579: PGNM_Single,
|
||||||
|
130580: PGNM_Fast,
|
||||||
|
130581: PGNM_Fast,
|
||||||
|
130582: PGNM_Single,
|
||||||
|
130583: PGNM_Fast,
|
||||||
|
130584: PGNM_Fast,
|
||||||
|
130585: PGNM_Single,
|
||||||
|
130586: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130816: PGNM_Fast,
|
||||||
|
130817: PGNM_Fast,
|
||||||
|
130817: PGNM_Fast,
|
||||||
|
130818: PGNM_Fast,
|
||||||
|
130819: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130820: PGNM_Fast,
|
||||||
|
130821: PGNM_Fast,
|
||||||
|
130821: PGNM_Fast,
|
||||||
|
130822: PGNM_Fast,
|
||||||
|
130823: PGNM_Fast,
|
||||||
|
130824: PGNM_Fast,
|
||||||
|
130824: PGNM_Fast,
|
||||||
|
130825: PGNM_Fast,
|
||||||
|
130827: PGNM_Fast,
|
||||||
|
130828: PGNM_Fast,
|
||||||
|
130831: PGNM_Fast,
|
||||||
|
130832: PGNM_Fast,
|
||||||
|
130833: PGNM_Fast,
|
||||||
|
130834: PGNM_Fast,
|
||||||
|
130835: PGNM_Fast,
|
||||||
|
130836: PGNM_Fast,
|
||||||
|
130836: PGNM_Fast,
|
||||||
|
130837: PGNM_Fast,
|
||||||
|
130837: PGNM_Fast,
|
||||||
|
130838: PGNM_Fast,
|
||||||
|
130839: PGNM_Fast,
|
||||||
|
130840: PGNM_Fast,
|
||||||
|
130842: PGNM_Fast,
|
||||||
|
130842: PGNM_Fast,
|
||||||
|
130842: PGNM_Fast,
|
||||||
|
130843: PGNM_Fast,
|
||||||
|
130843: PGNM_Fast,
|
||||||
|
130845: PGNM_Fast,
|
||||||
|
130845: PGNM_Fast,
|
||||||
|
130846: PGNM_Fast,
|
||||||
|
130846: PGNM_Fast,
|
||||||
|
130847: PGNM_Fast,
|
||||||
|
130850: PGNM_Fast,
|
||||||
|
130850: PGNM_Fast,
|
||||||
|
130850: PGNM_Fast,
|
||||||
|
130851: PGNM_Fast,
|
||||||
|
130856: PGNM_Fast,
|
||||||
|
130860: PGNM_Fast,
|
||||||
|
130880: PGNM_Fast,
|
||||||
|
130881: PGNM_Fast,
|
||||||
|
130944: PGNM_Fast,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def logError(fmt,*args,keep=False):
|
||||||
|
print("ERROR:" +fmt%(args),file=sys.stderr)
|
||||||
|
if not keep:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def dataToSep(data,maxbytes=None):
|
||||||
|
pd=None
|
||||||
|
dl=int(len(data)/2)
|
||||||
|
if maxbytes is not None and maxbytes < dl:
|
||||||
|
dl=maxbytes
|
||||||
|
for p in range(0,dl):
|
||||||
|
i=2*p
|
||||||
|
if pd is None:
|
||||||
|
pd=data[i:i+2]
|
||||||
|
else:
|
||||||
|
pd+=","+data[i:i+2]
|
||||||
|
return pd
|
||||||
|
class Format:
|
||||||
|
F_PLAIN=0
|
||||||
|
N_PLAIN='plain'
|
||||||
|
F_ACT=1
|
||||||
|
N_ACT='actisense'
|
||||||
|
F_PASS=2
|
||||||
|
N_PASS='pass'
|
||||||
|
F_SEASMART=3
|
||||||
|
N_SEASMART="seasmart"
|
||||||
|
def __init__(self,name,key,merge=True):
|
||||||
|
self.key=key
|
||||||
|
self.name=name
|
||||||
|
self.merge=merge
|
||||||
|
|
||||||
|
class CanFrame:
|
||||||
|
DUMP_PAT=re.compile(r'\(([^)]*)\) *([^ ]*) *([^#]*)#(.*)')
|
||||||
|
|
||||||
|
def __init__(self,ts,pgn,src=1,dst=255,prio=1,dev=None,hdr=None,data=None):
|
||||||
|
self.pgn=pgn
|
||||||
|
self.mode=PGN_MODES.get(pgn)
|
||||||
|
self.ts=ts
|
||||||
|
self.src=src
|
||||||
|
self.dst=dst
|
||||||
|
self.data=data
|
||||||
|
self.prio=prio
|
||||||
|
self.sequence=None
|
||||||
|
self.frame=None
|
||||||
|
self.len=8
|
||||||
|
self.dev=dev
|
||||||
|
self.hdr=hdr
|
||||||
|
if self.mode == PGNM_Fast and data is not None and len(self.data) >= 2:
|
||||||
|
fb=int(data[0:2],16)
|
||||||
|
self.frame=fb & 0x1f
|
||||||
|
self.sequence=fb >> 5
|
||||||
|
|
||||||
|
def key(self):
|
||||||
|
if self.sequence is None or self.pgn == 0:
|
||||||
|
return None
|
||||||
|
return f"{self.pgn}-{self.sequence}-{self.src}"
|
||||||
|
def getFPNum(self,bytes=False):
|
||||||
|
if self.frame != 0:
|
||||||
|
return None
|
||||||
|
if len(self.data) < 4:
|
||||||
|
return None
|
||||||
|
numbytes=int(self.data[2:4],16)
|
||||||
|
if bytes:
|
||||||
|
return numbytes
|
||||||
|
frames=int((numbytes-6-1)/7)+1+1 if numbytes > 6 else 1
|
||||||
|
return frames
|
||||||
|
|
||||||
|
def _formatTs(self):
|
||||||
|
dt=datetime.datetime.fromtimestamp(self.ts,tz=datetime.UTC)
|
||||||
|
return dt.strftime("%F-%T.")+dt.strftime("%f")[0:3]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self._formatTs()},{self.prio},{self.pgn},{self.src},{self.dst},{self.len},{dataToSep(self.data)}"
|
||||||
|
|
||||||
|
def printOut(self,format:Format):
|
||||||
|
if format.key == Format.F_PASS:
|
||||||
|
return f"({self.ts:.6f}) {self.dev} {self.hdr}#{self.data}"
|
||||||
|
else:
|
||||||
|
return str(self)
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fromDump(cls,line:str):
|
||||||
|
'''(1658058069.867835) can0 09F80103#ACAF6C20B79AAC06'''
|
||||||
|
if line is None or line == '':
|
||||||
|
return None
|
||||||
|
match=cls.DUMP_PAT.search(line)
|
||||||
|
if match is None:
|
||||||
|
logError("no dump pattern in line %s",line,keep=True)
|
||||||
|
return
|
||||||
|
ts=match[1]
|
||||||
|
data=match[4]
|
||||||
|
hdr=match[3]
|
||||||
|
hdrval=int(hdr,16)
|
||||||
|
#see candump2analyzer
|
||||||
|
src=hdrval & 0xff
|
||||||
|
prio=(hdrval >> 26) & 0x7
|
||||||
|
PF=(hdrval >> 16) & 0xff
|
||||||
|
PS=(hdrval >> 8) & 0xff
|
||||||
|
RDP=(hdrval >> 24) & 3
|
||||||
|
pgn=0
|
||||||
|
if PF < 240:
|
||||||
|
dst=PS
|
||||||
|
pgn=(RDP << 16) + (PF << 8)
|
||||||
|
else:
|
||||||
|
dst=0xff
|
||||||
|
pgn=(RDP << 16) + (PF << 8)+PS
|
||||||
|
return CanFrame(float(ts),pgn,src=src,dst=dst,prio=prio,data=data,dev=match[2],hdr=hdr)
|
||||||
|
|
||||||
|
class MultiFrame(CanFrame):
|
||||||
|
def __init__(self,firstFrame: CanFrame):
|
||||||
|
super().__init__(firstFrame.ts,firstFrame.pgn,
|
||||||
|
src=firstFrame.src,dst=firstFrame.dst,prio=firstFrame.prio,
|
||||||
|
dev=firstFrame.dev,hdr=firstFrame.hdr)
|
||||||
|
self.data=""
|
||||||
|
self.numFrames=firstFrame.getFPNum(bytes=False)
|
||||||
|
self.len=firstFrame.getFPNum(bytes=True)
|
||||||
|
self.finished=False
|
||||||
|
self.addFrame(firstFrame)
|
||||||
|
|
||||||
|
def addFrame(self,frame:CanFrame):
|
||||||
|
if self.finished:
|
||||||
|
return False
|
||||||
|
if frame.frame is None:
|
||||||
|
return False
|
||||||
|
if frame.frame == 0:
|
||||||
|
self.data+=frame.data[4:]
|
||||||
|
else:
|
||||||
|
self.data+=frame.data[2:]
|
||||||
|
if frame.frame >= (self.numFrames-1):
|
||||||
|
self.finished=True
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self._formatTs()},{self.prio},{self.pgn},{self.src},{self.dst},{self.len},{dataToSep(self.data,self.len)}"
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print(f"usage: {sys.argv[0]} [-q] [-p pgn,pgn,...] [-w waitsec] [ -f plain|actisense] file",file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FORMATS=[
|
||||||
|
Format(Format.N_PLAIN,Format.F_PLAIN),
|
||||||
|
Format(Format.N_ACT,Format.F_ACT),
|
||||||
|
Format(Format.N_PASS,Format.F_PASS,False),
|
||||||
|
Format(Format.N_SEASMART,Format.F_SEASMART)
|
||||||
|
]
|
||||||
|
|
||||||
|
MAX_ACT=400
|
||||||
|
ACT_ESC=0x10
|
||||||
|
ACT_START=0x2
|
||||||
|
ACT_N2K=0x93
|
||||||
|
ACT_END=0x3
|
||||||
|
|
||||||
|
class ActBuffer:
|
||||||
|
def __init__(self):
|
||||||
|
self.buf=bytearray(MAX_ACT)
|
||||||
|
self.sum=0
|
||||||
|
self.idx=0
|
||||||
|
self.clear()
|
||||||
|
def clear(self):
|
||||||
|
self.sum=0
|
||||||
|
self.idx=2
|
||||||
|
self.buf[0:2]=(ACT_ESC,ACT_START)
|
||||||
|
def add(self,val):
|
||||||
|
#TODO: len check?
|
||||||
|
val=val & 0xff
|
||||||
|
self.buf[self.idx]=val
|
||||||
|
self.sum = (self.sum + val) & 0xff
|
||||||
|
self.idx+=1
|
||||||
|
if val == ACT_ESC:
|
||||||
|
self.buf[self.idx]=ACT_ESC
|
||||||
|
self.idx+=1
|
||||||
|
def finalize(self):
|
||||||
|
self.sum=self.sum % 256
|
||||||
|
self.sum = 256 - self.sum if self.sum != 0 else 0
|
||||||
|
self.add(self.sum)
|
||||||
|
self.buf[self.idx]=ACT_ESC
|
||||||
|
self.idx+=1
|
||||||
|
self.buf[self.idx]=ACT_END
|
||||||
|
self.idx+=1
|
||||||
|
|
||||||
|
actBuffer=ActBuffer()
|
||||||
|
|
||||||
|
|
||||||
|
LB=b'0000000000000'
|
||||||
|
B_STAR=0x2a
|
||||||
|
class SeasmartBuffer:
|
||||||
|
def __init__(self):
|
||||||
|
self.buf=bytearray(500)
|
||||||
|
self.idx=0
|
||||||
|
self.clear()
|
||||||
|
def clear(self):
|
||||||
|
self.idx=0
|
||||||
|
def addB(self,bv,mlen=None):
|
||||||
|
l=len(bv)
|
||||||
|
if mlen is not None and mlen < l:
|
||||||
|
l=mlen
|
||||||
|
self.buf[self.idx:self.idx+l]=memoryview(bv)[0:l]
|
||||||
|
else:
|
||||||
|
self.buf[self.idx:self.idx+l]=bv
|
||||||
|
self.idx+=l
|
||||||
|
def addVal(self,val,blen=2):
|
||||||
|
hs=hex(val)[2:].encode()
|
||||||
|
if len(hs) != blen:
|
||||||
|
hs=(LB+hs)[-blen:]
|
||||||
|
self.addB(hs)
|
||||||
|
|
||||||
|
def finalize(self):
|
||||||
|
sum=0
|
||||||
|
self.buf[self.idx]=B_STAR
|
||||||
|
self.idx+=1
|
||||||
|
for b in memoryview(self.buf)[1:]:
|
||||||
|
if b == B_STAR:
|
||||||
|
break
|
||||||
|
sum ^= b
|
||||||
|
sum = sum & 0xff
|
||||||
|
self.addVal(sum)
|
||||||
|
self.addB(b'\x0d\x0a')
|
||||||
|
|
||||||
|
seasmartBuffer=SeasmartBuffer()
|
||||||
|
|
||||||
|
def send_act(frame_like:CanFrame,quiet,stream):
|
||||||
|
try:
|
||||||
|
actBuffer.clear()
|
||||||
|
actBuffer.add(ACT_N2K)
|
||||||
|
actBuffer.add(frame_like.len+11)
|
||||||
|
actBuffer.add(frame_like.prio)
|
||||||
|
pgn=frame_like.pgn
|
||||||
|
actBuffer.add(pgn)
|
||||||
|
pgn = pgn >> 8
|
||||||
|
actBuffer.add(pgn)
|
||||||
|
pgn = pgn >> 8;
|
||||||
|
actBuffer.add(pgn)
|
||||||
|
actBuffer.add(frame_like.dst)
|
||||||
|
actBuffer.add(frame_like.src)
|
||||||
|
#Time
|
||||||
|
ts=int(frame_like.ts)
|
||||||
|
actBuffer.add(ts>>24)
|
||||||
|
actBuffer.add(ts>>16)
|
||||||
|
actBuffer.add(ts>>8)
|
||||||
|
actBuffer.add(ts)
|
||||||
|
|
||||||
|
actBuffer.add(frame_like.len)
|
||||||
|
for i in range(0,frame_like.len*2,2):
|
||||||
|
actBuffer.add(int(frame_like.data[i:i+2],16))
|
||||||
|
actBuffer.finalize()
|
||||||
|
written=stream.write(memoryview(actBuffer.buf)[0:actBuffer.idx])
|
||||||
|
if (written != actBuffer.idx):
|
||||||
|
if not quiet:
|
||||||
|
logError(f"actisense not all bytes written {written}/{actBuffer.idx} for pgn={frame_like.pgn} ts={frame_like.ts}",keep=True)
|
||||||
|
stream.flush()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
if not quiet:
|
||||||
|
print(f"Error writing actisense for pgn {frame_like.pgn}, idx={actBuffer.idx}: {e}",file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
BK=b','
|
||||||
|
def send_seasmart(frame_like:CanFrame,quiet,stream):
|
||||||
|
try:
|
||||||
|
seasmartBuffer.clear()
|
||||||
|
seasmartBuffer.addB(b'$PCDIN,')
|
||||||
|
seasmartBuffer.addVal(frame_like.pgn,6)
|
||||||
|
seasmartBuffer.addB(BK)
|
||||||
|
seasmartBuffer.addVal(int(frame_like.ts),8)
|
||||||
|
seasmartBuffer.addB(BK)
|
||||||
|
seasmartBuffer.addVal(frame_like.src)
|
||||||
|
seasmartBuffer.addB(BK)
|
||||||
|
seasmartBuffer.addB(frame_like.data.encode(),mlen=frame_like.len*2)
|
||||||
|
seasmartBuffer.finalize()
|
||||||
|
written=stream.write(memoryview(seasmartBuffer.buf)[0:seasmartBuffer.idx])
|
||||||
|
if (written != seasmartBuffer.idx):
|
||||||
|
if not quiet:
|
||||||
|
raise Exception(f"seasmart not all bytes written {written}/{seasmartBuffer.idx} for pgn={frame_like.pgn} ts={frame_like.ts}")
|
||||||
|
stream.flush()
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
if not quiet:
|
||||||
|
logError(f"writing seasmart for pgn {frame_like.pgn}, idx={seasmartBuffer.idx}: {e}",keep=True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
class Counters:
|
||||||
|
C_OK=1
|
||||||
|
C_FAIL=2
|
||||||
|
C_FRAME=3
|
||||||
|
TITLES={
|
||||||
|
C_OK:'OK',
|
||||||
|
C_FAIL:'FAIL',
|
||||||
|
C_FRAME:'FRAMES'
|
||||||
|
}
|
||||||
|
def __init__(self):
|
||||||
|
self.counters={}
|
||||||
|
for i in self.TITLES.keys():
|
||||||
|
self.counters[i]=0
|
||||||
|
def add(self,idx:int):
|
||||||
|
if idx not in self.TITLES.keys():
|
||||||
|
return
|
||||||
|
self.counters[idx]+=1
|
||||||
|
def __str__(self):
|
||||||
|
rt=None
|
||||||
|
for i in self.TITLES.keys():
|
||||||
|
v=f"{self.TITLES[i]}:{self.counters[i]}"
|
||||||
|
if rt is None:
|
||||||
|
rt=v
|
||||||
|
else:
|
||||||
|
rt+=","+v
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def writeOut(frame:CanFrame,format:Format,quiet:bool,counters:Counters):
|
||||||
|
rt=False
|
||||||
|
if format.key == Format.F_ACT:
|
||||||
|
rt= send_act(frame,quiet,sys.stdout.buffer)
|
||||||
|
elif format.key == Format.F_SEASMART:
|
||||||
|
rt= send_seasmart(frame,quiet,sys.stdout.buffer)
|
||||||
|
else:
|
||||||
|
print(frame.printOut(format))
|
||||||
|
rt=True
|
||||||
|
counters.add(Counters.C_OK if rt else Counters.C_FAIL)
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def findFormat(name:str)->Format:
|
||||||
|
for f in FORMATS:
|
||||||
|
if f.name == name:
|
||||||
|
return f
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
opts,args=getopt.getopt(sys.argv[1:],"hp:qw:f:")
|
||||||
|
except getopt.GetoptError as e:
|
||||||
|
logError(e)
|
||||||
|
pgnlist=[]
|
||||||
|
quiet=False
|
||||||
|
delay=0.0
|
||||||
|
format=findFormat(Format.N_PLAIN)
|
||||||
|
for o,a in opts:
|
||||||
|
if o == '-h':
|
||||||
|
usage()
|
||||||
|
elif o == '-q':
|
||||||
|
quiet=True
|
||||||
|
elif o == '-p':
|
||||||
|
pgns=(int(x) for x in a.split(","))
|
||||||
|
pgnlist.extend(pgns)
|
||||||
|
elif o == '-w':
|
||||||
|
delay=float(a)
|
||||||
|
elif o == '-f':
|
||||||
|
format=findFormat(a)
|
||||||
|
if format is None:
|
||||||
|
logError(f"invalid format {a}, allowed {','.join(x.name for x in FORMATS)}")
|
||||||
|
if len(args) < 1:
|
||||||
|
usage()
|
||||||
|
hasFilter=len(pgnlist) > 0
|
||||||
|
if not quiet and hasFilter:
|
||||||
|
print(f"PGNs: {','.join(str(x) for x in pgnlist)}",file=sys.stderr)
|
||||||
|
counters=Counters()
|
||||||
|
with open (args[0],"r") as fh:
|
||||||
|
buffer={}
|
||||||
|
lnr=0
|
||||||
|
for line in fh:
|
||||||
|
lnr+=1
|
||||||
|
frame=CanFrame.fromDump(line)
|
||||||
|
if frame is None:
|
||||||
|
continue
|
||||||
|
if hasFilter and not frame.pgn in pgnlist:
|
||||||
|
continue
|
||||||
|
counters.add(Counters.C_FRAME)
|
||||||
|
if frame.sequence is None or not format.merge:
|
||||||
|
writeOut(frame,format,quiet,counters=counters)
|
||||||
|
if delay > 0:
|
||||||
|
time.sleep(delay)
|
||||||
|
else:
|
||||||
|
key=frame.key()
|
||||||
|
mf=buffer.get(key)
|
||||||
|
mustDelete=False
|
||||||
|
if mf is None:
|
||||||
|
if frame.frame != 0:
|
||||||
|
if not quiet:
|
||||||
|
print(f"floating multi frame in line {lnr}: {frame}",file=sys.stderr)
|
||||||
|
continue
|
||||||
|
mf=MultiFrame(frame)
|
||||||
|
if not mf.finished:
|
||||||
|
buffer[key]=mf
|
||||||
|
else:
|
||||||
|
mf.addFrame(frame)
|
||||||
|
mustDelete=True
|
||||||
|
if mf.finished:
|
||||||
|
writeOut(mf,format,quiet,counters=counters)
|
||||||
|
if mustDelete:
|
||||||
|
del buffer[key]
|
||||||
|
if delay > 0:
|
||||||
|
time.sleep(delay)
|
||||||
|
if not quiet:
|
||||||
|
print(f"STATISTICS: {counters}",file=sys.stderr)
|
||||||
|
|
||||||
@@ -53,16 +53,16 @@ types:
|
|||||||
- value: M5_ENV3#grv#
|
- value: M5_ENV3#grv#
|
||||||
key: true
|
key: true
|
||||||
resource: qmp69881#grv#1,sht3x#grv#1
|
resource: qmp69881#grv#1,sht3x#grv#1
|
||||||
# - label: "M5 ENV4"
|
- label: "M5 ENV4"
|
||||||
# type: checkbox
|
type: checkbox
|
||||||
# key: m5env4#grv#
|
key: m5env4#grv#
|
||||||
# target: define
|
target: define
|
||||||
# url: "https://docs.m5stack.com/en/unit/ENV%E2%85%A3%20Unit"
|
url: "https://docs.m5stack.com/en/unit/ENV%E2%85%A3%20Unit"
|
||||||
# description: "M5 sensor module temperature, humidity, pressure"
|
description: "M5 sensor module temperature, humidity, pressure"
|
||||||
# values:
|
values:
|
||||||
# - value: M5_ENV4#grv#
|
- value: M5_ENV4#grv#
|
||||||
# key: true
|
key: true
|
||||||
# resource: bmp280#grv#1,sht3x#grv#1
|
resource: bmp280#grv#1,sht4x#grv#1
|
||||||
- type: checkbox
|
- type: checkbox
|
||||||
label: SHT3X-1
|
label: SHT3X-1
|
||||||
description: "SHT30 temperature and humidity sensor 0x44"
|
description: "SHT30 temperature and humidity sensor 0x44"
|
||||||
@@ -179,6 +179,11 @@ types:
|
|||||||
description: "M5 Gps Unit"
|
description: "M5 Gps Unit"
|
||||||
url: "https://docs.m5stack.com/en/unit/gps"
|
url: "https://docs.m5stack.com/en/unit/gps"
|
||||||
resource: serial
|
resource: serial
|
||||||
|
- label: "Gps Unit v1.1"
|
||||||
|
value: M5_GPSV11_UNIT#grv#
|
||||||
|
description: "M5 Gps Unit v1.1"
|
||||||
|
url: "https://docs.m5stack.com/en/unit/Unit-GPS%20v1.1"
|
||||||
|
resource: serial
|
||||||
- label: "RS232/RS422"
|
- label: "RS232/RS422"
|
||||||
value: SERIAL_GROOVE_232#grv#
|
value: SERIAL_GROOVE_232#grv#
|
||||||
description: "Generic RS232/RS422 Unit (bidirectional)"
|
description: "Generic RS232/RS422 Unit (bidirectional)"
|
||||||
@@ -234,6 +239,46 @@ types:
|
|||||||
- 37
|
- 37
|
||||||
- 38
|
- 38
|
||||||
|
|
||||||
|
- &gpiopinvs3
|
||||||
|
- {label: unset,value:}
|
||||||
|
- {label: "0: boot mode control",value: 0}
|
||||||
|
- 1
|
||||||
|
- 2
|
||||||
|
- {label: "3: JTAG control", value: 3}
|
||||||
|
- 4
|
||||||
|
- 5
|
||||||
|
- 6
|
||||||
|
- 7
|
||||||
|
- 8
|
||||||
|
- 9
|
||||||
|
- 10
|
||||||
|
- 11
|
||||||
|
- 12
|
||||||
|
- 13
|
||||||
|
- 14
|
||||||
|
- 17
|
||||||
|
- 18
|
||||||
|
- 19
|
||||||
|
- 20
|
||||||
|
- 21
|
||||||
|
- 33
|
||||||
|
- 34
|
||||||
|
- 35
|
||||||
|
- 36
|
||||||
|
- 37
|
||||||
|
- 38
|
||||||
|
- 39
|
||||||
|
- 40
|
||||||
|
- 41
|
||||||
|
- 42
|
||||||
|
- 43
|
||||||
|
- 44
|
||||||
|
- {label: "45: strapping pin", value: 45}
|
||||||
|
- {label: "46: strapping pin", value: 46}
|
||||||
|
- 47
|
||||||
|
- 48
|
||||||
|
|
||||||
|
|
||||||
- &gpioinput
|
- &gpioinput
|
||||||
type: dropdown
|
type: dropdown
|
||||||
resource: "gpio:"
|
resource: "gpio:"
|
||||||
@@ -275,12 +320,39 @@ types:
|
|||||||
|
|
||||||
- &protogpio
|
- &protogpio
|
||||||
- {label: unset,value:}
|
- {label: unset,value:}
|
||||||
- PPIN19
|
- {label: "PPIN19(left-2,gpio 19)", value: PPIN19}
|
||||||
- PPIN21
|
- {label: "PPIN21(right-1,gpio 21)", value: PPIN21}
|
||||||
- PPIN22
|
- {label: "PPIN22(left-1,gpio 22)", value: PPIN22}
|
||||||
- PPIN23
|
- {label: "PPIN23(left-3,gpio 23)", value: PPIN23}
|
||||||
- PPIN25
|
- {label: "PPIN25(right-2,gpio 25)", value: PPIN25}
|
||||||
- PPIN33
|
- {label: "PPIN33(left-4,gpio 33)", value: PPIN33}
|
||||||
|
|
||||||
|
- &protogpios3
|
||||||
|
- {label: unset,value:}
|
||||||
|
- {label: "PPIN19(left-2,gpio 6)", value: PPIN19}
|
||||||
|
- {label: "PPIN21(right-1,gpio 39)", value: PPIN21}
|
||||||
|
- {label: "PPIN22(left-1,gpio 5)", value: PPIN22}
|
||||||
|
- {label: "PPIN23(left-3,gpio 7)", value: PPIN23}
|
||||||
|
- {label: "PPIN25(right-2,gpio 38)", value: PPIN25}
|
||||||
|
- {label: "PPIN33(left-4,gpio 8)", value: PPIN33}
|
||||||
|
|
||||||
|
- &baudselect
|
||||||
|
type: dropdown
|
||||||
|
help: 'Select the baud rate'
|
||||||
|
values:
|
||||||
|
- {label: unset,value:}
|
||||||
|
- 1200
|
||||||
|
- 2400
|
||||||
|
- 4800
|
||||||
|
- 9600
|
||||||
|
- 14400
|
||||||
|
- 19200
|
||||||
|
- 28800
|
||||||
|
- 38400
|
||||||
|
- 57600
|
||||||
|
- 115200
|
||||||
|
- 230400
|
||||||
|
- 460800
|
||||||
|
|
||||||
- &serialRX
|
- &serialRX
|
||||||
<<: *gpioinput
|
<<: *gpioinput
|
||||||
@@ -294,6 +366,33 @@ types:
|
|||||||
help: 'number of the GPIO pin for the transmit function'
|
help: 'number of the GPIO pin for the transmit function'
|
||||||
target: "define:#serial#TX"
|
target: "define:#serial#TX"
|
||||||
mandatory: true
|
mandatory: true
|
||||||
|
- &serialEnablePin
|
||||||
|
<<: *gpiopin
|
||||||
|
key: ENA
|
||||||
|
label: "enable pin"
|
||||||
|
help: "GPIO pin for output enable"
|
||||||
|
target: "define:#serial#ENA"
|
||||||
|
mandatory: false
|
||||||
|
- &serialEnableLow
|
||||||
|
type: checkbox
|
||||||
|
key: ELOW
|
||||||
|
label: "enable low"
|
||||||
|
target: "define:#serial#ELO"
|
||||||
|
default: false
|
||||||
|
help: "set: low on enable pin for output, unset: high on enable pin for output"
|
||||||
|
values:
|
||||||
|
- key: true
|
||||||
|
value: 1
|
||||||
|
- key: false
|
||||||
|
value: 0
|
||||||
|
|
||||||
|
- &serialFixedBaud
|
||||||
|
<<: *baudselect
|
||||||
|
key: fixedBaud
|
||||||
|
label: "fixed baud"
|
||||||
|
help: "you can set a fixed baud rate here, this disables changing the baud rate in the UI"
|
||||||
|
target: "define:#serial#BAUD"
|
||||||
|
|
||||||
- &serialValues
|
- &serialValues
|
||||||
- key: true
|
- key: true
|
||||||
children:
|
children:
|
||||||
@@ -310,6 +409,9 @@ types:
|
|||||||
children:
|
children:
|
||||||
- *serialRX
|
- *serialRX
|
||||||
- *serialTX
|
- *serialTX
|
||||||
|
- *serialEnablePin
|
||||||
|
- *serialEnableLow
|
||||||
|
- *serialFixedBaud
|
||||||
- key: bi
|
- key: bi
|
||||||
value: 2
|
value: 2
|
||||||
label: "BiDir"
|
label: "BiDir"
|
||||||
@@ -318,18 +420,25 @@ types:
|
|||||||
children:
|
children:
|
||||||
- *serialRX
|
- *serialRX
|
||||||
- *serialTX
|
- *serialTX
|
||||||
|
- *serialFixedBaud
|
||||||
- key: rx
|
- key: rx
|
||||||
value: 3
|
value: 3
|
||||||
label: "RX"
|
label: "RX"
|
||||||
description: "Input only"
|
description: "Input only"
|
||||||
children:
|
children:
|
||||||
- *serialRX
|
- *serialRX
|
||||||
|
- *serialEnablePin
|
||||||
|
- *serialEnableLow
|
||||||
|
- *serialFixedBaud
|
||||||
- key: tx
|
- key: tx
|
||||||
value: 1
|
value: 1
|
||||||
label: "TX"
|
label: "TX"
|
||||||
description: "output only"
|
description: "output only"
|
||||||
children:
|
children:
|
||||||
- *serialTX
|
- *serialTX
|
||||||
|
- *serialEnablePin
|
||||||
|
- *serialEnableLow
|
||||||
|
- *serialFixedBaud
|
||||||
- &serial1
|
- &serial1
|
||||||
type: checkbox
|
type: checkbox
|
||||||
label: 'Serial 1'
|
label: 'Serial 1'
|
||||||
@@ -664,13 +773,18 @@ types:
|
|||||||
label: "Gps Base"
|
label: "Gps Base"
|
||||||
url: "https://docs.m5stack.com/en/atom/atomicgps"
|
url: "https://docs.m5stack.com/en/atom/atomicgps"
|
||||||
resource: serial
|
resource: serial
|
||||||
|
- value: M5_GPSV2_KIT
|
||||||
|
description: "M5 Stack Gps Base v2.0"
|
||||||
|
label: "Gps Base"
|
||||||
|
url: "https://docs.m5stack.com/en/atom/Atomic_GPS_Base_v2.0"
|
||||||
|
resource: serial
|
||||||
- value: M5_PROTO_HUB
|
- value: M5_PROTO_HUB
|
||||||
description: "M5 Stack HUB PROTO"
|
description: "M5 Stack HUB PROTO"
|
||||||
url: "https://docs.m5stack.com/en/atom/atomhub"
|
url: "https://docs.m5stack.com/en/atom/atomhub"
|
||||||
label: "Hub Proto"
|
label: "Hub Proto"
|
||||||
base:
|
base:
|
||||||
gpioinputv: *protogpio
|
gpioinputv: "#protogpio#"
|
||||||
gpiopinv: *protogpio
|
gpiopinv: "#protogpio#"
|
||||||
children:
|
children:
|
||||||
*m5protochildren
|
*m5protochildren
|
||||||
- value: M5_PORTABC
|
- value: M5_PORTABC
|
||||||
@@ -689,6 +803,13 @@ resources:
|
|||||||
|
|
||||||
config:
|
config:
|
||||||
children:
|
children:
|
||||||
|
- type: string
|
||||||
|
label: 'Build Name'
|
||||||
|
key: buildname
|
||||||
|
target: "define:GWBUILD_NAME"
|
||||||
|
help: "Set a name to identify your build. Will also become the name for the generated files and the firmware type in the image. Max 31 characters."
|
||||||
|
max: 31
|
||||||
|
allowed: "0-9A-Za-z_-"
|
||||||
- type: select
|
- type: select
|
||||||
target: environment
|
target: environment
|
||||||
label: 'Board'
|
label: 'Board'
|
||||||
@@ -697,6 +818,7 @@ config:
|
|||||||
gpiopinv: *gpiopinv
|
gpiopinv: *gpiopinv
|
||||||
gpioinputv: *gpioinputv
|
gpioinputv: *gpioinputv
|
||||||
grv: ""
|
grv: ""
|
||||||
|
protogpio: *protogpio
|
||||||
values:
|
values:
|
||||||
- value: m5stack-atom-generic
|
- value: m5stack-atom-generic
|
||||||
label: m5stack-atom
|
label: m5stack-atom
|
||||||
@@ -711,6 +833,8 @@ config:
|
|||||||
description: "M5 Stack AtomS3 light"
|
description: "M5 Stack AtomS3 light"
|
||||||
url: "http://docs.m5stack.com/en/core/AtomS3%20Lite"
|
url: "http://docs.m5stack.com/en/core/AtomS3%20Lite"
|
||||||
resource: *esp32default
|
resource: *esp32default
|
||||||
|
base:
|
||||||
|
protogpio: *protogpios3
|
||||||
children:
|
children:
|
||||||
- *m5base
|
- *m5base
|
||||||
- *m5groove
|
- *m5groove
|
||||||
@@ -725,7 +849,7 @@ config:
|
|||||||
|
|
||||||
- value: nodemcu-generic
|
- value: nodemcu-generic
|
||||||
label: nodemcu
|
label: nodemcu
|
||||||
description: "Node mcu esp32"
|
description: "Node mcu esp32,4MB flash, no PSRAM"
|
||||||
url: "https://docs.platformio.org/en/stable/boards/espressif32/nodemcu-32s.html"
|
url: "https://docs.platformio.org/en/stable/boards/espressif32/nodemcu-32s.html"
|
||||||
resource: *esp32default
|
resource: *esp32default
|
||||||
children:
|
children:
|
||||||
@@ -750,3 +874,35 @@ config:
|
|||||||
base:
|
base:
|
||||||
busname: "2"
|
busname: "2"
|
||||||
bus: "2"
|
bus: "2"
|
||||||
|
|
||||||
|
- value: s3devkitm-generic
|
||||||
|
label: s3devkitm
|
||||||
|
description: "esp32 s3 generic, 8MB flash, no PSRAM "
|
||||||
|
url: "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/esp32s3/user-guide-devkitm-1.html"
|
||||||
|
resource: *esp32default
|
||||||
|
base:
|
||||||
|
gpiopinv: *gpiopinvs3
|
||||||
|
gpioinputv: *gpiopinvs3
|
||||||
|
protogpio: *protogpios3
|
||||||
|
children:
|
||||||
|
- *serial1
|
||||||
|
- *serial2
|
||||||
|
- *can
|
||||||
|
- *resetButton
|
||||||
|
- *led
|
||||||
|
- <<: *iicsensors
|
||||||
|
base:
|
||||||
|
busname: "1"
|
||||||
|
bus: ""
|
||||||
|
- <<: *iicsensors
|
||||||
|
base:
|
||||||
|
busname: "2"
|
||||||
|
bus: "2"
|
||||||
|
- <<: *spisensors
|
||||||
|
base:
|
||||||
|
busname: "1"
|
||||||
|
bus: "1"
|
||||||
|
- <<: *spisensors
|
||||||
|
base:
|
||||||
|
busname: "2"
|
||||||
|
bus: "2"
|
||||||
@@ -167,9 +167,18 @@ class PipelineInfo{
|
|||||||
updateStatus();
|
updateStatus();
|
||||||
if (gitSha !== undefined) param.tag=gitSha;
|
if (gitSha !== undefined) param.tag=gitSha;
|
||||||
param.config=JSON.stringify(config);
|
param.config=JSON.stringify(config);
|
||||||
|
let buildname=config['root:buildname']
|
||||||
|
if (buildname){
|
||||||
|
param.suffix="-"+buildname
|
||||||
|
}
|
||||||
if (buildVersion !== undefined){
|
if (buildVersion !== undefined){
|
||||||
|
if (param.suffix){
|
||||||
|
param.suffix+="-"+buildVersion;
|
||||||
|
}
|
||||||
|
else{
|
||||||
param.suffix="-"+buildVersion;
|
param.suffix="-"+buildVersion;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fetchJson(API,Object.assign({
|
fetchJson(API,Object.assign({
|
||||||
api:'start'},param))
|
api:'start'},param))
|
||||||
.then((json)=>{
|
.then((json)=>{
|
||||||
@@ -234,7 +243,11 @@ class PipelineInfo{
|
|||||||
}
|
}
|
||||||
const downloadConfig=()=>{
|
const downloadConfig=()=>{
|
||||||
let name=configName;
|
let name=configName;
|
||||||
if (isModified) name=name.replace(/[0-9]*$/,'')+formatDate(undefined,true);
|
const buildname=config["root:buildname"]
|
||||||
|
if (buildname && name != buildname){
|
||||||
|
name+="-"+buildname+"-";
|
||||||
|
}
|
||||||
|
name=name.replace(/[0-9]*$/,'')+formatDate(undefined,true);
|
||||||
name+=".json";
|
name+=".json";
|
||||||
fileDownload(JSON.stringify(config),name);
|
fileDownload(JSON.stringify(config),name);
|
||||||
}
|
}
|
||||||
@@ -521,6 +534,38 @@ class PipelineInfo{
|
|||||||
addDescription(config,inputFrame);
|
addDescription(config,inputFrame);
|
||||||
initialConfig=expandedValues[0];
|
initialConfig=expandedValues[0];
|
||||||
}
|
}
|
||||||
|
if (config.type === 'string'){
|
||||||
|
let ip=addEl('input','t'+config.type,inputFrame);
|
||||||
|
addDescription(config,inputFrame);
|
||||||
|
const buildChild=(value)=>{
|
||||||
|
if (value) {
|
||||||
|
if (config.max) {
|
||||||
|
if (value && value.length > config.max) {
|
||||||
|
value = value.substring(0, config.max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.allowed) {
|
||||||
|
let check = new RegExp("[^" + config.allowed + "]", "g");
|
||||||
|
let nv = value.replace(check, "");
|
||||||
|
if (nv != value) {
|
||||||
|
value = nv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Object.assign({},config,{key: value,value:value});
|
||||||
|
}
|
||||||
|
initialConfig=buildChild(current);
|
||||||
|
ip.value=initialConfig.value||"";
|
||||||
|
ip.addEventListener('change',(ev)=>{
|
||||||
|
let value=ev.target.value;
|
||||||
|
let cbv=buildChild(value);
|
||||||
|
if (cbv.value != value){
|
||||||
|
ev.target.value=cbv.value;
|
||||||
|
}
|
||||||
|
callback(cbv,false);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
let childFrame=addEl('div','childFrame',frame);
|
let childFrame=addEl('div','childFrame',frame);
|
||||||
if (initialConfig !== undefined){
|
if (initialConfig !== undefined){
|
||||||
callback(initialConfig,true,childFrame);
|
callback(initialConfig,true,childFrame);
|
||||||
|
|||||||
1
webinstall/config/m5stack-atom-gps_v2-canunit.json
Normal file
1
webinstall/config/m5stack-atom-gps_v2-canunit.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"root:board":"m5stack-atom-generic","root:board:m5lightbase":"M5_GPSV2_KIT","root:board:m5groove":"CAN","root:board:m5groove:m5groovecan":"M5_CANUNIT"}
|
||||||
Reference in New Issue
Block a user