add calset input

This commit is contained in:
andreas 2024-03-17 18:20:09 +01:00
parent 32e48b126c
commit a240cade7e
9 changed files with 131 additions and 9 deletions

View File

@ -182,6 +182,13 @@ class GwApi{
* The name should be similar to the function name of the user task (although not mandatory) * 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; 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 * not thread safe methods

View File

@ -116,6 +116,10 @@ bool GwWebServer::registerMainHandler(const char *url,RequestCreator creator){
}); });
return true; 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, bool GwWebServer::registerPostHandler(const char *url, ArRequestHandlerFunction requestHandler,
ArBodyHandlerFunction bodyHandler){ ArBodyHandlerFunction bodyHandler){

View File

@ -11,10 +11,12 @@ class GwWebServer{
GwLog *logger; GwLog *logger;
public: public:
typedef GwRequestMessage *(RequestCreator)(AsyncWebServerRequest *request); typedef GwRequestMessage *(RequestCreator)(AsyncWebServerRequest *request);
using HandlerFunction=std::function<void(AsyncWebServerRequest *)>;
GwWebServer(GwLog *logger, GwRequestQueue *queue,int port); GwWebServer(GwLog *logger, GwRequestQueue *queue,int port);
~GwWebServer(); ~GwWebServer();
void begin(); void begin();
bool registerMainHandler(const char *url,RequestCreator creator); bool registerMainHandler(const char *url,RequestCreator creator);
bool registerHandler(const char * url,HandlerFunction handler);
bool registerPostHandler(const char *url, ArRequestHandlerFunction requestHandler, ArBodyHandlerFunction bodyHandler); bool registerPostHandler(const char *url, ArRequestHandlerFunction requestHandler, ArBodyHandlerFunction bodyHandler);
void handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg); void handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg);
AsyncWebServer * getServer(){return server;} AsyncWebServer * getServer(){return server;}

View File

