use a more semantic input for the NMEA filters
This commit is contained in:
parent
3cf67d387e
commit
93180be220
|
@ -116,26 +116,44 @@ int GwConfigHandler::getInt(const String name,int defaultv) const{
|
||||||
return i->asInt();
|
return i->asInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GwNmeaFilter::handleToken(String token, int index){
|
||||||
|
switch(index){
|
||||||
|
case 0:
|
||||||
|
ais=token.toInt() != 0;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
blacklist=token.toInt() != 0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
int found=0;
|
||||||
|
int last=0;
|
||||||
|
while ((found = token.indexOf(',',last)) >= 0){
|
||||||
|
filter.push_back(token.substring(last,found));
|
||||||
|
last=found+1;
|
||||||
|
}
|
||||||
|
if (last < token.length()){
|
||||||
|
filter.push_back(token.substring(last));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
void GwNmeaFilter::parseFilter(){
|
void GwNmeaFilter::parseFilter(){
|
||||||
|
// "0:1:RMB,RMC"
|
||||||
|
// 0: AIS off, 1:whitelist, list of sentences
|
||||||
if (isReady) return;
|
if (isReady) return;
|
||||||
int found=0;
|
int found=0;
|
||||||
int last=0;
|
int last=0;
|
||||||
|
int index=0;
|
||||||
String data=config->asString();
|
String data=config->asString();
|
||||||
while ((found = data.indexOf(',',last)) >= 0){
|
while ((found = data.indexOf(':',last)) >= 0){
|
||||||
String tok=data.substring(last,found);
|
String tok=data.substring(last,found);
|
||||||
if (tok != ""){
|
handleToken(tok,index);
|
||||||
if (tok.startsWith("^")) blacklist.push_back(tok);
|
|
||||||
else whitelist.push_back(tok);
|
|
||||||
}
|
|
||||||
last=found+1;
|
last=found+1;
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
if (last < data.length()){
|
if (last < data.length()){
|
||||||
String tok=data.substring(last);
|
String tok=data.substring(last);
|
||||||
if (tok != "" && tok != "^" ){
|
handleToken(tok,index);
|
||||||
if (tok.startsWith("^")) blacklist.push_back(tok.substring(1));
|
|
||||||
else whitelist.push_back(tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
isReady=true;
|
isReady=true;
|
||||||
}
|
}
|
||||||
|
@ -144,27 +162,24 @@ bool GwNmeaFilter::canPass(const char *buffer){
|
||||||
size_t len=strlen(buffer);
|
size_t len=strlen(buffer);
|
||||||
if (len < 5) return false; //invalid NMEA
|
if (len < 5) return false; //invalid NMEA
|
||||||
if (!isReady) parseFilter();
|
if (!isReady) parseFilter();
|
||||||
bool hasWhitelist=false;
|
if (buffer[0] == '!') return ais;
|
||||||
for (auto it=blacklist.begin();it != blacklist.end();it++){
|
char sentence[4];
|
||||||
if (buffer[0] == '$'){
|
strncpy(sentence,buffer+3,3);
|
||||||
if ((strncmp(buffer,(*it).c_str(),1) == 0) &&
|
sentence[3]=0;
|
||||||
(strncmp(buffer+3,(*it).c_str()+1,it->length()-1) == 0)
|
for (auto it=filter.begin();it != filter.end();it++){
|
||||||
) return false;
|
if (strncmp(sentence,(*it).c_str(),3) == 0) return !blacklist;
|
||||||
}
|
|
||||||
else{
|
|
||||||
if (strncmp(buffer,(*it).c_str(),it->length()) == 0) return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (auto it=whitelist.begin();it != whitelist.end();it++){
|
//if we have a whitelist we return false
|
||||||
hasWhitelist=true;
|
//if nothing matches
|
||||||
if (buffer[0] == '$'){
|
return blacklist;
|
||||||
if ((strncmp(buffer,(*it).c_str(),1) == 0) &&
|
}
|
||||||
(strncmp(buffer+3,(*it).c_str()+1,it->length()-1) == 0)
|
String GwNmeaFilter::toString(){
|
||||||
) return true;
|
parseFilter();
|
||||||
}
|
String rt("NMEAFilter: ");
|
||||||
else{
|
rt+="ais: "+String(ais);
|
||||||
if (strncmp(buffer,(*it).c_str(),it->length()) == 0) return true;
|
rt+=", bl:"+String(blacklist);
|
||||||
}
|
for (auto it=filter.begin();it != filter.end();it++){
|
||||||
|
rt+=","+*it;
|
||||||
}
|
}
|
||||||
return !hasWhitelist;
|
return rt;
|
||||||
}
|
}
|
|
@ -53,15 +53,18 @@ class GwNmeaFilter{
|
||||||
private:
|
private:
|
||||||
GwConfigInterface *config=NULL;
|
GwConfigInterface *config=NULL;
|
||||||
bool isReady=false;
|
bool isReady=false;
|
||||||
std::vector<String> whitelist;
|
bool ais=true;
|
||||||
std::vector<String> blacklist;
|
bool blacklist=true;
|
||||||
|
std::vector<String> filter;
|
||||||
|
void handleToken(String token, int index);
|
||||||
void parseFilter();
|
void parseFilter();
|
||||||
public:
|
public:
|
||||||
GwNmeaFilter(GwConfigInterface *config){
|
GwNmeaFilter(GwConfigInterface *config){
|
||||||
this->config=config;
|
this->config=config;
|
||||||
isReady=false;
|
isReady=false;
|
||||||
}
|
}
|
||||||
bool canPass(const char *buffer);
|
bool canPass(const char *buffer);
|
||||||
|
String toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -336,6 +336,9 @@ void setup() {
|
||||||
socketServer.begin();
|
socketServer.begin();
|
||||||
usbSerial->flush();
|
usbSerial->flush();
|
||||||
|
|
||||||
|
logger.logDebug(GwLog::LOG,"usbRead: %s", usbReadFilter.toString().c_str());
|
||||||
|
usbSerial->flush();
|
||||||
|
|
||||||
webserver.registerMainHandler("/api/reset", [](AsyncWebServerRequest *request)->GwRequestMessage *{
|
webserver.registerMainHandler("/api/reset", [](AsyncWebServerRequest *request)->GwRequestMessage *{
|
||||||
return new ResetRequest();
|
return new ResetRequest();
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,14 +41,14 @@
|
||||||
"label": "USB read Filter",
|
"label": "USB read Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from USB\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA"
|
"description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "usbWriteFilter",
|
"name": "usbWriteFilter",
|
||||||
"label": "USB write Filter",
|
"label": "USB write Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to USB\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA"
|
"description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "serialDirection",
|
"name": "serialDirection",
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
"label": "serial read Filter",
|
"label": "serial read Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from serial\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA",
|
"description": "filter for NMEA0183 data when reading from serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"capabilities":{"serialmode":["RX","BI","UNI"]}
|
"capabilities":{"serialmode":["RX","BI","UNI"]}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -105,7 +105,7 @@
|
||||||
"label": "serial write Filter",
|
"label": "serial write Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to serial\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA",
|
"description": "filter for NMEA0183 data when writing to serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
|
||||||
"capabilities":{"serialmode":["TX","BI","UNI"]}
|
"capabilities":{"serialmode":["TX","BI","UNI"]}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -149,14 +149,14 @@
|
||||||
"label": "TCP read Filter",
|
"label": "TCP read Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when reading from TCP\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA"
|
"description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tcpWriteFilter",
|
"name": "tcpWriteFilter",
|
||||||
"label": "TCP write Filter",
|
"label": "TCP write Filter",
|
||||||
"type": "filter",
|
"type": "filter",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "filter for NMEA0183 data when writing to TCP\nempty to let all data pass\nexamples:\n! \t: all AIS\n$RMB,$APB \t: only NMEA RMB and APB\n^! \t: no AIS but other NMEA"
|
"description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sendSeasmart",
|
"name": "sendSeasmart",
|
||||||
|
|
|
@ -58,7 +58,8 @@
|
||||||
let v=jsonData[k];
|
let v=jsonData[k];
|
||||||
el.value=v;
|
el.value=v;
|
||||||
el.setAttribute('data-loaded',v);
|
el.setAttribute('data-loaded',v);
|
||||||
checkChange(el);
|
let changeEvent=new Event('change');
|
||||||
|
el.dispatchEvent(changeEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -80,6 +81,9 @@
|
||||||
let values=document.querySelectorAll('.configForm select , .configForm input');
|
let values=document.querySelectorAll('.configForm select , .configForm input');
|
||||||
for (let i=0;i<values.length;i++){
|
for (let i=0;i<values.length;i++){
|
||||||
let v=values[i];
|
let v=values[i];
|
||||||
|
let name=v.getAttribute('name');
|
||||||
|
if (! name) continue;
|
||||||
|
if (name.indexOf("_") >= 0) continue;
|
||||||
let check=v.getAttribute('data-check');
|
let check=v.getAttribute('data-check');
|
||||||
if (check){
|
if (check){
|
||||||
if (typeof(self[check]) === 'function'){
|
if (typeof(self[check]) === 'function'){
|
||||||
|
@ -90,7 +94,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
url+=v.getAttribute('name')+"="+encodeURIComponent(v.value)+"&";
|
url+=name+"="+encodeURIComponent(v.value)+"&";
|
||||||
}
|
}
|
||||||
getJson(url)
|
getJson(url)
|
||||||
.then(function(status){
|
.then(function(status){
|
||||||
|
@ -152,18 +156,18 @@
|
||||||
let container=document.getElementById('overlayContainer');
|
let container=document.getElementById('overlayContainer');
|
||||||
container.classList.add('hidden');
|
container.classList.add('hidden');
|
||||||
}
|
}
|
||||||
function checkChange(el) {
|
function checkChange(el,row) {
|
||||||
let loaded = el.getAttribute('data-loaded');
|
let loaded = el.getAttribute('data-loaded');
|
||||||
if (loaded !== undefined) {
|
if (loaded !== undefined) {
|
||||||
if (loaded != el.value) {
|
if (loaded != el.value) {
|
||||||
el.classList.add('changed');
|
row.classList.add('changed');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
el.classList.remove("changed");
|
row.classList.remove("changed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createInput(configItem){
|
function createInput(configItem,frame){
|
||||||
let el;
|
let el;
|
||||||
if (configItem.type === 'boolean' || configItem.type === 'list'){
|
if (configItem.type === 'boolean' || configItem.type === 'list'){
|
||||||
el=document.createElement('select')
|
el=document.createElement('select')
|
||||||
|
@ -184,8 +188,56 @@
|
||||||
sitemEl.textContent=sitem.l;
|
sitemEl.textContent=sitem.l;
|
||||||
el.appendChild(sitemEl);
|
el.appendChild(sitemEl);
|
||||||
})
|
})
|
||||||
|
frame.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
if (configItem.type === 'filter'){
|
||||||
|
el=document.createElement('div');
|
||||||
|
el.classList.add('filter');
|
||||||
|
let ais=createInput({
|
||||||
|
type:'list',
|
||||||
|
name:configItem.name+"_ais",
|
||||||
|
list:['aison','aisoff']
|
||||||
|
},el);
|
||||||
|
let mode=createInput({
|
||||||
|
type:'list',
|
||||||
|
name:configItem.name+"_mode",
|
||||||
|
list: ['whitelist','blacklist']
|
||||||
|
},el);
|
||||||
|
let sentences=createInput({
|
||||||
|
type:'text',
|
||||||
|
name:configItem.name+"_sentences",
|
||||||
|
},el);
|
||||||
|
let data=document.createElement('input');
|
||||||
|
data.setAttribute('type','hidden');
|
||||||
|
el.appendChild(data);
|
||||||
|
let changeFunction=function(){
|
||||||
|
let cv=data.value||"";
|
||||||
|
let parts=cv.split(":");
|
||||||
|
ais.value=(parts[0]=='0')?"aisoff":"aison";
|
||||||
|
mode.value=(parts[1]=='0')?"whitelist":"blacklist";
|
||||||
|
sentences.value=parts[2]||"";
|
||||||
|
}
|
||||||
|
let updateFunction=function(){
|
||||||
|
let nv=(ais.value == 'aison')?"1":"0";
|
||||||
|
nv+=":";
|
||||||
|
nv+=(mode.value == 'blacklist')?"1":"0";
|
||||||
|
nv+=":";
|
||||||
|
nv+=sentences.value;
|
||||||
|
data.value=nv;
|
||||||
|
let chev=new Event('change');
|
||||||
|
data.dispatchEvent(chev);
|
||||||
|
}
|
||||||
|
mode.addEventListener('change',updateFunction);
|
||||||
|
ais.addEventListener("change",updateFunction);
|
||||||
|
sentences.addEventListener("change",updateFunction);
|
||||||
|
data.addEventListener('change',function(ev){
|
||||||
|
changeFunction();
|
||||||
|
});
|
||||||
|
data.setAttribute('name',configItem.name);
|
||||||
|
frame.appendChild(el);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
el=document.createElement('input');
|
el=document.createElement('input');
|
||||||
el.setAttribute('name',configItem.name)
|
el.setAttribute('name',configItem.name)
|
||||||
if (configItem.type === 'password'){
|
if (configItem.type === 'password'){
|
||||||
|
@ -197,6 +249,7 @@
|
||||||
else{
|
else{
|
||||||
el.setAttribute('type','text');
|
el.setAttribute('type','text');
|
||||||
}
|
}
|
||||||
|
frame.appendChild(el);
|
||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
let configDefinitions;
|
let configDefinitions;
|
||||||
|
@ -229,21 +282,21 @@
|
||||||
labelEl.classList.add('label');
|
labelEl.classList.add('label');
|
||||||
labelEl.textContent = label;
|
labelEl.textContent = label;
|
||||||
row.appendChild(labelEl);
|
row.appendChild(labelEl);
|
||||||
let valueEl = createInput(item);
|
let valueEl = createInput(item,row);
|
||||||
if (!valueEl) return;
|
if (!valueEl) return;
|
||||||
valueEl.setAttribute('data-default', item.default);
|
valueEl.setAttribute('data-default', item.default);
|
||||||
valueEl.addEventListener('change', function (ev) {
|
valueEl.addEventListener('change', function (ev) {
|
||||||
let el = ev.target;
|
let el = ev.target;
|
||||||
checkChange(el);
|
checkChange(el,row);
|
||||||
})
|
})
|
||||||
if (item.check) valueEl.setAttribute('data-check', item.check);
|
if (item.check) valueEl.setAttribute('data-check', item.check);
|
||||||
row.appendChild(valueEl);
|
|
||||||
let bt = document.createElement('button');
|
let bt = document.createElement('button');
|
||||||
bt.classList.add('defaultButton');
|
bt.classList.add('defaultButton');
|
||||||
bt.setAttribute('data-default', item.default);
|
bt.setAttribute('data-default', item.default);
|
||||||
bt.addEventListener('click', function (ev) {
|
bt.addEventListener('click', function (ev) {
|
||||||
valueEl.value = valueEl.getAttribute('data-default');
|
valueEl.value = valueEl.getAttribute('data-default');
|
||||||
checkChange(valueEl);
|
let changeEvent=new Event('change');
|
||||||
|
valueEl.dispatchEvent(changeEvent);
|
||||||
})
|
})
|
||||||
bt.textContent = "X";
|
bt.textContent = "X";
|
||||||
row.appendChild(bt);
|
row.appendChild(bt);
|
||||||
|
@ -284,7 +337,10 @@
|
||||||
border: 1px solid grey;
|
border: 1px solid grey;
|
||||||
max-width: 40em;
|
max-width: 40em;
|
||||||
}
|
}
|
||||||
.changed {
|
.changed input{
|
||||||
|
color: green
|
||||||
|
}
|
||||||
|
.changed select{
|
||||||
color: green
|
color: green
|
||||||
}
|
}
|
||||||
span.label {
|
span.label {
|
||||||
|
@ -305,6 +361,9 @@ span#connected.ok{
|
||||||
.row {
|
.row {
|
||||||
margin: 0.5em;
|
margin: 0.5em;
|
||||||
}
|
}
|
||||||
|
.filter {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
.buttons {
|
.buttons {
|
||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue