diff --git a/lib/api/GwApi.h b/lib/api/GwApi.h index 95892cf..d4d0716 100644 --- a/lib/api/GwApi.h +++ b/lib/api/GwApi.h @@ -182,6 +182,13 @@ class GwApi{ * The name should be similar to the function name of the user task (although not mandatory) */ virtual bool addUserTask(GwUserTaskFunction task,const String Name, int stackSize=2000)=0; + /** + * set a value that is used for calibration in config values + * for cfg types calset, calvalue + * @param name: the config name this value is used for + * @param value: the current value + */ + virtual void setCalibrationValue(const String &name, double value); /** * not thread safe methods diff --git a/lib/gwwebserver/GwWebServer.cpp b/lib/gwwebserver/GwWebServer.cpp index 6261c42..67df54f 100644 --- a/lib/gwwebserver/GwWebServer.cpp +++ b/lib/gwwebserver/GwWebServer.cpp @@ -116,6 +116,10 @@ bool GwWebServer::registerMainHandler(const char *url,RequestCreator creator){ }); return true; } +bool GwWebServer::registerHandler(const char * url,GwWebServer::HandlerFunction handler){ + server->on(url,HTTP_GET,handler); + return true; +} bool GwWebServer::registerPostHandler(const char *url, ArRequestHandlerFunction requestHandler, ArBodyHandlerFunction bodyHandler){ diff --git a/lib/gwwebserver/GwWebServer.h b/lib/gwwebserver/GwWebServer.h index 795988e..84c265a 100644 --- a/lib/gwwebserver/GwWebServer.h +++ b/lib/gwwebserver/GwWebServer.h @@ -11,10 +11,12 @@ class GwWebServer{ GwLog *logger; public: typedef GwRequestMessage *(RequestCreator)(AsyncWebServerRequest *request); + using HandlerFunction=std::function; GwWebServer(GwLog *logger, GwRequestQueue *queue,int port); ~GwWebServer(); void begin(); bool registerMainHandler(const char *url,RequestCreator creator); + bool registerHandler(const char * url,HandlerFunction handler); bool registerPostHandler(const char *url, ArRequestHandlerFunction requestHandler, ArBodyHandlerFunction bodyHandler); void handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg); AsyncWebServer * getServer(){return server;} diff --git a/lib/spitask/GWDMS22B.cpp b/lib/spitask/GWDMS22B.cpp index 0cf2218..91c4964 100644 --- a/lib/spitask/GWDMS22B.cpp +++ b/lib/spitask/GWDMS22B.cpp @@ -81,6 +81,7 @@ class GWDMS22B : public SSISensor{ int zero=2047; bool invt=false; + String zeroConfigName; public: using SSISensor::SSISensor; virtual bool preinit(GwApi * api){ @@ -102,6 +103,8 @@ class GWDMS22B : public SSISensor{ tN2kMsg msg; SetN2kRudder(msg,DegToRad(resolved),iid); api->sendN2kMessage(msg); + api->increment(counterId,prefix); + api->setCalibrationValue(zeroConfigName,(double)value); } #define DMS22B(PRFX,...) \ if (prefix == #PRFX) {\ @@ -109,6 +112,7 @@ class GWDMS22B : public SSISensor{ CFG_GET(iid,PRFX); \ CFG_GET(fintv,PRFX); \ CFG_GET(zero,PRFX); \ + zeroConfigName=GwConfigDefinitions::PRFX ## zero;\ CFG_GET(invt,PRFX); \ bits=12; \ clock=500000; \ diff --git a/lib/spitask/config.json b/lib/spitask/config.json index cb96db6..1b96171 100644 --- a/lib/spitask/config.json +++ b/lib/spitask/config.json @@ -67,7 +67,7 @@ { "name": "DMS22B$izero", "label": "DMS22B$i Zero", - "type": "number", + "type": "calset", "default": 2048, "description": "Zero position (0...2^bits-1)", "category": "spisensors$b", diff --git a/lib/usercode/GwUserCode.cpp b/lib/usercode/GwUserCode.cpp index ef6fbd7..4522c92 100644 --- a/lib/usercode/GwUserCode.cpp +++ b/lib/usercode/GwUserCode.cpp @@ -332,6 +332,9 @@ public: api->getLogger()->logDebug(GwLog::LOG,"adding user task %s",tname.c_str()); return true; } + virtual void setCalibrationValue(const String &name, double value){ + api->setCalibrationValue(name,value); + } }; diff --git a/src/main.cpp b/src/main.cpp index 5ce1b7a..6a6005b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -235,15 +235,38 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool conv }); } +class CalibrationValues { + using Map=std::map; + Map values; + SemaphoreHandle_t lock; + public: + CalibrationValues(){ + lock=xSemaphoreCreateMutex(); + } + void set(const String &name,double value){ + GWSYNCHRONIZED(&lock); + values[name]=value; + } + bool get(const String &name, double &value){ + GWSYNCHRONIZED(&lock); + auto it=values.find(name); + if (it==values.end()) return false; + value=it->second; + return true; + } +}; + class ApiImpl : public GwApiInternal { private: int sourceId = -1; + std::unique_ptr calibrations; public: ApiImpl(int sourceId) { this->sourceId = sourceId; + calibrations.reset(new CalibrationValues()); } virtual GwRequestQueue *getQueue() { @@ -332,6 +355,13 @@ public: virtual bool addUserTask(GwUserTaskFunction task,const String Name, int stackSize=2000){ return false; } + virtual void setCalibrationValue(const String &name, double value){ + calibrations->set(name,value); + } + + bool getCalibrationValue(const String &name,double &value){ + return calibrations->get(name,value); + } }; bool delayedRestart(){ @@ -803,7 +833,19 @@ void setup() { [](AsyncWebServerRequest *request){ }, - handleConfigRequestData); + handleConfigRequestData); + webserver.registerHandler("/api/calibrate",[](AsyncWebServerRequest *request){ + const String name=request->arg("name"); + double value; + if (! apiImpl->getCalibrationValue(name,value)){ + request->send(400, "text/plain", "name not found"); + return; + } + char buffer[30]; + snprintf(buffer,29,"%g",value); + buffer[29]=0; + request->send(200,"text/plain",buffer); + }); webserver.begin(); xdrMappings.begin(); diff --git a/web/index.html b/web/index.html index da16fc8..7172b41 100644 --- a/web/index.html +++ b/web/index.html @@ -131,7 +131,6 @@ AHA
-
@@ -190,6 +189,10 @@ + diff --git a/web/index.js b/web/index.js index bc5bcdf..92a58ea 100644 --- a/web/index.js +++ b/web/index.js @@ -371,22 +371,37 @@ function updateMsgDetails(key, details) { }); } -function showOverlay(text, isHtml) { +function showOverlay(text, isHtml,buttons) { let el = document.getElementById('overlayContent'); - if (isHtml) { - el.innerHTML = text; - el.classList.remove("text"); + if (text instanceof Object){ + el.textContent=''; + el.appendChild(text); } else { - el.textContent = text; - el.classList.add("text"); + if (isHtml) { + el.innerHTML = text; + el.classList.remove("text"); + } + else { + el.textContent = text; + el.classList.add("text"); + } } + buttons=(buttons?buttons:[]).concat([{label:"Close",click:hideOverlay}]); let container = document.getElementById('overlayContainer'); + let btframe=container.querySelector('.overlayButtons'); + btframe.textContent=''; + buttons.forEach((btconfig)=>{ + let bt=addEl('button','',btframe,btconfig.label); + bt.addEventListener("click",btconfig.click); + }); container.classList.remove('hidden'); } function hideOverlay() { let container = document.getElementById('overlayContainer'); container.classList.add('hidden'); + let el = document.getElementById('overlayContent'); + el.textContent=''; } function checkChange(el, row,name) { let loaded = el.getAttribute('data-loaded'); @@ -456,6 +471,45 @@ function checkCondition(element){ if (visible) row.classList.remove('hidden'); else row.classList.add('hidden'); } +let caliv=0; +function createCalSetInput(configItem,frame,clazz){ + let el = addEl('input',clazz,frame); + let cb = addEl('button','',frame,'C'); + //el.disabled=true; + cb.addEventListener('click',(ev)=>{ + let cs=document.getElementById("calset").cloneNode(true); + cs.classList.remove("hidden"); + cs.querySelector(".heading").textContent=configItem.name; + let vel=cs.querySelector(".val"); + if (caliv != 0) window.clearInterval(caliv); + caliv=window.setInterval(()=>{ + if (document.body.contains(cs)){ + fetch("/api/calibrate?name="+encodeURIComponent(configItem.name)) + .then((r)=>r.text()) + .then((txt)=>{ + if (txt != vel.textContent){ + vel.textContent=txt; + } + }) + .catch((e)=>{ + alert(e); + hideOverlay(); + window.clearInterval(caliv); + }) + } + else{ + window.clearInterval(caliv); + } + },200); + showOverlay(cs,false,[{label:'Set',click:()=>{ + el.value=vel.textContent; + let cev=new Event('change'); + el.dispatchEvent(cev); + }}]); + }) + el.setAttribute('name', configItem.name) + return el; +} function createInput(configItem, frame,clazz) { let el; if (configItem.type === 'boolean' || configItem.type === 'list' || configItem.type == 'boatData') { @@ -492,6 +546,9 @@ function createInput(configItem, frame,clazz) { if (configItem.type === 'xdr'){ return createXdrInput(configItem,frame,clazz); } + if (configItem.type === "calset"){ + return createCalSetInput(configItem,frame,clazz); + } el = addEl('input',clazz,frame); if (configItem.readOnly) el.setAttribute('disabled',true); el.setAttribute('name', configItem.name)