1
0
mirror of https://github.com/thooge/esp32-nmea2000-obp60.git synced 2025-12-13 05:53:06 +01:00

intermediate: xdr mappings

This commit is contained in:
wellenvogel
2021-11-20 11:20:49 +01:00
parent fbc955cd53
commit d927861cdf
4 changed files with 361 additions and 129 deletions

View File

@@ -1,100 +1,183 @@
#include "GwXDRMappings.h"
#include "N2kMessages.h"
double PtoBar(double v){
if (N2kIsNA(v)) return v;
return v/100000L;
double PtoBar(double v)
{
if (N2kIsNA(v))
return v;
return v / 100000L;
}
double BarToP(double v){
if (N2kIsNA(v)) return v;
return v*100000L;
double BarToP(double v)
{
if (N2kIsNA(v))
return v;
return v * 100000L;
}
GwXDRType * types[]={
new GwXDRType(GwXDRType::PRESS,"P","P"),
new GwXDRType(GwXDRType::PRESS,"P","B",
PtoBar,
BarToP),
new GwXDRType(GwXDRType::VOLT,"U","V"),
new GwXDRType(GwXDRType::AMP,"I","A"),
NULL
};
double ltrTom3(double v)
{
if (N2kIsNA(v))
return v;
return v / 1000.0;
}
double m3ToL(double v)
{
if (N2kIsNA(v))
return v;
return v * 1000.0;
}
double ph2ps(double v)
{
if (N2kIsNA(v))
return v;
return v * 3600.0;
}
double ps2ph(double v)
{
if (N2kIsNA(v))
return v;
return v / 3600.0;
}
//https://www.nmea.org/Assets/20190916%20Standards%20Update%20NMEA%20Conferencev2.pdf
GwXDRType *types[] = {
new GwXDRType(GwXDRType::PRESS, "P", "P"),
new GwXDRType(GwXDRType::PRESS, "P", "B",
PtoBar,
BarToP),
new GwXDRType(GwXDRType::VOLT, "U", "V"),
new GwXDRType(GwXDRType::AMP, "I", "A"),
new GwXDRType(GwXDRType::TEMP, "C", "K"),
new GwXDRType(GwXDRType::TEMP, "C", "C", CToKelvin, KelvinToC),
new GwXDRType(GwXDRType::HUMID, "H", "P"), //percent
new GwXDRType(GwXDRType::VOLPERCENT, "V", "P"),
new GwXDRType(GwXDRType::VOLUME, "V", "M", m3ToL, ltrTom3),
new GwXDRType(GwXDRType::FLOW, "R", "I", ps2ph, ph2ps),
//important to have 2x NULL!
NULL,
NULL};
static GwXDRType *findType(GwXDRType::TypeCode type, int *start = NULL)
{
int from = 0;
if (start != NULL)
from = *start;
if (types[from] == NULL)
return NULL;
int i = from;
for (; types[i] != NULL; i++)
{
if (types[i]->code == type)
{
if (start != NULL)
*start = i + 1;
return types[i];
}
}
if (start != NULL)
*start = i;
return NULL;
}
String GwXDRMappingDef::toString(){
String rt="";
rt+=String((int)category);
rt+=",";
rt+=String((int)direction);
rt+=",";
rt+=String(selector);
rt+=",";
rt+=String(field);
rt+=",";
rt+=String(instanceMode);
rt+=",";
rt+=String(instanceId);
#include "GwXdrTypeMappings.h"
static GwXDRType::TypeCode findTypeMapping(GwXDRCategory category, int field)
{
for (int i = 0; typeMappings[i] != NULL; i++)
{
if (typeMappings[i]->fieldIndex == field &&
typeMappings[i]->category == category)
{
return typeMappings[i]->type;
}
}
return GwXDRType::UNKNOWN;
}
String GwXDRMappingDef::toString()
{
String rt = "";
rt += String((int)category);
rt += ",";
rt += String((int)direction);
rt += ",";
rt += String(selector);
rt += ",";
rt += String(field);
rt += ",";
rt += String(instanceMode);
rt += ",";
rt += String(instanceId);
return rt;
}
bool GwXDRMappingDef::handleToken(String tok,int index,GwXDRMappingDef *def){
switch(index){
bool GwXDRMappingDef::handleToken(String tok, int index, GwXDRMappingDef *def)
{
switch (index)
{
int i;
case 0:
//category
i=tok.toInt();
if (i< XDRTEMP || i > XDRENGINE) return false;
def->category=(GwXDRCategory)i;
return true;
case 1:
//direction
i=tok.toInt();
if (i < GwXDRMappingDef::M_DISABLED ||
i>= GwXDRMappingDef::M_LAST) return false;
def->direction=(GwXDRMappingDef::Direction)i;
return true;
case 2:
//selector
//TODO: check selector?
i=tok.toInt();
def->selector=i;
return true;
case 3:
//field
i=tok.toInt();
def->field=i;
return true;
case 4:
//instance mode
i=tok.toInt();
if (i < GwXDRMappingDef::IS_SINGLE ||
i>= GwXDRMappingDef::IS_LAST) return false;
def->instanceMode=(GwXDRMappingDef::InstanceMode)i;
return true;
case 5:
//instance id
i=tok.toInt();
def->instanceId=i;
return true;
default:
break;
case 0:
//category
i = tok.toInt();
if (i < XDRTEMP || i > XDRENGINE)
return false;
def->category = (GwXDRCategory)i;
return true;
case 1:
//direction
i = tok.toInt();
if (i < GwXDRMappingDef::M_DISABLED ||
i >= GwXDRMappingDef::M_LAST)
return false;
def->direction = (GwXDRMappingDef::Direction)i;
return true;
case 2:
//selector
//TODO: check selector?
i = tok.toInt();
def->selector = i;
return true;
case 3:
//field
i = tok.toInt();
def->field = i;
return true;
case 4:
//instance mode
i = tok.toInt();
if (i < GwXDRMappingDef::IS_SINGLE ||
i >= GwXDRMappingDef::IS_LAST)
return false;
def->instanceMode = (GwXDRMappingDef::InstanceMode)i;
return true;
case 5:
//instance id
i = tok.toInt();
def->instanceId = i;
return true;
default:
break;
}
return false;
}
GwXDRMappingDef *GwXDRMappingDef::fromString(String s){
int found=0;
int last=0;
int index=0;
GwXDRMappingDef *rt=new GwXDRMappingDef();
while ((found = s.indexOf(',',last)) >= 0){
String tok=s.substring(last,found);
if (!handleToken(tok,index,rt)){
GwXDRMappingDef *GwXDRMappingDef::fromString(String s)
{
int found = 0;
int last = 0;
int index = 0;
GwXDRMappingDef *rt = new GwXDRMappingDef();
while ((found = s.indexOf(',', last)) >= 0)
{
String tok = s.substring(last, found);
if (!handleToken(tok, index, rt))
{
delete rt;
return NULL;
}
last=found+1;
last = found + 1;
index++;
}
if (last < s.length()){
String tok=s.substring(last);
if (!handleToken(tok,index,rt)){
if (last < s.length())
{
String tok = s.substring(last);
if (!handleToken(tok, index, rt))
{
delete rt;
return NULL;
}
@@ -109,16 +192,73 @@ GwXDRMappings::GwXDRMappings(GwLog *logger, GwConfigHandler *config)
}
#define MAX_MAPPINGS 100
void GwXDRMappings::begin(){
void GwXDRMappings::begin()
{
char namebuf[10];
for (int i=0;i<MAX_MAPPINGS;i++){
snprintf(namebuf,9,"XDR%d",i);
namebuf[9]=0;
GwConfigInterface *cfg=config->getConfigItem(String(namebuf));
if (cfg){
GwXDRMappingDef *mapping=GwXDRMappingDef::fromString(cfg->asCString());
if (mapping){
LOG_DEBUG(GwLog::DEBUG,"read xdr mapping %s",mapping->toString().c_str());
/*
build our mappings
for each defined mapping we fetch the type code and type definition
and create a mapping entries in our 2 maps:
n2kmap: map category,selector and field index to a mapping
n183map: map transducer name, transducer type and transducer unit to a mapping
a #nnn will be stripped from the transducer name
entries in the map are lists of mappings as potentially
we have different mappings for different instances
*/
for (int i = 0; i < MAX_MAPPINGS; i++)
{
snprintf(namebuf, 9, "XDR%d", i);
namebuf[9] = 0;
GwConfigInterface *cfg = config->getConfigItem(String(namebuf));
if (cfg)
{
GwXDRMappingDef *def = GwXDRMappingDef::fromString(cfg->asCString());
if (def)
{
int typeIndex = 0;
LOG_DEBUG(GwLog::DEBUG, "read xdr mapping %s", def->toString().c_str());
//n2k: find first matching type mapping
GwXDRType::TypeCode code = findTypeMapping(def->category, def->field);
if (code == GwXDRType::UNKNOWN)
{
LOG_DEBUG(GwLog::DEBUG, "no type mapping for %s", def->toString().c_str());
continue;
}
GwXDRType *type = findType(code, &typeIndex);
if (!type)
{
LOG_DEBUG(GwLog::DEBUG, "no type definition for %s", def->toString().c_str());
continue;
}
long n2kkey=def->n2kKey();
auto it=n2kMap.find(n2kkey);
if (it == n2kMap.end()){
LOG_DEBUG(GwLog::DEBUG,"insert mapping with key %ld",n2kkey);
GwXDRMapping *mapping = new GwXDRMapping(def, type);
n2kMap[n2kkey]=mapping;
}
else{
LOG_DEBUG(GwLog::DEBUG,"append mapping with key %ld",n2kkey);
it->second->addMappingDef(def);
}
//for nmea0183 there could be multiple entries
//as potentially there are different units that we can handle
//so after we inserted the definition we do additional type lookups
while (type != NULL){
String n183key=GwXDRMappingDef::n183key(def->xdrName,
type->xdrtype,type->xdrunit);
auto it=n183Map.find(n183key);
if (it == n183Map.end()){
LOG_DEBUG(GwLog::DEBUG,"insert mapping with n183key %s",n183key.c_str());
n183Map[n183key]=new GwXDRMapping(def,type);
}
else{
LOG_DEBUG(GwLog::DEBUG,"append mapping with n183key %s",n183key.c_str());
it->second->addMappingDef(def);
}
type=findType(code,&typeIndex);
if (! type) break;
}
}
}
}

View File

@@ -4,6 +4,7 @@
#include "GWConfig.h"
#include <WString.h>
#include <vector>
#include <map>
//enum must match the defines in xdrconfig.json
typedef enum {
XDRTEMP=0,
@@ -24,7 +25,13 @@ class GwXDRType{
PRESS=0,
PERCENT=1,
VOLT=2,
AMP=3
AMP=3,
TEMP=4,
HUMID=5,
VOLPERCENT=6,
VOLUME=7,
FLOW=8,
UNKNOWN=99
}TypeCode;
typedef double (* convert)(double);
TypeCode code;
@@ -45,11 +52,11 @@ class GwXDRTypeMapping{
GwXDRCategory category;
int fieldIndex;
GwXDRType::TypeCode type;
GwXDRTypeMapping(GwXDRCategory category,
GwXDRTypeMapping(int category,
int fieldIndex,
GwXDRType::TypeCode type){
this->category=category;
this->type=type;
int type){
this->category=(GwXDRCategory) category;
this->type=(GwXDRType::TypeCode)type;
this->fieldIndex=fieldIndex;
}
};
@@ -91,44 +98,63 @@ class GwXDRMappingDef{
category=XDRTEMP;
}
String toString();
static GwXDRMappingDef *fromString(String s);
static GwXDRMappingDef *fromString(String s);
//we allow 100 entities of code,selector and field nid
static long n2kKey(GwXDRCategory category, int selector, int field)
{
long rt = (int)category;
if (selector < 0)
selector = 0;
rt = rt * 100 + selector;
if (field < 0)
field = 0;
rt = rt * 100 * field;
return rt;
}
long n2kKey(){
return n2kKey(category,selector,field);
}
static String n183key(String xdrName, String xdrType, String xdrUnit)
{
String rt = xdrName;
rt += ",";
rt += xdrType;
rt += ",";
rt += xdrUnit;
return rt;
}
typedef std::vector<GwXDRMappingDef*> MappingList;
private:
static bool handleToken(String tok,int index,GwXDRMappingDef *def);
};
class GwXDRMapping{
public:
GwXDRMappingDef *definition;
GwXDRMappingDef::MappingList definitions;
GwXDRType *type;
GwXDRMapping(GwXDRMappingDef *definition,GwXDRType *type){
this->definition=definition;
this->definitions.push_back(definition);
this->type=type;
}
//we allow 100 entities of code,selector and field nid
static long n2kKey(GwXDRType::TypeCode code,int selector,int field){
long rt=(int)code;
if (selector < 0) selector=0;
rt=rt*100+selector;
if (field < 0) field=0;
rt=rt*100*field;
return rt;
}
static String n183key(String xdrName,String xdrType,String xdrUnit){
String rt=xdrName;
rt+=",";
rt+=xdrType;
rt+=",";
rt+=xdrUnit;
return rt;
void addMappingDef(GwXDRMappingDef *definition){
this->definitions.push_back(definition);
}
typedef std::map<String,GwXDRMapping*> N138Map;
typedef std::map<long,GwXDRMapping*> N2KMap;
};
class GwXDRMappings{
private:
GwLog *logger;
GwConfigHandler *config;
GwXDRMapping::N138Map n183Map;
GwXDRMapping::N2KMap n2kMap;
public:
GwXDRMappings(GwLog *logger,GwConfigHandler *config);
void begin();
//get the mappings
//the returned mapping will exactly contain one mapping def
GwXDRMapping getMapping(String xName,String xType,String xUnit);
GwXDRMapping getMapping(GwXDRCategory category,int selector,int field=0,int instance=0);
};