@ -81,6 +81,7 @@
class GWDMS22B : public SSISensor{ class GWDMS22B : public SSISensor{
int zero=2047; int zero=2047;
bool invt=false; bool invt=false;
String zeroConfigName;
public: public:
using SSISensor::SSISensor; using SSISensor::SSISensor;
virtual bool preinit(GwApi * api){ virtual bool preinit(GwApi * api){
@ -102,6 +103,8 @@ class GWDMS22B : public SSISensor{
tN2kMsg msg; tN2kMsg msg;
SetN2kRudder(msg,DegToRad(resolved),iid); SetN2kRudder(msg,DegToRad(resolved),iid);
api->sendN2kMessage(msg); api->sendN2kMessage(msg);
api->increment(counterId,prefix);
api->setCalibrationValue(zeroConfigName,(double)value);
} }
#define DMS22B(PRFX,...) \ #define DMS22B(PRFX,...) \
if (prefix == #PRFX) {\ if (prefix == #PRFX) {\
@ -109,6 +112,7 @@ class GWDMS22B : public SSISensor{
CFG_GET(iid,PRFX); \ CFG_GET(iid,PRFX); \
CFG_GET(fintv,PRFX); \ CFG_GET(fintv,PRFX); \
CFG_GET(zero,PRFX); \ CFG_GET(zero,PRFX); \
zeroConfigName=GwConfigDefinitions::PRFX ## zero;\
CFG_GET(invt,PRFX); \ CFG_GET(invt,PRFX); \
bits=12; \ bits=12; \
clock=500000; \ clock=500000; \

View File

@ -67,7 +67,7 @@
{ {
"name": "DMS22B$izero", "name": "DMS22B$izero",
"label": "DMS22B$i Zero", "label": "DMS22B$i Zero",
"type": "number", "type": "calset",
"default": 2048, "default": 2048,
"description": "Zero position (0...2^bits-1)", "description": "Zero position (0...2^bits-1)",
"category": "spisensors$b", "category": "spisensors$b",

View File

@ -332,6 +332,9 @@ public:
api->getLogger()->logDebug(GwLog::LOG,"adding user task %s",tname.c_str()); api->getLogger()->logDebug(GwLog::LOG,"adding user task %s",tname.c_str());
return true; return true;
} }
virtual void setCalibrationValue(const String &name, double value){
api->setCalibrationValue(name,value);
}
}; };

View File

@ -235,15 +235,38 @@ void SendNMEA0183Message(const tNMEA0183Msg &NMEA0183Msg, int sourceId,bool conv
}); });
} }
class CalibrationValues {
using Map=std::map<String,double>;
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 class ApiImpl : public GwApiInternal
{ {
private: private:
int sourceId = -1; int sourceId = -1;
std::unique_ptr<CalibrationValues> calibrations;
public: public:
ApiImpl(int sourceId) ApiImpl(int sourceId)
{ {
this->sourceId = sourceId; this->sourceId = sourceId;
calibrations.reset(new CalibrationValues());
} }
virtual GwRequestQueue *getQueue() virtual GwRequestQueue *getQueue()
{ {
@ -332,6 +355,13 @@ public:
virtual bool addUserTask(GwUserTaskFunction task,const String Name, int stackSize=2000){ virtual bool addUserTask(GwUserTaskFunction task,const String Name, int stackSize=2000){
return false; 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(){ bool delayedRestart(){
@ -804,6 +834,18 @@ void setup() {
}, },
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(); webserver.begin();
xdrMappings.begin(); xdrMappings.begin();

View File

@ -131,7 +131,6 @@
AHA AHA
</div> </div>
<div class="overlayButtons"> <div class="overlayButtons">
<button id="hideOverlay">Close</button>
</div> </div>
</div> </div>
</div> </div>
@ -190,6 +189,10 @@
<div class="hidden"> <div class="hidden">
<a id="downloadXdr"></a> <a id="downloadXdr"></a>
</div> </div>
<div class="hidden" id="calset">
<h2 class="heading"></h2>
<p class="val"></p>
</div>
</body> </body>
</html> </html>

View File

@ -371,22 +371,37 @@ function updateMsgDetails(key, details) {
}); });
} }
function showOverlay(text, isHtml) { function showOverlay(text, isHtml,buttons) {
let el = document.getElementById('overlayContent'); let el = document.getElementById('overlayContent');
if (isHtml) { if (text instanceof Object){
el.innerHTML = text; el.textContent='';
el.classList.remove("text"); el.appendChild(text);
} }
else { else {
el.textContent = text; if (isHtml) {
el.classList.add("text"); 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 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'); container.classList.remove('hidden');
} }
function hideOverlay() { function hideOverlay() {
let container = document.getElementById('overlayContainer'); let container = document.getElementById('overlayContainer');
container.classList.add('hidden'); container.classList.add('hidden');
let el = document.getElementById('overlayContent');
el.textContent='';
} }
function checkChange(el, row,name) { function checkChange(el, row,name) {
let loaded = el.getAttribute('data-loaded'); let loaded = el.getAttribute('data-loaded');
@ -456,6 +471,45 @@ function checkCondition(element){
if (visible) row.classList.remove('hidden'); if (visible) row.classList.remove('hidden');
else row.classList.add('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) { function createInput(configItem, frame,clazz) {
let el; let el;
if (configItem.type === 'boolean' || configItem.type === 'list' || configItem.type == 'boatData') { if (configItem.type === 'boolean' || configItem.type === 'list' || configItem.type == 'boatData') {
@ -492,6 +546,9 @@ function createInput(configItem, frame,clazz) {
if (configItem.type === 'xdr'){ if (configItem.type === 'xdr'){
return createXdrInput(configItem,frame,clazz); return createXdrInput(configItem,frame,clazz);
} }
if (configItem.type === "calset"){
return createCalSetInput(configItem,frame,clazz);
}
el = addEl('input',clazz,frame); el = addEl('input',clazz,frame);
if (configItem.readOnly) el.setAttribute('disabled',true); if (configItem.readOnly) el.setAttribute('disabled',true);
el.setAttribute('name', configItem.name) el.setAttribute('name', configItem.name)