esp32-nmea2000-obp60/lib/exampletask/GwExampleTask.cpp

138 lines
5.9 KiB
C++

//we only compile for some boards
#ifdef BOARD_TEST
#include "GwExampleTask.h"
#include "GwApi.h"
#include <vector>
/**
* an init function that ist being called before other initializations from the core
*/
void exampleInit(GwApi *api){
api->getLogger()->logDebug(GwLog::LOG,"example init running");
}
#define INVALID_COORD -99999
class GetBoatDataRequest: public GwMessage{
private:
GwApi *api;
public:
double latitude;
double longitude;
GetBoatDataRequest(GwApi *api):GwMessage(F("boat data")){
this->api=api;
}
virtual ~GetBoatDataRequest(){}
protected:
/**
* this methos will be executed within the main thread
* be sure not to make any time consuming or blocking operation
*/
virtual void processImpl(){
//api->getLogger()->logDebug(GwLog::DEBUG,"boatData request from example task");
/*access the values from boatData (see GwBoatData.h)
by using getDataWithDefault it will return the given default value
if there is no valid data available
so be sure to use a value that never will be a valid one
alternatively you can check using the isValid() method at each boatData item
*/
latitude=api->getBoatData()->Latitude->getDataWithDefault(INVALID_COORD);
longitude=api->getBoatData()->Longitude->getDataWithDefault(INVALID_COORD);
};
};
void exampleTask(GwApi *api){
GwLog *logger=api->getLogger();
//get some configuration data
bool exampleSwitch=api->getConfig()->getConfigItem(
api->getConfig()->exampleConfig,
true)->asBoolean();
//------
//initialization goes here
//------
bool hasPosition=false;
bool hasPosition2=false;
LOG_DEBUG(GwLog::DEBUG,"example switch ist %s",exampleSwitch?"true":"false");
GwApi::StringList itemNames;
itemNames.push_back(F("Latitude"));
itemNames.push_back(F("Longitude"));
while(true){
delay(1000);
/*
* getting values from the internal data store (boatData) requires some special handling
* our tasks runs (potentially) at some time on a different core then the main code
* and as the boatData has no synchronization (for performance reasons)
* we must ensure to access it only from the main thread.
* The pattern is to create a request object (a class that inherits from GwMessage -
* GetBoatDataRequest above)
* and to access the boatData in the processImpl method of this object.
* Once the object is created we enqueue it into a request queue and wait for
* the main thread to call the processImpl method (sendAndWait).
* Afterwards we can use the data we have stored in the request.
* As this request object can be accessed from different threads we must be careful
* about it's lifetime.
* The pattern below handles this correctly. We do not call delete on this object but
* instead call the "unref" Method when we don't need it any more.
*/
GetBoatDataRequest *r=new GetBoatDataRequest(api);
if (api->getQueue()->sendAndWait(r,10000) != GwRequestQueue::MSG_OK){
r->unref(); //delete the request
api->getLogger()->logDebug(GwLog::ERROR,"request not handled");
continue;
}
if (r->latitude == INVALID_COORD || r->longitude == INVALID_COORD){
if (hasPosition){
if (exampleSwitch) logger->logDebug(GwLog::ERROR,"position lost...");
hasPosition=false;
}
}
else{
//do something with the data we have from boatData
if (! hasPosition){
if (exampleSwitch) logger->logDebug(GwLog::LOG,"postion now available lat=%f, lon=%f",
r->latitude,r->longitude);
hasPosition=true;
}
}
r->unref(); //delete the request
/** second example with string based functions to access boatData
uses STL vector and map - but does not need any request handling
this uses a reasonable amount of mmeory on the stack:
up to 2x the size of the list of names and 2x the size of the returned map
the default stack size of 2000 will not fit.
So be sure to use DECLARA_USERTASK_PARAM(taskFuntion,stackSize) and provide
a reasonable stack size (e.g. 4000 in this example).
Finally it only makes sense to use one of the versions - either with the request
or with the ValueMap approach.
The request access to boatData gives you more options on how to access the data
and ueses less ressources and runtime but this one is maybe easier to understand and implement
**/
//fetch the current values of the items that we have in itemNames
GwApi::ValueMap boatItems=api->getBoatDataValues(itemNames);
//get the values out of the map
//the returned item is a map iterator
auto longitude=boatItems.find(itemNames[1]);
auto latitude=boatItems.find(itemNames[0]);
//check if the iterators are valid (i.e. the values we requested have been found in boatData)
if (longitude != boatItems.end() && latitude != boatItems.end()){
//both values are there - so we have a valid position
if (! hasPosition2){
//access to the values via iterator->second (iterator->first would be the name)
if (exampleSwitch) LOG_DEBUG(GwLog::LOG,"(2)position availale lat=%f, lon=%f",
latitude->second,longitude->second);
hasPosition2=true;
}
}
else{
if (hasPosition2){
if (exampleSwitch) LOG_DEBUG(GwLog::LOG,"(2)position lost");
hasPosition2=false;
}
}
}
vTaskDelete(NULL);
}
#endif