Merge branch 'master' of https://github.com/wellenvogel/esp32-nmea2000 into feature/env2
This commit is contained in:
commit
48a4142438
|
@ -1,4 +1,256 @@
|
|||
#include "GwBoatData.h"
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
#define GWTYPE_DOUBLE 1
|
||||
#define GWTYPE_UINT32 2
|
||||
#define GWTYPE_UINT16 3
|
||||
#define GWTYPE_INT16 4
|
||||
#define GWTYPE_USER 100
|
||||
class GwBoatItemTypes{
|
||||
public:
|
||||
static int getType(const uint32_t &x){return GWTYPE_UINT32;}
|
||||
static int getType(const uint16_t &x){return GWTYPE_UINT16;}
|
||||
static int getType(const int16_t &x){return GWTYPE_INT16;}
|
||||
static int getType(const double &x){return GWTYPE_DOUBLE;}
|
||||
static int getType(const GwSatInfoList &x){ return GWTYPE_USER+1;}
|
||||
};
|
||||
|
||||
bool GwBoatItemBase::isValid(unsigned long now) const
|
||||
{
|
||||
if (lastSet == 0)
|
||||
return false;
|
||||
if (invalidTime == 0)
|
||||
return true;
|
||||
if (now == 0)
|
||||
now = millis();
|
||||
return (lastSet + invalidTime) >= now;
|
||||
}
|
||||
GwBoatItemBase::GwBoatItemBase(String name, String format, unsigned long invalidTime)
|
||||
{
|
||||
lastSet = 0;
|
||||
this->invalidTime = invalidTime;
|
||||
this->name = name;
|
||||
this->format = format;
|
||||
this->type = 0;
|
||||
this->lastUpdateSource=-1;
|
||||
}
|
||||
#define STRING_SIZE 40
|
||||
GwBoatItemBase::StringWriter::StringWriter(){
|
||||
buffer=new uint8_t[STRING_SIZE];
|
||||
wp=buffer;
|
||||
bufferSize=STRING_SIZE;
|
||||
buffer [0]=0;
|
||||
};
|
||||
const char *GwBoatItemBase::StringWriter::c_str() const{
|
||||
return (const char *)buffer;
|
||||
}
|
||||
int GwBoatItemBase::StringWriter::getSize() const{
|
||||
return wp-buffer;
|
||||
}
|
||||
void GwBoatItemBase::StringWriter::reset(){
|
||||
wp=buffer;
|
||||
*wp=0;
|
||||
}
|
||||
void GwBoatItemBase::StringWriter::ensure(size_t size){
|
||||
size_t fill=wp-buffer;
|
||||
size_t newSize=bufferSize;
|
||||
while ((fill+size) >= (newSize-1) ){
|
||||
newSize+=STRING_SIZE;
|
||||
}
|
||||
if (newSize != bufferSize){
|
||||
uint8_t *newBuffer=new uint8_t[newSize];
|
||||
memcpy(newBuffer,buffer,fill);
|
||||
newBuffer[fill]=0;
|
||||
delete buffer;
|
||||
buffer=newBuffer;
|
||||
wp=newBuffer+fill;
|
||||
bufferSize=newSize;
|
||||
}
|
||||
}
|
||||
size_t GwBoatItemBase::StringWriter::write(uint8_t c){
|
||||
ensure(1);
|
||||
*wp=c;
|
||||
wp++;
|
||||
*wp=0;
|
||||
return 1;
|
||||
}
|
||||
size_t GwBoatItemBase::StringWriter::write(const uint8_t* s, size_t n){
|
||||
ensure(n);
|
||||
memcpy(wp,s,n);
|
||||
wp+=n;
|
||||
*wp=0;
|
||||
return n;
|
||||
}
|
||||
template<class T> GwBoatItem<T>::GwBoatItem(String name,String formatInfo,unsigned long invalidTime,GwBoatItemMap *map):
|
||||
GwBoatItemBase(name,formatInfo,invalidTime){
|
||||
T dummy;
|
||||
this->type=GwBoatItemTypes::getType(dummy);
|
||||
if (map){
|
||||
(*map)[name]=this;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GwBoatItem<T>::update(T nv, int source)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
if (isValid(now))
|
||||
{
|
||||
//priority handling
|
||||
//sources with lower ids will win
|
||||
//and we will not overwrite their value
|
||||
if (lastUpdateSource < source && lastUpdateSource >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
data = nv;
|
||||
lastUpdateSource = source;
|
||||
uls(now);
|
||||
return true;
|
||||
}
|
||||
template <class T>
|
||||
bool GwBoatItem<T>::updateMax(T nv, int sourceId)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
if (!isValid(now))
|
||||
{
|
||||
return update(nv, sourceId);
|
||||
}
|
||||
if (getData() < nv)
|
||||
{
|
||||
data = nv;
|
||||
lastUpdateSource = sourceId;
|
||||
uls(now);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
void GwBoatItem<T>::toJsonDoc(JsonDocument *doc, unsigned long minTime)
|
||||
{
|
||||
JsonObject o = doc->createNestedObject(name);
|
||||
o[F("value")] = getData();
|
||||
o[F("update")] = minTime - lastSet;
|
||||
o[F("source")] = lastUpdateSource;
|
||||
o[F("valid")] = isValid(minTime);
|
||||
o[F("format")] = format;
|
||||
}
|
||||
|
||||
|
||||
class WriterWrapper{
|
||||
GwBoatItemBase::StringWriter *writer=NULL;
|
||||
public:
|
||||
WriterWrapper(GwBoatItemBase::StringWriter *w){
|
||||
writer=w;
|
||||
}
|
||||
size_t write(uint8_t c){
|
||||
if (! writer) return 0;
|
||||
return writer->write(c);
|
||||
}
|
||||
size_t write(const uint8_t* s, size_t n){
|
||||
if (! writer) return 0;
|
||||
return writer->write(s,n);
|
||||
}
|
||||
};
|
||||
typedef ARDUINOJSON_NAMESPACE::TextFormatter<WriterWrapper> GwTextWriter;
|
||||
|
||||
static void writeToString(GwTextWriter *writer,const double &value){
|
||||
writer->writeFloat(value);
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer,const uint16_t &value){
|
||||
writer->writeInteger(value);
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer,const uint32_t &value){
|
||||
writer->writeInteger(value);
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer,const int16_t &value){
|
||||
writer->writeInteger(value);
|
||||
}
|
||||
static void writeToString(GwTextWriter *writer,GwSatInfoList &value){
|
||||
writer->writeInteger(value.getNumSats());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void GwBoatItem<T>::fillString(){
|
||||
bool valid=isValid();
|
||||
if (writer.getSize() && (valid == lastStringValid)) return;
|
||||
lastStringValid=valid;
|
||||
writer.reset();
|
||||
WriterWrapper wrapper(&writer);
|
||||
GwTextWriter stringWriter(wrapper);
|
||||
stringWriter.writeRaw(name.c_str());
|
||||
stringWriter.writeChar(',');
|
||||
stringWriter.writeInteger(valid?1:0);
|
||||
stringWriter.writeChar(',');
|
||||
stringWriter.writeInteger(lastSet);
|
||||
stringWriter.writeChar(',');
|
||||
stringWriter.writeInteger(lastUpdateSource);
|
||||
stringWriter.writeChar(',');
|
||||
stringWriter.writeRaw(format.c_str());
|
||||
stringWriter.writeChar(',');
|
||||
writeToString(&stringWriter,data);
|
||||
}
|
||||
|
||||
template class GwBoatItem<double>;
|
||||
template class GwBoatItem<uint32_t>;
|
||||
template class GwBoatItem<uint16_t>;
|
||||
template class GwBoatItem<int16_t>;
|
||||
void GwSatInfoList::houseKeeping(unsigned long ts)
|
||||
{
|
||||
if (ts == 0)
|
||||
ts = millis();
|
||||
sats.erase(std::remove_if(
|
||||
sats.begin(),
|
||||
sats.end(),
|
||||
[ts, this](const GwSatInfo &info)
|
||||
{
|
||||
return (info.timestamp + lifeTime) < ts;
|
||||
}),
|
||||
sats.end());
|
||||
}
|
||||
void GwSatInfoList::update(GwSatInfo entry)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
entry.timestamp = now;
|
||||
for (auto it = sats.begin(); it != sats.end(); it++)
|
||||
{
|
||||
if (it->PRN == entry.PRN)
|
||||
{
|
||||
*it = entry;
|
||||
houseKeeping();
|
||||
return;
|
||||
}
|
||||
}
|
||||
houseKeeping();
|
||||
sats.push_back(entry);
|
||||
}
|
||||
|
||||
GwBoatDataSatList::GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime , GwBoatItemMap *map) :
|
||||
GwBoatItem<GwSatInfoList>(name, formatInfo, invalidTime, map) {}
|
||||
|
||||
bool GwBoatDataSatList::update(GwSatInfo info, int source)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
if (isValid(now))
|
||||
{
|
||||
//priority handling
|
||||
//sources with lower ids will win
|
||||
//and we will not overwrite their value
|
||||
if (lastUpdateSource < source)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lastUpdateSource = source;
|
||||
uls(now);
|
||||
data.update(info);
|
||||
return true;
|
||||
}
|
||||
void GwBoatDataSatList::toJsonDoc(JsonDocument *doc, unsigned long minTime)
|
||||
{
|
||||
data.houseKeeping();
|
||||
GwBoatItem<GwSatInfoList>::toJsonDoc(doc, minTime);
|
||||
}
|
||||
|
||||
GwBoatData::GwBoatData(GwLog *logger){
|
||||
this->logger=logger;
|
||||
|
@ -23,7 +275,7 @@ template<class T> GwBoatItem<T> *GwBoatData::getOrCreate(T initial, GwBoatItemNa
|
|||
}
|
||||
return (GwBoatItem<T>*)(it->second);
|
||||
}
|
||||
GwBoatItem<T> *rt=new GwBoatItem<T>(GwBoatItemTypes::getType(initial), name,
|
||||
GwBoatItem<T> *rt=new GwBoatItem<T>(name,
|
||||
provider->getBoatItemFormat(),
|
||||
provider->getInvalidTime(),
|
||||
&values);
|
||||
|
@ -65,7 +317,14 @@ String GwBoatData::toJson() const {
|
|||
serializeJson(json,buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
String GwBoatData::toString(){
|
||||
String rt;
|
||||
for (auto it=values.begin() ; it != values.end();it++){
|
||||
rt+=it->second->getDataString();
|
||||
rt+="\n";
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
double formatCourse(double cv)
|
||||
{
|
||||
double rt = cv * 180.0 / M_PI;
|
||||
|
@ -101,4 +360,19 @@ double mtr2nm(double m)
|
|||
|
||||
bool convertToJson(const GwSatInfoList &si,JsonVariant &variant){
|
||||
return variant.set(si.getNumSats());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _UNDEF
|
||||
#include <ArduinoJson/Json/TextFormatter.hpp>
|
||||
|
||||
class XWriter{
|
||||
public:
|
||||
void write(uint8_t c) {
|
||||
}
|
||||
|
||||
void write(const uint8_t* s, size_t n) {
|
||||
}
|
||||
};
|
||||
static XWriter xwriter;
|
||||
ARDUINOJSON_NAMESPACE::TextFormatter<XWriter> testWriter(xwriter);
|
||||
#endif
|
|
@ -7,20 +7,22 @@
|
|||
#include <map>
|
||||
#define GW_BOAT_VALUE_LEN 32
|
||||
#define GWSC(name) static constexpr const __FlashStringHelper* name=F(#name)
|
||||
#define GWTYPE_DOUBLE 1
|
||||
#define GWTYPE_UINT32 2
|
||||
#define GWTYPE_UINT16 3
|
||||
#define GWTYPE_INT16 4
|
||||
#define GWTYPE_USER 100
|
||||
class GwBoatItemTypes{
|
||||
public:
|
||||
static int getType(const uint32_t &x){return GWTYPE_UINT32;}
|
||||
static int getType(const uint16_t &x){return GWTYPE_UINT16;}
|
||||
static int getType(const int16_t &x){return GWTYPE_INT16;}
|
||||
static int getType(const double &x){return GWTYPE_DOUBLE;}
|
||||
};
|
||||
|
||||
class GwBoatItemBase{
|
||||
public:
|
||||
class StringWriter{
|
||||
uint8_t *buffer =NULL;
|
||||
uint8_t *wp=NULL;
|
||||
size_t bufferSize=0;
|
||||
void ensure(size_t size);
|
||||
public:
|
||||
StringWriter();
|
||||
size_t write(uint8_t c);
|
||||
size_t write(const uint8_t* s, size_t n);
|
||||
const char * c_str() const;
|
||||
int getSize() const;
|
||||
void reset();
|
||||
};
|
||||
static const unsigned long INVALID_TIME=60000;
|
||||
//the formatter names that must be known in js
|
||||
GWSC(formatCourse);
|
||||
|
@ -42,33 +44,30 @@ class GwBoatItemBase{
|
|||
unsigned long invalidTime=INVALID_TIME;
|
||||
String name;
|
||||
String format;
|
||||
StringWriter writer;
|
||||
void uls(unsigned long ts=0){
|
||||
if (ts) lastSet=ts;
|
||||
else lastSet=millis();
|
||||
writer.reset(); //value has changed
|
||||
}
|
||||
int lastUpdateSource;
|
||||
public:
|
||||
int getCurrentType(){return type;}
|
||||
unsigned long getLastSet() const {return lastSet;}
|
||||
bool isValid(unsigned long now=0) const {
|
||||
if (lastSet == 0) return false;
|
||||
if (invalidTime == 0) return true;
|
||||
if (now == 0) now=millis();
|
||||
return (lastSet + invalidTime) >= now;
|
||||
}
|
||||
GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME){
|
||||
lastSet=0;
|
||||
this->invalidTime=invalidTime;
|
||||
this->name=name;
|
||||
this->format=format;
|
||||
this->type=0;
|
||||
}
|
||||
bool isValid(unsigned long now=0) const ;
|
||||
GwBoatItemBase(String name,String format,unsigned long invalidTime=INVALID_TIME);
|
||||
virtual ~GwBoatItemBase(){}
|
||||
void invalidate(){
|
||||
lastSet=0;
|
||||
}
|
||||
const char *getDataString(){
|
||||
fillString();
|
||||
return writer.c_str();
|
||||
}
|
||||
virtual void fillString()=0;
|
||||
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime)=0;
|
||||
virtual size_t getJsonSize(){return JSON_OBJECT_SIZE(10);}
|
||||
virtual int getLastSource()=0;
|
||||
virtual int getLastSource(){return lastUpdateSource;}
|
||||
virtual void refresh(unsigned long ts=0){uls(ts);}
|
||||
String getName(){return name;}
|
||||
};
|
||||
|
@ -76,45 +75,12 @@ class GwBoatData;
|
|||
template<class T> class GwBoatItem : public GwBoatItemBase{
|
||||
protected:
|
||||
T data;
|
||||
int lastUpdateSource;
|
||||
bool lastStringValid=false;
|
||||
public:
|
||||
GwBoatItem(int type,String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL):
|
||||
GwBoatItemBase(name,formatInfo,invalidTime){
|
||||
this->type=type;
|
||||
if (map){
|
||||
(*map)[name]=this;
|
||||
}
|
||||
lastUpdateSource=-1;
|
||||
}
|
||||
GwBoatItem(String name,String formatInfo,unsigned long invalidTime=INVALID_TIME,GwBoatItemMap *map=NULL);
|
||||
virtual ~GwBoatItem(){}
|
||||
bool update(T nv, int source=-1){
|
||||
unsigned long now=millis();
|
||||
if (isValid(now)){
|
||||
//priority handling
|
||||
//sources with lower ids will win
|
||||
//and we will not overwrite their value
|
||||
if (lastUpdateSource < source && lastUpdateSource >= 0){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
data=nv;
|
||||
lastUpdateSource=source;
|
||||
uls(now);
|
||||
return true;
|
||||
}
|
||||
bool updateMax(T nv,int sourceId=-1){
|
||||
unsigned long now=millis();
|
||||
if (! isValid(now)){
|
||||
return update(nv,sourceId);
|
||||
}
|
||||
if (getData() < nv){
|
||||
data=nv;
|
||||
lastUpdateSource=sourceId;
|
||||
uls(now);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool update(T nv, int source=-1);
|
||||
bool updateMax(T nv,int sourceId=-1);
|
||||
T getData(){
|
||||
return data;
|
||||
}
|
||||
|
@ -122,14 +88,8 @@ template<class T> class GwBoatItem : public GwBoatItemBase{
|
|||
if (! isValid(millis())) return defaultv;
|
||||
return data;
|
||||
}
|
||||
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime){
|
||||
JsonObject o=doc->createNestedObject(name);
|
||||
o[F("value")]=getData();
|
||||
o[F("update")]=minTime-lastSet;
|
||||
o[F("source")]=lastUpdateSource;
|
||||
o[F("valid")]=isValid(minTime);
|
||||
o[F("format")]=format;
|
||||
}
|
||||
virtual void fillString();
|
||||
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime);
|
||||
virtual int getLastSource(){return lastUpdateSource;}
|
||||
};
|
||||
double formatCourse(double cv);
|
||||
|
@ -151,29 +111,8 @@ class GwSatInfoList{
|
|||
public:
|
||||
static const unsigned long lifeTime=32000;
|
||||
std::vector<GwSatInfo> sats;
|
||||
void houseKeeping(unsigned long ts=0){
|
||||
if (ts == 0) ts=millis();
|
||||
sats.erase(std::remove_if(
|
||||
sats.begin(),
|
||||
sats.end(),
|
||||
[ts,this](const GwSatInfo &info){
|
||||
return (info.timestamp + lifeTime) < ts;
|
||||
}
|
||||
),sats.end());
|
||||
}
|
||||
void update(GwSatInfo entry){
|
||||
unsigned long now=millis();
|
||||
entry.timestamp=now;
|
||||
for (auto it=sats.begin();it!=sats.end();it++){
|
||||
if (it->PRN == entry.PRN){
|
||||
*it=entry;
|
||||
houseKeeping();
|
||||
return;
|
||||
}
|
||||
}
|
||||
houseKeeping();
|
||||
sats.push_back(entry);
|
||||
}
|
||||
void houseKeeping(unsigned long ts=0);
|
||||
void update(GwSatInfo entry);
|
||||
int getNumSats() const{
|
||||
return sats.size();
|
||||
}
|
||||
|
@ -183,34 +122,12 @@ class GwSatInfoList{
|
|||
}
|
||||
};
|
||||
|
||||
bool convertToJson(const GwSatInfoList &si,JsonVariant &variant);
|
||||
class GwBoatDataSatList : public GwBoatItem<GwSatInfoList>
|
||||
{
|
||||
public:
|
||||
GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL) :
|
||||
GwBoatItem<GwSatInfoList>(GWTYPE_USER+1, name, formatInfo, invalidTime, map) {}
|
||||
bool update(GwSatInfo info, int source)
|
||||
{
|
||||
unsigned long now = millis();
|
||||
if (isValid(now))
|
||||
{
|
||||
//priority handling
|
||||
//sources with lower ids will win
|
||||
//and we will not overwrite their value
|
||||
if (lastUpdateSource < source)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lastUpdateSource = source;
|
||||
uls(now);
|
||||
data.update(info);
|
||||
return true;
|
||||
}
|
||||
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime){
|
||||
data.houseKeeping();
|
||||
GwBoatItem<GwSatInfoList>::toJsonDoc(doc,minTime);
|
||||
}
|
||||
GwBoatDataSatList(String name, String formatInfo, unsigned long invalidTime = INVALID_TIME, GwBoatItemMap *map = NULL);
|
||||
bool update(GwSatInfo info, int source);
|
||||
virtual void toJsonDoc(JsonDocument *doc, unsigned long minTime);
|
||||
GwSatInfo *getAt(int idx){
|
||||
if (! isValid()) return NULL;
|
||||
return data.getAt(idx);
|
||||
|
@ -231,7 +148,7 @@ public:
|
|||
virtual ~GwBoatItemNameProvider() {}
|
||||
};
|
||||
#define GWBOATDATA(type,name,time,fmt) \
|
||||
GwBoatItem<type> *name=new GwBoatItem<type>(GwBoatItemTypes::getType((type)0),F(#name),GwBoatItemBase::fmt,time,&values) ;
|
||||
GwBoatItem<type> *name=new GwBoatItem<type>(F(#name),GwBoatItemBase::fmt,time,&values) ;
|
||||
#define GWSPECBOATDATA(clazz,name,time,fmt) \
|
||||
clazz *name=new clazz(F(#name),GwBoatItemBase::fmt,time,&values) ;
|
||||
class GwBoatData{
|
||||
|
@ -283,6 +200,7 @@ class GwBoatData{
|
|||
template<class T> bool update(T value,int source,GwBoatItemNameProvider *provider);
|
||||
template<class T> T getDataWithDefault(T defaultv, GwBoatItemNameProvider *provider);
|
||||
String toJson() const;
|
||||
String toString();
|
||||
};
|
||||
|
||||
|
||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -420,6 +420,17 @@ protected:
|
|||
result = boatData.toJson();
|
||||
}
|
||||
};
|
||||
class BoatDataStringRequest : public GwRequestMessage
|
||||
{
|
||||
public:
|
||||
BoatDataStringRequest() : GwRequestMessage(F("text/plain"),F("boatDataString")){};
|
||||
|
||||
protected:
|
||||
virtual void processRequest()
|
||||
{
|
||||
result = boatData.toString();
|
||||
}
|
||||
};
|
||||
|
||||
class XdrExampleRequest : public GwRequestMessage
|
||||
{
|
||||
|
@ -562,6 +573,8 @@ void setup() {
|
|||
{ return new ResetConfigRequest(); });
|
||||
webserver.registerMainHandler("/api/boatData", [](AsyncWebServerRequest *request)->GwRequestMessage *
|
||||
{ return new BoatDataRequest(); });
|
||||
webserver.registerMainHandler("/api/boatDataString", [](AsyncWebServerRequest *request)->GwRequestMessage *
|
||||
{ return new BoatDataStringRequest(); });
|
||||
webserver.registerMainHandler("/api/xdrExample", [](AsyncWebServerRequest *request)->GwRequestMessage *
|
||||
{
|
||||
String mapping=request->arg("mapping");
|
||||
|
|
57
web/index.js
57
web/index.js
|
@ -1035,6 +1035,7 @@ function resizeFont(el,reset,maxIt){
|
|||
}
|
||||
}
|
||||
function createDashboardItem(name, def, parent) {
|
||||
if (! def.name) return;
|
||||
let frame = addEl('div', 'dash', parent);
|
||||
let title = addEl('span', 'dashTitle', frame, name);
|
||||
let value = addEl('span', 'dashValue', frame);
|
||||
|
@ -1044,22 +1045,35 @@ function createDashboardItem(name, def, parent) {
|
|||
let footer = addEl('div','footer',frame);
|
||||
let src= addEl('span','source',footer);
|
||||
src.setAttribute('id','source_'+name);
|
||||
let u=fmt?fmt.u:'';
|
||||
if (! fmt && def.format.match(/formatXdr/)){
|
||||
let u=fmt?fmt.u:' ';
|
||||
if (! fmt && def.format && def.format.match(/formatXdr/)){
|
||||
u=def.format.replace(/formatXdr/,'');
|
||||
}
|
||||
addEl('span','unit',footer,u);
|
||||
return value;
|
||||
}
|
||||
function parseBoatDataLine(line){
|
||||
let rt={};
|
||||
let parts=line.split(',');
|
||||
rt.name=parts[0];
|
||||
rt.valid=parts[1] === '1';
|
||||
rt.update=parseInt(parts[2]);
|
||||
rt.source=parseInt(parts[3]);
|
||||
rt.format=parts[4];
|
||||
rt.value=parts[5];
|
||||
return rt;
|
||||
}
|
||||
function createDashboard() {
|
||||
let frame = document.getElementById('dashboardPage');
|
||||
if (!frame) return;
|
||||
getJson("api/boatData").then(function (json) {
|
||||
getText("api/boatDataString").then(function (txt) {
|
||||
frame.innerHTML = '';
|
||||
for (let n in json) {
|
||||
createDashboardItem(n, json[n], frame);
|
||||
let values=txt.split('\n');
|
||||
for (let n in values) {
|
||||
let def=parseBoatDataLine(values[n]);
|
||||
createDashboardItem(def.name, def, frame);
|
||||
}
|
||||
updateDashboard(json);
|
||||
updateDashboard(values);
|
||||
});
|
||||
}
|
||||
function sourceName(v){
|
||||
|
@ -1071,30 +1085,34 @@ function sourceName(v){
|
|||
}
|
||||
function updateDashboard(data) {
|
||||
let frame = document.getElementById('dashboardPage');
|
||||
let names={};
|
||||
for (let n in data) {
|
||||
let de = document.getElementById('data_' + n);
|
||||
let current=parseBoatDataLine(data[n]);
|
||||
if (! current.name) continue;
|
||||
names[current.name]=true;
|
||||
let de = document.getElementById('data_' + current.name);
|
||||
if (! de && frame){
|
||||
de=createDashboardItem(n,data[n],frame);
|
||||
de=createDashboardItem(current.name,current,frame);
|
||||
}
|
||||
if (de) {
|
||||
let newContent='----';
|
||||
if (data[n].valid) {
|
||||
if (current.valid) {
|
||||
let formatter;
|
||||
if (data[n].format && data[n].format != "NULL") {
|
||||
let key = data[n].format.replace(/^\&/, '');
|
||||
if (current.format && current.format != "NULL") {
|
||||
let key = current.format.replace(/^\&/, '');
|
||||
formatter = valueFormatters[key];
|
||||
}
|
||||
if (formatter) {
|
||||
newContent = formatter.f(data[n].value);
|
||||
newContent = formatter.f(current.value);
|
||||
}
|
||||
else {
|
||||
let v = parseFloat(data[n].value);
|
||||
let v = parseFloat(current.value);
|
||||
if (!isNaN(v)) {
|
||||
v = v.toFixed(3)
|
||||
newContent = v;
|
||||
}
|
||||
else {
|
||||
newContent = data[n].value;
|
||||
newContent = current.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1104,15 +1122,16 @@ function updateDashboard(data) {
|
|||
resizeFont(de,true);
|
||||
}
|
||||
}
|
||||
let src=document.getElementById('source_'+n);
|
||||
let src=document.getElementById('source_'+current.name);
|
||||
if (src){
|
||||
src.textContent=sourceName(data[n].source);
|
||||
src.textContent=sourceName(current.source);
|
||||
}
|
||||
}
|
||||
console.log("update");
|
||||
forEl('.dashValue',function(el){
|
||||
let id=el.getAttribute('id');
|
||||
if (id){
|
||||
if (! data[id.replace(/^data_/,'')]){
|
||||
if (! names[id.replace(/^data_/,'')]){
|
||||
el.parentElement.remove();
|
||||
}
|
||||
}
|
||||
|
@ -1123,8 +1142,8 @@ window.setInterval(update, 1000);
|
|||
window.setInterval(function () {
|
||||
let dp = document.getElementById('dashboardPage');
|
||||
if (dp.classList.contains('hidden')) return;
|
||||
getJson('api/boatData').then(function (data) {
|
||||
updateDashboard(data);
|
||||
getText('api/boatDataString').then(function (data) {
|
||||
updateDashboard(data.split('\n'));
|
||||
});
|
||||
}, 1000);
|
||||
window.addEventListener('load', function () {
|
||||
|
|
Loading…
Reference in New Issue