Merge branch 'master' of https://github.com/TobiasE-github/esp32-nmea2000-obp60
This commit is contained in:
commit
93402841cb
|
@ -19,8 +19,8 @@
|
||||||
"flash_mode": "qio",
|
"flash_mode": "qio",
|
||||||
"hwids": [
|
"hwids": [
|
||||||
[
|
[
|
||||||
"0x303A",
|
"0x1A86",
|
||||||
"0x1001"
|
"0x7523"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"mcu": "esp32s3",
|
"mcu": "esp32s3",
|
||||||
|
|
|
@ -10,7 +10,7 @@ from datetime import datetime
|
||||||
import re
|
import re
|
||||||
import pprint
|
import pprint
|
||||||
from platformio.project.config import ProjectConfig
|
from platformio.project.config import ProjectConfig
|
||||||
|
from platformio.project.exception import InvalidProjectConfError
|
||||||
|
|
||||||
Import("env")
|
Import("env")
|
||||||
#print(env.Dump())
|
#print(env.Dump())
|
||||||
|
@ -104,7 +104,17 @@ def writeFileIfChanged(fileName,data):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def mergeConfig(base,other):
|
def mergeConfig(base,other):
|
||||||
|
try:
|
||||||
|
customconfig = env.GetProjectOption("custom_config")
|
||||||
|
except InvalidProjectConfError:
|
||||||
|
customconfig = None
|
||||||
for bdir in other:
|
for bdir in other:
|
||||||
|
if customconfig and os.path.exists(os.path.join(bdir,customconfig)):
|
||||||
|
cname=os.path.join(bdir,customconfig)
|
||||||
|
print("merge custom config {}".format(cname))
|
||||||
|
with open(cname,'rb') as ah:
|
||||||
|
base += json.load(ah)
|
||||||
|
continue
|
||||||
cname=os.path.join(bdir,"config.json")
|
cname=os.path.join(bdir,"config.json")
|
||||||
if os.path.exists(cname):
|
if os.path.exists(cname):
|
||||||
print("merge config %s"%cname)
|
print("merge config %s"%cname)
|
||||||
|
@ -274,9 +284,9 @@ class Grove:
|
||||||
def _ss(self,z=False):
|
def _ss(self,z=False):
|
||||||
if z:
|
if z:
|
||||||
return self.name
|
return self.name
|
||||||
return self.name if self.name is not 'Z' else ''
|
return self.name if self.name != 'Z' else ''
|
||||||
def _suffix(self):
|
def _suffix(self):
|
||||||
return '_'+self.name if self.name is not 'Z' else ''
|
return '_'+self.name if self.name != 'Z' else ''
|
||||||
def replace(self,line):
|
def replace(self,line):
|
||||||
if line is None:
|
if line is None:
|
||||||
return line
|
return line
|
||||||
|
|
|
@ -0,0 +1,518 @@
|
||||||
|
print("running extra...")
|
||||||
|
import gzip
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import inspect
|
||||||
|
import json
|
||||||
|
import glob
|
||||||
|
from datetime import datetime
|
||||||
|
import re
|
||||||
|
import pprint
|
||||||
|
from platformio.project.config import ProjectConfig
|
||||||
|
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
#print(env.Dump())
|
||||||
|
OWN_FILE="extra_script.py"
|
||||||
|
GEN_DIR='lib/generated'
|
||||||
|
CFG_FILE='web/config.json'
|
||||||
|
XDR_FILE='web/xdrconfig.json'
|
||||||
|
INDEXJS="index.js"
|
||||||
|
INDEXCSS="index.css"
|
||||||
|
CFG_INCLUDE='GwConfigDefinitions.h'
|
||||||
|
CFG_INCLUDE_IMPL='GwConfigDefImpl.h'
|
||||||
|
XDR_INCLUDE='GwXdrTypeMappings.h'
|
||||||
|
TASK_INCLUDE='GwUserTasks.h'
|
||||||
|
GROVE_CONFIG="GwM5GroveGen.h"
|
||||||
|
GROVE_CONFIG_IN="lib/hardware/GwM5Grove.in"
|
||||||
|
EMBEDDED_INCLUDE="GwEmbeddedFiles.h"
|
||||||
|
|
||||||
|
def getEmbeddedFiles(env):
|
||||||
|
rt=[]
|
||||||
|
efiles=env.GetProjectOption("board_build.embed_files")
|
||||||
|
for f in efiles.split("\n"):
|
||||||
|
if f == '':
|
||||||
|
continue
|
||||||
|
rt.append(f)
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def basePath():
|
||||||
|
#see: https://stackoverflow.com/questions/16771894/python-nameerror-global-name-file-is-not-defined
|
||||||
|
return os.path.dirname(inspect.getfile(lambda: None))
|
||||||
|
|
||||||
|
def outPath():
|
||||||
|
return os.path.join(basePath(),GEN_DIR)
|
||||||
|
def checkDir():
|
||||||
|
dn=outPath()
|
||||||
|
if not os.path.exists(dn):
|
||||||
|
os.makedirs(dn)
|
||||||
|
if not os.path.isdir(dn):
|
||||||
|
print("unable to create %s"%dn)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isCurrent(infile,outfile):
|
||||||
|
if os.path.exists(outfile):
|
||||||
|
otime=os.path.getmtime(outfile)
|
||||||
|
itime=os.path.getmtime(infile)
|
||||||
|
if (otime >= itime):
|
||||||
|
own=os.path.join(basePath(),OWN_FILE)
|
||||||
|
if os.path.exists(own):
|
||||||
|
owntime=os.path.getmtime(own)
|
||||||
|
if owntime > otime:
|
||||||
|
return False
|
||||||
|
print("%s is newer then %s, no need to recreate"%(outfile,infile))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
def compressFile(inFile,outfile):
|
||||||
|
if isCurrent(inFile,outfile):
|
||||||
|
return
|
||||||
|
print("compressing %s"%inFile)
|
||||||
|
with open(inFile, 'rb') as f_in:
|
||||||
|
with gzip.open(outfile, 'wb') as f_out:
|
||||||
|
shutil.copyfileobj(f_in, f_out)
|
||||||
|
|
||||||
|
def generateFile(infile,outfile,callback,inMode='rb',outMode='w'):
|
||||||
|
if isCurrent(infile,outfile):
|
||||||
|
return
|
||||||
|
print("creating %s"%outfile)
|
||||||
|
oh=None
|
||||||
|
with open(infile,inMode) as ch:
|
||||||
|
with open(outfile,outMode) as oh:
|
||||||
|
try:
|
||||||
|
callback(ch,oh,inFile=infile)
|
||||||
|
oh.close()
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
oh.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
os.unlink(outfile)
|
||||||
|
raise
|
||||||
|
|
||||||
|
def writeFileIfChanged(fileName,data):
|
||||||
|
if os.path.exists(fileName):
|
||||||
|
with open(fileName,"r") as ih:
|
||||||
|
old=ih.read()
|
||||||
|
ih.close()
|
||||||
|
if old == data:
|
||||||
|
return False
|
||||||
|
print("#generating %s"%fileName)
|
||||||
|
with open(fileName,"w") as oh:
|
||||||
|
oh.write(data)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def mergeConfig(base,other):
|
||||||
|
for bdir in other:
|
||||||
|
cname=os.path.join(bdir,"config.json")
|
||||||
|
if os.path.exists(cname):
|
||||||
|
print("merge config %s"%cname)
|
||||||
|
with open(cname,'rb') as ah:
|
||||||
|
merge=json.load(ah)
|
||||||
|
base=base+merge
|
||||||
|
return base
|
||||||
|
|
||||||
|
def replaceTexts(data,replacements):
|
||||||
|
if replacements is None:
|
||||||
|
return data
|
||||||
|
if isinstance(data,str):
|
||||||
|
for k,v in replacements.items():
|
||||||
|
data=data.replace("$"+k,str(v))
|
||||||
|
return data
|
||||||
|
if isinstance(data,list):
|
||||||
|
rt=[]
|
||||||
|
for e in data:
|
||||||
|
rt.append(replaceTexts(e,replacements))
|
||||||
|
return rt
|
||||||
|
if isinstance(data,dict):
|
||||||
|
rt={}
|
||||||
|
for k,v in data.items():
|
||||||
|
rt[replaceTexts(k,replacements)]=replaceTexts(v,replacements)
|
||||||
|
return rt
|
||||||
|
return data
|
||||||
|
def expandConfig(config):
|
||||||
|
rt=[]
|
||||||
|
for item in config:
|
||||||
|
type=item.get('type')
|
||||||
|
if type != 'array':
|
||||||
|
rt.append(item)
|
||||||
|
continue
|
||||||
|
replacements=item.get('replace')
|
||||||
|
children=item.get('children')
|
||||||
|
name=item.get('name')
|
||||||
|
if name is None:
|
||||||
|
name="#unknown#"
|
||||||
|
if not isinstance(replacements,list):
|
||||||
|
raise Exception("missing replacements at array %s"%name)
|
||||||
|
for replace in replacements:
|
||||||
|
if children is not None:
|
||||||
|
for c in children:
|
||||||
|
rt.append(replaceTexts(c,replace))
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def generateMergedConfig(inFile,outFile,addDirs=[]):
|
||||||
|
if not os.path.exists(inFile):
|
||||||
|
raise Exception("unable to read cfg file %s"%inFile)
|
||||||
|
data=""
|
||||||
|
with open(inFile,'rb') as ch:
|
||||||
|
config=json.load(ch)
|
||||||
|
config=mergeConfig(config,addDirs)
|
||||||
|
config=expandConfig(config)
|
||||||
|
data=json.dumps(config,indent=2)
|
||||||
|
writeFileIfChanged(outFile,data)
|
||||||
|
|
||||||
|
def generateCfg(inFile,outFile,impl):
|
||||||
|
if not os.path.exists(inFile):
|
||||||
|
raise Exception("unable to read cfg file %s"%inFile)
|
||||||
|
data=""
|
||||||
|
with open(inFile,'rb') as ch:
|
||||||
|
config=json.load(ch)
|
||||||
|
data+="//generated from %s\n"%inFile
|
||||||
|
l=len(config)
|
||||||
|
idx=0
|
||||||
|
if not impl:
|
||||||
|
data+='#include "GwConfigItem.h"\n'
|
||||||
|
data+='class GwConfigDefinitions{\n'
|
||||||
|
data+=' public:\n'
|
||||||
|
data+=' int getNumConfig() const{return %d;}\n'%(l)
|
||||||
|
for item in config:
|
||||||
|
n=item.get('name')
|
||||||
|
if n is None:
|
||||||
|
continue
|
||||||
|
if len(n) > 15:
|
||||||
|
raise Exception("%s: config names must be max 15 caracters"%n)
|
||||||
|
data+=' static constexpr const char* %s="%s";\n'%(n,n)
|
||||||
|
data+="};\n"
|
||||||
|
else:
|
||||||
|
data+='void GwConfigHandler::populateConfigs(GwConfigInterface **config){\n'
|
||||||
|
for item in config:
|
||||||
|
name=item.get('name')
|
||||||
|
if name is None:
|
||||||
|
continue
|
||||||
|
data+=' configs[%d]='%(idx)
|
||||||
|
idx+=1
|
||||||
|
secret="false";
|
||||||
|
if item.get('type') == 'password':
|
||||||
|
secret="true"
|
||||||
|
data+=" new GwConfigInterface(%s,\"%s\",%s);\n"%(name,item.get('default'),secret)
|
||||||
|
data+='}\n'
|
||||||
|
writeFileIfChanged(outFile,data)
|
||||||
|
|
||||||
|
def labelFilter(label):
|
||||||
|
return re.sub("[^a-zA-Z0-9]","",re.sub("\([0-9]*\)","",label))
|
||||||
|
def generateXdrMappings(fp,oh,inFile=''):
|
||||||
|
jdoc=json.load(fp)
|
||||||
|
oh.write("static GwXDRTypeMapping* typeMappings[]={\n")
|
||||||
|
first=True
|
||||||
|
for cat in jdoc:
|
||||||
|
item=jdoc[cat]
|
||||||
|
cid=item.get('id')
|
||||||
|
if cid is None:
|
||||||
|
continue
|
||||||
|
tc=item.get('type')
|
||||||
|
if tc is not None:
|
||||||
|
if first:
|
||||||
|
first=False
|
||||||
|
else:
|
||||||
|
oh.write(",\n")
|
||||||
|
oh.write(" new GwXDRTypeMapping(%d,0,%d) /*%s*/"%(cid,tc,cat))
|
||||||
|
fields=item.get('fields')
|
||||||
|
if fields is None:
|
||||||
|
continue
|
||||||
|
idx=0
|
||||||
|
for fe in fields:
|
||||||
|
if not isinstance(fe,dict):
|
||||||
|
continue
|
||||||
|
tc=fe.get('t')
|
||||||
|
id=fe.get('v')
|
||||||
|
if id is None:
|
||||||
|
id=idx
|
||||||
|
idx+=1
|
||||||
|
l=fe.get('l') or ''
|
||||||
|
if tc is None or id is None:
|
||||||
|
continue
|
||||||
|
if first:
|
||||||
|
first=False
|
||||||
|
else:
|
||||||
|
oh.write(",\n")
|
||||||
|
oh.write(" new GwXDRTypeMapping(%d,%d,%d) /*%s:%s*/"%(cid,id,tc,cat,l))
|
||||||
|
oh.write("\n")
|
||||||
|
oh.write("};\n")
|
||||||
|
for cat in jdoc:
|
||||||
|
item=jdoc[cat]
|
||||||
|
cid=item.get('id')
|
||||||
|
if cid is None:
|
||||||
|
continue
|
||||||
|
selectors=item.get('selector')
|
||||||
|
if selectors is not None:
|
||||||
|
for selector in selectors:
|
||||||
|
label=selector.get('l')
|
||||||
|
value=selector.get('v')
|
||||||
|
if label is not None and value is not None:
|
||||||
|
label=labelFilter(label)
|
||||||
|
define=("GWXDRSEL_%s_%s"%(cat,label)).upper()
|
||||||
|
oh.write(" #define %s %s\n"%(define,value))
|
||||||
|
fields=item.get('fields')
|
||||||
|
if fields is not None:
|
||||||
|
idx=0
|
||||||
|
for field in fields:
|
||||||
|
v=field.get('v')
|
||||||
|
if v is None:
|
||||||
|
v=idx
|
||||||
|
else:
|
||||||
|
v=int(v)
|
||||||
|
label=field.get('l')
|
||||||
|
if v is not None and label is not None:
|
||||||
|
define=("GWXDRFIELD_%s_%s"%(cat,labelFilter(label))).upper();
|
||||||
|
oh.write(" #define %s %s\n"%(define,str(v)))
|
||||||
|
idx+=1
|
||||||
|
|
||||||
|
class Grove:
|
||||||
|
def __init__(self,name) -> None:
|
||||||
|
self.name=name
|
||||||
|
def _ss(self,z=False):
|
||||||
|
if z:
|
||||||
|
return self.name
|
||||||
|
return self.name if self.name is not 'Z' else ''
|
||||||
|
def _suffix(self):
|
||||||
|
return '_'+self.name if self.name is not 'Z' else ''
|
||||||
|
def replace(self,line):
|
||||||
|
if line is None:
|
||||||
|
return line
|
||||||
|
return line.replace('$G$',self._ss()).replace('$Z$',self._ss(True)).replace('$GS$',self._suffix())
|
||||||
|
def generateGroveDefs(inh,outh,inFile=''):
|
||||||
|
GROVES=[Grove('Z'),Grove('A'),Grove('B'),Grove('C')]
|
||||||
|
definition=[]
|
||||||
|
started=False
|
||||||
|
def writeConfig():
|
||||||
|
for grove in GROVES:
|
||||||
|
for cl in definition:
|
||||||
|
outh.write(grove.replace(cl))
|
||||||
|
|
||||||
|
for line in inh:
|
||||||
|
if re.match(" *#GROVE",line):
|
||||||
|
started=True
|
||||||
|
if len(definition) > 0:
|
||||||
|
writeConfig()
|
||||||
|
definition=[]
|
||||||
|
continue
|
||||||
|
if started:
|
||||||
|
definition.append(line)
|
||||||
|
if len(definition) > 0:
|
||||||
|
writeConfig()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
userTaskDirs=[]
|
||||||
|
|
||||||
|
def getUserTaskDirs():
|
||||||
|
rt=[]
|
||||||
|
taskdirs=glob.glob(os.path.join( basePath(),'lib','*task*'))
|
||||||
|
for task in taskdirs:
|
||||||
|
rt.append(task)
|
||||||
|
return rt
|
||||||
|
|
||||||
|
def checkAndAdd(file,names,ilist):
|
||||||
|
if not file.endswith('.h'):
|
||||||
|
return
|
||||||
|
match=False
|
||||||
|
for cmp in names:
|
||||||
|
#print("##check %s<->%s"%(f.lower(),cmp))
|
||||||
|
if file.lower() == cmp:
|
||||||
|
match=True
|
||||||
|
if not match:
|
||||||
|
return
|
||||||
|
ilist.append(file)
|
||||||
|
def genereateUserTasks(outfile):
|
||||||
|
includes=[]
|
||||||
|
for task in userTaskDirs:
|
||||||
|
#print("##taskdir=%s"%task)
|
||||||
|
base=os.path.basename(task)
|
||||||
|
includeNames=[base.lower()+".h",'gw'+base.lower()+'.h']
|
||||||
|
for f in os.listdir(task):
|
||||||
|
checkAndAdd(f,includeNames,includes)
|
||||||
|
includeData=""
|
||||||
|
for i in includes:
|
||||||
|
print("#task include %s"%i)
|
||||||
|
includeData+="#include <%s>\n"%i
|
||||||
|
writeFileIfChanged(outfile,includeData)
|
||||||
|
|
||||||
|
def generateEmbedded(elist,outFile):
|
||||||
|
content=""
|
||||||
|
for entry in elist:
|
||||||
|
content+="EMBED_GZ_FILE(\"%s\",%s,\"%s\");\n"%entry
|
||||||
|
writeFileIfChanged(outFile,content)
|
||||||
|
|
||||||
|
def getContentType(fn):
|
||||||
|
if (fn.endswith('.gz')):
|
||||||
|
fn=fn[0:-3]
|
||||||
|
if (fn.endswith('html')):
|
||||||
|
return "text/html"
|
||||||
|
if (fn.endswith('json')):
|
||||||
|
return "application/json"
|
||||||
|
if (fn.endswith('js')):
|
||||||
|
return "text/javascript"
|
||||||
|
if (fn.endswith('css')):
|
||||||
|
return "text/css"
|
||||||
|
return "application/octet-stream"
|
||||||
|
|
||||||
|
|
||||||
|
def getLibs():
|
||||||
|
base=os.path.join(basePath(),"lib")
|
||||||
|
rt=[]
|
||||||
|
for sd in os.listdir(base):
|
||||||
|
if sd == '..':
|
||||||
|
continue
|
||||||
|
if sd == '.':
|
||||||
|
continue
|
||||||
|
fn=os.path.join(base,sd)
|
||||||
|
if os.path.isdir(fn):
|
||||||
|
rt.append(sd)
|
||||||
|
EXTRAS=['generated']
|
||||||
|
for e in EXTRAS:
|
||||||
|
if not e in rt:
|
||||||
|
rt.append(e)
|
||||||
|
return rt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def joinFiles(target,pattern,dirlist):
|
||||||
|
flist=[]
|
||||||
|
for dir in dirlist:
|
||||||
|
fn=os.path.join(dir,pattern)
|
||||||
|
if os.path.exists(fn):
|
||||||
|
flist.append(fn)
|
||||||
|
current=False
|
||||||
|
if os.path.exists(target):
|
||||||
|
current=True
|
||||||
|
for f in flist:
|
||||||
|
if not isCurrent(f,target):
|
||||||
|
current=False
|
||||||
|
break
|
||||||
|
if current:
|
||||||
|
print("%s is up to date"%target)
|
||||||
|
return
|
||||||
|
print("creating %s"%target)
|
||||||
|
with gzip.open(target,"wb") as oh:
|
||||||
|
for fn in flist:
|
||||||
|
print("adding %s to %s"%(fn,target))
|
||||||
|
with open(fn,"rb") as rh:
|
||||||
|
shutil.copyfileobj(rh,oh)
|
||||||
|
|
||||||
|
|
||||||
|
OWNLIBS=getLibs()+["FS","WiFi"]
|
||||||
|
GLOBAL_INCLUDES=[]
|
||||||
|
|
||||||
|
def handleDeps(env):
|
||||||
|
#overwrite the GetProjectConfig
|
||||||
|
#to inject all our libs
|
||||||
|
oldGetProjectConfig=env.GetProjectConfig
|
||||||
|
def GetProjectConfigX(env):
|
||||||
|
rt=oldGetProjectConfig()
|
||||||
|
cenv="env:"+env['PIOENV']
|
||||||
|
libs=[]
|
||||||
|
for section,options in rt.as_tuple():
|
||||||
|
if section == cenv:
|
||||||
|
for key,values in options:
|
||||||
|
if key == 'lib_deps':
|
||||||
|
libs=values
|
||||||
|
|
||||||
|
mustUpdate=False
|
||||||
|
for lib in OWNLIBS:
|
||||||
|
if not lib in libs:
|
||||||
|
libs.append(lib)
|
||||||
|
mustUpdate=True
|
||||||
|
if mustUpdate:
|
||||||
|
update=[(cenv,[('lib_deps',libs)])]
|
||||||
|
rt.update(update)
|
||||||
|
return rt
|
||||||
|
env.AddMethod(GetProjectConfigX,"GetProjectConfig")
|
||||||
|
#store the list of all includes after we resolved
|
||||||
|
#the dependencies for our main project
|
||||||
|
#we will use them for all compilations afterwards
|
||||||
|
oldLibBuilder=env.ConfigureProjectLibBuilder
|
||||||
|
def ConfigureProjectLibBuilderX(env):
|
||||||
|
global GLOBAL_INCLUDES
|
||||||
|
project=oldLibBuilder()
|
||||||
|
#print("##ConfigureProjectLibBuilderX")
|
||||||
|
#pprint.pprint(project)
|
||||||
|
if project.depbuilders:
|
||||||
|
#print("##depbuilders %s"%",".join(map(lambda x: x.path,project.depbuilders)))
|
||||||
|
for db in project.depbuilders:
|
||||||
|
idirs=db.get_include_dirs()
|
||||||
|
for id in idirs:
|
||||||
|
if not id in GLOBAL_INCLUDES:
|
||||||
|
GLOBAL_INCLUDES.append(id)
|
||||||
|
return project
|
||||||
|
env.AddMethod(ConfigureProjectLibBuilderX,"ConfigureProjectLibBuilder")
|
||||||
|
def injectIncludes(env,node):
|
||||||
|
return env.Object(
|
||||||
|
node,
|
||||||
|
CPPPATH=env["CPPPATH"]+GLOBAL_INCLUDES
|
||||||
|
)
|
||||||
|
env.AddBuildMiddleware(injectIncludes)
|
||||||
|
|
||||||
|
|
||||||
|
def prebuild(env):
|
||||||
|
global userTaskDirs
|
||||||
|
print("#prebuild running")
|
||||||
|
if not checkDir():
|
||||||
|
sys.exit(1)
|
||||||
|
ldf_mode=env.GetProjectOption("lib_ldf_mode")
|
||||||
|
if ldf_mode == 'off':
|
||||||
|
print("##ldf off - own dependency handling")
|
||||||
|
handleDeps(env)
|
||||||
|
userTaskDirs=getUserTaskDirs()
|
||||||
|
mergedConfig=os.path.join(outPath(),os.path.basename(CFG_FILE))
|
||||||
|
generateMergedConfig(os.path.join(basePath(),CFG_FILE),mergedConfig,userTaskDirs)
|
||||||
|
compressFile(mergedConfig,mergedConfig+".gz")
|
||||||
|
generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE),False)
|
||||||
|
generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE_IMPL),True)
|
||||||
|
joinFiles(os.path.join(outPath(),INDEXJS+".gz"),INDEXJS,["web"]+userTaskDirs)
|
||||||
|
joinFiles(os.path.join(outPath(),INDEXCSS+".gz"),INDEXCSS,["web"]+userTaskDirs)
|
||||||
|
embedded=getEmbeddedFiles(env)
|
||||||
|
filedefs=[]
|
||||||
|
for ef in embedded:
|
||||||
|
print("#checking embedded file %s"%ef)
|
||||||
|
(dn,fn)=os.path.split(ef)
|
||||||
|
pureName=fn
|
||||||
|
if pureName.endswith('.gz'):
|
||||||
|
pureName=pureName[0:-3]
|
||||||
|
ct=getContentType(pureName)
|
||||||
|
usname=ef.replace('/','_').replace('.','_')
|
||||||
|
filedefs.append((pureName,usname,ct))
|
||||||
|
inFile=os.path.join(basePath(),"web",pureName)
|
||||||
|
if os.path.exists(inFile):
|
||||||
|
compressFile(inFile,ef)
|
||||||
|
else:
|
||||||
|
print("#WARNING: infile %s for %s not found"%(inFile,ef))
|
||||||
|
generateEmbedded(filedefs,os.path.join(outPath(),EMBEDDED_INCLUDE))
|
||||||
|
genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE))
|
||||||
|
generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings)
|
||||||
|
generateFile(os.path.join(basePath(),GROVE_CONFIG_IN),os.path.join(outPath(),GROVE_CONFIG),generateGroveDefs,inMode='r')
|
||||||
|
version="dev"+datetime.now().strftime("%Y%m%d")
|
||||||
|
env.Append(CPPDEFINES=[('GWDEVVERSION',version)])
|
||||||
|
|
||||||
|
def cleangenerated(source, target, env):
|
||||||
|
od=outPath()
|
||||||
|
if os.path.isdir(od):
|
||||||
|
print("#cleaning up %s"%od)
|
||||||
|
for f in os.listdir(od):
|
||||||
|
if f == "." or f == "..":
|
||||||
|
continue
|
||||||
|
fn=os.path.join(od,f)
|
||||||
|
os.unlink(f)
|
||||||
|
|
||||||
|
|
||||||
|
print("#prescript...")
|
||||||
|
prebuild(env)
|
||||||
|
board="PLATFORM_BOARD_%s"%env["BOARD"].replace("-","_").upper()
|
||||||
|
print("Board=#%s#"%board)
|
||||||
|
print("BuildFlags=%s"%(" ".join(env["BUILD_FLAGS"])))
|
||||||
|
env.Append(
|
||||||
|
LINKFLAGS=[ "-u", "custom_app_desc" ],
|
||||||
|
CPPDEFINES=[(board,"1")]
|
||||||
|
)
|
||||||
|
#script does not run on clean yet - maybe in the future
|
||||||
|
env.AddPostAction("clean",cleangenerated)
|
|
@ -70,6 +70,9 @@ bool statusBacklightLED = false;// Actual status of flash LED on/off
|
||||||
|
|
||||||
int uvDuration = 0; // Under voltage duration in n x 100ms
|
int uvDuration = 0; // Under voltage duration in n x 100ms
|
||||||
|
|
||||||
|
RTC_DATA_ATTR uint8_t RTC_lastpage; // Remember last page while deep sleeping
|
||||||
|
|
||||||
|
|
||||||
LedTaskData *ledTaskData=nullptr;
|
LedTaskData *ledTaskData=nullptr;
|
||||||
|
|
||||||
void hardwareInit(GwApi *api)
|
void hardwareInit(GwApi *api)
|
||||||
|
@ -118,6 +121,61 @@ void startLedTask(GwApi *api){
|
||||||
createSpiLedTask(ledTaskData);
|
createSpiLedTask(ledTaskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t getLastPage() {
|
||||||
|
return RTC_lastpage;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
void deepSleep(CommonData &common){
|
||||||
|
RTC_lastpage = common.data.actpage - 1;
|
||||||
|
// Switch off all power lines
|
||||||
|
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||||
|
setFlashLED(false); // Flash LED Off
|
||||||
|
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
|
||||||
|
// Shutdown EInk display
|
||||||
|
getdisplay().setFullWindow(); // Set full Refresh
|
||||||
|
getdisplay().fillScreen(common.bgcolor); // Clear screen
|
||||||
|
getdisplay().setTextColor(common.fgcolor);
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||||
|
getdisplay().setCursor(85, 150);
|
||||||
|
getdisplay().print("Sleep Mode");
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
getdisplay().setCursor(65, 175);
|
||||||
|
getdisplay().print("To wake up press key and wait 5s");
|
||||||
|
getdisplay().nextPage(); // Update display contents
|
||||||
|
getdisplay().powerOff(); // Display power off
|
||||||
|
setPortPin(OBP_POWER_50, false); // Power off ePaper display
|
||||||
|
// Stop system
|
||||||
|
esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
// Deep sleep funktion
|
||||||
|
void deepSleep(CommonData &common){
|
||||||
|
RTC_lastpage = common.data.actpage - 1;
|
||||||
|
// Switch off all power lines
|
||||||
|
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||||
|
setFlashLED(false); // Flash LED Off
|
||||||
|
// Shutdown EInk display
|
||||||
|
getdisplay().setFullWindow(); // Set full Refresh
|
||||||
|
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||||
|
getdisplay().fillScreen(common.bgcolor); // Clear screen
|
||||||
|
getdisplay().setTextColor(common.fgcolor);
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||||
|
getdisplay().setCursor(85, 150);
|
||||||
|
getdisplay().print("Sleep Mode");
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
getdisplay().setCursor(65, 175);
|
||||||
|
getdisplay().print("To wake up press wheel and wait 5s");
|
||||||
|
getdisplay().nextPage(); // Partial update
|
||||||
|
getdisplay().powerOff(); // Display power off
|
||||||
|
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
|
||||||
|
setPortPin(OBP_POWER_SD, false); // Power off SD card
|
||||||
|
// Stop system
|
||||||
|
esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Valid colors see hue
|
// Valid colors see hue
|
||||||
Color colorMapping(const String &colorString){
|
Color colorMapping(const String &colorString){
|
||||||
Color color = COLOR_RED;
|
Color color = COLOR_RED;
|
||||||
|
@ -334,6 +392,25 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa
|
||||||
getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
|
getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef LIPO_ACCU_1200
|
||||||
|
if (commonData.data.BatteryChargeStatus == 1) {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_loading_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
} else {
|
||||||
|
#ifdef VOLTAGE_SENSOR
|
||||||
|
if (commonData.data.batteryLevelLiPo < 10) {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_0_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
} else if (commonData.data.batteryLevelLiPo < 25) {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_25_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
} else if (commonData.data.batteryLevelLiPo < 50) {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_50_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
} else if (commonData.data.batteryLevelLiPo < 75) {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_75_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
} else {
|
||||||
|
getdisplay().drawXBitmap(170, 1, battery_100_bits, battery_width, battery_height, commonData.fgcolor);
|
||||||
|
}
|
||||||
|
#endif // VOLTAGE_SENSOR
|
||||||
|
}
|
||||||
|
#endif // LIPO_ACCU_1200
|
||||||
|
|
||||||
// Heartbeat as dot
|
// Heartbeat as dot
|
||||||
getdisplay().setTextColor(commonData.fgcolor);
|
getdisplay().setTextColor(commonData.fgcolor);
|
||||||
|
|
|
@ -64,6 +64,10 @@ Point rotatePoint(const Point& origin, const Point& p, double angle);
|
||||||
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
|
std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle);
|
||||||
void fillPoly4(const std::vector<Point>& p4, uint16_t color);
|
void fillPoly4(const std::vector<Point>& p4, uint16_t color);
|
||||||
|
|
||||||
|
void deepSleep(CommonData &common);
|
||||||
|
|
||||||
|
uint8_t getLastPage();
|
||||||
|
|
||||||
void hardwareInit(GwApi *api);
|
void hardwareInit(GwApi *api);
|
||||||
|
|
||||||
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
void setPortPin(uint pin, bool value); // Set port pin for extension port
|
||||||
|
@ -96,8 +100,8 @@ void displayFooter(CommonData &commonData);
|
||||||
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise
|
SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise
|
||||||
|
|
||||||
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level
|
void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level
|
||||||
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level
|
void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic
|
||||||
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level
|
void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic
|
||||||
void startLedTask(GwApi *api);
|
void startLedTask(GwApi *api);
|
||||||
|
|
||||||
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
|
void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request);
|
||||||
|
@ -156,6 +160,46 @@ static std::map<String, unsigned char *> iconmap = {
|
||||||
{"AP", ap_bits}
|
{"AP", ap_bits}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Battery
|
||||||
|
#define battery_width 24
|
||||||
|
#define battery_height 16
|
||||||
|
|
||||||
|
static unsigned char battery_0_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
|
||||||
|
0x03, 0x00, 0x18, 0x03, 0x00, 0x78, 0x03, 0x00, 0xf8, 0x03, 0x00, 0xd8,
|
||||||
|
0x03, 0x00, 0xd8, 0x03, 0x00, 0xd8, 0x03, 0x00, 0xf8, 0x03, 0x00, 0x78,
|
||||||
|
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
static unsigned char battery_25_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
|
||||||
|
0x03, 0x00, 0x18, 0x3b, 0x00, 0x78, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0xd8,
|
||||||
|
0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0x78,
|
||||||
|
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
static unsigned char battery_50_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
|
||||||
|
0x03, 0x00, 0x18, 0xbb, 0x03, 0x78, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0xd8,
|
||||||
|
0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0x78,
|
||||||
|
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
static unsigned char battery_75_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
|
||||||
|
0x03, 0x00, 0x18, 0xbb, 0x3b, 0x78, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0xd8,
|
||||||
|
0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0x78,
|
||||||
|
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
static unsigned char battery_100_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f,
|
||||||
|
0x03, 0x00, 0x18, 0xbb, 0xbb, 0x7b, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0xdb,
|
||||||
|
0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0x7b,
|
||||||
|
0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
static unsigned char battery_loading_bits[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xe4, 0x0f, 0xff, 0xec, 0x1f,
|
||||||
|
0x03, 0x08, 0x18, 0x03, 0x18, 0x78, 0x03, 0x30, 0xf8, 0x83, 0x3f, 0xd8,
|
||||||
|
0x03, 0x7f, 0xd8, 0x03, 0x03, 0xd8, 0x03, 0x06, 0xf8, 0x03, 0x04, 0x78,
|
||||||
|
0x03, 0x0c, 0x18, 0xff, 0xcb, 0x1f, 0xfe, 0xd3, 0x0f, 0x00, 0x10, 0x00 };
|
||||||
|
|
||||||
// Other symbols
|
// Other symbols
|
||||||
#define swipe_width 24
|
#define swipe_width 24
|
||||||
#define swipe_height 16
|
#define swipe_height 16
|
||||||
|
|
|
@ -60,7 +60,7 @@ void initKeys(CommonData &commonData) {
|
||||||
|
|
||||||
#ifdef HARDWARE_V21
|
#ifdef HARDWARE_V21
|
||||||
// Keypad functions for original OBP60 hardware
|
// Keypad functions for original OBP60 hardware
|
||||||
int readKeypad(GwLog* logger, uint thSensitivity) {
|
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
|
||||||
|
|
||||||
// Touch sensor values
|
// Touch sensor values
|
||||||
// 35000 - Not touched
|
// 35000 - Not touched
|
||||||
|
@ -261,7 +261,7 @@ void initKeys(CommonData &commonData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keypad functions for OBP60 clone (thSensitivity is inactiv)
|
// Keypad functions for OBP60 clone (thSensitivity is inactiv)
|
||||||
int readKeypad(GwLog* logger, uint thSensitivity) {
|
int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) {
|
||||||
pinMode(UP, INPUT);
|
pinMode(UP, INPUT);
|
||||||
pinMode(DOWN, INPUT);
|
pinMode(DOWN, INPUT);
|
||||||
pinMode(CONF, INPUT);
|
pinMode(CONF, INPUT);
|
||||||
|
@ -277,9 +277,13 @@ void initKeys(CommonData &commonData) {
|
||||||
starttime = millis(); // Start key pressed
|
starttime = millis(); // Start key pressed
|
||||||
keycodeold = keycode;
|
keycodeold = keycode;
|
||||||
}
|
}
|
||||||
// If key pressed longer than 200ms
|
// If key pressed longer than 100ms
|
||||||
if(millis() > starttime + 200 && keycode == keycodeold) {
|
if(millis() > starttime + 100 && keycode == keycodeold) {
|
||||||
keystatus = keycode;
|
if (use_syspage and keycode == 3) {
|
||||||
|
keystatus = 12;
|
||||||
|
} else {
|
||||||
|
keystatus = keycode;
|
||||||
|
}
|
||||||
// Copy keycode
|
// Copy keycode
|
||||||
keycodeold = keycode;
|
keycodeold = keycode;
|
||||||
while(readSensorpads() > 0){} // Wait for pad release
|
while(readSensorpads() > 0){} // Wait for pad release
|
||||||
|
|
|
@ -88,8 +88,16 @@ void sensorTask(void *param){
|
||||||
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
|
double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat();
|
||||||
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
|
double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat();
|
||||||
if(String(powsensor1) == "off"){
|
if(String(powsensor1) == "off"){
|
||||||
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
|
#ifdef VOLTAGE_SENSOR
|
||||||
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
|
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||||
|
#else
|
||||||
|
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||||
|
#endif
|
||||||
|
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||||
|
#ifdef LIPO_ACCU_1200
|
||||||
|
sensors.BatteryChargeStatus = 0; // Set to discharging
|
||||||
|
sensors.batteryLevelLiPo = 0; // Level 0...100%
|
||||||
|
#endif
|
||||||
sensors.batteryCurrent = 0;
|
sensors.batteryCurrent = 0;
|
||||||
sensors.batteryPower = 0;
|
sensors.batteryPower = 0;
|
||||||
// Fill average arrays with start values
|
// Fill average arrays with start values
|
||||||
|
@ -459,19 +467,49 @@ void sensorTask(void *param){
|
||||||
// Send supply voltage value all 1s
|
// Send supply voltage value all 1s
|
||||||
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
|
if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){
|
||||||
starttime5 = millis();
|
starttime5 = millis();
|
||||||
sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20
|
#ifdef VOLTAGE_SENSOR
|
||||||
sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration
|
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||||
|
#else
|
||||||
|
float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||||
|
#endif
|
||||||
|
sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration
|
||||||
// Save new data in average array
|
// Save new data in average array
|
||||||
batV.reading(int(sensors.batteryVoltage * 100));
|
batV.reading(int(sensors.batteryVoltage * 100));
|
||||||
// Calculate the average values for different time lines from integer values
|
// Calculate the average values for different time lines from integer values
|
||||||
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
|
sensors.batteryVoltage10 = batV.getAvg(10) / 100.0;
|
||||||
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
|
sensors.batteryVoltage60 = batV.getAvg(60) / 100.0;
|
||||||
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
|
sensors.batteryVoltage300 = batV.getAvg(300) / 100.0;
|
||||||
|
#if defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
|
||||||
|
// Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100%
|
||||||
|
sensors.batteryLevelLiPo = sensors.batteryVoltage60 * 203.8312 -738.1635;
|
||||||
|
// Limiter
|
||||||
|
if(sensors.batteryLevelLiPo > 100){
|
||||||
|
sensors.batteryLevelLiPo = 100;
|
||||||
|
}
|
||||||
|
if(sensors.batteryLevelLiPo < 0){
|
||||||
|
sensors.batteryLevelLiPo = 0;
|
||||||
|
}
|
||||||
|
// Charging detection
|
||||||
|
float deltaV = sensors.batteryVoltage - sensors.batteryVoltage10;
|
||||||
|
if(deltaV > 0.045){
|
||||||
|
sensors.BatteryChargeStatus = 1; // Charging active
|
||||||
|
}
|
||||||
|
if(deltaV < -0.04){
|
||||||
|
sensors.BatteryChargeStatus = 0; // Discharging
|
||||||
|
}
|
||||||
|
// Send to NMEA200 bus as instance 10
|
||||||
|
if(!isnan(sensors.batteryVoltage)){
|
||||||
|
SetN2kDCBatStatus(N2kMsg, 10, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 0);
|
||||||
|
api->sendN2kMessage(N2kMsg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
// Send to NMEA200 bus
|
// Send to NMEA200 bus
|
||||||
if(!isnan(sensors.batteryVoltage)){
|
if(!isnan(sensors.batteryVoltage)){
|
||||||
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1);
|
SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1);
|
||||||
api->sendN2kMessage(N2kMsg);
|
api->sendN2kMessage(N2kMsg);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send data from environment sensor all 2s
|
// Send data from environment sensor all 2s
|
||||||
|
|
|
@ -48,7 +48,7 @@ class PageBME280 : public Page
|
||||||
value1 = 23.0 + float(random(0, 10)) / 10.0;
|
value1 = 23.0 + float(random(0, 10)) / 10.0;
|
||||||
}
|
}
|
||||||
// Display data when sensor activated
|
// Display data when sensor activated
|
||||||
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){
|
if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
|
||||||
svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places
|
svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
@ -66,7 +66,7 @@ class PageBME280 : public Page
|
||||||
value2 = 43 + float(random(0, 4));
|
value2 = 43 + float(random(0, 4));
|
||||||
}
|
}
|
||||||
// Display data when sensor activated
|
// Display data when sensor activated
|
||||||
if(String(useenvsensor) == "BME280"){
|
if(useenvsensor == "BME280"){
|
||||||
svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places
|
svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
@ -84,7 +84,7 @@ class PageBME280 : public Page
|
||||||
value3 = 1006 + float(random(0, 5));
|
value3 = 1006 + float(random(0, 5));
|
||||||
}
|
}
|
||||||
// Display data when sensor activated
|
// Display data when sensor activated
|
||||||
if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){
|
if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){
|
||||||
svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places
|
svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "OBP60Extensions.h"
|
#include "OBP60Extensions.h"
|
||||||
#include "images/logo64.xbm"
|
#include "images/logo64.xbm"
|
||||||
#include <esp32/clk.h>
|
#include <esp32/clk.h>
|
||||||
|
#include "qrcode.h"
|
||||||
|
|
||||||
#define STRINGIZE_IMPL(x) #x
|
#define STRINGIZE_IMPL(x) #x
|
||||||
#define STRINGIZE(x) STRINGIZE_IMPL(x)
|
#define STRINGIZE(x) STRINGIZE_IMPL(x)
|
||||||
|
@ -48,7 +49,7 @@ public:
|
||||||
commonData->keydata[0].label = "EXIT";
|
commonData->keydata[0].label = "EXIT";
|
||||||
commonData->keydata[1].label = "MODE";
|
commonData->keydata[1].label = "MODE";
|
||||||
commonData->keydata[2].label = "";
|
commonData->keydata[2].label = "";
|
||||||
commonData->keydata[3].label = "";
|
commonData->keydata[3].label = "RST";
|
||||||
commonData->keydata[4].label = "STBY";
|
commonData->keydata[4].label = "STBY";
|
||||||
commonData->keydata[5].label = "ILUM";
|
commonData->keydata[5].label = "ILUM";
|
||||||
}
|
}
|
||||||
|
@ -66,18 +67,64 @@ public:
|
||||||
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
|
if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// grab cursor keys to disable page navigation
|
#ifdef BOARD_OBP60S3
|
||||||
if (key == 3 or key == 4) {
|
// grab cursor key to disable page navigation
|
||||||
|
if (key == 3) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
// soft reset
|
||||||
|
if (key == 4) {
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
// standby / deep sleep
|
||||||
|
if (key == 5) {
|
||||||
|
deepSleep(*commonData);
|
||||||
|
}
|
||||||
// Code for keylock
|
// Code for keylock
|
||||||
if (key == 11) {
|
if (key == 11) {
|
||||||
commonData->keylock = !commonData->keylock;
|
commonData->keylock = !commonData->keylock;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
// grab cursor keys to disable page navigation
|
||||||
|
if (key == 9 or key == 10) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// standby / deep sleep
|
||||||
|
if (key == 12) {
|
||||||
|
deepSleep(*commonData);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void displayBarcode(String serialno, uint16_t x, uint16_t y, uint16_t s) {
|
||||||
|
// Barcode with serial number
|
||||||
|
// x, y is top left corner
|
||||||
|
// s is pixel size of a single box
|
||||||
|
QRCode qrcode;
|
||||||
|
uint8_t qrcodeData[qrcode_getBufferSize(4)];
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
String prefix = "OBP40:SN:";
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
String prefix = "OBP60:SN:";
|
||||||
|
#endif
|
||||||
|
qrcode_initText(&qrcode, qrcodeData, 4, 0, (prefix + serialno).c_str());
|
||||||
|
int16_t x0 = x;
|
||||||
|
for (uint8_t j = 0; j < qrcode.size; j++) {
|
||||||
|
for (uint8_t i = 0; i < qrcode.size; i++) {
|
||||||
|
if (qrcode_getModule(&qrcode, i, j)) {
|
||||||
|
getdisplay().fillRect(x, y, s, s, commonData->fgcolor);
|
||||||
|
}
|
||||||
|
x += s;
|
||||||
|
}
|
||||||
|
y += s;
|
||||||
|
x = x0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void displayPage(PageData &pageData){
|
virtual void displayPage(PageData &pageData){
|
||||||
GwConfigHandler *config = commonData->config;
|
GwConfigHandler *config = commonData->config;
|
||||||
GwLog *logger = commonData->logger;
|
GwLog *logger = commonData->logger;
|
||||||
|
@ -104,66 +151,88 @@ public:
|
||||||
|
|
||||||
if (mode == 'N') {
|
if (mode == 'N') {
|
||||||
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
getdisplay().setFont(&Ubuntu_Bold12pt7b);
|
||||||
getdisplay().setCursor(20, 50);
|
getdisplay().setCursor(8, 50);
|
||||||
getdisplay().print("System Information");
|
getdisplay().print("System Information");
|
||||||
|
|
||||||
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
|
getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor);
|
||||||
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
|
||||||
char ssid[23];
|
char ssid[13];
|
||||||
snprintf(ssid, 23, "MCUDEVICE-%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
||||||
getdisplay().setCursor(20, 70);
|
displayBarcode(String(ssid), 320, 200, 2);
|
||||||
getdisplay().print(ssid);
|
getdisplay().setCursor(8, 70);
|
||||||
getdisplay().setCursor(20, 100);
|
getdisplay().print(String("MUDEVICE-") + String(ssid));
|
||||||
getdisplay().print("Press STBY for white page and standby");
|
|
||||||
|
getdisplay().setCursor(8, 90);
|
||||||
|
getdisplay().print("Firmware Version: ");
|
||||||
|
getdisplay().print(VERSINFO);
|
||||||
|
|
||||||
|
getdisplay().setCursor(8, 265);
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
getdisplay().print("Press STBY to enter deep sleep mode");
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
getdisplay().print("Press wheel to enter deep sleep mode");
|
||||||
|
#endif
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0);
|
getdisplay().setCursor(2, y0);
|
||||||
getdisplay().print("Simulation:");
|
getdisplay().print("Simulation:");
|
||||||
getdisplay().setCursor(120, y0);
|
getdisplay().setCursor(120, y0);
|
||||||
getdisplay().print(simulation ? "on" : "off");
|
getdisplay().print(simulation ? "on" : "off");
|
||||||
|
|
||||||
getdisplay().setCursor(202, y0);
|
|
||||||
getdisplay().print("Wifi:");
|
|
||||||
getdisplay().setCursor(300, y0);
|
|
||||||
getdisplay().print(commonData->status.wifiApOn ? "On" : "Off");
|
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 16);
|
getdisplay().setCursor(2, y0 + 16);
|
||||||
getdisplay().print("Environment:");
|
getdisplay().print("Environment:");
|
||||||
getdisplay().setCursor(120, y0 + 16);
|
getdisplay().setCursor(120, y0 + 16);
|
||||||
getdisplay().print(env_module);
|
getdisplay().print(env_module);
|
||||||
|
|
||||||
|
// total RAM free
|
||||||
|
int Heap_free = esp_get_free_heap_size();
|
||||||
|
getdisplay().setCursor(202, y0);
|
||||||
|
getdisplay().print("Total free:");
|
||||||
|
getdisplay().setCursor(300, y0);
|
||||||
|
getdisplay().print(String(Heap_free));
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 32);
|
getdisplay().setCursor(2, y0 + 32);
|
||||||
getdisplay().print("Buzzer:");
|
getdisplay().print("Buzzer:");
|
||||||
getdisplay().setCursor(120, y0 + 32);
|
getdisplay().setCursor(120, y0 + 32);
|
||||||
getdisplay().print(buzzer_mode);
|
getdisplay().print(buzzer_mode);
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 48);
|
// RAM free for task
|
||||||
|
int RAM_free = uxTaskGetStackHighWaterMark(NULL);
|
||||||
|
getdisplay().setCursor(202, y0 + 16);
|
||||||
|
getdisplay().print("Task free:");
|
||||||
|
getdisplay().setCursor(300, y0 + 16);
|
||||||
|
getdisplay().print(String(RAM_free));
|
||||||
|
|
||||||
|
// FRAM available / status
|
||||||
|
getdisplay().setCursor(202, y0 + 32);
|
||||||
|
getdisplay().print("FRAM:");
|
||||||
|
getdisplay().setCursor(300, y0 + 32);
|
||||||
|
getdisplay().print(hasFRAM ? "available" : "not found");
|
||||||
|
|
||||||
|
getdisplay().setCursor(202, y0 + 64);
|
||||||
getdisplay().print("CPU speed:");
|
getdisplay().print("CPU speed:");
|
||||||
getdisplay().setCursor(120, y0 + 48);
|
getdisplay().setCursor(300, y0 + 64);
|
||||||
getdisplay().print(cpuspeed);
|
getdisplay().print(cpuspeed);
|
||||||
getdisplay().print(" / ");
|
getdisplay().print(" / ");
|
||||||
int cpu_freq = esp_clk_cpu_freq() / 1000000;
|
int cpu_freq = esp_clk_cpu_freq() / 1000000;
|
||||||
getdisplay().print(String(cpu_freq));
|
getdisplay().print(String(cpu_freq));
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 64);
|
getdisplay().setCursor(2, y0 + 64);
|
||||||
getdisplay().print("RTC:");
|
|
||||||
getdisplay().setCursor(120, y0 + 64);
|
|
||||||
getdisplay().print(rtc_module);
|
|
||||||
|
|
||||||
getdisplay().setCursor(202, y0 + 64);
|
|
||||||
getdisplay().print("GPS:");
|
getdisplay().print("GPS:");
|
||||||
getdisplay().setCursor(300, y0 + 64);
|
getdisplay().setCursor(120, y0 + 64);
|
||||||
getdisplay().print(gps_module);
|
getdisplay().print(gps_module);
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 80);
|
getdisplay().setCursor(2, y0 + 80);
|
||||||
getdisplay().print("FRAM:");
|
getdisplay().print("RTC:");
|
||||||
getdisplay().setCursor(120, y0 + 80);
|
getdisplay().setCursor(120, y0 + 80);
|
||||||
getdisplay().print(hasFRAM ? "available" : "not found");
|
getdisplay().print(rtc_module);
|
||||||
|
|
||||||
getdisplay().setCursor(2, y0 + 120);
|
getdisplay().setCursor(2, y0 + 96);
|
||||||
getdisplay().print("Firmware Version: ");
|
getdisplay().print("Wifi:");
|
||||||
getdisplay().print(VERSINFO);
|
getdisplay().setCursor(120, y0 + 96);
|
||||||
|
getdisplay().print(commonData->status.wifiApOn ? "On" : "Off");
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -205,6 +205,18 @@ public:
|
||||||
getdisplay().setCursor(20, 100);
|
getdisplay().setCursor(20, 100);
|
||||||
getdisplay().print(name1); // Value name
|
getdisplay().print(name1); // Value name
|
||||||
|
|
||||||
|
#if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
|
||||||
|
// Show charge status
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
getdisplay().setCursor(185, 100);
|
||||||
|
if(commonData->data.BatteryChargeStatus == true){
|
||||||
|
getdisplay().print("Charge");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
getdisplay().print("Discharge");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Show unit
|
// Show unit
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||||
getdisplay().setCursor(270, 100);
|
getdisplay().setCursor(270, 100);
|
||||||
|
@ -213,7 +225,12 @@ public:
|
||||||
// Show battery type
|
// Show battery type
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
getdisplay().setCursor(295, 100);
|
getdisplay().setCursor(295, 100);
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
getdisplay().print(batType);
|
getdisplay().print(batType);
|
||||||
|
#endif
|
||||||
|
#if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR
|
||||||
|
getdisplay().print("LiPo");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Show average settings
|
// Show average settings
|
||||||
printAvg(average, 320, 84, true);
|
printAvg(average, 320, 84, true);
|
||||||
|
|
|
@ -13,6 +13,7 @@ public:
|
||||||
PageWhite(CommonData &common){
|
PageWhite(CommonData &common){
|
||||||
commonData = &common;
|
commonData = &common;
|
||||||
common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite");
|
common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite");
|
||||||
|
refreshtime = 15000;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int handleKey(int key) {
|
virtual int handleKey(int key) {
|
||||||
|
@ -53,7 +54,11 @@ public:
|
||||||
int bgcolor = GxEPD_WHITE;
|
int bgcolor = GxEPD_WHITE;
|
||||||
|
|
||||||
// Set display in partial refresh mode
|
// Set display in partial refresh mode
|
||||||
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
if (mode == 'W') {
|
||||||
|
getdisplay().setFullWindow();
|
||||||
|
} else {
|
||||||
|
getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == 'L') {
|
if (mode == 'L') {
|
||||||
getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
|
getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor);
|
||||||
|
@ -62,7 +67,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update display
|
// Update display
|
||||||
getdisplay().nextPage(); // Partial update (fast)
|
getdisplay().nextPage();
|
||||||
|
if (mode == 'W') {
|
||||||
|
getdisplay().hibernate();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,6 +31,8 @@ typedef struct{
|
||||||
double batteryVoltage300 = 0; // Sliding average over 300 values
|
double batteryVoltage300 = 0; // Sliding average over 300 values
|
||||||
double batteryCurrent300 = 0;
|
double batteryCurrent300 = 0;
|
||||||
double batteryPower300 = 0;
|
double batteryPower300 = 0;
|
||||||
|
double batteryLevelLiPo = 0; // Battery level for OBP40 LiPo accu
|
||||||
|
int BatteryChargeStatus = 0; // LiPo charge status: 0 = discharge, 1 = loading activ
|
||||||
double solarVoltage = 0;
|
double solarVoltage = 0;
|
||||||
double solarCurrent = 0;
|
double solarCurrent = 0;
|
||||||
double solarPower = 0;
|
double solarPower = 0;
|
||||||
|
@ -100,6 +102,7 @@ class Page{
|
||||||
protected:
|
protected:
|
||||||
CommonData *commonData;
|
CommonData *commonData;
|
||||||
public:
|
public:
|
||||||
|
int refreshtime = 1000;
|
||||||
virtual void displayPage(PageData &pageData)=0;
|
virtual void displayPage(PageData &pageData)=0;
|
||||||
virtual void displayNew(PageData &pageData){}
|
virtual void displayNew(PageData &pageData){}
|
||||||
virtual void setupKeys() {
|
virtual void setupKeys() {
|
||||||
|
|
|
@ -609,10 +609,10 @@
|
||||||
"label": "Undervoltage",
|
"label": "Undervoltage",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": "false",
|
"default": "false",
|
||||||
"description": "Switch off device if voltage drops below 9V [on|off]",
|
"description": "Switch off device if LiPo voltage drops below 3.65V [on|off]",
|
||||||
"category": "OBP40 Hardware",
|
"category": "OBP40 Hardware",
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"obp40": "false"
|
"obp40":"true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -913,6 +913,17 @@
|
||||||
"obp40": "true"
|
"obp40": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "systemPage",
|
||||||
|
"label": "System Page",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "false",
|
||||||
|
"description": "Use wheel button for system page or direct deep sleep mode",
|
||||||
|
"category":"OBP40 Pages",
|
||||||
|
"capabilities": {
|
||||||
|
"obp40": "true"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "imageFormat",
|
"name": "imageFormat",
|
||||||
"label": "Screenshot Format",
|
"label": "Screenshot Format",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <NMEA0183.h> // NMEA0183
|
#include <NMEA0183.h> // NMEA0183
|
||||||
#include <NMEA0183Msg.h>
|
#include <NMEA0183Msg.h>
|
||||||
#include <NMEA0183Messages.h>
|
#include <NMEA0183Messages.h>
|
||||||
#include <GxEPD2_BW.h> // GxEPD2 lib for black 6 white E-Ink displays
|
#include <GxEPD2_BW.h> // GxEPD2 lib for b/w E-Ink displays
|
||||||
#include "OBP60Extensions.h" // Functions lib for extension board
|
#include "OBP60Extensions.h" // Functions lib for extension board
|
||||||
#include "OBP60Keypad.h" // Functions for keypad
|
#include "OBP60Keypad.h" // Functions for keypad
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ void OBP60Init(GwApi *api){
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
//String sdcard = config->getConfigItem(config->useSDCard, true)->asString();
|
// String sdcard = config->getConfigItem(config->useSDCard, true)->asString();
|
||||||
String sdcard = "on";
|
String sdcard = "on";
|
||||||
if (sdcard == "on") {
|
if (sdcard == "on") {
|
||||||
SPIClass SD_SPI = SPIClass(HSPI);
|
SPIClass SD_SPI = SPIClass(HSPI);
|
||||||
|
@ -117,6 +117,16 @@ void OBP60Init(GwApi *api){
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
touchSleepWakeUpEnable(TP1, 45); // TODO sensitivity should be configurable via web interface
|
||||||
|
touchSleepWakeUpEnable(TP2, 45);
|
||||||
|
touchSleepWakeUpEnable(TP3, 45);
|
||||||
|
touchSleepWakeUpEnable(TP4, 45);
|
||||||
|
touchSleepWakeUpEnable(TP5, 45);
|
||||||
|
touchSleepWakeUpEnable(TP6, 45);
|
||||||
|
esp_sleep_enable_touchpad_wakeup();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Get CPU speed
|
// Get CPU speed
|
||||||
int freq = getCpuFrequencyMhz();
|
int freq = getCpuFrequencyMhz();
|
||||||
api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
|
api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq);
|
||||||
|
@ -159,6 +169,7 @@ typedef struct {
|
||||||
GwLog* logger = NULL;
|
GwLog* logger = NULL;
|
||||||
// GwApi* api = NULL;
|
// GwApi* api = NULL;
|
||||||
uint sensitivity = 100;
|
uint sensitivity = 100;
|
||||||
|
bool use_syspage = true;
|
||||||
} MyData;
|
} MyData;
|
||||||
|
|
||||||
// Keyboard Task
|
// Keyboard Task
|
||||||
|
@ -170,7 +181,7 @@ void keyboardTask(void *param){
|
||||||
|
|
||||||
// Loop for keyboard task
|
// Loop for keyboard task
|
||||||
while (true){
|
while (true){
|
||||||
keycode = readKeypad(data->logger, data->sensitivity);
|
keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage);
|
||||||
//send a key event
|
//send a key event
|
||||||
if(keycode != 0){
|
if(keycode != 0){
|
||||||
xQueueSend(data->queue, &keycode, 0);
|
xQueueSend(data->queue, &keycode, 0);
|
||||||
|
@ -302,9 +313,36 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
||||||
float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
|
float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat());
|
||||||
float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
|
float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat());
|
||||||
// Read supply voltage
|
// Read supply voltage
|
||||||
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // V = 1/20 * Vin
|
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
|
||||||
actVoltage = actVoltage * vslope + voffset;
|
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40
|
||||||
if(actVoltage < MIN_VOLTAGE){
|
float minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu
|
||||||
|
#else
|
||||||
|
float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60
|
||||||
|
float minVoltage = MIN_VOLTAGE;
|
||||||
|
#endif
|
||||||
|
float corrVoltage = actVoltage * vslope + voffset; // Calibration
|
||||||
|
if(corrVoltage < minVoltage){
|
||||||
|
#if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200
|
||||||
|
// Switch off all power lines
|
||||||
|
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||||
|
setFlashLED(false); // Flash LED Off
|
||||||
|
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
|
||||||
|
// Shutdown EInk display
|
||||||
|
getdisplay().setFullWindow(); // Set full Refresh
|
||||||
|
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
||||||
|
getdisplay().fillScreen(common.bgcolor);// Clear screen
|
||||||
|
getdisplay().setTextColor(common.fgcolor);
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||||
|
getdisplay().setCursor(65, 150);
|
||||||
|
getdisplay().print("Undervoltage");
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
getdisplay().setCursor(65, 175);
|
||||||
|
getdisplay().print("Charge battery and restart");
|
||||||
|
getdisplay().nextPage(); // Partial update
|
||||||
|
getdisplay().powerOff(); // Display power off
|
||||||
|
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
|
||||||
|
setPortPin(OBP_POWER_SD, false); // Power off SD card
|
||||||
|
#else
|
||||||
// Switch off all power lines
|
// Switch off all power lines
|
||||||
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
||||||
setFlashLED(false); // Flash LED Off
|
setFlashLED(false); // Flash LED Off
|
||||||
|
@ -317,8 +355,12 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
||||||
getdisplay().setCursor(65, 150);
|
getdisplay().setCursor(65, 150);
|
||||||
getdisplay().print("Undervoltage");
|
getdisplay().print("Undervoltage");
|
||||||
|
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
||||||
|
getdisplay().setCursor(65, 175);
|
||||||
|
getdisplay().print("To wake up repower system");
|
||||||
getdisplay().nextPage(); // Partial update
|
getdisplay().nextPage(); // Partial update
|
||||||
getdisplay().powerOff(); // Display power off
|
getdisplay().powerOff(); // Display power off
|
||||||
|
#endif
|
||||||
// Stop system
|
// Stop system
|
||||||
while(true){
|
while(true){
|
||||||
esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart).
|
esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart).
|
||||||
|
@ -326,36 +368,6 @@ void underVoltageDetection(GwApi *api, CommonData &common){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOARD_OBP40S3
|
|
||||||
// Deep sleep funktion
|
|
||||||
void deepSleep(CommonData &common){
|
|
||||||
// Switch off all power lines
|
|
||||||
setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off
|
|
||||||
setFlashLED(false); // Flash LED Off
|
|
||||||
buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms
|
|
||||||
// Shutdown EInk display
|
|
||||||
getdisplay().setFullWindow(); // Set full Refresh
|
|
||||||
//getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update
|
|
||||||
getdisplay().fillScreen(common.bgcolor); // Clear screen
|
|
||||||
getdisplay().setTextColor(common.fgcolor);
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold20pt7b);
|
|
||||||
getdisplay().setCursor(85, 150);
|
|
||||||
getdisplay().print("Sleep Mode");
|
|
||||||
getdisplay().setFont(&Ubuntu_Bold8pt7b);
|
|
||||||
getdisplay().setCursor(65, 175);
|
|
||||||
getdisplay().print("For wakeup press wheel and wait 5s");
|
|
||||||
getdisplay().nextPage(); // Partial update
|
|
||||||
getdisplay().powerOff(); // Display power off
|
|
||||||
setPortPin(OBP_POWER_EPD, false); // Power off ePaper display
|
|
||||||
setPortPin(OBP_POWER_SD, false); // Power off SD card
|
|
||||||
// Stop system
|
|
||||||
while(true){
|
|
||||||
esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// OBP60 Task
|
// OBP60 Task
|
||||||
//####################################################################################
|
//####################################################################################
|
||||||
void OBP60Task(GwApi *api){
|
void OBP60Task(GwApi *api){
|
||||||
|
@ -400,6 +412,10 @@ void OBP60Task(GwApi *api){
|
||||||
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
|
bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean();
|
||||||
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
|
String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString();
|
||||||
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
|
uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt());
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
// bool syspage_enabled = config->getBool(config->systemPage);
|
||||||
|
bool syspage_enabled = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DISPLAY_GDEY042T81
|
#ifdef DISPLAY_GDEY042T81
|
||||||
getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
|
getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse
|
||||||
|
@ -440,6 +456,26 @@ void OBP60Task(GwApi *api){
|
||||||
PageStruct pages[MAX_PAGE_NUMBER];
|
PageStruct pages[MAX_PAGE_NUMBER];
|
||||||
// Set start page
|
// Set start page
|
||||||
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
|
int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1;
|
||||||
|
|
||||||
|
LOG_DEBUG(GwLog::LOG,"Checking wakeup...");
|
||||||
|
#ifdef BOARD_OBP60S3
|
||||||
|
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) {
|
||||||
|
LOG_DEBUG(GwLog::LOG,"Wake up by touch pad %d",esp_sleep_get_touchpad_wakeup_status());
|
||||||
|
pageNumber = getLastPage();
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) {
|
||||||
|
LOG_DEBUG(GwLog::LOG,"Wake up by key");
|
||||||
|
pageNumber = getLastPage();
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(GwLog::LOG,"Other wakeup reason");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
LOG_DEBUG(GwLog::LOG,"...done");
|
||||||
|
|
||||||
int lastPage=pageNumber;
|
int lastPage=pageNumber;
|
||||||
|
|
||||||
BoatValueList boatValues; //all the boat values for the api query
|
BoatValueList boatValues; //all the boat values for the api query
|
||||||
|
@ -501,6 +537,9 @@ void OBP60Task(GwApi *api){
|
||||||
allParameters.page0=3;
|
allParameters.page0=3;
|
||||||
allParameters.queue=xQueueCreate(10,sizeof(int));
|
allParameters.queue=xQueueCreate(10,sizeof(int));
|
||||||
allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity);
|
allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity);
|
||||||
|
#ifdef BOARD_OBP40S3
|
||||||
|
allParameters.use_syspage = syspage_enabled;
|
||||||
|
#endif
|
||||||
xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL);
|
xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL);
|
||||||
SharedData *shared=new SharedData(api);
|
SharedData *shared=new SharedData(api);
|
||||||
createSensorTask(shared);
|
createSensorTask(shared);
|
||||||
|
@ -550,8 +589,10 @@ void OBP60Task(GwApi *api){
|
||||||
//####################################################################################
|
//####################################################################################
|
||||||
|
|
||||||
bool systemPage = false;
|
bool systemPage = false;
|
||||||
|
Page *currentPage;
|
||||||
while (true){
|
while (true){
|
||||||
delay(100); // Delay 100ms (loop time)
|
delay(100); // Delay 100ms (loop time)
|
||||||
|
bool keypressed = false;
|
||||||
|
|
||||||
// Undervoltage detection
|
// Undervoltage detection
|
||||||
if(uvoltage == true){
|
if(uvoltage == true){
|
||||||
|
@ -593,12 +634,13 @@ void OBP60Task(GwApi *api){
|
||||||
int keyboardMessage=0;
|
int keyboardMessage=0;
|
||||||
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
|
while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){
|
||||||
LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage);
|
LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage);
|
||||||
|
keypressed = true;
|
||||||
|
|
||||||
Page *currentPage;
|
if (keyboardMessage == 12 and !systemPage) {
|
||||||
if (keyboardMessage == 12) {
|
|
||||||
LOG_DEBUG(GwLog::LOG, "Calling system page");
|
LOG_DEBUG(GwLog::LOG, "Calling system page");
|
||||||
systemPage = true; // System page is out of band
|
systemPage = true; // System page is out of band
|
||||||
syspage->setupKeys();
|
syspage->setupKeys();
|
||||||
|
keyboardMessage = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
currentPage = pages[pageNumber].page;
|
currentPage = pages[pageNumber].page;
|
||||||
|
@ -606,6 +648,7 @@ void OBP60Task(GwApi *api){
|
||||||
// exit system mode with exit key number 1
|
// exit system mode with exit key number 1
|
||||||
systemPage = false;
|
systemPage = false;
|
||||||
currentPage->setupKeys();
|
currentPage->setupKeys();
|
||||||
|
keyboardMessage = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (systemPage) {
|
if (systemPage) {
|
||||||
|
@ -626,7 +669,7 @@ void OBP60Task(GwApi *api){
|
||||||
}
|
}
|
||||||
#ifdef BOARD_OBP40S3
|
#ifdef BOARD_OBP40S3
|
||||||
// #3 Deep sleep mode for OBP40
|
// #3 Deep sleep mode for OBP40
|
||||||
if (keyboardMessage == 3){
|
if ((keyboardMessage == 3) and !syspage_enabled){
|
||||||
deepSleep(commonData);
|
deepSleep(commonData);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -725,9 +768,17 @@ void OBP60Task(GwApi *api){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh display data all 1s
|
// Refresh display data, default all 1s
|
||||||
if(millis() > starttime3 + 1000){
|
currentPage = pages[pageNumber].page;
|
||||||
|
int pagetime = 1000;
|
||||||
|
if ((lastPage == pageNumber) and (!keypressed)) {
|
||||||
|
// same page we use page defined time
|
||||||
|
pagetime = currentPage->refreshtime;
|
||||||
|
}
|
||||||
|
if(millis() > starttime3 + pagetime){
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"Page with refreshtime=%d", pagetime);
|
||||||
starttime3 = millis();
|
starttime3 = millis();
|
||||||
|
|
||||||
//refresh data from api
|
//refresh data from api
|
||||||
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues);
|
||||||
api->getStatus(commonData.status);
|
api->getStatus(commonData.status);
|
||||||
|
@ -749,7 +800,6 @@ void OBP60Task(GwApi *api){
|
||||||
syspage->displayPage(sysparams);
|
syspage->displayPage(sysparams);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Page *currentPage = pages[pageNumber].page;
|
|
||||||
if (currentPage == NULL){
|
if (currentPage == NULL){
|
||||||
LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber);
|
LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber);
|
||||||
// Error handling for missing page
|
// Error handling for missing page
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
#if you want a pio run to only build
|
#if you want a pio run to only build
|
||||||
#your special environments you can set this here
|
#your special environments you can set this here
|
||||||
#by uncommenting the next line
|
#by uncommenting the next line
|
||||||
default_envs = obp60_s3
|
|
||||||
|
default_envs =
|
||||||
|
obp60_s3
|
||||||
|
obp40_s3
|
||||||
|
|
||||||
[env:obp60_s3]
|
[env:obp60_s3]
|
||||||
platform = espressif32@6.8.1
|
platform = espressif32@6.8.1
|
||||||
|
@ -91,6 +94,8 @@ build_flags=
|
||||||
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
-D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib
|
||||||
-D BOARD_OBP40S3 #Board OBP40 V1.0 with ESP32S3 SKU:DIE07300S (CrowPanel 4.2)
|
-D BOARD_OBP40S3 #Board OBP40 V1.0 with ESP32S3 SKU:DIE07300S (CrowPanel 4.2)
|
||||||
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
|
-D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm
|
||||||
|
-D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh
|
||||||
|
-D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors
|
||||||
${env.build_flags}
|
${env.build_flags}
|
||||||
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter
|
||||||
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27
|
||||||
|
|
Loading…
Reference in New Issue