intermediate: generic handling of user tasks

This commit is contained in:
wellenvogel 2021-11-27 14:57:16 +01:00
parent 5bf2aeaffe
commit 1e4285fe5d
11 changed files with 157 additions and 19 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
generated/* generated/*
lib/generated

View File

@ -5,15 +5,17 @@ import os
import sys import sys
import inspect import inspect
import json import json
import glob
from datetime import datetime from datetime import datetime
Import("env") Import("env")
#print(env.Dump()) #print(env.Dump())
OWN_FILE="extra_script.py" OWN_FILE="extra_script.py"
GEN_DIR='generated' GEN_DIR='lib/generated'
CFG_FILE='web/config.json' CFG_FILE='web/config.json'
XDR_FILE='web/xdrconfig.json' XDR_FILE='web/xdrconfig.json'
CFG_INCLUDE='GwConfigDefinitions.h' CFG_INCLUDE='GwConfigDefinitions.h'
XDR_INCLUDE='GwXdrTypeMappings.h' XDR_INCLUDE='GwXdrTypeMappings.h'
TASK_INCLUDE='GwUserTasks.h'
EMBEDDED_INCLUDE="GwEmbeddedFiles.h" EMBEDDED_INCLUDE="GwEmbeddedFiles.h"
def getEmbeddedFiles(env): def getEmbeddedFiles(env):
@ -155,6 +157,30 @@ def generateXdrMappings(fp,oh,inFile=''):
oh.write("\n") oh.write("\n")
oh.write("};\n") oh.write("};\n")
def genereateUserTasks(outfile):
includes=[]
taskdirs=glob.glob(os.path.join('lib','*task*'))
for task in taskdirs:
#print("##taskdir=%s"%task)
base=os.path.basename(task)
includeNames=[base.lower()+".h",'gw'+base.lower()+'.h']
for f in os.listdir(task):
if not f.endswith('.h'):
continue
match=False
for cmp in includeNames:
#print("##check %s<->%s"%(f.lower(),cmp))
if f.lower() == cmp:
match=True
if not match:
continue
includes.append(f)
includeData=""
for i in includes:
print("#task include %s"%i)
includeData+="#include <%s>\n"%i
writeFileIfChanged(outfile,includeData)
def generateEmbedded(elist,outFile): def generateEmbedded(elist,outFile):
content="" content=""
for entry in elist: for entry in elist:
@ -196,6 +222,7 @@ def prebuild(env):
else: else:
print("#WARNING: infile %s for %s not found"%(inFile,ef)) print("#WARNING: infile %s for %s not found"%(inFile,ef))
generateEmbedded(filedefs,os.path.join(outPath(),EMBEDDED_INCLUDE)) generateEmbedded(filedefs,os.path.join(outPath(),EMBEDDED_INCLUDE))
genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE))
generateFile(os.path.join(basePath(),CFG_FILE),os.path.join(outPath(),CFG_INCLUDE),generateCfg) generateFile(os.path.join(basePath(),CFG_FILE),os.path.join(outPath(),CFG_INCLUDE),generateCfg)
generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings) generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings)
version="dev"+datetime.now().strftime("%Y%m%d") version="dev"+datetime.now().strftime("%Y%m%d")

View File

@ -1,8 +1,8 @@
#ifndef _GWAPI_H #ifndef _GWAPI_H
#define _GWAPI_H #define _GWAPI_H
#include "GwMessage.h" #include "GwMessage.h"
#include "N2kMessages.h" #include "N2kMsg.h"
#include "NMEA0183Messages.h" #include "NMEA0183Msg.h"
#include "GWConfig.h" #include "GWConfig.h"
#include "GwBoatData.h" #include "GwBoatData.h"
//API to be used for additional tasks //API to be used for additional tasks
@ -16,4 +16,7 @@ class GwApi{
virtual GwLog *getLogger()=0; virtual GwLog *getLogger()=0;
virtual GwBoatData *getBoatData()=0; virtual GwBoatData *getBoatData()=0;
}; };
#ifndef DECLARE_USERTASK
#define DECLARE_USERTASK(task)
#endif
#endif #endif

View File

@ -0,0 +1,25 @@
#ifndef _GWEXAMPLEHARDWARE_H
#define _GWEXAMPLEHARDWARE_H
#ifdef BOARD_TEST
#define ESP32_CAN_TX_PIN GPIO_NUM_22
#define ESP32_CAN_RX_PIN GPIO_NUM_19
//if using tail485
#define GWSERIAL_TX 26
#define GWSERIAL_RX 32
#define GWSERIAL_MODE "UNI"
#define GWBUTTON_PIN GPIO_NUM_39
#define GWBUTTON_ACTIVE LOW
//if GWBUTTON_PULLUPDOWN we enable a pulup/pulldown
#define GWBUTTON_PULLUPDOWN
//led handling
//if we define GWLED_FASTNET the arduino fastnet lib is used
#define GWLED_FASTLED
#define GWLED_TYPE SK6812
//color schema for fastled
#define GWLED_SCHEMA GRB
#define GWLED_PIN GPIO_NUM_27
//brightness 0...255
#define GWLED_BRIGHTNESS 64
#endif
#endif

View File

@ -1,4 +1,7 @@
//we only compile for some boards
#ifdef BOARD_TEST
#include "GwExampleTask.h"
#include "GwApi.h" #include "GwApi.h"
#define INVALID_COORD -99999 #define INVALID_COORD -99999
@ -80,3 +83,5 @@ void exampleTask(void *param){
vTaskDelete(NULL); vTaskDelete(NULL);
} }
#endif

View File

@ -1,5 +1,11 @@
#ifndef _GWEXAMPLETASK_H #ifndef _GWEXAMPLETASK_H
#define _GWEXAMPLETASK_H #define _GWEXAMPLETASK_H
//task function #include "GwExampleHardware.h"
#include "GwApi.h"
//we only compile for some boards
#ifdef BOARD_TEST
void exampleTask(void *param); void exampleTask(void *param);
//make the task known to the core
DECLARE_USERTASK(exampleTask);
#endif
#endif #endif

31
lib/exampletask/Readme.md Normal file
View File

@ -0,0 +1,31 @@
Extending the Core
==================
This directory contains an example on how you can extend the base functionality of the gateway.
Basically you can define own boards here and can add one or more tasks that will be started by the core.
You can also add additional libraries that will be used for your task.
In this example we define an addtional board (environment) with the name "testboard".
When building for this board we add the -DTEST_BOARD to the compilation - see [platformio.ini](platformio.ini).
The additional task that we defined will only be compiled and started for this environment (see the #ifdef TEST_BOARD in the code).
You can add your own directory below "lib". The name of the directory must contain "task".
Files
-----
* [platformio.ini](platformio.ini)
extend the base configuration - we add a dummy library here and define our buil environment (board)
* [GwExampleTask.h](GwExampleTask.h) the name of this include must match the name of the directory (ignoring case) with a "gw" in front. This file includes our special hardware definitions and registers our task at the core (DECLARE_USERTASK in the code).
* [GwExampleTaks.cpp](GwExampleTask.cpp) includes the implementation of our task. This tasks runs in an own thread - see the comments in the code.
* [GwExampleHardware.h](GwExampleHardware.h) includes our pin definitions for the board.
Hints
-----
Just be careful not to interfere with names from the core - so it is a good practice to prefix your files and class like in the example.
Developing
----------
To develop I recommend forking the gateway repository and adding your own directory below lib (with the string task in it's name).
As your code goes into a separate directory it should be very easy to fetch upstream changes without the need to adapt your code.
Future Plans
------------
If there will be a need we can extend this extension API by means of adding config items and specific java script code and css for the UI.

View File

@ -0,0 +1,10 @@
[env:testboard]
board = m5stack-atom
lib_deps =
${env.lib_deps}
own_lib
build_flags=
-D BOARD_TEST
${env.build_flags}
upload_port = /dev/esp32
upload_protocol = esptool

View File

@ -13,6 +13,7 @@
*/ */
#ifndef _GWHARDWARE_H #ifndef _GWHARDWARE_H
#define _GWHARDWARE_H #define _GWHARDWARE_H
#include "GwUserTasks.h"
//SERIAL_MODE can be: UNI (RX or TX only), BI (both), RX, TX //SERIAL_MODE can be: UNI (RX or TX only), BI (both), RX, TX
//board specific pins //board specific pins

View File

@ -7,6 +7,9 @@
; ;
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio]
extra_configs=
lib/*task*/platformio.ini
[env] [env]
platform = espressif32 platform = espressif32
@ -19,16 +22,16 @@ lib_deps =
ottowinter/ESPAsyncWebServer-esphome@^2.0.1 ottowinter/ESPAsyncWebServer-esphome@^2.0.1
fastled/FastLED @ ^3.4.0 fastled/FastLED @ ^3.4.0
board_build.embed_files = board_build.embed_files =
generated/index.html.gz lib/generated/index.html.gz
generated/index.js.gz lib/generated/index.js.gz
generated/index.css.gz lib/generated/index.css.gz
generated/config.json.gz lib/generated/config.json.gz
generated/xdrconfig.json.gz lib/generated/xdrconfig.json.gz
board_build.partitions = partitions_custom.csv board_build.partitions = partitions_custom.csv
extra_scripts = extra_scripts =
pre:extra_script.py pre:extra_script.py
post:post.py post:post.py
build_flags = -Igenerated lib_ldf_mode = chain+
monitor_speed = 115200 monitor_speed = 115200
[env:m5stack-atom] [env:m5stack-atom]

View File

@ -30,9 +30,25 @@
// #define GW_MESSAGE_DEBUG_ENABLED // #define GW_MESSAGE_DEBUG_ENABLED
// #define FALLBACK_SERIAL // #define FALLBACK_SERIAL
const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
#include <Arduino.h>
//user task handling
std::vector<TaskFunction_t> userTasks;
void registerUserTask(TaskFunction_t task){
//logWriter.write("register user task\n");
userTasks.push_back(task);
}
class GwUserTask{
public:
GwUserTask(TaskFunction_t task){
registerUserTask(task);
}
};
#define DECLARE_USERTASK(task) GwUserTask __##task##__(task);
//#include "GwUserTasks.h"
#include "GwHardware.h" #include "GwHardware.h"
#include <Arduino.h>
#include <NMEA2000_CAN.h> // This will automatically choose right CAN library and create suitable NMEA2000 object #include <NMEA2000_CAN.h> // This will automatically choose right CAN library and create suitable NMEA2000 object
#include <ActisenseReader.h> #include <ActisenseReader.h>
#include <Seasmart.h> #include <Seasmart.h>
@ -43,6 +59,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <map> #include <map>
#include <vector>
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "N2kDataToNMEA0183.h" #include "N2kDataToNMEA0183.h"
@ -57,14 +74,14 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
#include "GwSerial.h" #include "GwSerial.h"
#include "GwWebServer.h" #include "GwWebServer.h"
#include "NMEA0183DataToN2K.h" #include "NMEA0183DataToN2K.h"
#include "GwApi.h"
#include "GwButtons.h" #include "GwButtons.h"
#include "GwLeds.h" #include "GwLeds.h"
#include "GwCounter.h" #include "GwCounter.h"
#include "GwXDRMappings.h" #include "GwXDRMappings.h"
#include "GwExampleTask.h"
#include "GwApi.h"
//NMEA message channels //NMEA message channels
#define N2K_CHANNEL_ID 0 #define N2K_CHANNEL_ID 0
#define USB_CHANNEL_ID 1 #define USB_CHANNEL_ID 1
@ -74,6 +91,8 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
#define MAX_NMEA2000_MESSAGE_SEASMART_SIZE 500 #define MAX_NMEA2000_MESSAGE_SEASMART_SIZE 500
#define MAX_NMEA0183_MESSAGE_SIZE 150 // For AIS #define MAX_NMEA0183_MESSAGE_SIZE 150 // For AIS
typedef std::map<String,String> StringMap; typedef std::map<String,String> StringMap;
@ -211,6 +230,8 @@ class GwSerialLog : public GwLogWriter{
}; };
GwSerialLog logWriter;
class ApiImpl : public GwApi class ApiImpl : public GwApi
{ {
private: private:
@ -260,6 +281,7 @@ bool delayedRestart(){
} }
void startAddOnTask(TaskFunction_t task,int sourceId){ void startAddOnTask(TaskFunction_t task,int sourceId){
ApiImpl* api=new ApiImpl(sourceId); ApiImpl* api=new ApiImpl(sourceId);
xTaskCreate(task,"user",2000,api,3,NULL); xTaskCreate(task,"user",2000,api,3,NULL);
@ -522,9 +544,8 @@ void setup() {
logger.prefix="FALLBACK:"; logger.prefix="FALLBACK:";
} }
else{ else{
GwSerialLog *writer=new GwSerialLog();
logger.prefix="GWSERIAL:"; logger.prefix="GWSERIAL:";
logger.setWriter(writer); logger.setWriter(&logWriter);
logger.logDebug(GwLog::LOG,"created GwSerial for USB port"); logger.logDebug(GwLog::LOG,"created GwSerial for USB port");
} }
logger.logDebug(GwLog::LOG,"config: %s", config.toString().c_str()); logger.logDebug(GwLog::LOG,"config: %s", config.toString().c_str());
@ -695,7 +716,12 @@ void setup() {
startAddOnTask(handleButtons,100); startAddOnTask(handleButtons,100);
setLedMode(LED_GREEN); setLedMode(LED_GREEN);
startAddOnTask(handleLeds,101); startAddOnTask(handleLeds,101);
startAddOnTask(exampleTask,102); int userTaskId=200;
for (auto it=userTasks.begin();it != userTasks.end();it++){
logger.logDebug(GwLog::LOG,"starting user task with id %d",userTaskId);
startAddOnTask(*it,userTaskId);
userTaskId++;
}
logger.logDebug(GwLog::LOG,"setup done"); logger.logDebug(GwLog::LOG,"setup done");
} }
//***************************************************************************** //*****************************************************************************